Merge branch 'main' into feature/member-repos

This commit is contained in:
Jacob Overgaard
2024-02-16 12:46:36 +01:00
committed by GitHub
47 changed files with 1059 additions and 959 deletions

View File

@@ -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 <code>@RenderBody()</code> placeholder.\n ',
renderBodyDesc: 'Renders the contents of a child template, by inserting a <code>@RenderBody()</code> placeholder.',
defineSection: 'Define a named section',
defineSectionDesc:
'\n Defines a part of your template as a named section by wrapping it in\n <code>@section { ... }</code>. This can be rendered in a\n specific area of the parent of this template, by using <code>@RenderSection</code>.\n ',
'Defines a part of your template as a named section by wrapping it in <code>@section { ... }</code>. This can be rendered in a specific area of the parent of this template, by using <code>@RenderSection</code>.',
renderSection: 'Render a named section',
renderSectionDesc:
'\n Renders a named area of a child template, by inserting a <code>@RenderSection(name)</code> placeholder.\n This renders an area of a child template which is wrapped in a corresponding <code>@section [name]{ ... }</code> definition.\n ',
'Renders a named area of a child template, by inserting a <code>@RenderSection(name)</code> placeholder. This renders an area of a child template which is wrapped in a corresponding <code>@section [name]{ ... }</code> definition.',
sectionName: 'Section Name',
sectionMandatory: 'Section is mandatory',
sectionMandatoryDesc:
'\n If mandatory, the child template must contain a <code>@section</code> definition, otherwise an error is shown.\n ',
'If mandatory, the child template must contain a <code>@section</code> definition, otherwise an error is shown.',
queryBuilder: 'Query builder',
itemsReturned: 'items returned, in',
iWant: 'I want',

View File

@@ -13,3 +13,4 @@ export type ContentCollectionResponseModelBaseDocumentValueModelDocumentVariantR
creator?: string | null;
sortOrder: number;
};

View File

@@ -13,3 +13,4 @@ export type ContentCollectionResponseModelBaseMediaValueModelMediaVariantRespons
creator?: string | null;
sortOrder: number;
};

View File

@@ -8,3 +8,4 @@ export type ContentTypeCollectionReferenceResponseModelBaseModel = {
alias: string;
icon: string;
};

View File

@@ -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;
});

View File

@@ -6,3 +6,4 @@
import type { ContentTypeCollectionReferenceResponseModelBaseModel } from './ContentTypeCollectionReferenceResponseModelBaseModel';
export type DocumentTypeCollectionReferenceResponseModel = ContentTypeCollectionReferenceResponseModelBaseModel;

View File

@@ -7,5 +7,6 @@ import type { ContentCollectionResponseModelBaseMediaValueModelMediaVariantRespo
import type { MediaTypeCollectionReferenceResponseModel } from './MediaTypeCollectionReferenceResponseModel';
export type MediaCollectionResponseModel = (ContentCollectionResponseModelBaseMediaValueModelMediaVariantResponseModel & {
mediaType: MediaTypeCollectionReferenceResponseModel;
mediaType: MediaTypeCollectionReferenceResponseModel;
});

View File

@@ -6,3 +6,4 @@
import type { ContentTypeCollectionReferenceResponseModelBaseModel } from './ContentTypeCollectionReferenceResponseModelBaseModel';
export type MediaTypeCollectionReferenceResponseModel = ContentTypeCollectionReferenceResponseModelBaseModel;

View File

@@ -9,3 +9,4 @@ export type PagedDocumentCollectionResponseModel = {
total: number;
items: Array<DocumentCollectionResponseModel>;
};

View File

@@ -9,3 +9,4 @@ export type PagedMediaCollectionResponseModel = {
total: number;
items: Array<MediaCollectionResponseModel>;
};

View File

@@ -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<PagedDocumentCollectionResponseModel> {
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<PagedDocumentCollectionResponseModel> {
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<string> {
requestBody,
}: {
requestBody?: CreateDocumentRequestModel,
}): CancelablePromise<string> {
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<DocumentResponseModel> {
id,
}: {
id: string,
}): CancelablePromise<DocumentResponseModel> {
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<any> {
id,
}: {
id: string,
}): CancelablePromise<any> {
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<any> {
id,
requestBody,
}: {
id: string,
requestBody?: UpdateDocumentRequestModel,
}): CancelablePromise<any> {
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<string> {
id,
requestBody,
}: {
id: string,
requestBody?: CopyDocumentRequestModel,
}): CancelablePromise<string> {
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<DomainsResponseModel> {
id,
}: {
id: string,
}): CancelablePromise<DomainsResponseModel> {
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<any> {
id,
requestBody,
}: {
id: string,
requestBody?: UpdateDomainsRequestModel,
}): CancelablePromise<any> {
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<any> {
id,
requestBody,
}: {
id: string,
requestBody?: MoveDocumentRequestModel,
}): CancelablePromise<any> {
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<any> {
id,
}: {
id: string,
}): CancelablePromise<any> {
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<Array<DocumentNotificationResponseModel>> {
id,
}: {
id: string,
}): CancelablePromise<Array<DocumentNotificationResponseModel>> {
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<any> {
id,
requestBody,
}: {
id: string,
requestBody?: UpdateDocumentNotificationsRequestModel,
}): CancelablePromise<any> {
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<string> {
id,
requestBody,
}: {
id: string,
requestBody?: PublicAccessRequestModel,
}): CancelablePromise<string> {
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<any> {
id,
}: {
id: string,
}): CancelablePromise<any> {
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<void> {
id,
}: {
id: string,
}): CancelablePromise<void> {
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<any> {
id,
requestBody,
}: {
id: string,
requestBody?: PublicAccessRequestModel,
}): CancelablePromise<any> {
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<any> {
id,
requestBody,
}: {
id: string,
requestBody?: (PublishDocumentRequestModel | PublishDocumentWithDescendantsRequestModel),
}): CancelablePromise<any> {
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<any> {
id,
requestBody,
}: {
id: string,
requestBody?: PublishDocumentWithDescendantsRequestModel,
}): CancelablePromise<any> {
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<any> {
id,
requestBody,
}: {
id: string,
requestBody?: UnpublishDocumentRequestModel,
}): CancelablePromise<any> {
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<any> {
id,
requestBody,
}: {
id: string,
requestBody?: UpdateDocumentRequestModel,
}): CancelablePromise<any> {
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<any> {
requestBody,
}: {
requestBody?: SortingRequestModel,
}): CancelablePromise<any> {
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<any> {
requestBody,
}: {
requestBody?: CreateDocumentRequestModel,
}): CancelablePromise<any> {
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<string>,
}): CancelablePromise<Array<DocumentItemResponseModel>> {
id,
}: {
id?: Array<string>,
}): CancelablePromise<Array<DocumentItemResponseModel>> {
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/item/document',
@@ -664,10 +664,10 @@ id?: Array<string>,
* @throws ApiError
*/
public static deleteRecycleBinDocumentById({
id,
}: {
id: string,
}): CancelablePromise<any> {
id,
}: {
id: string,
}): CancelablePromise<any> {
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<PagedDocumentRecycleBinItemResponseModel> {
parentId,
skip,
take = 100,
}: {
parentId?: string,
skip?: number,
take?: number,
}): CancelablePromise<PagedDocumentRecycleBinItemResponseModel> {
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<PagedDocumentRecycleBinItemResponseModel> {
skip,
take = 100,
}: {
skip?: number,
take?: number,
}): CancelablePromise<PagedDocumentRecycleBinItemResponseModel> {
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<PagedDocumentTreeItemResponseModel> {
parentId,
skip,
take = 100,
dataTypeId,
}: {
parentId?: string,
skip?: number,
take?: number,
dataTypeId?: string,
}): CancelablePromise<PagedDocumentTreeItemResponseModel> {
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<PagedDocumentTreeItemResponseModel> {
skip,
take = 100,
dataTypeId,
}: {
skip?: number,
take?: number,
dataTypeId?: string,
}): CancelablePromise<PagedDocumentTreeItemResponseModel> {
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/tree/document/root',

View File

@@ -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<PagedMediaCollectionResponseModel> {
id,
dataTypeId,
orderBy = 'updateDate',
orderDirection,
filter,
skip,
take = 100,
}: {
id?: string,
dataTypeId?: string,
orderBy?: string,
orderDirection?: DirectionModel,
filter?: string,
skip?: number,
take?: number,
}): CancelablePromise<PagedMediaCollectionResponseModel> {
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<string>,
}): CancelablePromise<Array<MediaItemResponseModel>> {
id,
}: {
id?: Array<string>,
}): CancelablePromise<Array<MediaItemResponseModel>> {
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/item/media',
@@ -87,10 +87,10 @@ id?: Array<string>,
* @throws ApiError
*/
public static postMedia({
requestBody,
}: {
requestBody?: CreateMediaRequestModel,
}): CancelablePromise<string> {
requestBody,
}: {
requestBody?: CreateMediaRequestModel,
}): CancelablePromise<string> {
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<MediaResponseModel> {
id,
}: {
id: string,
}): CancelablePromise<MediaResponseModel> {
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<any> {
id,
}: {
id: string,
}): CancelablePromise<any> {
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<any> {
id,
requestBody,
}: {
id: string,
requestBody?: UpdateMediaRequestModel,
}): CancelablePromise<any> {
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<any> {
id,
requestBody,
}: {
id: string,
requestBody?: MoveMediaRequestModel,
}): CancelablePromise<any> {
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<any> {
id,
}: {
id: string,
}): CancelablePromise<any> {
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<any> {
id,
requestBody,
}: {
id: string,
requestBody?: UpdateMediaRequestModel,
}): CancelablePromise<any> {
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<any> {
requestBody,
}: {
requestBody?: SortingRequestModel,
}): CancelablePromise<any> {
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<any> {
requestBody,
}: {
requestBody?: CreateMediaRequestModel,
}): CancelablePromise<any> {
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<any> {
id,
}: {
id: string,
}): CancelablePromise<any> {
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<PagedMediaRecycleBinItemResponseModel> {
parentId,
skip,
take = 100,
}: {
parentId?: string,
skip?: number,
take?: number,
}): CancelablePromise<PagedMediaRecycleBinItemResponseModel> {
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<PagedMediaRecycleBinItemResponseModel> {
skip,
take = 100,
}: {
skip?: number,
take?: number,
}): CancelablePromise<PagedMediaRecycleBinItemResponseModel> {
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<PagedMediaTreeItemResponseModel> {
parentId,
skip,
take = 100,
dataTypeId,
}: {
parentId?: string,
skip?: number,
take?: number,
dataTypeId?: string,
}): CancelablePromise<PagedMediaTreeItemResponseModel> {
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<PagedMediaTreeItemResponseModel> {
skip,
take = 100,
dataTypeId,
}: {
skip?: number,
take?: number,
dataTypeId?: string,
}): CancelablePromise<PagedMediaTreeItemResponseModel> {
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/tree/media/root',

View File

@@ -23,10 +23,10 @@ export class TemplateResource {
* @throws ApiError
*/
public static getItemTemplate({
id,
}: {
id?: Array<string>,
}): CancelablePromise<Array<TemplateItemResponseModel>> {
id,
}: {
id?: Array<string>,
}): CancelablePromise<Array<TemplateItemResponseModel>> {
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/item/template',
@@ -44,10 +44,10 @@ id?: Array<string>,
* @throws ApiError
*/
public static postTemplate({
requestBody,
}: {
requestBody?: CreateTemplateRequestModel,
}): CancelablePromise<string> {
requestBody,
}: {
requestBody?: CreateTemplateRequestModel,
}): CancelablePromise<string> {
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<TemplateResponseModel> {
id,
}: {
id: string,
}): CancelablePromise<TemplateResponseModel> {
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<any> {
id,
}: {
id: string,
}): CancelablePromise<any> {
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<any> {
id,
requestBody,
}: {
id: string,
requestBody?: UpdateTemplateRequestModel,
}): CancelablePromise<any> {
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<TemplateQueryResultResponseModel> {
requestBody,
}: {
requestBody?: TemplateQueryExecuteModel,
}): CancelablePromise<TemplateQueryResultResponseModel> {
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<PagedNamedEntityTreeItemResponseModel> {
parentId,
skip,
take = 100,
}: {
parentId?: string,
skip?: number,
take?: number,
}): CancelablePromise<PagedNamedEntityTreeItemResponseModel> {
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<PagedNamedEntityTreeItemResponseModel> {
skip,
take = 100,
}: {
skip?: number,
take?: number,
}): CancelablePromise<PagedNamedEntityTreeItemResponseModel> {
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/tree/template/root',

View File

@@ -1017,6 +1017,46 @@ export const data: Array<UmbMockDocumentTypeModel> = [
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<UmbMockDocumentTypeModel> = [
type: 'Group',
sortOrder: 0,
},
{
id: '2e845ca8-1e3e-4b03-be1d-0b4149ce2120',
parent: null,
name: 'Alchemy',
type: 'Group',
sortOrder: 0,
},
],
allowedDocumentTypes: [],
compositions: [],

View File

@@ -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';

View File

@@ -1,22 +0,0 @@
import { UmbModalToken } from './modal-token.js';
export interface UmbPartialViewPickerModalData {
multiple: boolean;
selection: string[];
}
export interface UmbPartialViewPickerModalValue {
selection: Array<string | null> | 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',
},
});

View File

@@ -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<UmbDocumentTypeItemModel>;

View File

@@ -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<UmbPropertyTypeModel> = {
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<UmbPropertyTypeModel> = [];
#sorter = new UmbSorterController<UmbPropertyTypeModel, UmbDocumentTypeWorkspacePropertyElement>(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`<div id="property-list">
return html`
<div id="property-list" ?sort-mode-active=${this._sortModeActive}>
${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`<umb-document-type-workspace-view-edit-property
data-umb-property-id=${property.id}
owner-document-type-id=${ifDefined(inheritedFromDocument?.unique)}
owner-document-type-name=${ifDefined(inheritedFromDocument?.name)}
?inherited=${property.container?.id !== this.containerId}
?sort-mode-active=${this._sortModeActive}
.property=${property}
@partial-property-update=${(event: CustomEvent) => {
this._propertyStructureHelper.partialUpdateProperty(property.id, event.detail);
}}
@property-delete=${() => {
this._propertyStructureHelper.removeProperty(property.id!);
}}>
</umb-document-type-workspace-view-edit-property>`;
return html`
<umb-document-type-workspace-view-edit-property
data-umb-property-id=${property.id}
owner-document-type-id=${ifDefined(inheritedFromDocument?.unique)}
owner-document-type-name=${ifDefined(inheritedFromDocument?.name)}
?inherited=${property.container?.id !== this.containerId}
?sort-mode-active=${this._sortModeActive}
.property=${property}
@partial-property-update=${(event: CustomEvent) => {
this._propertyStructureHelper.partialUpdateProperty(property.id, event.detail);
}}
@property-delete=${() => {
this._propertyStructureHelper.removeProperty(property.id!);
}}>
</umb-document-type-workspace-view-edit-property>
`;
},
)}
</div>
${!this._sortModeActive
? html`<uui-button
label=${this.localize.term('contentTypeEditor_addProperty')}
@@ -205,7 +228,8 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle
href=${ifDefined(this._modalRouteNewProperty)}>
<umb-localize key="contentTypeEditor_addProperty">Add property</umb-localize>
</uui-button> `
: ''} `;
: ''}
`;
}
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);
}
`,
];
}

View File

@@ -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}></uui-input>
`;
}
@@ -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;
}
`,
];
}

View File

@@ -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<PropertyTypeContainerModelBaseModel> = {
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<PropertyTypeContainerModelBaseModel>;
#model: Array<UmbPropertyTypeContainerModel> = [];
#sorter = new UmbSorterController<UmbPropertyTypeContainerModel, UmbDocumentTypeWorkspaceViewEditPropertiesElement>(
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<PropertyTypeContainerModelBaseModel> = {
...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<UmbDocumentTypeDetailModel>(this);
@state()
_groups: Array<PropertyTypeContainerModelBaseModel> = [];
_groups: Array<UmbPropertyTypeContainerModel> = [];
@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`<uui-button
id="convert-to-tab"
label=${this.localize.term('contentTypeEditor_convertToTab') + '(Not implemented)'}
look="placeholder"></uui-button>`
: ''
}
${
!this._noTabName
? html`
<uui-box>
<umb-document-type-workspace-view-edit-properties
@@ -152,73 +181,86 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement {
container-name=${this.tabName || ''}></umb-document-type-workspace-view-edit-properties>
</uui-box>
`
: ''}
<div id="group-list">
${repeat(
this._groups,
(group) => group.id ?? '' + group.name,
(group) => html`<span data-umb-group-id=${ifDefined(group.id)}>
<uui-box>
${
this._groupStructureHelper.isOwnerChildContainer(group.id!)
? html`
<div slot="header">
<div>
${this._sortModeActive ? html`<uui-icon name="icon-navigation"></uui-icon>` : ''}
<uui-input
label="Group name"
placeholder="Enter a group name"
value=${group.name ?? ''}
@change=${(e: InputEvent) => {
const newName = (e.target as HTMLInputElement).value;
this._groupStructureHelper.updateContainerName(
group.id!,
group.parent?.id ?? null,
newName,
);
}}>
</uui-input>
</div>
${this._sortModeActive
? html`<uui-input type="number" label="sort order" .value=${group.sortOrder ?? 0}></uui-input>`
: ''}
</div>
`
: html`<div slot="header">
<div><uui-icon name="icon-merge"></uui-icon><b>${group.name ?? ''}</b> (Inherited)</div>
${!this._sortModeActive
? html`<uui-input
readonly
type="number"
label="sort order"
.value=${group.sortOrder ?? 0}></uui-input>`
: ''}
</div>`
}
</div>
<umb-document-type-workspace-view-edit-properties
container-id=${ifDefined(group.id)}
container-type="Group"
container-name=${group.name || ''}></umb-document-type-workspace-view-edit-properties>
</uui-box></span>`,
)}
: ''
}
<div class="container-list" ?sort-mode-active=${this._sortModeActive}>
${repeat(
this._groups,
(group) => group.id + '' + group.name + group.sortOrder,
(group) =>
html`<uui-box class="container-handle">
${this.#renderHeader(group)}
<umb-document-type-workspace-view-edit-properties
container-id=${ifDefined(group.id)}
container-type="Group"
container-name=${group.name || ''}></umb-document-type-workspace-view-edit-properties>
</uui-box> `,
)}
</div>
${this.#renderAddGroupButton()}
</div>
${!this._sortModeActive
? html`<uui-button
label=${this.localize.term('contentTypeEditor_addGroup')}
id="add"
look="placeholder"
@click=${this.#onAddGroup}>
${this.localize.term('contentTypeEditor_addGroup')}
</uui-button>`
: ''}
`;
}
#renderHeader(group: UmbPropertyTypeContainerModel) {
const inherited = !this._groupStructureHelper.isOwnerChildContainer(group.id!);
if (this._sortModeActive) {
return html`<div slot="header">
<div>
<uui-icon name=${inherited ? 'icon-merge' : 'icon-navigation'}></uui-icon>
${this.#renderInputGroupName(group)}
</div>
<uui-input
type="number"
label=${this.localize.term('sort_sortOrder')}
@change=${(e: UUIInputEvent) =>
this._groupStructureHelper.partialUpdateContainer(group.id!, {
sortOrder: parseInt(e.target.value as string) || 0,
})}
.value=${group.sortOrder || 0}
?disabled=${inherited}></uui-input>
</div> `;
} else {
return html`<div slot="header">
${inherited ? html`<uui-icon name="icon-merge"></uui-icon>` : this.#renderInputGroupName(group)}
</div> `;
}
}
#renderInputGroupName(group: UmbPropertyTypeContainerModel) {
return html`<uui-input
label=${this.localize.term('contentTypeEditor_group')}
placeholder=${this.localize.term('placeholders_entername')}
.value=${group.name}
@change=${(e: InputEvent) => {
const newName = (e.target as HTMLInputElement).value;
this._groupStructureHelper.updateContainerName(group.id!, group.parent?.id ?? null, newName);
}}></uui-input>`;
}
#renderAddGroupButton() {
if (this._sortModeActive) return;
return html`<uui-button
label=${this.localize.term('contentTypeEditor_addGroup')}
id="add"
look="placeholder"
@click=${this.#onAddGroup}>
${this.localize.term('contentTypeEditor_addGroup')}
</uui-button>`;
}
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;
}
`,
];

View File

@@ -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<PropertyTypeContainerModelBaseModel> = {
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<PropertyTypeContainerModelBaseModel>;
#model: Array<PropertyTypeContainerModelBaseModel> = [];
#sorter = new UmbSorterController<PropertyTypeContainerModelBaseModel, UUITabElement>(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<PropertyTypeContainerModelBaseModel> = {
...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`
<umb-body-layout header-fit-height>
<div id="header" slot="header">
<div id="tabs-wrapper" class="flex">
<div id="container-list" class="flex">
${this._routerPath ? this.renderTabsNavigation() : ''} ${this.renderAddButton()}
</div>
${this.renderActions()}
@@ -328,7 +340,7 @@ export class UmbDocumentTypeWorkspaceViewEditElement extends UmbLitElement imple
}
renderAddButton() {
if (this.sortModeActive) return;
if (this._sortModeActive) return;
return html`<uui-button id="add-tab" @click="${this.#addTab}" label="Add tab" compact>
<uui-icon name="icon-add"></uui-icon>
Add tab
@@ -336,7 +348,7 @@ export class UmbDocumentTypeWorkspaceViewEditElement extends UmbLitElement imple
}
renderActions() {
const sortButtonText = this.sortModeActive
const sortButtonText = this._sortModeActive
? this.localize.term('general_reorderDone')
: this.localize.term('general_reorder');
@@ -375,6 +387,7 @@ export class UmbDocumentTypeWorkspaceViewEditElement extends UmbLitElement imple
const rootTabPath = this._routerPath + '/root';
const rootTabActive = rootTabPath === this._activePath;
return html`<uui-tab
id="root-tab"
class=${this._hasRootGroups || rootTabActive ? '' : 'content-tab-is-empty'}
label=${this.localize.term('general_content')}
.active=${rootTabActive}
@@ -398,7 +411,7 @@ export class UmbDocumentTypeWorkspaceViewEditElement extends UmbLitElement imple
}
renderTabInner(tab: PropertyTypeContainerModelBaseModel, tabActive: boolean, tabInherited: boolean) {
if (this.sortModeActive) {
if (this._sortModeActive) {
return html`<div class="no-edit">
${tabInherited
? html`<uui-icon class="external" name="icon-merge"></uui-icon>${tab.name!}`
@@ -408,7 +421,7 @@ export class UmbDocumentTypeWorkspaceViewEditElement extends UmbLitElement imple
type="number"
value=${ifDefined(tab.sortOrder)}
style="width:50px"
@keypress=${(e: UUIInputEvent) => this.#changeOrderNumber(tab, e)}></uui-input>`}
@change=${(e: UUIInputEvent) => this.#changeOrderNumber(tab, e)}></uui-input>`}
</div>`;
}
@@ -474,7 +487,16 @@ export class UmbDocumentTypeWorkspaceViewEditElement extends UmbLitElement imple
--uui-tab-background: var(--uui-color-surface);
}
[drag-placeholder] {
opacity: 0.5;
}
[drag-placeholder] uui-input {
visibility: hidden;
}
/* TODO: This should be replaced with a general workspace bar — naming is hard */
#header {
width: 100%;
display: flex;
@@ -486,6 +508,7 @@ export class UmbDocumentTypeWorkspaceViewEditElement extends UmbLitElement imple
.flex {
display: flex;
}
uui-tab-group {
flex-wrap: nowrap;
}
@@ -534,15 +557,8 @@ export class UmbDocumentTypeWorkspaceViewEditElement extends UmbLitElement imple
vertical-align: sub;
}
.--umb-sorter-placeholder > * {
visibility: hidden;
}
.--umb-sorter-placeholder::after {
content: '';
position: absolute;
inset: 2px;
border: 1px dashed var(--uui-color-divider-emphasis);
[drag-placeholder] {
opacity: 0.2;
}
`,
];

View File

@@ -1,6 +1,6 @@
import { UmbDocumentPickerContext } from '../../documents/documents/components/input-document/input-document.context.js';
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
import { css, html, customElement, map, state, ifDefined } from '@umbraco-cms/backoffice/external/lit';
import { css, html, customElement, state, ifDefined, repeat } from '@umbraco-cms/backoffice/external/lit';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import type { ManifestDynamicRootOrigin } from '@umbraco-cms/backoffice/extension-registry';
import type { UmbTreePickerDynamicRoot } from '@umbraco-cms/backoffice/components';
@@ -63,8 +63,9 @@ export class UmbDynamicRootOriginPickerModalModalElement extends UmbModalBaseEle
<umb-body-layout headline="${this.localize.term('dynamicRoot_pickDynamicRootOriginTitle')}">
<div id="main">
<uui-box>
${map(
${repeat(
this._origins,
(item) => item.alias,
(item) => html`
<uui-button @click=${() => this.#choose(item)} look="placeholder" label="${ifDefined(item.meta.label)}">
<h3>${item.meta.label}</h3>

View File

@@ -2,7 +2,7 @@ import { UmbDocumentTypePickerContext } from '../../documents/document-types/com
import { UmbId } from '@umbraco-cms/backoffice/id';
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, customElement, map, state, ifDefined } from '@umbraco-cms/backoffice/external/lit';
import { css, html, customElement, state, ifDefined, repeat } from '@umbraco-cms/backoffice/external/lit';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import type { UmbTreePickerDynamicRootQueryStep } from '@umbraco-cms/backoffice/components';
import type { ManifestDynamicRootQueryStep } from '@umbraco-cms/backoffice/extension-registry';
@@ -58,8 +58,9 @@ export class UmbDynamicRootQueryStepPickerModalModalElement extends UmbModalBase
<umb-body-layout headline="${this.localize.term('dynamicRoot_pickDynamicRootQueryStepTitle')}">
<div id="main">
<uui-box>
${map(
${repeat(
this._querySteps,
(item) => item.alias,
(item) => html`
<uui-button @click=${() => this.#choose(item)} look="placeholder" label="${ifDefined(item.meta.label)}">
<h3>${item.meta.label}</h3>

View File

@@ -1 +1 @@
export * from './insert-menu/templating-insert-menu.element.js';
export * from './templating-item-menu/index.js';

View File

@@ -0,0 +1 @@
export * from './templating-item-menu.element.js';

View File

@@ -1,7 +1,13 @@
import { UMB_MODAL_TEMPLATING_INSERT_CHOOSE_TYPE_SIDEBAR_ALIAS } from '../../modals/manifests.js';
import {
UMB_PARTIAL_VIEW_PICKER_MODAL,
type UmbPartialViewPickerModalValue,
} from '../../modals/partial-view-picker/partial-view-picker-modal.token.js';
import { CodeSnippetType } from '../../types.js';
import {
UMB_TEMPLATING_ITEM_PICKER_MODAL,
type UmbTemplatingItemPickerModalValue,
} from '../../modals/templating-item-picker/templating-item-picker-modal.token.js';
import { getInsertDictionarySnippet, getInsertPartialSnippet } from '../../utils/index.js';
import type { UmbChooseInsertTypeModalValue } from '../../modals/insert-choose-type-sidebar.element.js';
import { CodeSnippetType } from '../../modals/insert-choose-type-sidebar.element.js';
import { UmbDictionaryDetailRepository } from '@umbraco-cms/backoffice/dictionary';
import { customElement, property, css, html } from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
@@ -9,26 +15,10 @@ import type {
UmbDictionaryItemPickerModalValue,
UmbModalManagerContext,
UmbModalContext,
UmbPartialViewPickerModalValue,
} from '@umbraco-cms/backoffice/modal';
import {
UMB_DICTIONARY_ITEM_PICKER_MODAL,
UMB_MODAL_MANAGER_CONTEXT,
UMB_PARTIAL_VIEW_PICKER_MODAL,
UmbModalToken,
} from '@umbraco-cms/backoffice/modal';
import { UMB_DICTIONARY_ITEM_PICKER_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
export const UMB_MODAL_TEMPLATING_INSERT_CHOOSE_TYPE_SIDEBAR_MODAL = new UmbModalToken<{ hidePartialView: boolean }>(
UMB_MODAL_TEMPLATING_INSERT_CHOOSE_TYPE_SIDEBAR_ALIAS,
{
modal: {
type: 'sidebar',
size: 'small',
},
},
);
@customElement('umb-templating-insert-menu')
export class UmbTemplatingInsertMenuElement extends UmbLitElement {
@property()
@@ -47,7 +37,7 @@ export class UmbTemplatingInsertMenuElement extends UmbLitElement {
});
}
async determineInsertValue(modalValue: UmbChooseInsertTypeModalValue) {
async determineInsertValue(modalValue: UmbTemplatingItemPickerModalValue) {
const { type, value } = modalValue;
switch (type) {
@@ -76,16 +66,20 @@ export class UmbTemplatingInsertMenuElement extends UmbLitElement {
};
#openChooseTypeModal = () => {
this.#openModal = this._modalContext?.open(UMB_MODAL_TEMPLATING_INSERT_CHOOSE_TYPE_SIDEBAR_MODAL, {
this.#openModal = this._modalContext?.open(UMB_TEMPLATING_ITEM_PICKER_MODAL, {
data: {
hidePartialView: this.hidePartialView,
hidePartialViews: this.hidePartialView,
},
});
this.#openModal?.onSubmit().then((closedModal: UmbChooseInsertTypeModalValue) => {
this.#openModal?.onSubmit().then((closedModal: UmbTemplatingItemPickerModalValue) => {
this.determineInsertValue(closedModal);
});
};
#openInsertPageFieldSidebar() {
//this.#openModel = this._modalContext?.open();
}
#openInsertPartialViewSidebar() {
this.#openModal = this._modalContext?.open(UMB_PARTIAL_VIEW_PICKER_MODAL);
this.#openModal?.onSubmit().then((value) => {
@@ -98,6 +92,7 @@ export class UmbTemplatingInsertMenuElement extends UmbLitElement {
#openInsertDictionaryItemModal() {
this.#openModal = this._modalContext?.open(UMB_DICTIONARY_ITEM_PICKER_MODAL, {
data: {
hideTreeRoot: true,
pickableFilter: (item) => item.id !== null,
},
});
@@ -118,14 +113,30 @@ export class UmbTemplatingInsertMenuElement extends UmbLitElement {
render() {
return html`
<uui-button-group>
<uui-button look="secondary" @click=${this.#openChooseTypeModal} label="Choose value to insert">
<uui-icon name="icon-add"></uui-icon>Insert
<uui-button look="secondary" @click=${this.#openChooseTypeModal} label=${this.localize.term('template_insert')}>
<uui-icon name="icon-add"></uui-icon>${this.localize.term('template_insert')}
</uui-button>
<umb-dropdown look="secondary" compact placement="bottom-end" id="insert-button" label="open insert menu">
<umb-dropdown
look="secondary"
compact
placement="bottom-end"
id="insert-button"
label=${this.localize.term('template_insert')}>
<uui-menu-item
class="insert-menu-item"
label="Dictionary item"
title="Dictionary item"
label=${this.localize.term('template_insertPageField')}
title=${this.localize.term('template_insertPageField')}
@click=${this.#openInsertPageFieldSidebar}></uui-menu-item>
<uui-menu-item
class="insert-menu-item"
label=${this.localize.term('template_insertPartialView')}
title=${this.localize.term('template_insertPartialView')}
@click=${this.#openInsertPartialViewSidebar}>
</uui-menu-item>
<uui-menu-item
class="insert-menu-item"
label=${this.localize.term('template_insertDictionaryItem')}
title=${this.localize.term('template_insertDictionaryItem')}
@click=${this.#openInsertDictionaryItemModal}>
</uui-menu-item>
</umb-dropdown>
@@ -133,18 +144,6 @@ export class UmbTemplatingInsertMenuElement extends UmbLitElement {
`;
}
//TODO: put this back in when partial view is implemented
// ${this.hidePartialView
// ? ''
// : html` <li>
// <uui-menu-item
// class="insert-menu-item"
// label="Partial view"
// title="Partial view"
// @click=${this.#openInsertPartialViewSidebar}>
// </uui-menu-item>
// </li>`}
static styles = [
UmbTextStyles,
css`

View File

@@ -1,2 +1,4 @@
export * from './components/index.js';
export * from './templates/index.js';
export * from './modals/index.js';
export * from './types.js';

View File

@@ -0,0 +1,3 @@
export * from './templating-section-picker/index.js';
export * from './templating-item-picker/index.js';
export * from './partial-view-picker/index.js';

View File

@@ -1,142 +0,0 @@
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, customElement } from '@umbraco-cms/backoffice/external/lit';
import type {
UmbModalManagerContext,
UmbModalContext,
UmbDictionaryItemPickerModalValue,
} from '@umbraco-cms/backoffice/modal';
import {
UMB_MODAL_MANAGER_CONTEXT,
UMB_PARTIAL_VIEW_PICKER_MODAL,
UMB_DICTIONARY_ITEM_PICKER_MODAL,
UmbModalBaseElement,
} from '@umbraco-cms/backoffice/modal';
export interface ChooseInsertTypeModalData {
hidePartialViews?: boolean;
}
export enum CodeSnippetType {
partialView = 'partialView',
dictionaryItem = 'dictionaryItem',
}
export interface UmbChooseInsertTypeModalValue {
value: string | UmbDictionaryItemPickerModalValue;
type: CodeSnippetType;
}
@customElement('umb-templating-choose-insert-type-modal')
export default class UmbChooseInsertTypeModalElement extends UmbModalBaseElement<
ChooseInsertTypeModalData,
UmbChooseInsertTypeModalValue
> {
private _close() {
this.modalContext?.reject();
}
private _modalContext?: UmbModalManagerContext;
constructor() {
super();
this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (instance) => {
this._modalContext = instance;
});
}
#openModal?: UmbModalContext;
#openInsertPartialViewSidebar() {
this.#openModal = this._modalContext?.open(UMB_PARTIAL_VIEW_PICKER_MODAL);
this.#openModal?.onSubmit().then((partialViewPickerModalValue) => {
if (partialViewPickerModalValue) {
this.value = {
type: CodeSnippetType.partialView,
value: partialViewPickerModalValue.selection[0],
};
this.modalContext?.submit();
}
});
}
#openInsertDictionaryItemModal() {
this.#openModal = this._modalContext?.open(UMB_DICTIONARY_ITEM_PICKER_MODAL, {
data: {
pickableFilter: (item) => item.id !== null,
},
});
this.#openModal?.onSubmit().then((dictionaryItemPickerModalValue) => {
if (dictionaryItemPickerModalValue) {
this.value = { value: dictionaryItemPickerModalValue, type: CodeSnippetType.dictionaryItem };
this.modalContext?.submit();
}
});
}
//TODO: insert this when we have partial views
#renderInsertPartialViewButton() {
return html`${this.data?.hidePartialViews
? ''
: html`<uui-button @click=${this.#openInsertPartialViewSidebar} look="placeholder" label="Insert value"
><h3>Partial view</h3>
<p>
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.
</p></uui-button
>`}`;
}
render() {
return html`
<umb-body-layout headline="Insert">
<div id="main">
<uui-box>
<uui-button @click=${this.#openInsertDictionaryItemModal} look="placeholder" label="Insert Dictionary item"
><h3>Dictionary item</h3>
<p>
A dictionary item is a placeholder for a translatable piece of text, which makes it easy to create
designs for multilingual websites.
</p></uui-button
>
</uui-box>
</div>
<div slot="actions">
<uui-button @click=${this._close} look="secondary" label="Close">Close</uui-button>
</div>
</umb-body-layout>
`;
}
static styles = [
UmbTextStyles,
css`
:host {
display: block;
color: var(--uui-color-text);
--umb-header-layout-height: 70px;
}
#main {
box-sizing: border-box;
height: calc(
100dvh - var(--umb-header-layout-height) - var(--umb-footer-layout-height) - 2 * var(--uui-size-layout-1)
);
}
#main uui-button:not(:last-of-type) {
display: block;
margin-bottom: var(--uui-size-space-5);
}
h3,
p {
text-align: left;
}
`,
];
}
declare global {
interface HTMLElementTagNameMap {
'umb-templating-choose-insert-type-modal': UmbChooseInsertTypeModalElement;
}
}

View File

@@ -1,27 +1,17 @@
import type { ManifestModal } from '@umbraco-cms/backoffice/extension-registry';
import { UMB_PARTIAL_VIEW_PICKER_MODAL_ALIAS } from '@umbraco-cms/backoffice/modal';
export const UMB_MODAL_TEMPLATING_INSERT_CHOOSE_TYPE_SIDEBAR_ALIAS = 'Umb.Modal.Templating.Insert.ChooseType.Sidebar';
export const UMB_MODAL_TEMPLATING_INSERT_SECTION_SIDEBAR_ALIAS = 'Umb.Modal.Templating.Insert.Section.Sidebar';
const modals: Array<ManifestModal> = [
{
type: 'modal',
alias: UMB_MODAL_TEMPLATING_INSERT_CHOOSE_TYPE_SIDEBAR_ALIAS,
name: 'Choose insert type sidebar',
js: () => import('./insert-choose-type-sidebar.element.js'),
alias: 'Umb.Modal.TemplatingItemPicker',
name: 'Templating Item Picker Modal',
js: () => import('./templating-item-picker/templating-item-picker-modal.element.js'),
},
{
type: 'modal',
alias: UMB_PARTIAL_VIEW_PICKER_MODAL_ALIAS,
name: 'Partial View Picker Modal',
js: () => import('../../templating/modals/partial-view-picker-modal.element.js'),
},
{
type: 'modal',
alias: UMB_MODAL_TEMPLATING_INSERT_SECTION_SIDEBAR_ALIAS,
name: 'Partial Insert Section Picker Modal',
js: () => import('./insert-section-modal/insert-section-modal.element.js'),
alias: 'Umb.Modal.TemplatingSectionPicker',
name: 'Templating Section Picker Modal',
js: () => import('./templating-section-picker/templating-section-picker-modal.element.js'),
},
];

View File

@@ -1 +0,0 @@
//TODO: move tokens here nad import this file somewhere

View File

@@ -1,89 +0,0 @@
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import type { UmbPartialViewPickerModalData, UmbPartialViewPickerModalValue } from '@umbraco-cms/backoffice/modal';
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
import type { UmbTreeElement, UmbTreeSelectionConfiguration } from '@umbraco-cms/backoffice/tree';
@customElement('umb-partial-view-picker-modal')
export default class UmbPartialViewPickerModalElement extends UmbModalBaseElement<
UmbPartialViewPickerModalData,
UmbPartialViewPickerModalValue
> {
@state()
_selectionConfiguration: UmbTreeSelectionConfiguration = {
multiple: false,
selectable: true,
selection: [],
};
connectedCallback() {
super.connectedCallback();
this._selectionConfiguration.selection = this.value?.selection ?? [];
this._selectionConfiguration.multiple = this.data?.multiple ?? true;
}
private _handleSelectionChange(e: CustomEvent) {
e.stopPropagation();
const element = e.target as UmbTreeElement;
this.value = { selection: element.getSelection() };
this._submit();
}
private _submit() {
this.modalContext?.submit();
}
private _close() {
this.modalContext?.reject();
}
render() {
return html`
<umb-body-layout headline="Insert Partial view">
<div id="main">
<uui-box>
<umb-tree
alias="Umb.Tree.PartialViews"
@selection-change=${this._handleSelectionChange}
.selectionConfiguration=${this._selectionConfiguration}></umb-tree>
</uui-box>
</div>
<div slot="actions">
<uui-button @click=${this._close} look="secondary">Close</uui-button>
</div>
</umb-body-layout>
`;
}
static styles = [
UmbTextStyles,
css`
:host {
display: block;
color: var(--uui-color-text);
--umb-header-layout-height: 70px;
}
#main {
box-sizing: border-box;
padding: var(--uui-size-space-5);
height: calc(100vh - 124px);
}
#main uui-button {
width: 100%;
}
h3,
p {
text-align: left;
}
`,
];
}
declare global {
interface HTMLElementTagNameMap {
'umb-partial-view-picker-modal': UmbPartialViewPickerModalElement;
}
}

View File

@@ -0,0 +1 @@
export * from './partial-view-picker-modal.token.js';

View File

@@ -0,0 +1,18 @@
import { UMB_PARTIAL_VIEW_TREE_ALIAS } from '../../partial-views/tree/manifests.js';
import { UmbModalToken, type UmbPickerModalValue, type UmbTreePickerModalData } from '@umbraco-cms/backoffice/modal';
import type { UmbEntityTreeItemModel } from '@umbraco-cms/backoffice/tree';
export type UmbPartialViewPickerModalData = UmbTreePickerModalData<UmbEntityTreeItemModel>;
export type UmbPartialViewPickerModalValue = UmbPickerModalValue;
export const UMB_PARTIAL_VIEW_PICKER_MODAL = new UmbModalToken<
UmbPartialViewPickerModalData,
UmbPartialViewPickerModalValue
>('Umb.Modal.TreePicker', {
modal: {
type: 'sidebar',
size: 'small',
},
data: { treeAlias: UMB_PARTIAL_VIEW_TREE_ALIAS, hideTreeRoot: true },
});

View File

@@ -0,0 +1,2 @@
export * from './templating-item-picker-modal.element.js';
export * from './templating-item-picker-modal.token.js';

View File

@@ -0,0 +1,140 @@
import { CodeSnippetType } from '../../types.js';
import { UMB_PARTIAL_VIEW_PICKER_MODAL } from '../partial-view-picker/partial-view-picker-modal.token.js';
import type {
UmbTemplatingItemPickerModalData,
UmbTemplatingItemPickerModalValue,
} from './templating-item-picker-modal.token.js';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, customElement } from '@umbraco-cms/backoffice/external/lit';
import type { UmbModalManagerContext, UmbModalContext } from '@umbraco-cms/backoffice/modal';
import {
UMB_MODAL_MANAGER_CONTEXT,
UMB_DICTIONARY_ITEM_PICKER_MODAL,
UmbModalBaseElement,
} from '@umbraco-cms/backoffice/modal';
@customElement('umb-templating-item-picker-modal')
export class UmbTemplatingItemPickerModalElement extends UmbModalBaseElement<
UmbTemplatingItemPickerModalData,
UmbTemplatingItemPickerModalValue
> {
private _close() {
this.modalContext?.reject();
}
private _modalContext?: UmbModalManagerContext;
constructor() {
super();
this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (instance) => {
this._modalContext = instance;
});
}
#openModal?: UmbModalContext;
#openInsertPartialViewSidebar() {
this.#openModal = this._modalContext?.open(UMB_PARTIAL_VIEW_PICKER_MODAL);
this.#openModal?.onSubmit().then((partialViewPickerModalValue) => {
if (partialViewPickerModalValue) {
this.value = {
type: CodeSnippetType.partialView,
value: partialViewPickerModalValue.selection[0],
};
this.modalContext?.submit();
}
});
}
#openInsertDictionaryItemModal() {
this.#openModal = this._modalContext?.open(UMB_DICTIONARY_ITEM_PICKER_MODAL, {
data: {
hideTreeRoot: true,
pickableFilter: (item) => item.id !== null,
},
});
this.#openModal?.onSubmit().then((dictionaryItemPickerModalValue) => {
if (dictionaryItemPickerModalValue) {
this.value = { value: dictionaryItemPickerModalValue, type: CodeSnippetType.dictionaryItem };
this.modalContext?.submit();
}
});
}
render() {
return html`
<umb-body-layout headline=${this.localize.term('template_insert')}>
<uui-box> ${this.#renderItems()} </uui-box>
<uui-button
slot="actions"
@click=${this._close}
look="secondary"
label=${this.localize.term('general_close')}></uui-button>
</umb-body-layout>
`;
}
#renderItems() {
return html`<div id="main">
<uui-button
@click=${() => console.log('to be continued')}
look="placeholder"
label=${this.localize.term('template_insert')}>
<h3><umb-localize key="template_insertPageField">Value</umb-localize> (Not implemented)</h3>
<p>
<umb-localize key="template_insertPageFieldDesc">
Displays the value of a named field from the current page, with options to modify the value or fallback to
alternative values.
</umb-localize>
</p>
</uui-button>
<uui-button
@click=${this.#openInsertPartialViewSidebar}
look="placeholder"
label=${this.localize.term('template_insert')}>
<h3><umb-localize key="template_insertPartialView">Partial view</umb-localize></h3>
<p>
<umb-localize key="template_insertPartialViewDesc">
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.
</umb-localize>
</p>
</uui-button>
<uui-button
@click=${this.#openInsertDictionaryItemModal}
look="placeholder"
label=${this.localize.term('template_insertDictionaryItem')}>
<h3><umb-localize key="template_insertDictionaryItem">Dictionary Item</umb-localize></h3>
<p>
<umb-localize key="template_insertDictionaryItemDesc">
A dictionary item is a placeholder for a translatable piece of text, which makes it easy to create designs
for multilingual websites.
</umb-localize>
</p>
</uui-button>
</div>`;
}
static styles = [
UmbTextStyles,
css`
#main uui-button:not(:last-of-type) {
display: block;
margin-bottom: var(--uui-size-space-5);
}
h3,
p {
text-align: left;
}
`,
];
}
export default UmbTemplatingItemPickerModalElement;
declare global {
interface HTMLElementTagNameMap {
'umb-templating-item-picker-modal': UmbTemplatingItemPickerModalElement;
}
}

View File

@@ -0,0 +1,21 @@
import type { CodeSnippetType } from '../../types.js';
import { type UmbDictionaryItemPickerModalValue, UmbModalToken } from '@umbraco-cms/backoffice/modal';
export interface UmbTemplatingItemPickerModalData {
hidePartialViews?: boolean;
}
export type UmbTemplatingItemPickerModalValue = {
value: string | UmbDictionaryItemPickerModalValue;
type: CodeSnippetType;
};
export const UMB_TEMPLATING_ITEM_PICKER_MODAL = new UmbModalToken<
UmbTemplatingItemPickerModalData,
UmbTemplatingItemPickerModalValue
>('Umb.Modal.TemplatingItemPicker', {
modal: {
type: 'sidebar',
size: 'small',
},
});

View File

@@ -0,0 +1,2 @@
export * from './templating-section-picker-input.element.js';
export * from './templating-section-picker-modal.element.js';

View File

@@ -1,31 +1,18 @@
import { UMB_MODAL_TEMPLATING_INSERT_SECTION_SIDEBAR_ALIAS } from '../manifests.js';
import { getAddSectionSnippet, getRenderBodySnippet, getRenderSectionSnippet } from '../../utils/index.js';
import type {
UmbTemplatingSectionPickerModalData,
UmbTemplatingSectionPickerModalValue,
} from './templating-section-picker-modal.token.js';
import type { UmbInsertSectionCheckboxElement } from './templating-section-picker-input.element.js';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, customElement, queryAll, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbModalToken, UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
import './templating-section-picker-input.element.js';
import './insert-section-input.element.js';
// eslint-disable-next-line local-rules/ensure-relative-import-use-js-extension
import type { UmbInsertSectionCheckboxElement } from './insert-section-input.element';
export const UMB_MODAL_TEMPLATING_INSERT_SECTION_MODAL = new UmbModalToken<object, UmbInsertSectionModalModalValue>(
UMB_MODAL_TEMPLATING_INSERT_SECTION_SIDEBAR_ALIAS,
{
modal: {
type: 'sidebar',
size: 'small',
},
},
);
export interface UmbInsertSectionModalModalValue {
value?: string;
}
@customElement('umb-templating-insert-section-modal')
export default class UmbTemplatingInsertSectionModalElement extends UmbModalBaseElement<
object,
UmbInsertSectionModalModalValue
@customElement('umb-templating-section-picker-modal')
export class UmbTemplatingSectionPickerModalElement extends UmbModalBaseElement<
UmbTemplatingSectionPickerModalData,
UmbTemplatingSectionPickerModalValue
> {
@queryAll('umb-insert-section-checkbox')
checkboxes!: NodeListOf<UmbInsertSectionCheckboxElement>;
@@ -74,40 +61,47 @@ export default class UmbTemplatingInsertSectionModalElement extends UmbModalBase
render() {
return html`
<umb-body-layout headline="Insert">
<umb-body-layout headline=${this.localize.term('template_insert')}>
<div id="main">
<uui-box>
<umb-insert-section-checkbox
@change=${this.#chooseSection}
label="Render child template"
label=${this.localize.term('template_renderBody')}
checked
.snippetMethod=${getRenderBodySnippet}>
<p slot="description">
Renders the contents of a child template, by inserting a <code>@RenderBody()</code> placeholder.
<umb-localize key="template_renderBodyDesc">
Renders the contents of a child template, by inserting a <code>@RenderBody()</code> placeholder.
</umb-localize>
</p>
</umb-insert-section-checkbox>
<umb-insert-section-checkbox
@change=${this.#chooseSection}
label="Render a named section"
label=${this.localize.term('template_renderSection')}
show-mandatory
show-input
.snippetMethod=${getRenderSectionSnippet}>
<p slot="description">
Renders a named area of a child template, by inserting a <code>@RenderSection(name)</code> placeholder.
This renders an area of a child template which is wrapped in a corresponding
<code>@section [name]{ ... }</code> definition.
<umb-localize key="template_renderSectionDesc">
Renders a named area of a child template, by inserting a
<code>@RenderSection(name)</code> placeholder. This renders an area of a child template which is
wrapped in a corresponding <code>@section [name]{ ... }</code> definition.
</umb-localize>
</p>
</umb-insert-section-checkbox>
<umb-insert-section-checkbox
@change=${this.#chooseSection}
label="Define a named section"
label=${this.localize.term('template_defineSection')}
show-input
.snippetMethod=${getAddSectionSnippet}>
<p slot="description">
Defines a part of your template as a named section by wrapping it in <code>@section { ... }</code>. This
can be rendered in a specific area of the parent of this template, by using <code>@RenderSection</code>.
<umb-localize key="template_defineSectionDesc">
Renders a named area of a child template, by inserting a
<code>@RenderSection(name)</code> placeholder. This renders an area of a child template which is
wrapped in a corresponding <code>@section [name]{ ... }</code> definition.
</umb-localize>
</p>
</umb-insert-section-checkbox>
</uui-box>
@@ -139,12 +133,19 @@ export default class UmbTemplatingInsertSectionModalElement extends UmbModalBase
#main umb-insert-section-checkbox:not(:last-of-type) {
margin-bottom: var(--uui-size-space-5);
}
code {
background-color: var(--uui-color-surface-alt);
border: 1px solid var(--uui-color-border);
border-radius: var(--uui-border-radius);
}
`,
];
}
export default UmbTemplatingSectionPickerModalElement;
declare global {
interface HTMLElementTagNameMap {
'umb-templating-insert-section-modal': UmbTemplatingInsertSectionModalElement;
'umb-templating-section-picker-modal': UmbTemplatingSectionPickerModalElement;
}
}

View File

@@ -0,0 +1,17 @@
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
export interface UmbTemplatingSectionPickerModalData {}
export type UmbTemplatingSectionPickerModalValue = {
value: string;
};
export const UMB_TEMPLATING_SECTION_PICKER_MODAL = new UmbModalToken<
UmbTemplatingSectionPickerModalData,
UmbTemplatingSectionPickerModalValue
>('Umb.Modal.TemplatingSectionPicker', {
modal: {
type: 'sidebar',
size: 'small',
},
});

View File

@@ -6,7 +6,7 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbRoute, IRoutingInfo, PageComponent } from '@umbraco-cms/backoffice/router';
import { UmbWorkspaceIsNewRedirectController } from '@umbraco-cms/backoffice/workspace';
import '../../components/insert-menu/templating-insert-menu.element.js';
import '../../components/templating-item-menu/templating-item-menu.element.js';
@customElement('umb-partial-view-workspace')
export class UmbPartialViewWorkspaceElement extends UmbLitElement {

View File

@@ -34,17 +34,19 @@ export class UmbTemplateServerDataSource implements UmbDetailDataSource<UmbTempl
* @return { CreateTemplateRequestModel }
* @memberof UmbTemplateServerDataSource
*/
async createScaffold(parentUnique: string | null) {
async createScaffold(parentUnique: string | null, preset?: Partial<UmbTemplateDetailModel>) {
const scaffold =
'@using Umbraco.Cms.Web.Common.PublishedModels;\n@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage\n@{\n\tLayout = null;\n}';
const data: UmbTemplateDetailModel = {
entityType: UMB_TEMPLATE_ENTITY_TYPE,
unique: UmbId.new(),
parentUnique,
name: '',
alias: '',
content: '',
masterTemplate: null,
name: preset?.name ?? '',
alias: preset?.alias ?? '',
content: preset?.content ?? scaffold,
masterTemplate: preset?.masterTemplate ?? null,
};
return { data };
}

View File

@@ -1,5 +1,5 @@
import type { UmbTemplatingInsertMenuElement } from '../../components/insert-menu/templating-insert-menu.element.js';
import { UMB_MODAL_TEMPLATING_INSERT_SECTION_MODAL } from '../../modals/insert-section-modal/insert-section-modal.element.js';
import { UMB_TEMPLATING_SECTION_PICKER_MODAL } from '../../modals/templating-section-picker/templating-section-picker-modal.token.js';
import type { UmbTemplatingInsertMenuElement } from '../../components/templating-item-menu/templating-item-menu.element.js';
import { UMB_TEMPLATE_QUERY_BUILDER_MODAL } from '../modals/query-builder/index.js';
import { getQuerySnippet } from '../../utils/index.js';
import { UMB_TEMPLATE_WORKSPACE_CONTEXT } from './template-workspace.context.js';
@@ -108,7 +108,7 @@ export class UmbTemplateWorkspaceEditorElement extends UmbLitElement {
private _modalContext?: UmbModalManagerContext;
#openInsertSectionModal() {
const sectionModal = this._modalContext?.open(UMB_MODAL_TEMPLATING_INSERT_SECTION_MODAL);
const sectionModal = this._modalContext?.open(UMB_TEMPLATING_SECTION_PICKER_MODAL);
sectionModal?.onSubmit().then((insertSectionModalValue) => {
if (insertSectionModalValue?.value) {
this._codeEditor?.insert(insertSectionModalValue.value);
@@ -123,6 +123,7 @@ export class UmbTemplateWorkspaceEditorElement extends UmbLitElement {
#openMasterTemplatePicker() {
const modalContext = this._modalContext?.open(UMB_TEMPLATE_PICKER_MODAL, {
data: {
hideTreeRoot: true,
pickableFilter: (item) => {
return item.unique !== null && item.unique !== this.#templateWorkspaceContext?.getEntityId();
},
@@ -155,15 +156,13 @@ export class UmbTemplateWorkspaceEditorElement extends UmbLitElement {
@click=${this.#openMasterTemplatePicker}
look="secondary"
id="master-template-button"
label="Change Master template"
>${this._masterTemplateName
? `Master template: ${this._masterTemplateName}`
: 'Set master template'}</uui-button
>
label="${this.localize.term('template_mastertemplate')}: ${this._masterTemplateName
? this._masterTemplateName
: this.localize.term('template_noMaster')}"></uui-button>
${this._masterTemplateName
? html` <uui-button look="secondary" id="save-button" label="Remove master template" compact
><uui-icon name="icon-delete" @click=${this.#resetMasterTemplate}></uui-icon
></uui-button>`
? html`<uui-button look="secondary" label=${this.localize.term('actions_remove')} compact>
<uui-icon name="icon-delete" @click=${this.#resetMasterTemplate}></uui-icon>
</uui-button>`
: nothing}
</uui-button-group>
`;
@@ -181,35 +180,34 @@ export class UmbTemplateWorkspaceEditorElement extends UmbLitElement {
// TODO: add correct UI elements
return html`<umb-workspace-editor alias="Umb.Workspace.Template">
<uui-input
placeholder="Enter name..."
placeholder=${this.localize.term('placeholders_entername')}
slot="header"
.value=${this._name}
@input=${this.#onNameInput}
label="template name">
label=${this.localize.term('template_template')}>
<uui-input-lock slot="append" value=${ifDefined(this._alias!)} @input=${this.#onAliasInput}></uui-input-lock>
</uui-input>
<uui-box>
<div slot="header" id="code-editor-menu-container">
${this.#renderMasterTemplatePicker()}
<div>
<umb-templating-insert-menu @insert=${this.#insertSnippet}></umb-templating-insert-menu>
<uui-button
look="secondary"
id="query-builder-button"
label="Query builder"
@click=${this.#openQueryBuilder}>
<uui-icon name="icon-wand"></uui-icon>Query builder
</uui-button>
<uui-button
look="secondary"
id="sections-button"
label="Query builder"
@click=${this.#openInsertSectionModal}>
<uui-icon name="icon-indent"></uui-icon>Sections
</uui-button>
</div>
<div slot="header" id="code-editor-menu-container">${this.#renderMasterTemplatePicker()}</div>
<div slot="header-actions">
<umb-templating-insert-menu @insert=${this.#insertSnippet}></umb-templating-insert-menu>
<uui-button
look="secondary"
id="query-builder-button"
label=${this.localize.term('template_queryBuilder')}
@click=${this.#openQueryBuilder}>
<uui-icon name="icon-wand"></uui-icon> ${this.localize.term('template_queryBuilder')}
</uui-button>
<uui-button
look="secondary"
id="sections-button"
label=${this.localize.term('template_insertSections')}
@click=${this.#openInsertSectionModal}>
<uui-icon name="icon-indent"></uui-icon> ${this.localize.term('template_insertSections')}
</uui-button>
</div>
${this._ready
? this.#renderCodeEditor()
: html`<div id="loader-container">

View File

@@ -79,7 +79,7 @@ export class UmbTemplateWorkspaceContext
const { data } = await this.detailRepository.requestByUnique(unique);
if (data) {
this.setIsNew(false);
//this.setMasterTemplate(data.masterTemplateId ?? null);
this.setMasterTemplate(data.masterTemplate?.unique ?? null);
this.#data.setValue(data);
}
}
@@ -129,15 +129,14 @@ ${currentContent}`;
this.setContent(string);
};
async create(parentUnique: string | null) {
const { data } = await this.detailRepository.createScaffold(parentUnique);
async create(parentUnique: string | null, preset?: Partial<UmbTemplateDetailModel>) {
const { data } = await this.detailRepository.createScaffold(parentUnique, preset);
if (!data) return;
this.setIsNew(true);
this.#data.setValue(data);
/*
if (!parentUnique) return;
await this.setMasterTemplate(parentUnique);
*/
}
async save() {

View File

@@ -4,7 +4,7 @@ import { html, customElement, state } from '@umbraco-cms/backoffice/external/lit
import type { IRoutingInfo, PageComponent, UmbRoute } from '@umbraco-cms/backoffice/router';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import '../../components/insert-menu/templating-insert-menu.element.js';
import '../../components/templating-item-menu/templating-item-menu.element.js';
import { UmbWorkspaceIsNewRedirectController } from '@umbraco-cms/backoffice/workspace';
@customElement('umb-template-workspace')

View File

@@ -0,0 +1,4 @@
export enum CodeSnippetType {
partialView = 'partialView',
dictionaryItem = 'dictionaryItem',
}