diff --git a/src/Umbraco.Web.UI.Client/src/assets/lang/en-us.ts b/src/Umbraco.Web.UI.Client/src/assets/lang/en-us.ts index 626e399b24..9933826ee2 100644 --- a/src/Umbraco.Web.UI.Client/src/assets/lang/en-us.ts +++ b/src/Umbraco.Web.UI.Client/src/assets/lang/en-us.ts @@ -1440,31 +1440,30 @@ export default { insertDesc: 'Choose what to insert into your template', insertDictionaryItem: 'Dictionary item', insertDictionaryItemDesc: - 'A dictionary item is a placeholder for a translatable piece of text, which\n makes it easy to create designs for multilingual websites.\n ', + 'A dictionary item is a placeholder for a translatable piece of text, which makes it easy to create designs for multilingual websites.', insertMacro: 'Macro', insertMacroDesc: - '\n A Macro is a configurable component which is great for\n reusable parts of your design, where you need the option to provide parameters,\n such as galleries, forms and lists.\n ', + 'A Macro is a configurable component which is great for reusable parts of your design, where you need the option to provide parameters, such as galleries, forms and lists.', insertPageField: 'Value', insertPageFieldDesc: - 'Displays the value of a named field from the current page, with options to modify\n the value or fallback to alternative values.\n ', + 'Displays the value of a named field from the current page, with options to modify the value or fallback to alternative values.', insertPartialView: 'Partial view', insertPartialViewDesc: - "\n A partial view is a separate template file which can be rendered inside another\n template, it's great for reusing markup or for separating complex templates into separate files.\n ", + "A partial view is a separate template file which can be rendered inside another template, it's great for reusing markup or for separating complex templates into separate files.", mastertemplate: 'Master template', noMaster: 'No master', renderBody: 'Render child template', - renderBodyDesc: - '\n Renders the contents of a child template, by inserting a\n @RenderBody() placeholder.\n ', + renderBodyDesc: 'Renders the contents of a child template, by inserting a @RenderBody() placeholder.', defineSection: 'Define a named section', defineSectionDesc: - '\n Defines a part of your template as a named section by wrapping it in\n @section { ... }. This can be rendered in a\n specific area of the parent of this template, by using @RenderSection.\n ', + 'Defines a part of your template as a named section by wrapping it in @section { ... }. This can be rendered in a specific area of the parent of this template, by using @RenderSection.', renderSection: 'Render a named section', renderSectionDesc: - '\n Renders a named area of a child template, by inserting a @RenderSection(name) placeholder.\n This renders an area of a child template which is wrapped in a corresponding @section [name]{ ... } definition.\n ', + 'Renders a named area of a child template, by inserting a @RenderSection(name) placeholder. This renders an area of a child template which is wrapped in a corresponding @section [name]{ ... } definition.', sectionName: 'Section Name', sectionMandatory: 'Section is mandatory', sectionMandatoryDesc: - '\n If mandatory, the child template must contain a @section definition, otherwise an error is shown.\n ', + 'If mandatory, the child template must contain a @section definition, otherwise an error is shown.', queryBuilder: 'Query builder', itemsReturned: 'items returned, in', iWant: 'I want', diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/ContentCollectionResponseModelBaseDocumentValueModelDocumentVariantResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/ContentCollectionResponseModelBaseDocumentValueModelDocumentVariantResponseModel.ts index ca88835f92..c3a8073181 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/ContentCollectionResponseModelBaseDocumentValueModelDocumentVariantResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/ContentCollectionResponseModelBaseDocumentValueModelDocumentVariantResponseModel.ts @@ -13,3 +13,4 @@ export type ContentCollectionResponseModelBaseDocumentValueModelDocumentVariantR creator?: string | null; sortOrder: number; }; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/ContentCollectionResponseModelBaseMediaValueModelMediaVariantResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/ContentCollectionResponseModelBaseMediaValueModelMediaVariantResponseModel.ts index 5c6313d652..b9da60ae41 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/ContentCollectionResponseModelBaseMediaValueModelMediaVariantResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/ContentCollectionResponseModelBaseMediaValueModelMediaVariantResponseModel.ts @@ -13,3 +13,4 @@ export type ContentCollectionResponseModelBaseMediaValueModelMediaVariantRespons creator?: string | null; sortOrder: number; }; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/ContentTypeCollectionReferenceResponseModelBaseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/ContentTypeCollectionReferenceResponseModelBaseModel.ts index b0f98e2348..26866fcb40 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/ContentTypeCollectionReferenceResponseModelBaseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/ContentTypeCollectionReferenceResponseModelBaseModel.ts @@ -8,3 +8,4 @@ export type ContentTypeCollectionReferenceResponseModelBaseModel = { alias: string; icon: string; }; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DocumentCollectionResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DocumentCollectionResponseModel.ts index 67a94b519b..49b0b794b6 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DocumentCollectionResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DocumentCollectionResponseModel.ts @@ -7,6 +7,7 @@ import type { ContentCollectionResponseModelBaseDocumentValueModelDocumentVarian import type { DocumentTypeCollectionReferenceResponseModel } from './DocumentTypeCollectionReferenceResponseModel'; export type DocumentCollectionResponseModel = (ContentCollectionResponseModelBaseDocumentValueModelDocumentVariantResponseModel & { -documentType: DocumentTypeCollectionReferenceResponseModel; -updater?: string | null; + documentType: DocumentTypeCollectionReferenceResponseModel; + updater?: string | null; }); + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DocumentTypeCollectionReferenceResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DocumentTypeCollectionReferenceResponseModel.ts index b83f57600b..b934c7618f 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DocumentTypeCollectionReferenceResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DocumentTypeCollectionReferenceResponseModel.ts @@ -6,3 +6,4 @@ import type { ContentTypeCollectionReferenceResponseModelBaseModel } from './ContentTypeCollectionReferenceResponseModelBaseModel'; export type DocumentTypeCollectionReferenceResponseModel = ContentTypeCollectionReferenceResponseModelBaseModel; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MediaCollectionResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MediaCollectionResponseModel.ts index 4091844770..a28f2123e6 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MediaCollectionResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MediaCollectionResponseModel.ts @@ -7,5 +7,6 @@ import type { ContentCollectionResponseModelBaseMediaValueModelMediaVariantRespo import type { MediaTypeCollectionReferenceResponseModel } from './MediaTypeCollectionReferenceResponseModel'; export type MediaCollectionResponseModel = (ContentCollectionResponseModelBaseMediaValueModelMediaVariantResponseModel & { -mediaType: MediaTypeCollectionReferenceResponseModel; + mediaType: MediaTypeCollectionReferenceResponseModel; }); + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MediaTypeCollectionReferenceResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MediaTypeCollectionReferenceResponseModel.ts index 47e72b36dc..fa9d9718fb 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MediaTypeCollectionReferenceResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MediaTypeCollectionReferenceResponseModel.ts @@ -6,3 +6,4 @@ import type { ContentTypeCollectionReferenceResponseModelBaseModel } from './ContentTypeCollectionReferenceResponseModelBaseModel'; export type MediaTypeCollectionReferenceResponseModel = ContentTypeCollectionReferenceResponseModelBaseModel; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedDocumentCollectionResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedDocumentCollectionResponseModel.ts index 42732a99cf..b3b1a29bed 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedDocumentCollectionResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedDocumentCollectionResponseModel.ts @@ -9,3 +9,4 @@ export type PagedDocumentCollectionResponseModel = { total: number; items: Array; }; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedMediaCollectionResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedMediaCollectionResponseModel.ts index 3b7673ae7c..3859caa0cb 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedMediaCollectionResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedMediaCollectionResponseModel.ts @@ -9,3 +9,4 @@ export type PagedMediaCollectionResponseModel = { total: number; items: Array; }; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/DocumentResource.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/DocumentResource.ts index 0bc1f4c525..dab44ef423 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/DocumentResource.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/DocumentResource.ts @@ -34,24 +34,24 @@ export class DocumentResource { * @throws ApiError */ public static getCollectionDocumentById({ -id, -dataTypeId, -orderBy = 'updateDate', -orderCulture, -orderDirection, -filter, -skip, -take = 100, -}: { -id: string, -dataTypeId?: string, -orderBy?: string, -orderCulture?: string, -orderDirection?: DirectionModel, -filter?: string, -skip?: number, -take?: number, -}): CancelablePromise { + id, + dataTypeId, + orderBy = 'updateDate', + orderCulture, + orderDirection, + filter, + skip, + take = 100, + }: { + id: string, + dataTypeId?: string, + orderBy?: string, + orderCulture?: string, + orderDirection?: DirectionModel, + filter?: string, + skip?: number, + take?: number, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/collection/document/{id}', @@ -80,10 +80,10 @@ take?: number, * @throws ApiError */ public static postDocument({ -requestBody, -}: { -requestBody?: CreateDocumentRequestModel, -}): CancelablePromise { + requestBody, + }: { + requestBody?: CreateDocumentRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'POST', url: '/umbraco/management/api/v1/document', @@ -104,10 +104,10 @@ requestBody?: CreateDocumentRequestModel, * @throws ApiError */ public static getDocumentById({ -id, -}: { -id: string, -}): CancelablePromise { + id, + }: { + id: string, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/document/{id}', @@ -127,10 +127,10 @@ id: string, * @throws ApiError */ public static deleteDocumentById({ -id, -}: { -id: string, -}): CancelablePromise { + id, + }: { + id: string, + }): CancelablePromise { return __request(OpenAPI, { method: 'DELETE', url: '/umbraco/management/api/v1/document/{id}', @@ -151,12 +151,12 @@ id: string, * @throws ApiError */ public static putDocumentById({ -id, -requestBody, -}: { -id: string, -requestBody?: UpdateDocumentRequestModel, -}): CancelablePromise { + id, + requestBody, + }: { + id: string, + requestBody?: UpdateDocumentRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', url: '/umbraco/management/api/v1/document/{id}', @@ -179,12 +179,12 @@ requestBody?: UpdateDocumentRequestModel, * @throws ApiError */ public static postDocumentByIdCopy({ -id, -requestBody, -}: { -id: string, -requestBody?: CopyDocumentRequestModel, -}): CancelablePromise { + id, + requestBody, + }: { + id: string, + requestBody?: CopyDocumentRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'POST', url: '/umbraco/management/api/v1/document/{id}/copy', @@ -207,10 +207,10 @@ requestBody?: CopyDocumentRequestModel, * @throws ApiError */ public static getDocumentByIdDomains({ -id, -}: { -id: string, -}): CancelablePromise { + id, + }: { + id: string, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/document/{id}/domains', @@ -229,12 +229,12 @@ id: string, * @throws ApiError */ public static putDocumentByIdDomains({ -id, -requestBody, -}: { -id: string, -requestBody?: UpdateDomainsRequestModel, -}): CancelablePromise { + id, + requestBody, + }: { + id: string, + requestBody?: UpdateDomainsRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', url: '/umbraco/management/api/v1/document/{id}/domains', @@ -254,12 +254,12 @@ requestBody?: UpdateDomainsRequestModel, * @throws ApiError */ public static putDocumentByIdMove({ -id, -requestBody, -}: { -id: string, -requestBody?: MoveDocumentRequestModel, -}): CancelablePromise { + id, + requestBody, + }: { + id: string, + requestBody?: MoveDocumentRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', url: '/umbraco/management/api/v1/document/{id}/move', @@ -281,10 +281,10 @@ requestBody?: MoveDocumentRequestModel, * @throws ApiError */ public static putDocumentByIdMoveToRecycleBin({ -id, -}: { -id: string, -}): CancelablePromise { + id, + }: { + id: string, + }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', url: '/umbraco/management/api/v1/document/{id}/move-to-recycle-bin', @@ -305,10 +305,10 @@ id: string, * @throws ApiError */ public static getDocumentByIdNotifications({ -id, -}: { -id: string, -}): CancelablePromise> { + id, + }: { + id: string, + }): CancelablePromise> { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/document/{id}/notifications', @@ -328,12 +328,12 @@ id: string, * @throws ApiError */ public static putDocumentByIdNotifications({ -id, -requestBody, -}: { -id: string, -requestBody?: UpdateDocumentNotificationsRequestModel, -}): CancelablePromise { + id, + requestBody, + }: { + id: string, + requestBody?: UpdateDocumentNotificationsRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', url: '/umbraco/management/api/v1/document/{id}/notifications', @@ -354,12 +354,12 @@ requestBody?: UpdateDocumentNotificationsRequestModel, * @throws ApiError */ public static postDocumentByIdPublicAccess({ -id, -requestBody, -}: { -id: string, -requestBody?: PublicAccessRequestModel, -}): CancelablePromise { + id, + requestBody, + }: { + id: string, + requestBody?: PublicAccessRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'POST', url: '/umbraco/management/api/v1/document/{id}/public-access', @@ -382,10 +382,10 @@ requestBody?: PublicAccessRequestModel, * @throws ApiError */ public static deleteDocumentByIdPublicAccess({ -id, -}: { -id: string, -}): CancelablePromise { + id, + }: { + id: string, + }): CancelablePromise { return __request(OpenAPI, { method: 'DELETE', url: '/umbraco/management/api/v1/document/{id}/public-access', @@ -401,14 +401,14 @@ id: string, } /** - * @returns void + * @returns void * @throws ApiError */ public static getDocumentByIdPublicAccess({ -id, -}: { -id: string, -}): CancelablePromise { + id, + }: { + id: string, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/document/{id}/public-access', @@ -428,12 +428,12 @@ id: string, * @throws ApiError */ public static putDocumentByIdPublicAccess({ -id, -requestBody, -}: { -id: string, -requestBody?: PublicAccessRequestModel, -}): CancelablePromise { + id, + requestBody, + }: { + id: string, + requestBody?: PublicAccessRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', url: '/umbraco/management/api/v1/document/{id}/public-access', @@ -455,12 +455,12 @@ requestBody?: PublicAccessRequestModel, * @throws ApiError */ public static putDocumentByIdPublish({ -id, -requestBody, -}: { -id: string, -requestBody?: (PublishDocumentRequestModel | PublishDocumentWithDescendantsRequestModel), -}): CancelablePromise { + id, + requestBody, + }: { + id: string, + requestBody?: (PublishDocumentRequestModel | PublishDocumentWithDescendantsRequestModel), + }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', url: '/umbraco/management/api/v1/document/{id}/publish', @@ -483,12 +483,12 @@ requestBody?: (PublishDocumentRequestModel | PublishDocumentWithDescendantsReque * @throws ApiError */ public static putDocumentByIdPublishWithDescendants({ -id, -requestBody, -}: { -id: string, -requestBody?: PublishDocumentWithDescendantsRequestModel, -}): CancelablePromise { + id, + requestBody, + }: { + id: string, + requestBody?: PublishDocumentWithDescendantsRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', url: '/umbraco/management/api/v1/document/{id}/publish-with-descendants', @@ -511,12 +511,12 @@ requestBody?: PublishDocumentWithDescendantsRequestModel, * @throws ApiError */ public static putDocumentByIdUnpublish({ -id, -requestBody, -}: { -id: string, -requestBody?: UnpublishDocumentRequestModel, -}): CancelablePromise { + id, + requestBody, + }: { + id: string, + requestBody?: UnpublishDocumentRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', url: '/umbraco/management/api/v1/document/{id}/unpublish', @@ -539,12 +539,12 @@ requestBody?: UnpublishDocumentRequestModel, * @throws ApiError */ public static putDocumentByIdValidate({ -id, -requestBody, -}: { -id: string, -requestBody?: UpdateDocumentRequestModel, -}): CancelablePromise { + id, + requestBody, + }: { + id: string, + requestBody?: UpdateDocumentRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', url: '/umbraco/management/api/v1/document/{id}/validate', @@ -581,10 +581,10 @@ requestBody?: UpdateDocumentRequestModel, * @throws ApiError */ public static putDocumentSort({ -requestBody, -}: { -requestBody?: SortingRequestModel, -}): CancelablePromise { + requestBody, + }: { + requestBody?: SortingRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', url: '/umbraco/management/api/v1/document/sort', @@ -604,10 +604,10 @@ requestBody?: SortingRequestModel, * @throws ApiError */ public static postDocumentValidate({ -requestBody, -}: { -requestBody?: CreateDocumentRequestModel, -}): CancelablePromise { + requestBody, + }: { + requestBody?: CreateDocumentRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'POST', url: '/umbraco/management/api/v1/document/validate', @@ -627,10 +627,10 @@ requestBody?: CreateDocumentRequestModel, * @throws ApiError */ public static getItemDocument({ -id, -}: { -id?: Array, -}): CancelablePromise> { + id, + }: { + id?: Array, + }): CancelablePromise> { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/item/document', @@ -664,10 +664,10 @@ id?: Array, * @throws ApiError */ public static deleteRecycleBinDocumentById({ -id, -}: { -id: string, -}): CancelablePromise { + id, + }: { + id: string, + }): CancelablePromise { return __request(OpenAPI, { method: 'DELETE', url: '/umbraco/management/api/v1/recycle-bin/document/{id}', @@ -688,14 +688,14 @@ id: string, * @throws ApiError */ public static getRecycleBinDocumentChildren({ -parentId, -skip, -take = 100, -}: { -parentId?: string, -skip?: number, -take?: number, -}): CancelablePromise { + parentId, + skip, + take = 100, + }: { + parentId?: string, + skip?: number, + take?: number, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/recycle-bin/document/children', @@ -715,12 +715,12 @@ take?: number, * @throws ApiError */ public static getRecycleBinDocumentRoot({ -skip, -take = 100, -}: { -skip?: number, -take?: number, -}): CancelablePromise { + skip, + take = 100, + }: { + skip?: number, + take?: number, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/recycle-bin/document/root', @@ -739,16 +739,16 @@ take?: number, * @throws ApiError */ public static getTreeDocumentChildren({ -parentId, -skip, -take = 100, -dataTypeId, -}: { -parentId?: string, -skip?: number, -take?: number, -dataTypeId?: string, -}): CancelablePromise { + parentId, + skip, + take = 100, + dataTypeId, + }: { + parentId?: string, + skip?: number, + take?: number, + dataTypeId?: string, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/tree/document/children', @@ -769,14 +769,14 @@ dataTypeId?: string, * @throws ApiError */ public static getTreeDocumentRoot({ -skip, -take = 100, -dataTypeId, -}: { -skip?: number, -take?: number, -dataTypeId?: string, -}): CancelablePromise { + skip, + take = 100, + dataTypeId, + }: { + skip?: number, + take?: number, + dataTypeId?: string, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/tree/document/root', diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/MediaResource.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/MediaResource.ts index 1b6a420a62..bbfb4abc63 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/MediaResource.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/MediaResource.ts @@ -25,22 +25,22 @@ export class MediaResource { * @throws ApiError */ public static getCollectionMedia({ -id, -dataTypeId, -orderBy = 'updateDate', -orderDirection, -filter, -skip, -take = 100, -}: { -id?: string, -dataTypeId?: string, -orderBy?: string, -orderDirection?: DirectionModel, -filter?: string, -skip?: number, -take?: number, -}): CancelablePromise { + id, + dataTypeId, + orderBy = 'updateDate', + orderDirection, + filter, + skip, + take = 100, + }: { + id?: string, + dataTypeId?: string, + orderBy?: string, + orderDirection?: DirectionModel, + filter?: string, + skip?: number, + take?: number, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/collection/media', @@ -66,10 +66,10 @@ take?: number, * @throws ApiError */ public static getItemMedia({ -id, -}: { -id?: Array, -}): CancelablePromise> { + id, + }: { + id?: Array, + }): CancelablePromise> { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/item/media', @@ -87,10 +87,10 @@ id?: Array, * @throws ApiError */ public static postMedia({ -requestBody, -}: { -requestBody?: CreateMediaRequestModel, -}): CancelablePromise { + requestBody, + }: { + requestBody?: CreateMediaRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'POST', url: '/umbraco/management/api/v1/media', @@ -111,10 +111,10 @@ requestBody?: CreateMediaRequestModel, * @throws ApiError */ public static getMediaById({ -id, -}: { -id: string, -}): CancelablePromise { + id, + }: { + id: string, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/media/{id}', @@ -134,10 +134,10 @@ id: string, * @throws ApiError */ public static deleteMediaById({ -id, -}: { -id: string, -}): CancelablePromise { + id, + }: { + id: string, + }): CancelablePromise { return __request(OpenAPI, { method: 'DELETE', url: '/umbraco/management/api/v1/media/{id}', @@ -158,12 +158,12 @@ id: string, * @throws ApiError */ public static putMediaById({ -id, -requestBody, -}: { -id: string, -requestBody?: UpdateMediaRequestModel, -}): CancelablePromise { + id, + requestBody, + }: { + id: string, + requestBody?: UpdateMediaRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', url: '/umbraco/management/api/v1/media/{id}', @@ -186,12 +186,12 @@ requestBody?: UpdateMediaRequestModel, * @throws ApiError */ public static putMediaByIdMove({ -id, -requestBody, -}: { -id: string, -requestBody?: MoveMediaRequestModel, -}): CancelablePromise { + id, + requestBody, + }: { + id: string, + requestBody?: MoveMediaRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', url: '/umbraco/management/api/v1/media/{id}/move', @@ -213,10 +213,10 @@ requestBody?: MoveMediaRequestModel, * @throws ApiError */ public static putMediaByIdMoveToRecycleBin({ -id, -}: { -id: string, -}): CancelablePromise { + id, + }: { + id: string, + }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', url: '/umbraco/management/api/v1/media/{id}/move-to-recycle-bin', @@ -237,12 +237,12 @@ id: string, * @throws ApiError */ public static putMediaByIdValidate({ -id, -requestBody, -}: { -id: string, -requestBody?: UpdateMediaRequestModel, -}): CancelablePromise { + id, + requestBody, + }: { + id: string, + requestBody?: UpdateMediaRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', url: '/umbraco/management/api/v1/media/{id}/validate', @@ -279,10 +279,10 @@ requestBody?: UpdateMediaRequestModel, * @throws ApiError */ public static putMediaSort({ -requestBody, -}: { -requestBody?: SortingRequestModel, -}): CancelablePromise { + requestBody, + }: { + requestBody?: SortingRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', url: '/umbraco/management/api/v1/media/sort', @@ -302,10 +302,10 @@ requestBody?: SortingRequestModel, * @throws ApiError */ public static postMediaValidate({ -requestBody, -}: { -requestBody?: CreateMediaRequestModel, -}): CancelablePromise { + requestBody, + }: { + requestBody?: CreateMediaRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'POST', url: '/umbraco/management/api/v1/media/validate', @@ -341,10 +341,10 @@ requestBody?: CreateMediaRequestModel, * @throws ApiError */ public static deleteRecycleBinMediaById({ -id, -}: { -id: string, -}): CancelablePromise { + id, + }: { + id: string, + }): CancelablePromise { return __request(OpenAPI, { method: 'DELETE', url: '/umbraco/management/api/v1/recycle-bin/media/{id}', @@ -365,14 +365,14 @@ id: string, * @throws ApiError */ public static getRecycleBinMediaChildren({ -parentId, -skip, -take = 100, -}: { -parentId?: string, -skip?: number, -take?: number, -}): CancelablePromise { + parentId, + skip, + take = 100, + }: { + parentId?: string, + skip?: number, + take?: number, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/recycle-bin/media/children', @@ -392,12 +392,12 @@ take?: number, * @throws ApiError */ public static getRecycleBinMediaRoot({ -skip, -take = 100, -}: { -skip?: number, -take?: number, -}): CancelablePromise { + skip, + take = 100, + }: { + skip?: number, + take?: number, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/recycle-bin/media/root', @@ -416,16 +416,16 @@ take?: number, * @throws ApiError */ public static getTreeMediaChildren({ -parentId, -skip, -take = 100, -dataTypeId, -}: { -parentId?: string, -skip?: number, -take?: number, -dataTypeId?: string, -}): CancelablePromise { + parentId, + skip, + take = 100, + dataTypeId, + }: { + parentId?: string, + skip?: number, + take?: number, + dataTypeId?: string, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/tree/media/children', @@ -446,14 +446,14 @@ dataTypeId?: string, * @throws ApiError */ public static getTreeMediaRoot({ -skip, -take = 100, -dataTypeId, -}: { -skip?: number, -take?: number, -dataTypeId?: string, -}): CancelablePromise { + skip, + take = 100, + dataTypeId, + }: { + skip?: number, + take?: number, + dataTypeId?: string, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/tree/media/root', diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/TemplateResource.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/TemplateResource.ts index d6446c671f..e323315a8b 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/TemplateResource.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/TemplateResource.ts @@ -23,10 +23,10 @@ export class TemplateResource { * @throws ApiError */ public static getItemTemplate({ -id, -}: { -id?: Array, -}): CancelablePromise> { + id, + }: { + id?: Array, + }): CancelablePromise> { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/item/template', @@ -44,10 +44,10 @@ id?: Array, * @throws ApiError */ public static postTemplate({ -requestBody, -}: { -requestBody?: CreateTemplateRequestModel, -}): CancelablePromise { + requestBody, + }: { + requestBody?: CreateTemplateRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'POST', url: '/umbraco/management/api/v1/template', @@ -67,10 +67,10 @@ requestBody?: CreateTemplateRequestModel, * @throws ApiError */ public static getTemplateById({ -id, -}: { -id: string, -}): CancelablePromise { + id, + }: { + id: string, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/template/{id}', @@ -89,10 +89,10 @@ id: string, * @throws ApiError */ public static deleteTemplateById({ -id, -}: { -id: string, -}): CancelablePromise { + id, + }: { + id: string, + }): CancelablePromise { return __request(OpenAPI, { method: 'DELETE', url: '/umbraco/management/api/v1/template/{id}', @@ -112,12 +112,12 @@ id: string, * @throws ApiError */ public static putTemplateById({ -id, -requestBody, -}: { -id: string, -requestBody?: UpdateTemplateRequestModel, -}): CancelablePromise { + id, + requestBody, + }: { + id: string, + requestBody?: UpdateTemplateRequestModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'PUT', url: '/umbraco/management/api/v1/template/{id}', @@ -153,10 +153,10 @@ requestBody?: UpdateTemplateRequestModel, * @throws ApiError */ public static postTemplateQueryExecute({ -requestBody, -}: { -requestBody?: TemplateQueryExecuteModel, -}): CancelablePromise { + requestBody, + }: { + requestBody?: TemplateQueryExecuteModel, + }): CancelablePromise { return __request(OpenAPI, { method: 'POST', url: '/umbraco/management/api/v1/template/query/execute', @@ -187,14 +187,14 @@ requestBody?: TemplateQueryExecuteModel, * @throws ApiError */ public static getTreeTemplateChildren({ -parentId, -skip, -take = 100, -}: { -parentId?: string, -skip?: number, -take?: number, -}): CancelablePromise { + parentId, + skip, + take = 100, + }: { + parentId?: string, + skip?: number, + take?: number, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/tree/template/children', @@ -214,12 +214,12 @@ take?: number, * @throws ApiError */ public static getTreeTemplateRoot({ -skip, -take = 100, -}: { -skip?: number, -take?: number, -}): CancelablePromise { + skip, + take = 100, + }: { + skip?: number, + take?: number, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/tree/template/root', diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/document-type/document-type.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/document-type/document-type.data.ts index 69f61a87d9..b6ee696086 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/document-type/document-type.data.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/document-type/document-type.data.ts @@ -1017,6 +1017,46 @@ export const data: Array = [ labelOnTop: false, }, }, + { + id: 'a92de6ac-1a22-4a45-a481-b6cae1cccbba', + container: { id: '2e845ca8-1e3e-4b03-be1d-0b4149ce2120' }, + alias: 'alchemyElement', + name: 'Alchemy Element', + description: null, + dataType: { id: '0cc0eba1-9960-42c9-bf9b-60e150b429ae' }, + variesByCulture: false, + variesBySegment: false, + sortOrder: 0, + validation: { + mandatory: false, + mandatoryMessage: null, + regEx: null, + regExMessage: null, + }, + appearance: { + labelOnTop: false, + }, + }, + { + id: 'c92de6ac-1a22-4a45-a481-b6cae1cccbba', + container: { id: '2e845ca8-1e3e-4b03-be1d-0b4149ce2120' }, + alias: 'acidScale', + name: 'Acid Scale', + description: null, + dataType: { id: '0cc0eba1-9960-42c9-bf9b-60e150b429ae' }, + variesByCulture: false, + variesBySegment: false, + sortOrder: 0, + validation: { + mandatory: false, + mandatoryMessage: null, + regEx: null, + regExMessage: null, + }, + appearance: { + labelOnTop: false, + }, + }, ], containers: [ { @@ -1026,6 +1066,13 @@ export const data: Array = [ type: 'Group', sortOrder: 0, }, + { + id: '2e845ca8-1e3e-4b03-be1d-0b4149ce2120', + parent: null, + name: 'Alchemy', + type: 'Group', + sortOrder: 0, + }, ], allowedDocumentTypes: [], compositions: [], diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/token/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/token/index.ts index 7e03e7451b..8d49914d48 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/token/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/token/index.ts @@ -22,5 +22,4 @@ export * from './property-editor-ui-picker-modal.token.js'; export * from './property-settings-modal.token.js'; export * from './section-picker-modal.token.js'; export * from './template-picker-modal.token.js'; -export * from './partial-view-picker-modal.token.js'; export * from './workspace-modal.token.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/token/partial-view-picker-modal.token.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/token/partial-view-picker-modal.token.ts deleted file mode 100644 index 993eaa58cc..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/token/partial-view-picker-modal.token.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { UmbModalToken } from './modal-token.js'; - -export interface UmbPartialViewPickerModalData { - multiple: boolean; - selection: string[]; -} - -export interface UmbPartialViewPickerModalValue { - selection: Array | undefined; -} - -export const UMB_PARTIAL_VIEW_PICKER_MODAL_ALIAS = 'Umb.Modal.PartialViewPicker'; - -export const UMB_PARTIAL_VIEW_PICKER_MODAL = new UmbModalToken< - UmbPartialViewPickerModalData, - UmbPartialViewPickerModalValue ->(UMB_PARTIAL_VIEW_PICKER_MODAL_ALIAS, { - modal: { - type: 'sidebar', - size: 'small', - }, -}); diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/components/input-document-type/input-document-type.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/components/input-document-type/input-document-type.element.ts index aac219c253..bf6219a855 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/components/input-document-type/input-document-type.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/components/input-document-type/input-document-type.element.ts @@ -84,6 +84,9 @@ export class UmbInputDocumentTypeElement extends FormControlMixin(UmbLitElement) // Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection. this.selectedIds = splitStringToArray(idsString); } + public get value(): string { + return this.selectedIds.join(','); + } @state() private _items?: Array; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts index 02999e503d..1627991063 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts @@ -1,60 +1,79 @@ import type { UmbDocumentTypeWorkspaceContext } from '../../document-type-workspace.context.js'; import './document-type-workspace-view-edit-property.element.js'; import type { UmbDocumentTypeDetailModel } from '../../../types.js'; +import type { UmbDocumentTypeWorkspacePropertyElement } from './document-type-workspace-view-edit-property.element.js'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { css, html, customElement, property, state, repeat, ifDefined } from '@umbraco-cms/backoffice/external/lit'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import type { UmbPropertyContainerTypes, UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type'; import { UmbContentTypePropertyStructureHelper } from '@umbraco-cms/backoffice/content-type'; -import type { UmbSorterConfig } from '@umbraco-cms/backoffice/sorter'; import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; -import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UMB_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace'; import { UMB_PROPERTY_SETTINGS_MODAL, UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal'; -const SORTER_CONFIG: UmbSorterConfig = { - getUniqueOfElement: (element) => { - return element.getAttribute('data-umb-property-id'); - }, - getUniqueOfModel: (modelEntry) => { - return modelEntry.id; - }, - identifier: 'content-type-property-sorter', - itemSelector: '[data-umb-property-id]', - disabledItemSelector: '[inherited]', - containerSelector: '#property-list', -}; - @customElement('umb-document-type-workspace-view-edit-properties') export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitElement { - #propertySorter = new UmbSorterController(this, { - ...SORTER_CONFIG, - performItemInsert: (args) => { - let sortOrder = 0; - if (this._propertyStructure.length > 0) { - if (args.newIndex === 0) { - sortOrder = (this._propertyStructure[0].sortOrder ?? 0) - 1; - } else { - sortOrder = - (this._propertyStructure[Math.min(args.newIndex, this._propertyStructure.length - 1)].sortOrder ?? 0) + 1; - } - } - return this._propertyStructureHelper.insertProperty(args.item, sortOrder); + #model: Array = []; + #sorter = new UmbSorterController(this, { + getUniqueOfElement: (element) => { + return element.getAttribute('data-umb-property-id'); }, - performItemRemove: (args) => { - return this._propertyStructureHelper.removeProperty(args.item.id!); + getUniqueOfModel: (modelEntry) => { + return modelEntry.id; }, - performItemMove: (args) => { - this._propertyStructureHelper.removeProperty(args.item.id!); - let sortOrder = 0; - if (this._propertyStructure.length > 0) { - if (args.newIndex === 0) { - sortOrder = (this._propertyStructure[0].sortOrder ?? 0) - 1; - } else { - sortOrder = - (this._propertyStructure[Math.min(args.newIndex, this._propertyStructure.length - 1)].sortOrder ?? 0) + 1; - } + identifier: 'document-type-property-sorter', + itemSelector: 'umb-document-type-workspace-view-edit-property', + //disabledItemSelector: '[inherited]', + //TODO: Set the property list (sorter wrapper) to inherited, if its inherited + // This is because we don't want to move local properties into an inherited group container. + // Or maybe we do, but we still need to check if the group exists locally, if not, then it needs to be created before we move a property into it. + // TODO: Fix bug where a local property turn into an inherited when moved to a new group container. + containerSelector: '#property-list', + onChange: ({ item, model }) => { + this.#model = model; + this._propertyStructure = model; + }, + onEnd: ({ item }) => { + /** Explanation: If the item is the first in list, we compare it to the item behind it to set a sortOrder. + * If it's not the first in list, we will compare to the item in before it, and check the following item to see if it caused overlapping sortOrder, then update + * the overlap if true, which may cause another overlap, so we loop through them till no more overlaps... + */ + const model = this.#model; + const newIndex = model.findIndex((entry) => entry.id === item.id); + + // Doesn't exist in model + if (newIndex === -1) return; + + // First in list + if (newIndex === 0 && model.length > 1) { + this._propertyStructureHelper.partialUpdateProperty(item.id, { + sortOrder: model[1].sortOrder - 1, + container: this._containerId ? { id: this._containerId } : null, + }); + return; + } + + // Not first in list + if (newIndex > 0 && model.length > 1) { + const prevItemSortOrder = model[newIndex - 1].sortOrder; + + let weight = 1; + this._propertyStructureHelper.partialUpdateProperty(item.id, { + sortOrder: prevItemSortOrder + weight, + container: this._containerId ? { id: this._containerId } : null, + }); + + // Check for overlaps + model.some((entry, index) => { + if (index <= newIndex) return; + if (entry.sortOrder === prevItemSortOrder + weight) { + weight++; + this._propertyStructureHelper.partialUpdateProperty(entry.id, { sortOrder: prevItemSortOrder + weight }); + } + // Break the loop + return true; + }); } - return this._propertyStructureHelper.insertProperty(args.item, sortOrder); }, }); @@ -112,7 +131,11 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle (workspaceContext as UmbDocumentTypeWorkspaceContext).isSorting, (isSorting) => { this._sortModeActive = isSorting; - this.#setModel(isSorting); + if (isSorting) { + this.#sorter.setModel(this._propertyStructure); + } else { + this.#sorter.setModel([]); + } }, '_observeIsSorting', ); @@ -128,6 +151,11 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle }); this.observe(this._propertyStructureHelper.propertyStructure, (propertyStructure) => { this._propertyStructure = propertyStructure; + if (this._sortModeActive) { + this.#sorter.setModel(this._propertyStructure); + } else { + this.#sorter.setModel([]); + } }); // Note: Route for adding a new property @@ -153,15 +181,6 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle }); } - #setModel(isSorting?: boolean) { - if (isSorting) { - this.#propertySorter.setModel(this._propertyStructure); - } else { - // TODO: Make a more proper way to disable sorting: - this.#propertySorter.setModel([]); - } - } - async #addProperty(propertyData: UmbPropertyTypeModel) { const propertyPlaceholder = await this._propertyStructureHelper.addProperty(this._containerId); if (!propertyPlaceholder) return; @@ -170,33 +189,37 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle } render() { - return html`
+ return html` +
${repeat( this._propertyStructure, - (property) => property.id ?? '' + property.container?.id ?? '' + property.sortOrder ?? '', + (property) => '' + property.container?.id + property.id + '' + property.sortOrder, (property) => { // Note: This piece might be moved into the property component const inheritedFromDocument = this._ownerDocumentTypes?.find( (types) => types.containers?.find((containers) => containers.id === property.container?.id), ); - return html` { - this._propertyStructureHelper.partialUpdateProperty(property.id, event.detail); - }} - @property-delete=${() => { - this._propertyStructureHelper.removeProperty(property.id!); - }}> - `; + return html` + { + this._propertyStructureHelper.partialUpdateProperty(property.id, event.detail); + }} + @property-delete=${() => { + this._propertyStructureHelper.removeProperty(property.id!); + }}> + + `; }, )}
+ ${!this._sortModeActive ? html` Add property ` - : ''} `; + : ''} + `; } static styles = [ @@ -214,6 +238,11 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle #add { width: 100%; } + + #property-list[sort-mode-active]:not(:has(umb-document-type-workspace-view-edit-property)) { + /* Some height so that the sorter can target the area if the group is empty*/ + min-height: var(--uui-size-layout-1); + } `, ]; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts index 27112c4e49..b9e219b200 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts @@ -186,7 +186,6 @@ export class UmbDocumentTypeWorkspacePropertyElement extends UmbLitElement { } } } - renderSortableProperty() { if (!this.property) return; return html` @@ -198,6 +197,8 @@ export class UmbDocumentTypeWorkspacePropertyElement extends UmbLitElement { type="number" ?readonly=${this.inherited} label="sort order" + @change=${(e: UUIInputEvent) => + this._partialUpdate({ sortOrder: parseInt(e.target.value as string) || 0 } as UmbPropertyTypeModel)} .value=${this.property.sortOrder ?? 0}> `; } @@ -476,6 +477,13 @@ export class UmbDocumentTypeWorkspacePropertyElement extends UmbLitElement { a { color: inherit; } + + :host([drag-placeholder]) { + opacity: 0.5; + } + :host([drag-placeholder]) uui-input { + visibility: hidden; + } `, ]; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-tab.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-tab.element.ts index 0c18b304c6..f16d1512eb 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-tab.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-tab.element.ts @@ -1,58 +1,73 @@ import type { UmbDocumentTypeDetailModel } from '../../../types.js'; import type { UmbDocumentTypeWorkspaceContext } from '../../document-type-workspace.context.js'; +import type { UmbDocumentTypeWorkspaceViewEditPropertiesElement } from './document-type-workspace-view-edit-properties.element.js'; +import type { UUIInputEvent } from '@umbraco-cms/backoffice/external/uui'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { css, html, customElement, property, state, repeat, ifDefined } from '@umbraco-cms/backoffice/external/lit'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import { UmbContentTypeContainerStructureHelper } from '@umbraco-cms/backoffice/content-type'; -import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; -import type { PropertyTypeContainerModelBaseModel } from '@umbraco-cms/backoffice/external/backend-api'; +import { + UmbContentTypeContainerStructureHelper, + type UmbPropertyTypeContainerModel, +} from '@umbraco-cms/backoffice/content-type'; import { UMB_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace'; -import type { UmbSorterConfig } from '@umbraco-cms/backoffice/sorter'; -import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; import './document-type-workspace-view-edit-properties.element.js'; - -const SORTER_CONFIG: UmbSorterConfig = { - getUniqueOfElement: (element) => { - return element.getAttribute('data-umb-group-id'); - }, - getUniqueOfModel: (modelEntry) => { - return modelEntry.id; - }, - identifier: 'content-type-group-sorter', - itemSelector: '[data-umb-group-id]', - disabledItemSelector: '[inherited]', - containerSelector: '#group-list', -}; +import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; @customElement('umb-document-type-workspace-view-edit-tab') export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { - public sorter?: UmbSorterController; + #model: Array = []; + #sorter = new UmbSorterController( + this, + { + getUniqueOfElement: (element) => + element.querySelector('umb-document-type-workspace-view-edit-properties')!.getAttribute('container-id'), + getUniqueOfModel: (modelEntry) => modelEntry.id, + identifier: 'document-type-container-sorter', + itemSelector: '.container-handle', + containerSelector: '.container-list', + onChange: ({ model }) => { + this._groups = model; + this.#model = model; + }, + onEnd: ({ item }) => { + /** Explanation: If the item is the first in list, we compare it to the item behind it to set a sortOrder. + * If it's not the first in list, we will compare to the item in before it, and check the following item to see if it caused overlapping sortOrder, then update + * the overlap if true, which may cause another overlap, so we loop through them till no more overlaps... + */ + const model = this.#model; + const newIndex = model.findIndex((entry) => entry.id === item.id); - config: UmbSorterConfig = { - ...SORTER_CONFIG, - // TODO: Missing handlers to work properly: performItemMove and performItemRemove - performItemInsert: async (args) => { - if (!this._groups) return false; - const oldIndex = this._groups.findIndex((group) => group.id! === args.item.id); - if (args.newIndex === oldIndex) return true; + // Doesn't exist in model + if (newIndex === -1) return; - let sortOrder = 0; - //TODO the sortOrder set is not correct - if (this._groups.length > 0) { - if (args.newIndex === 0) { - sortOrder = (this._groups[0].sortOrder ?? 0) - 1; - } else { - sortOrder = (this._groups[Math.min(args.newIndex, this._groups.length - 1)].sortOrder ?? 0) + 1; + // First in list + if (newIndex === 0 && model.length > 1) { + this._groupStructureHelper.partialUpdateContainer(item.id, { sortOrder: model[1].sortOrder - 1 }); + return; } - if (sortOrder !== args.item.sortOrder) { - await this._groupStructureHelper.partialUpdateContainer(args.item.id!, { sortOrder }); - } - } + // Not first in list + if (newIndex > 0 && model.length > 1) { + const prevItemSortOrder = model[newIndex - 1].sortOrder; - return true; + let weight = 1; + this._groupStructureHelper.partialUpdateContainer(item.id, { sortOrder: prevItemSortOrder + weight }); + + // Check for overlaps + model.some((entry, index) => { + if (index <= newIndex) return; + if (entry.sortOrder === prevItemSortOrder + weight) { + weight++; + this._groupStructureHelper.partialUpdateContainer(entry.id, { sortOrder: prevItemSortOrder + weight }); + } + // Break the loop + return true; + }); + } + }, }, - }; + ); private _ownerTabId?: string | null; @@ -98,7 +113,7 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { _groupStructureHelper = new UmbContentTypeContainerStructureHelper(this); @state() - _groups: Array = []; + _groups: Array = []; @state() _hasProperties = false; @@ -109,18 +124,17 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { constructor() { super(); - this.sorter = new UmbSorterController(this, this.config); - this.consumeContext(UMB_WORKSPACE_CONTEXT, (context) => { this._groupStructureHelper.setStructureManager((context as UmbDocumentTypeWorkspaceContext).structure); this.observe( (context as UmbDocumentTypeWorkspaceContext).isSorting, (isSorting) => { this._sortModeActive = isSorting; + if (isSorting) { - this.sorter?.setModel(this._groups); + this.#sorter.setModel(this._groups); } else { - this.sorter?.setModel([]); + this.#sorter.setModel([]); } }, '_observeIsSorting', @@ -128,6 +142,11 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { }); this.observe(this._groupStructureHelper.containers, (groups) => { this._groups = groups; + if (this._sortModeActive) { + this.#sorter.setModel(this._groups); + } else { + this.#sorter.setModel([]); + } this.requestUpdate('_groups'); }); this.observe(this._groupStructureHelper.hasProperties, (hasProperties) => { @@ -143,7 +162,17 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { render() { return html` - ${!this._noTabName + ${ + this._sortModeActive + ? html`` + : '' + } + + ${ + !this._noTabName ? html` ` - : ''} -
- ${repeat( - this._groups, - (group) => group.id ?? '' + group.name, - (group) => html` - - ${ - this._groupStructureHelper.isOwnerChildContainer(group.id!) - ? html` -
-
- ${this._sortModeActive ? html`` : ''} - - { - const newName = (e.target as HTMLInputElement).value; - this._groupStructureHelper.updateContainerName( - group.id!, - group.parent?.id ?? null, - newName, - ); - }}> - -
- ${this._sortModeActive - ? html`` - : ''} -
- ` - : html`
-
${group.name ?? ''} (Inherited)
- ${!this._sortModeActive - ? html`` - : ''} -
` - } -
- - `, - )} + : '' + } +
+ ${repeat( + this._groups, + (group) => group.id + '' + group.name + group.sortOrder, + (group) => + html` + ${this.#renderHeader(group)} + + `, + )} +
+ ${this.#renderAddGroupButton()}
- ${!this._sortModeActive - ? html` - ${this.localize.term('contentTypeEditor_addGroup')} - ` - : ''} `; } + #renderHeader(group: UmbPropertyTypeContainerModel) { + const inherited = !this._groupStructureHelper.isOwnerChildContainer(group.id!); + + if (this._sortModeActive) { + return html`
+
+ + ${this.#renderInputGroupName(group)} +
+ + this._groupStructureHelper.partialUpdateContainer(group.id!, { + sortOrder: parseInt(e.target.value as string) || 0, + })} + .value=${group.sortOrder || 0} + ?disabled=${inherited}> +
`; + } else { + return html`
+ ${inherited ? html`` : this.#renderInputGroupName(group)} +
`; + } + } + + #renderInputGroupName(group: UmbPropertyTypeContainerModel) { + return html` { + const newName = (e.target as HTMLInputElement).value; + this._groupStructureHelper.updateContainerName(group.id!, group.parent?.id ?? null, newName); + }}>`; + } + + #renderAddGroupButton() { + if (this._sortModeActive) return; + return html` + ${this.localize.term('contentTypeEditor_addGroup')} + `; + } + static styles = [ UmbTextStyles, css` + [drag-placeholder] { + opacity: 0.5; + } + + [drag-placeholder] > * { + visibility: hidden; + } + #add { width: 100%; } @@ -226,6 +268,7 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { #add:first-child { margin-top: var(--uui-size-layout-1); } + uui-box { margin-bottom: var(--uui-size-layout-1); } @@ -236,6 +279,7 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { } div[slot='header'] { + flex: 1; display: flex; align-items: center; justify-content: space-between; @@ -251,20 +295,18 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { max-width: 75px; } - .sorting { + [sort-mode-active] div[slot='header'] { cursor: grab; } - .--umb-sorter-placeholder > uui-box { - visibility: hidden; + .container-list { + display: grid; + gap: 10px; } - .--umb-sorter-placeholder::after { - content: ''; - inset: 0; - position: absolute; - border-radius: var(--uui-border-radius); - border: 1px dashed var(--uui-color-divider-emphasis); + #convert-to-tab { + margin-bottom: var(--uui-size-layout-1); + display: flex; } `, ]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit.element.ts index 24123dcebd..494e6d5596 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit.element.ts @@ -3,7 +3,7 @@ import type { UmbDocumentTypeWorkspaceContext } from '../../document-type-worksp import type { UmbDocumentTypeDetailModel } from '../../../types.js'; import type { UmbDocumentTypeWorkspaceViewEditTabElement } from './document-type-workspace-view-edit-tab.element.js'; import { css, html, customElement, state, repeat, nothing, ifDefined } from '@umbraco-cms/backoffice/external/lit'; -import type { UUIInputElement, UUIInputEvent } from '@umbraco-cms/backoffice/external/uui'; +import type { UUIInputElement, UUIInputEvent, UUITabElement } from '@umbraco-cms/backoffice/external/uui'; import { UmbContentTypeContainerStructureHelper } from '@umbraco-cms/backoffice/content-type'; import { encodeFolderName } from '@umbraco-cms/backoffice/router'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; @@ -17,54 +17,60 @@ import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/extension- import type { UmbConfirmModalData } from '@umbraco-cms/backoffice/modal'; import { UMB_CONFIRM_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import type { UmbSorterConfig } from '@umbraco-cms/backoffice/sorter'; import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; -const SORTER_CONFIG: UmbSorterConfig = { - getUniqueOfElement: (element) => { - return element.getAttribute('data-umb-tabs-id'); - }, - getUniqueOfModel: (modelEntry) => { - return modelEntry.id; - }, - identifier: 'content-type-tabs-sorter', - itemSelector: '[data-umb-tabs-id]', - containerSelector: '#tabs-group', - disabledItemSelector: '[inherited]', - resolveVerticalDirection: () => { - return false; - }, -}; - @customElement('umb-document-type-workspace-view-edit') export class UmbDocumentTypeWorkspaceViewEditElement extends UmbLitElement implements UmbWorkspaceViewElement { - public sorter?: UmbSorterController; + #model: Array = []; + #sorter = new UmbSorterController(this, { + getUniqueOfElement: (element) => element.getAttribute('data-umb-tabs-id'), + getUniqueOfModel: (modelEntry) => modelEntry.id, + identifier: 'document-type-tabs-sorter', + itemSelector: 'uui-tab', + containerSelector: 'uui-tab-group', + disabledItemSelector: '#root-tab', + resolveVerticalDirection: () => false, + onChange: ({ model }) => { + this.#model = model; + this._tabs = model; + }, + onEnd: ({ item }) => { + /** Explanation: If the item is the first in list, we compare it to the item behind it to set a sortOrder. + * If it's not the first in list, we will compare to the item in before it, and check the following item to see if it caused overlapping sortOrder, then update + * the overlap if true, which may cause another overlap, so we loop through them till no more overlaps... + */ + const model = this.#model; + const newIndex = model.findIndex((entry) => entry.id === item.id); - config: UmbSorterConfig = { - ...SORTER_CONFIG, - // TODO: Missing handlers to work properly: performItemMove and performItemRemove - performItemInsert: async (args) => { - if (!this._tabs) return false; - const oldIndex = this._tabs.findIndex((tab) => tab.id! === args.item.id); - if (args.newIndex === oldIndex) return true; + // Doesn't exist in model + if (newIndex === -1) return; - let sortOrder = 0; - //TODO the sortOrder set is not correct - if (this._tabs.length > 0) { - if (args.newIndex === 0) { - sortOrder = (this._tabs[0].sortOrder ?? 0) - 1; - } else { - sortOrder = (this._tabs[Math.min(args.newIndex, this._tabs.length - 1)].sortOrder ?? 0) + 1; - } - - if (sortOrder !== args.item.sortOrder) { - await this._tabsStructureHelper.partialUpdateContainer(args.item.id!, { sortOrder }); - } + // First in list + if (newIndex === 0 && model.length > 1) { + this._tabsStructureHelper.partialUpdateContainer(item.id, { sortOrder: model[1].sortOrder - 1 }); + return; } - return true; + // Not first in list + if (newIndex > 0 && model.length > 1) { + const prevItemSortOrder = model[newIndex - 1].sortOrder; + + let weight = 1; + this._tabsStructureHelper.partialUpdateContainer(item.id, { sortOrder: prevItemSortOrder + weight }); + + // Check for overlaps + model.some((entry, index) => { + if (index <= newIndex) return; + if (entry.sortOrder === prevItemSortOrder + weight) { + weight++; + this._tabsStructureHelper.partialUpdateContainer(entry.id, { sortOrder: prevItemSortOrder + weight }); + } + // Break the loop + return true; + }); + } }, - }; + }); //private _hasRootProperties = false; @@ -84,7 +90,7 @@ export class UmbDocumentTypeWorkspaceViewEditElement extends UmbLitElement imple private _activePath = ''; @state() - private sortModeActive?: boolean; + private _sortModeActive?: boolean; @state() private _buttonDisabled: boolean = false; @@ -100,7 +106,6 @@ export class UmbDocumentTypeWorkspaceViewEditElement extends UmbLitElement imple constructor() { super(); - this.sorter = new UmbSorterController(this, this.config); //TODO: We need to differentiate between local and composition tabs (and hybrids) @@ -108,6 +113,12 @@ export class UmbDocumentTypeWorkspaceViewEditElement extends UmbLitElement imple this._tabsStructureHelper.setContainerChildType('Tab'); this.observe(this._tabsStructureHelper.containers, (tabs) => { this._tabs = tabs; + if (this._sortModeActive) { + this.#sorter.setModel(tabs); + } else { + this.#sorter.setModel([]); + } + this._createRoutes(); }); @@ -118,7 +129,14 @@ export class UmbDocumentTypeWorkspaceViewEditElement extends UmbLitElement imple this._tabsStructureHelper.setStructureManager((workspaceContext as UmbDocumentTypeWorkspaceContext).structure); this.observe( this._workspaceContext.isSorting, - (isSorting) => (this.sortModeActive = isSorting), + (isSorting) => { + this._sortModeActive = isSorting; + if (isSorting) { + this.#sorter.setModel(this._tabs!); + } else { + this.#sorter.setModel([]); + } + }, '_observeIsSorting', ); @@ -156,13 +174,7 @@ export class UmbDocumentTypeWorkspaceViewEditElement extends UmbLitElement imple } #changeMode() { - this._workspaceContext?.setIsSorting(!this.sortModeActive); - - if (this.sortModeActive && this._tabs) { - this.sorter?.setModel(this._tabs); - } else { - this.sorter?.setModel([]); - } + this._workspaceContext?.setIsSorting(!this._sortModeActive); } private _createRoutes() { @@ -309,7 +321,7 @@ export class UmbDocumentTypeWorkspaceViewEditElement extends UmbLitElement imple return html`