Merge branch 'main' into feature/property-editor-number-placeholder

This commit is contained in:
Niels Lyngsø
2024-05-16 09:05:57 +02:00
committed by GitHub
25 changed files with 276 additions and 78 deletions

View File

@@ -403,7 +403,7 @@ export type CreateUserRequestModel = {
email: string
userName: string
name: string
userGroupIds: Array<string>
userGroupIds: Array<ReferenceByIdModel>
id?: string | null
};
@@ -438,9 +438,9 @@ email: string
userName: string
name: string
languageIsoCode?: string | null
documentStartNodeIds: Array<string>
documentStartNodeIds: Array<ReferenceByIdModel>
hasDocumentRootAccess: boolean
mediaStartNodeIds: Array<string>
mediaStartNodeIds: Array<ReferenceByIdModel>
hasMediaRootAccess: boolean
avatarUrls: Array<string>
languages: Array<string>
@@ -541,11 +541,11 @@ icon?: string | null
};
export type DeleteUserGroupsRequestModel = {
userGroupIds: Array<string>
userGroupIds: Array<ReferenceByIdModel>
};
export type DeleteUsersRequestModel = {
userIds: Array<string>
userIds: Array<ReferenceByIdModel>
};
export type DictionaryItemItemResponseModel = {
@@ -577,7 +577,7 @@ export enum DirectionModel {
}
export type DisableUserRequestModel = {
userIds: Array<string>
userIds: Array<ReferenceByIdModel>
};
export type DocumentBlueprintItemResponseModel = {
@@ -898,7 +898,7 @@ secret: string
};
export type EnableUserRequestModel = {
userIds: Array<string>
userIds: Array<ReferenceByIdModel>
};
export enum EventMessageTypeModel {
@@ -991,6 +991,15 @@ url?: string | null
type?: string | null
};
export enum ImageCropModeModel {
CROP = 'Crop',
MAX = 'Max',
STRETCH = 'Stretch',
PAD = 'Pad',
BOX_PAD = 'BoxPad',
MIN = 'Min'
}
export type ImportDictionaryRequestModel = {
temporaryFile: ReferenceByIdModel
parent?: ReferenceByIdModel | null
@@ -1021,7 +1030,7 @@ export type InviteUserRequestModel = {
email: string
userName: string
name: string
userGroupIds: Array<string>
userGroupIds: Array<ReferenceByIdModel>
id?: string | null
message?: string | null
};
@@ -2268,7 +2277,7 @@ context: string
};
export type UnlockUsersRequestModel = {
userIds: Array<string>
userIds: Array<ReferenceByIdModel>
};
export type UnpublishDocumentRequestModel = {
@@ -2517,19 +2526,19 @@ permissions: Array<DocumentPermissionPresentationModel | UnknownTypePermissionPr
};
export type UpdateUserGroupsOnUserRequestModel = {
userIds: Array<string>
userGroupIds: Array<string>
userIds: Array<ReferenceByIdModel>
userGroupIds: Array<ReferenceByIdModel>
};
export type UpdateUserRequestModel = {
email: string
userName: string
name: string
userGroupIds: Array<string>
userGroupIds: Array<ReferenceByIdModel>
languageIsoCode: string
documentStartNodeIds: Array<string>
documentStartNodeIds: Array<ReferenceByIdModel>
hasDocumentRootAccess: boolean
mediaStartNodeIds: Array<string>
mediaStartNodeIds: Array<ReferenceByIdModel>
hasMediaRootAccess: boolean
};
@@ -2638,12 +2647,12 @@ export type UserResponseModel = {
email: string
userName: string
name: string
userGroupIds: Array<string>
userGroupIds: Array<ReferenceByIdModel>
id: string
languageIsoCode?: string | null
documentStartNodeIds: Array<string>
documentStartNodeIds: Array<ReferenceByIdModel>
hasDocumentRootAccess: boolean
mediaStartNodeIds: Array<string>
mediaStartNodeIds: Array<ReferenceByIdModel>
hasMediaRootAccess: boolean
avatarUrls: Array<string>
state: UserStateModel
@@ -3510,6 +3519,26 @@ tree?: string
}
export type ImagingData = {
payloads: {
GetImagingResizeUrls: {
height?: number
id?: Array<string>
mode?: ImageCropModeModel
width?: number
};
}
responses: {
GetImagingResizeUrls: Array<MediaUrlInfoResponseModel>
}
}
export type IndexerData = {
payloads: {
@@ -5015,12 +5044,12 @@ requestBody?: UpdateUserGroupRequestModel
};
DeleteUserGroupByIdUsers: {
id: string
requestBody?: Array<string>
requestBody?: Array<ReferenceByIdModel>
};
PostUserGroupByIdUsers: {
id: string
requestBody?: Array<string>
requestBody?: Array<ReferenceByIdModel>
};
}

View File

@@ -1,7 +1,7 @@
import type { CancelablePromise } from './core/CancelablePromise';
import { OpenAPI } from './core/OpenAPI';
import { request as __request } from './core/request';
import type { CultureData, DataTypeData, DictionaryData, DocumentBlueprintData, DocumentTypeData, DocumentVersionData, DocumentData, DynamicRootData, HealthCheckData, HelpData, IndexerData, InstallData, LanguageData, LogViewerData, ManifestData, MediaTypeData, MediaData, MemberGroupData, MemberTypeData, MemberData, ModelsBuilderData, ObjectTypesData, OembedData, PackageData, PartialViewData, PreviewData, ProfilingData, PropertyTypeData, PublishedCacheData, RedirectManagementData, RelationTypeData, RelationData, ScriptData, SearcherData, SecurityData, SegmentData, ServerData, StaticFileData, StylesheetData, TagData, TelemetryData, TemplateData, TemporaryFileData, UpgradeData, UserDataData, UserGroupData, UserData, WebhookData } from './models';
import type { CultureData, DataTypeData, DictionaryData, DocumentBlueprintData, DocumentTypeData, DocumentVersionData, DocumentData, DynamicRootData, HealthCheckData, HelpData, ImagingData, IndexerData, InstallData, LanguageData, LogViewerData, ManifestData, MediaTypeData, MediaData, MemberGroupData, MemberTypeData, MemberData, ModelsBuilderData, ObjectTypesData, OembedData, PackageData, PartialViewData, PreviewData, ProfilingData, PropertyTypeData, PublishedCacheData, RedirectManagementData, RelationTypeData, RelationData, ScriptData, SearcherData, SecurityData, SegmentData, ServerData, StaticFileData, StylesheetData, TagData, TelemetryData, TemplateData, TemporaryFileData, UpgradeData, UserDataData, UserGroupData, UserData, WebhookData } from './models';
export class CultureService {
@@ -2917,6 +2917,35 @@ baseUrl
}
export class ImagingService {
/**
* @returns unknown Success
* @throws ApiError
*/
public static getImagingResizeUrls(data: ImagingData['payloads']['GetImagingResizeUrls'] = {}): CancelablePromise<ImagingData['responses']['GetImagingResizeUrls']> {
const {
id,
height,
width,
mode
} = data;
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/imaging/resize/urls',
query: {
id, height, width, mode
},
errors: {
401: `The resource is protected and requires an authentication token`,
403: `The authenticated user do not have access to this resource`,
},
});
}
}
export class IndexerService {
/**

View File

@@ -1,3 +1,4 @@
import { queryFilter } from '../utils.js';
import { UmbEntityMockDbBase } from '../utils/entity/entity-base.js';
import { UmbMockEntityDetailManager } from '../utils/entity/entity-detail.manager.js';
import { UmbMockEntityItemManager } from '../utils/entity/entity-item.manager.js';
@@ -6,12 +7,22 @@ import { data } from './user-group.data.js';
import type {
CreateUserGroupRequestModel,
DocumentPermissionPresentationModel,
PagedUserGroupResponseModel,
UnknownTypePermissionPresentationModel,
UserGroupItemResponseModel,
UserGroupResponseModel,
} from '@umbraco-cms/backoffice/external/backend-api';
import { UmbId } from '@umbraco-cms/backoffice/id';
interface UserGroupFilterOptions {
skip: number;
take: number;
filter: string;
}
const userGroupQueryFilter = (filterOptions: UserGroupFilterOptions, item: UmbMockUserGroupModel) =>
queryFilter(filterOptions.filter, item.name);
export class UmbUserGroupMockDB extends UmbEntityMockDbBase<UmbMockUserGroupModel> {
item = new UmbMockEntityItemManager<UmbMockUserGroupModel>(this, itemMapper);
detail = new UmbMockEntityDetailManager<UmbMockUserGroupModel>(this, createMockMapper, detailResponseMapper);
@@ -27,10 +38,10 @@ export class UmbUserGroupMockDB extends UmbEntityMockDbBase<UmbMockUserGroupMode
* @memberof UmbUserGroupData
*/
getPermissions(
userGroupIds: string[],
userGroupIds: Array<{ id: string }>,
): Array<DocumentPermissionPresentationModel | UnknownTypePermissionPresentationModel> {
const permissions = this.data
.filter((userGroup) => userGroupIds.includes(userGroup.id))
.filter((userGroup) => userGroupIds.map((reference) => reference.id).includes(userGroup.id))
.map((userGroup) => (userGroup.permissions?.length ? userGroup.permissions : []))
.flat();
@@ -39,15 +50,32 @@ export class UmbUserGroupMockDB extends UmbEntityMockDbBase<UmbMockUserGroupMode
return uniqueArray;
}
getAllowedSections(userGroupIds: string[]): string[] {
getAllowedSections(userGroupIds: Array<{ id: string }>): string[] {
const sections = this.data
.filter((userGroup) => userGroupIds.includes(userGroup.id))
.filter((userGroup) => userGroupIds.map((reference) => reference.id).includes(userGroup.id))
.map((userGroup) => (userGroup.sections?.length ? userGroup.sections : []))
.flat();
// Remove duplicates
return Array.from(new Set(sections));
}
filter(options: UserGroupFilterOptions): PagedUserGroupResponseModel {
const allItems = this.getAll();
const filterOptions: UserGroupFilterOptions = {
skip: options.skip || 0,
take: options.take || 25,
filter: options.filter,
};
const filteredItems = allItems.filter((item) => userGroupQueryFilter(filterOptions, item));
const totalItems = filteredItems.length;
const paginatedItems = filteredItems.slice(filterOptions.skip, filterOptions.skip + filterOptions.take);
return { total: totalItems, items: paginatedItems };
}
}
const itemMapper = (item: UmbMockUserGroupModel): UserGroupItemResponseModel => {

View File

@@ -24,16 +24,16 @@ export const data: Array<UmbMockUserModel> = [
updateDate: '2/10/2022',
createDate: '3/13/2022',
failedLoginAttempts: 946,
userGroupIds: ['user-group-administrators-id', 'user-group-editors-id'],
userGroupIds: [{ id: 'user-group-administrators-id' }, { id: 'user-group-editors-id' }],
userName: '',
avatarUrls: [],
isAdmin: true,
},
{
id: '82e11d3d-b91d-43c9-9071-34d28e62e81d',
documentStartNodeIds: ['simple-document-id'],
documentStartNodeIds: [{ id: 'simple-document-id' }],
hasDocumentRootAccess: true,
mediaStartNodeIds: ['f2f81a40-c989-4b6b-84e2-057cecd3adc1'],
mediaStartNodeIds: [{ id: 'f2f81a40-c989-4b6b-84e2-057cecd3adc1' }],
hasMediaRootAccess: true,
name: 'Amelie Walker',
email: 'awalker1@domain.com',
@@ -45,7 +45,7 @@ export const data: Array<UmbMockUserModel> = [
updateDate: '2023-10-12T18:30:32.879Z',
createDate: '2023-10-12T18:30:32.879Z',
failedLoginAttempts: 0,
userGroupIds: ['user-group-administrators-id'],
userGroupIds: [{ id: 'user-group-administrators-id' }],
userName: '',
avatarUrls: [],
isAdmin: true,
@@ -66,7 +66,7 @@ export const data: Array<UmbMockUserModel> = [
updateDate: '2023-10-12T18:30:32.879Z',
createDate: '2023-10-12T18:30:32.879Z',
failedLoginAttempts: 0,
userGroupIds: ['user-group-editors-id'],
userGroupIds: [{ id: 'user-group-editors-id' }],
userName: '',
avatarUrls: [],
isAdmin: false,
@@ -87,7 +87,7 @@ export const data: Array<UmbMockUserModel> = [
updateDate: '2023-10-12T18:30:32.879Z',
createDate: '2023-10-12T18:30:32.879Z',
failedLoginAttempts: 0,
userGroupIds: ['user-group-editors-id'],
userGroupIds: [{ id: 'user-group-editors-id' }],
userName: '',
avatarUrls: [],
isAdmin: false,
@@ -108,7 +108,7 @@ export const data: Array<UmbMockUserModel> = [
updateDate: '2023-10-12T18:30:32.879Z',
createDate: '2023-10-12T18:30:32.879Z',
failedLoginAttempts: 25,
userGroupIds: ['user-group-editors-id', 'user-group-sensitive-data-id'],
userGroupIds: [{ id: 'user-group-editors-id' }, { id: 'user-group-sensitive-data-id' }],
userName: '',
avatarUrls: [],
isAdmin: false,

View File

@@ -1,5 +1,5 @@
import { umbUserGroupMockDb } from '../user-group/user-group.db.js';
import { arrayFilter, stringFilter, queryFilter } from '../utils.js';
import { arrayFilter, stringFilter, queryFilter, objectArrayFilter } from '../utils.js';
import { UmbEntityMockDbBase } from '../utils/entity/entity-base.js';
import { UmbMockEntityItemManager } from '../utils/entity/entity-item.manager.js';
import { UmbMockEntityDetailManager } from '../utils/entity/entity-detail.manager.js';
@@ -17,11 +17,22 @@ import type {
} from '@umbraco-cms/backoffice/external/backend-api';
import { UserStateModel } from '@umbraco-cms/backoffice/external/backend-api';
const userGroupFilter = (filterOptions: any, item: UmbMockUserModel) =>
arrayFilter(filterOptions.userGroupIds, item.userGroupIds);
const userStateFilter = (filterOptions: any, item: UmbMockUserModel) =>
interface UserFilterOptions {
skip: number;
take: number;
orderBy: string;
orderDirection: string;
userGroupIds: Array<{ id: string }>;
userStates: Array<string>;
filter: string;
}
const userGroupFilter = (filterOptions: UserFilterOptions, item: UmbMockUserModel) =>
objectArrayFilter(filterOptions.userGroupIds, item.userGroupIds, 'id');
const userStateFilter = (filterOptions: UserFilterOptions, item: UmbMockUserModel) =>
stringFilter(filterOptions.userStates, item.state);
const userQueryFilter = (filterOptions: any, item: UmbMockUserModel) => queryFilter(filterOptions.filter, item.name);
const userQueryFilter = (filterOptions: UserFilterOptions, item: UmbMockUserModel) =>
queryFilter(filterOptions.filter, item.name);
// Temp mocked database
class UmbUserMockDB extends UmbEntityMockDbBase<UmbMockUserModel> {
@@ -38,7 +49,8 @@ class UmbUserMockDB extends UmbEntityMockDbBase<UmbMockUserModel> {
* @memberof UmbUserData
*/
setUserGroups(data: UpdateUserGroupsOnUserRequestModel): void {
const users = this.data.filter((user) => data.userIds?.includes(user.id ?? ''));
const users = this.data.filter((user) => data.userIds?.map((reference) => reference.id).includes(user.id));
users.forEach((user) => {
user.userGroupIds = data.userGroupIds;
});
@@ -154,10 +166,10 @@ class UmbUserMockDB extends UmbEntityMockDbBase<UmbMockUserModel> {
return { userId: newUserId };
}
filter(options: any): PagedUserResponseModel {
filter(options: UserFilterOptions): PagedUserResponseModel {
const allItems = this.getAll();
const filterOptions = {
const filterOptions: UserFilterOptions = {
skip: options.skip || 0,
take: options.take || 25,
orderBy: options.orderBy || 'name',
@@ -209,7 +221,7 @@ const createMockMapper = (item: CreateUserRequestModel): UmbMockUserModel => {
lastLoginDate: null,
lastLockoutDate: null,
lastPasswordChangeDate: null,
isAdmin: item.userGroupIds.includes(umbUserGroupMockDb.getAll()[0].id),
isAdmin: item.userGroupIds.map((reference) => reference.id).includes(umbUserGroupMockDb.getAll()[0].id),
};
};

View File

@@ -7,11 +7,20 @@ export const arrayFilter = (filterBy: Array<string>, value?: Array<string>): boo
return filterBy.some((filterValue: string) => value?.includes(filterValue));
};
export const objectArrayFilter = (filterBy: Array<any>, value: Array<any>, key: string): boolean => {
if (!filterBy || !value) {
return true;
}
return value.map((value) => value[key]).some((value: any) => filterBy.includes(value));
};
export const stringFilter = (filterBy: Array<string>, value?: string): boolean => {
// if a filter is not set, return all items
if (!filterBy || !value) {
return true;
}
return filterBy.includes(value);
};

View File

@@ -0,0 +1,21 @@
const { rest } = window.MockServiceWorker;
import { umbUserGroupMockDb } from '../../data/user-group/user-group.db.js';
import { UMB_SLUG } from './slug.js';
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
export const handlers = [
rest.get(umbracoPath(`/filter${UMB_SLUG}`), (req, res, ctx) => {
const skip = Number(req.url.searchParams.get('skip'));
const take = Number(req.url.searchParams.get('take'));
const filter = req.url.searchParams.get('filter');
const options: any = {
skip: skip || undefined,
take: take || undefined,
filter: filter || undefined,
};
const response = umbUserGroupMockDb.filter(options);
return res(ctx.status(200), ctx.json(response));
}),
];

View File

@@ -1,4 +1,5 @@
import { detailHandlers } from './detail.handlers.js';
import { itemHandlers } from './item.handlers.js';
import { handlers as filterHandlers } from './filter.handlers.js';
export const handlers = [...itemHandlers, ...detailHandlers];
export const handlers = [...itemHandlers, ...filterHandlers, ...detailHandlers];

View File

@@ -13,7 +13,7 @@ export const handlers = [
const userStates = req.url.searchParams.getAll('userStates');
const filter = req.url.searchParams.get('filter');
const options = {
const options: any = {
skip: skip || undefined,
take: take || undefined,
orderBy: orderBy || undefined,

View File

@@ -32,7 +32,11 @@ export class UmbCurrentUserServerDataSource {
const user: UmbCurrentUserModel = {
allowedSections: data.allowedSections,
avatarUrls: data.avatarUrls,
documentStartNodeUniques: data.documentStartNodeIds,
documentStartNodeUniques: data.documentStartNodeIds.map((node) => {
return {
unique: node.id,
};
}),
email: data.email,
fallbackPermissions: data.fallbackPermissions,
hasAccessToAllLanguages: data.hasAccessToAllLanguages,
@@ -41,7 +45,11 @@ export class UmbCurrentUserServerDataSource {
isAdmin: data.isAdmin,
languageIsoCode: data.languageIsoCode || 'en-us', // TODO: make global variable
languages: data.languages,
mediaStartNodeUniques: data.mediaStartNodeIds,
mediaStartNodeUniques: data.mediaStartNodeIds.map((node) => {
return {
unique: node.id,
};
}),
name: data.name,
permissions: data.permissions,
unique: data.id,

View File

@@ -5,11 +5,12 @@ import type {
UnknownTypePermissionPresentationModel,
UserTwoFactorProviderModel,
} from '@umbraco-cms/backoffice/external/backend-api';
import type { UmbReferenceByUnique } from '@umbraco-cms/backoffice/models';
export interface UmbCurrentUserModel {
allowedSections: Array<string>;
avatarUrls: Array<string>;
documentStartNodeUniques: Array<string>;
documentStartNodeUniques: Array<UmbReferenceByUnique>;
email: string;
fallbackPermissions: Array<string>;
hasAccessToAllLanguages: boolean;
@@ -18,7 +19,7 @@ export interface UmbCurrentUserModel {
isAdmin: boolean;
languageIsoCode: string;
languages: Array<string>;
mediaStartNodeUniques: Array<string>;
mediaStartNodeUniques: Array<UmbReferenceByUnique>;
name: string;
permissions: Array<DocumentPermissionPresentationModel | UnknownTypePermissionPresentationModel>;
unique: string;

View File

@@ -59,11 +59,23 @@ export class UmbUserCollectionServerDataSource implements UmbCollectionDataSourc
email: item.email,
userName: item.userName,
name: item.name,
userGroupUniques: item.userGroupIds,
userGroupUniques: item.userGroupIds.map((reference) => {
return {
unique: reference.id,
};
}),
unique: item.id,
languageIsoCode: item.languageIsoCode || null,
documentStartNodeUniques: item.documentStartNodeIds,
mediaStartNodeUniques: item.mediaStartNodeIds,
documentStartNodeUniques: item.documentStartNodeIds.map((node) => {
return {
unique: node.id,
};
}),
mediaStartNodeUniques: item.mediaStartNodeIds.map((node) => {
return {
unique: node.id,
};
}),
hasDocumentRootAccess: item.hasDocumentRootAccess,
hasMediaRootAccess: item.hasMediaRootAccess,
avatarUrls: item.avatarUrls,

View File

@@ -137,7 +137,7 @@ export class UmbUserGridCollectionViewElement extends UmbLitElement {
#renderUserGroupNames(user: UmbUserDetailModel) {
const userGroupNames = this.#userGroups
.filter((userGroup) => user.userGroupUniques?.includes(userGroup.unique))
.filter((userGroup) => user.userGroupUniques?.map((reference) => reference.unique).includes(userGroup.unique))
.map((userGroup) => userGroup.name)
.join(', ');

View File

@@ -15,6 +15,7 @@ import { UMB_COLLECTION_CONTEXT } from '@umbraco-cms/backoffice/collection';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbUserGroupItemModel } from '@umbraco-cms/backoffice/user-group';
import { UmbUserGroupItemRepository } from '@umbraco-cms/backoffice/user-group';
import type { UmbReferenceByUnique } from '@umbraco-cms/backoffice/models';
import './column-layouts/name/user-table-name-column-layout.element.js';
import './column-layouts/status/user-table-status-column-layout.element.js';
@@ -87,7 +88,9 @@ export class UmbUserTableCollectionViewElement extends UmbLitElement {
async #observeUserGroups() {
if (this._users.length === 0) return;
const userGroupsUniques = [...new Set(this._users.flatMap((user) => user.userGroupUniques))];
const userGroupsUniques = [
...new Set(this._users.flatMap((user) => user.userGroupUniques.map((reference) => reference.unique))),
];
const { asObservable } = await this.#userGroupItemRepository.requestItems(userGroupsUniques);
this.observe(
asObservable(),
@@ -99,10 +102,10 @@ export class UmbUserTableCollectionViewElement extends UmbLitElement {
);
}
#getUserGroupNames(uniques: Array<string>) {
return uniques
.map((unique: string) => {
return this._userGroupItems.find((x) => x.unique === unique)?.name;
#getUserGroupNames(references: Array<UmbReferenceByUnique>) {
return references
.map((reference) => {
return this._userGroupItems.find((x) => x.unique === reference.unique)?.name;
})
.join(', ');
}

View File

@@ -3,6 +3,7 @@ import { UmbInviteUserRepository } from '../../repository/invite-user.repository
import { css, html, customElement } from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
import type { UmbReferenceByUnique } from '@umbraco-cms/backoffice/models';
@customElement('umb-invite-user-modal')
export class UmbInviteUserModalElement extends UmbModalBaseElement {
@@ -24,7 +25,9 @@ export class UmbInviteUserModalElement extends UmbModalBaseElement {
//TODO: How should we handle pickers forms?
const userGroupPicker = form.querySelector('#userGroups') as UmbUserGroupInputElement;
const userGroupUniques = userGroupPicker?.selection;
const userGroupUniques: Array<UmbReferenceByUnique> = userGroupPicker?.selection.map((unique) => {
return { unique };
});
const message = formData.get('message') as string;

View File

@@ -35,7 +35,9 @@ export class UmbInviteUserServerDataSource implements UmbInviteUserDataSource {
email: request.email,
userName: request.userName,
name: request.name,
userGroupIds: request.userGroupUniques,
userGroupIds: request.userGroupUniques.map((reference) => {
return { id: reference.unique };
}),
message: request.message,
};

View File

@@ -1,4 +1,5 @@
import type { UmbUserDetailModel } from '../../types.js';
import type { UmbReferenceByUnique } from '@umbraco-cms/backoffice/models';
import type { UmbDataSourceResponse, UmbDataSourceErrorResponse } from '@umbraco-cms/backoffice/repository';
export interface UmbInviteUserDataSource {
@@ -10,7 +11,7 @@ export interface UmbInviteUserRequestModel {
email: string;
userName: string;
name: string;
userGroupUniques: Array<string>;
userGroupUniques: Array<UmbReferenceByUnique>;
message: string | null;
}

View File

@@ -4,6 +4,7 @@ import type { UmbUserGroupInputElement } from '@umbraco-cms/backoffice/user-grou
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, customElement, query } from '@umbraco-cms/backoffice/external/lit';
import { UmbModalBaseElement, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import type { UmbReferenceByUnique } from '@umbraco-cms/backoffice/models';
@customElement('umb-create-user-modal')
export class UmbCreateUserModalElement extends UmbModalBaseElement {
@@ -27,7 +28,9 @@ export class UmbCreateUserModalElement extends UmbModalBaseElement {
const email = formData.get('email') as string;
const userGroupPicker = form.querySelector('#userGroups') as UmbUserGroupInputElement;
const userGroups = userGroupPicker?.selection;
const userGroupReferences: Array<UmbReferenceByUnique> = userGroupPicker?.selection.map((unique) => {
return { unique };
});
const { data: userScaffold } = await this.#userDetailRepository.createScaffold();
if (!userScaffold) return;
@@ -35,7 +38,7 @@ export class UmbCreateUserModalElement extends UmbModalBaseElement {
userScaffold.name = name;
userScaffold.email = email;
userScaffold.userName = email;
userScaffold.userGroupUniques = userGroups;
userScaffold.userGroupUniques = userGroupReferences;
// TODO: figure out when to use email or username
const { data } = await this.#userDetailRepository.create(userScaffold);

View File

@@ -78,7 +78,11 @@ export class UmbUserServerDataSource implements UmbDetailDataSource<UmbUserDetai
avatarUrls: data.avatarUrls,
createDate: data.createDate,
hasDocumentRootAccess: data.hasDocumentRootAccess,
documentStartNodeUniques: data.documentStartNodeIds,
documentStartNodeUniques: data.documentStartNodeIds.map((node) => {
return {
unique: node.id,
};
}),
email: data.email,
entityType: UMB_USER_ENTITY_TYPE,
failedLoginAttempts: data.failedLoginAttempts,
@@ -88,12 +92,20 @@ export class UmbUserServerDataSource implements UmbDetailDataSource<UmbUserDetai
lastLoginDate: data.lastLoginDate || null,
lastPasswordChangeDate: data.lastPasswordChangeDate || null,
hasMediaRootAccess: data.hasMediaRootAccess,
mediaStartNodeUniques: data.mediaStartNodeIds,
mediaStartNodeUniques: data.mediaStartNodeIds.map((node) => {
return {
unique: node.id,
};
}),
name: data.name,
state: data.state,
unique: data.id,
updateDate: data.updateDate,
userGroupUniques: data.userGroupIds,
userGroupUniques: data.userGroupIds.map((reference) => {
return {
unique: reference.id,
};
}),
userName: data.userName,
};
@@ -113,7 +125,11 @@ export class UmbUserServerDataSource implements UmbDetailDataSource<UmbUserDetai
const requestBody: CreateUserRequestModel = {
email: model.email,
name: model.name,
userGroupIds: model.userGroupUniques,
userGroupIds: model.userGroupUniques.map((reference) => {
return {
id: reference.unique,
};
}),
userName: model.userName,
};
@@ -142,14 +158,26 @@ export class UmbUserServerDataSource implements UmbDetailDataSource<UmbUserDetai
// TODO: make data mapper to prevent errors
const requestBody: UpdateUserRequestModel = {
documentStartNodeIds: model.documentStartNodeUniques,
documentStartNodeIds: model.documentStartNodeUniques.map((node) => {
return {
id: node.unique,
};
}),
email: model.email,
hasDocumentRootAccess: model.hasDocumentRootAccess,
hasMediaRootAccess: model.hasMediaRootAccess,
languageIsoCode: model.languageIsoCode || '',
mediaStartNodeIds: model.mediaStartNodeUniques,
mediaStartNodeIds: model.mediaStartNodeUniques.map((node) => {
return {
id: node.unique,
};
}),
name: model.name,
userGroupIds: model.userGroupUniques,
userGroupIds: model.userGroupUniques.map((reference) => {
return {
id: reference.unique,
};
}),
userName: model.userName,
};

View File

@@ -33,7 +33,7 @@ export class UmbDisableUserServerDataSource implements UmbDisableUserDataSource
this.#host,
UserService.postUserDisable({
requestBody: {
userIds,
userIds: userIds.map((id) => ({ id })),
},
}),
);

View File

@@ -33,7 +33,7 @@ export class UmbEnableUserServerDataSource implements UmbEnableUserDataSource {
this.#host,
UserService.postUserEnable({
requestBody: {
userIds,
userIds: userIds.map((id) => ({ id })),
},
}),
);

View File

@@ -33,8 +33,8 @@ export class UmbUserSetGroupsServerDataSource {
this.#host,
UserService.postUserSetUserGroups({
requestBody: {
userIds,
userGroupIds,
userIds: userIds.map((id) => ({ id })),
userGroupIds: userGroupIds.map((id) => ({ id })),
},
}),
);

View File

@@ -33,7 +33,7 @@ export class UmbUnlockUserServerDataSource implements UmbUnlockUserDataSource {
this.#host,
UserService.postUserUnlock({
requestBody: {
userIds,
userIds: userIds.map((id) => ({ id })),
},
}),
);

View File

@@ -1,4 +1,5 @@
import type { UmbUserEntityType } from './entity.js';
import type { UmbReferenceByUnique } from '@umbraco-cms/backoffice/models';
import { UserStateModel, type UserTwoFactorProviderModel } from '@umbraco-cms/backoffice/external/backend-api';
export type UmbUserStateEnum = UserStateModel;
@@ -7,7 +8,7 @@ export const UmbUserStateEnum = UserStateModel;
export interface UmbUserDetailModel {
avatarUrls: Array<string>;
createDate: string | null;
documentStartNodeUniques: Array<string>;
documentStartNodeUniques: Array<UmbReferenceByUnique>;
email: string;
entityType: UmbUserEntityType;
failedLoginAttempts: number;
@@ -18,12 +19,12 @@ export interface UmbUserDetailModel {
lastLockoutDate: string | null;
lastLoginDate: string | null;
lastPasswordChangeDate: string | null;
mediaStartNodeUniques: Array<string>;
mediaStartNodeUniques: Array<UmbReferenceByUnique>;
name: string;
state: UmbUserStateEnum | null;
unique: string;
updateDate: string | null;
userGroupUniques: Array<string>;
userGroupUniques: Array<UmbReferenceByUnique>;
userName: string;
}

View File

@@ -7,6 +7,7 @@ import type { UmbInputDocumentElement } from '@umbraco-cms/backoffice/document';
import type { UmbInputMediaElement } from '@umbraco-cms/backoffice/media';
import type { UmbUserGroupInputElement } from '@umbraco-cms/backoffice/user-group';
import type { UUIBooleanInputEvent } from '@umbraco-cms/backoffice/external/uui';
import type { UmbReferenceByUnique } from '@umbraco-cms/backoffice/models';
const elementName = 'umb-user-workspace-assign-access';
@customElement(elementName)
@@ -69,7 +70,9 @@ export class UmbUserWorkspaceAssignAccessElement extends UmbLitElement {
#onUserGroupsChange(event: CustomEvent) {
event.stopPropagation();
const target = event.target as UmbUserGroupInputElement;
const selection = target.selection;
const selection: Array<UmbReferenceByUnique> = target.selection.map((unique) => {
return { unique };
});
// TODO make contexts method
this.#workspaceContext?.updateProperty('userGroupUniques', selection);
}
@@ -85,7 +88,9 @@ export class UmbUserWorkspaceAssignAccessElement extends UmbLitElement {
#onDocumentStartNodeChange(event: CustomEvent) {
event.stopPropagation();
const target = event.target as UmbInputDocumentElement;
const selection = target.selection;
const selection: Array<UmbReferenceByUnique> = target.selection.map((unique) => {
return { unique };
});
// TODO make contexts method
this.#workspaceContext?.updateProperty('documentStartNodeUniques', selection);
}
@@ -101,7 +106,9 @@ export class UmbUserWorkspaceAssignAccessElement extends UmbLitElement {
#onMediaStartNodeChange(event: CustomEvent) {
event.stopPropagation();
const target = event.target as UmbInputMediaElement;
const selection = target.selection;
const selection: Array<UmbReferenceByUnique> = target.selection.map((unique) => {
return { unique };
});
// TODO make contexts method
this.#workspaceContext?.updateProperty('mediaStartNodeUniques', selection);
}