diff --git a/src/Umbraco.Web.UI.Client/.vscode/settings.json b/src/Umbraco.Web.UI.Client/.vscode/settings.json index acc2fe2f0d..88fb1f27a3 100644 --- a/src/Umbraco.Web.UI.Client/.vscode/settings.json +++ b/src/Umbraco.Web.UI.Client/.vscode/settings.json @@ -20,6 +20,7 @@ "tinymce", "umbraco", "Uncategorized", + "uninitialize", "variantable" ], "exportall.config.folderListener": [], diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 9a9654021c..fec9e8be0d 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -124,6 +124,8 @@ "check": "npm run lint:errors && npm run compile && npm run build-storybook && npm run generate:jsonschema:dist", "compile": "tsc", "dev": "vite", + "dev:server": "VITE_UMBRACO_USE_MSW=off vite", + "dev:mock": "VITE_UMBRACO_USE_MSW=on vite", "example": "node ./devops/example-runner/index.js", "format:fix": "npm run format -- --write", "format": "prettier 'src/**/*.ts' -- check", diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.ts index ea693c4a95..2cdcf19a73 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.ts @@ -197,6 +197,8 @@ export class UmbSorterController) { + enable(): void { + if (this.#enabled) return; + this.#enabled = true; + this.#initialize(); + } + disable(): void { + if (!this.#enabled) return; + this.#enabled = false; + this.#uninitialize(); + } + + setModel(model: Array): void { if (this.#model) { // TODO: Some updates might need to be done, as the modal is about to changed? Do make the changes after setting the model?.. } @@ -250,9 +263,16 @@ export class UmbSorterController { + hostDisconnected() { + if (this.#enabled) { + this.#uninitialize(); + } + } + #initialize = () => { const containerEl = (this.#config.containerSelector ? this.#host.shadowRoot!.querySelector(this.#config.containerSelector) @@ -281,7 +301,7 @@ export class UmbSorterController { - if (isNew === false) { - const unique = workspaceContext.getUnique(); - if (router && unique) { - const routerPath = router.absoluteRouterPath; - if (routerPath) { - const newPath = createRoutePathBuilder(ensurePathEndsWithSlash(routerPath) + 'edit/:id')({ id: unique }); - window.history.pushState({}, '', newPath); - - this.destroy(); - } + this.observe(workspaceContext.isNew, (isNew) => { + if (isNew === false) { + const unique = workspaceContext.getUnique(); + if (router && unique) { + const routerPath = router.absoluteRouterPath; + if (routerPath) { + const newPath: string = createRoutePathBuilder(ensurePathEndsWithSlash(routerPath) + 'edit/:id')({ + id: unique, + }); + this.destroy(); + window.history.pushState({}, '', newPath); } } - }, - '_observeIsNew', - ); + } + }); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace-editor.element.ts index bd13a0cb55..62896e5616 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace-editor.element.ts @@ -41,7 +41,7 @@ export class UmbDataTypeWorkspaceEditorElement extends UmbLitElement { (this.shadowRoot!.querySelector('#nameInput') as HTMLElement).focus(); }); } - this.removeControllerByAlias('_observeIsNew'); + this.removeControllerByAlias('isNewRedirectController'); }, '_observeIsNew', ); diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace-editor.element.ts index 30754a156d..88c400624b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace-editor.element.ts @@ -54,7 +54,7 @@ export class UmbDocumentTypeWorkspaceEditorElement extends UmbLitElement { // TODO: Would be good with a more general way to bring focus to the name input. (this.shadowRoot?.querySelector('#name') as HTMLElement)?.focus(); } - this.removeControllerByAlias('_observeIsNew'); + this.removeControllerByAlias('isNewRedirectController'); }, '_observeIsNew', ); diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace.element.ts index b31fa0e01d..d8e12c252f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace.element.ts @@ -30,7 +30,7 @@ export class UmbDocumentTypeWorkspaceElement extends UmbLitElement { path: 'edit/:id', component: this.#createElement, setup: (_component, info) => { - this.removeControllerByAlias('_observeIsNew'); + this.removeControllerByAlias('isNewRedirectController'); const id = info.match.params.id; this.#workspaceContext.load(id); }, diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts index 1627991063..8498263bd9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts @@ -13,7 +13,6 @@ import { UMB_PROPERTY_SETTINGS_MODAL, UmbModalRouteRegistrationController } from @customElement('umb-document-type-workspace-view-edit-properties') export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitElement { - #model: Array = []; #sorter = new UmbSorterController(this, { getUniqueOfElement: (element) => { return element.getAttribute('data-umb-property-id'); @@ -29,8 +28,7 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle // 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; + onChange: ({ model }) => { this._propertyStructure = model; }, onEnd: ({ item }) => { @@ -38,7 +36,7 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle * 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 model = this._propertyStructure; const newIndex = model.findIndex((entry) => entry.id === item.id); // Doesn't exist in model @@ -123,6 +121,8 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle constructor() { super(); + this.#sorter.disable(); + this.consumeContext(UMB_WORKSPACE_CONTEXT, async (workspaceContext) => { this._propertyStructureHelper.setStructureManager( (workspaceContext as UmbDocumentTypeWorkspaceContext).structure, @@ -132,9 +132,9 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle (isSorting) => { this._sortModeActive = isSorting; if (isSorting) { - this.#sorter.setModel(this._propertyStructure); + this.#sorter.enable(); } else { - this.#sorter.setModel([]); + this.#sorter.disable(); } }, '_observeIsSorting', @@ -151,11 +151,7 @@ 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([]); - } + this.#sorter.setModel(this._propertyStructure); }); // Note: Route for adding a new property @@ -171,9 +167,6 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle return { data: { documentTypeId }, value: propertyData }; }) .onSubmit((value) => { - if (!value.dataType) { - throw new Error('No data type selected'); - } this.#addProperty(value as UmbPropertyTypeModel); }) .observeRouteBuilder((routeBuilder) => { diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts index 6172d07212..975e0a9137 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts @@ -93,9 +93,6 @@ export class UmbDocumentTypeWorkspacePropertyElement extends UmbLitElement { return { data: { documentTypeId }, value: propertyData }; }) .onSubmit((result) => { - if (!result.dataType) { - throw new Error('No dataType found on property'); - } this._partialUpdate(result as UmbPropertyTypeModel); }) .observeRouteBuilder((routeBuilder) => { diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-tab.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-tab.element.ts index f16d1512eb..c6c6516ea9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-tab.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-tab.element.ts @@ -16,7 +16,6 @@ import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; @customElement('umb-document-type-workspace-view-edit-tab') export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { - #model: Array = []; #sorter = new UmbSorterController( this, { @@ -28,14 +27,13 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { 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 model = this._groups; const newIndex = model.findIndex((entry) => entry.id === item.id); // Doesn't exist in model @@ -43,7 +41,7 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { // First in list if (newIndex === 0 && model.length > 1) { - this._groupStructureHelper.partialUpdateContainer(item.id, { sortOrder: model[1].sortOrder - 1 }); + this.#groupStructureHelper.partialUpdateContainer(item.id, { sortOrder: model[1].sortOrder - 1 }); return; } @@ -52,14 +50,14 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { const prevItemSortOrder = model[newIndex - 1].sortOrder; let weight = 1; - this._groupStructureHelper.partialUpdateContainer(item.id, { sortOrder: prevItemSortOrder + weight }); + 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 }); + this.#groupStructureHelper.partialUpdateContainer(entry.id, { sortOrder: prevItemSortOrder + weight }); } // Break the loop return true; @@ -80,7 +78,7 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { if (value === this._ownerTabId) return; const oldValue = this._ownerTabId; this._ownerTabId = value; - this._groupStructureHelper.setOwnerId(value); + this.#groupStructureHelper.setOwnerId(value); this.requestUpdate('ownerTabId', oldValue); } @@ -88,13 +86,13 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { @property({ type: String }) public get tabName(): string | undefined { - return this._groupStructureHelper.getName(); + return this.#groupStructureHelper.getName(); } public set tabName(value: string | undefined) { if (value === this._tabName) return; const oldValue = this._tabName; this._tabName = value; - this._groupStructureHelper.setName(value); + this.#groupStructureHelper.setName(value); this.requestUpdate('tabName', oldValue); } @@ -103,15 +101,13 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { @property({ type: Boolean }) public get noTabName(): boolean { - return this._groupStructureHelper.getIsRoot(); + return this.#groupStructureHelper.getIsRoot(); } public set noTabName(value: boolean) { this._noTabName = value; - this._groupStructureHelper.setIsRoot(value); + this.#groupStructureHelper.setIsRoot(value); } - _groupStructureHelper = new UmbContentTypeContainerStructureHelper(this); - @state() _groups: Array = []; @@ -121,35 +117,32 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { @state() _sortModeActive?: boolean; + #groupStructureHelper = new UmbContentTypeContainerStructureHelper(this); + constructor() { super(); this.consumeContext(UMB_WORKSPACE_CONTEXT, (context) => { - this._groupStructureHelper.setStructureManager((context as UmbDocumentTypeWorkspaceContext).structure); + 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.enable(); } else { - this.#sorter.setModel([]); + this.#sorter.disable(); } }, '_observeIsSorting', ); }); - this.observe(this._groupStructureHelper.containers, (groups) => { + this.observe(this.#groupStructureHelper.containers, (groups) => { this._groups = groups; - if (this._sortModeActive) { - this.#sorter.setModel(this._groups); - } else { - this.#sorter.setModel([]); - } + this.#sorter.setModel(this._groups); this.requestUpdate('_groups'); }); - this.observe(this._groupStructureHelper.hasProperties, (hasProperties) => { + this.observe(this.#groupStructureHelper.hasProperties, (hasProperties) => { this._hasProperties = hasProperties; this.requestUpdate('_hasProperties'); }); @@ -157,7 +150,7 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { #onAddGroup = () => { // Idea, maybe we can gather the sortOrder from the last group rendered and add 1 to it? - this._groupStructureHelper.addContainer(this._ownerTabId); + this.#groupStructureHelper.addContainer(this._ownerTabId); }; render() { @@ -186,7 +179,7 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement {
${repeat( this._groups, - (group) => group.id + '' + group.name + group.sortOrder, + (group) => group.id, (group) => html` ${this.#renderHeader(group)} @@ -203,7 +196,7 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { } #renderHeader(group: UmbPropertyTypeContainerModel) { - const inherited = !this._groupStructureHelper.isOwnerChildContainer(group.id!); + const inherited = !this.#groupStructureHelper.isOwnerChildContainer(group.id!); if (this._sortModeActive) { return html`
@@ -215,7 +208,7 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { type="number" label=${this.localize.term('sort_sortOrder')} @change=${(e: UUIInputEvent) => - this._groupStructureHelper.partialUpdateContainer(group.id!, { + this.#groupStructureHelper.partialUpdateContainer(group.id!, { sortOrder: parseInt(e.target.value as string) || 0, })} .value=${group.sortOrder || 0} @@ -235,7 +228,7 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { .value=${group.name} @change=${(e: InputEvent) => { const newName = (e.target as HTMLInputElement).value; - this._groupStructureHelper.updateContainerName(group.id!, group.parent?.id ?? null, newName); + this.#groupStructureHelper.updateContainerName(group.id!, group.parent?.id ?? null, newName); }}>`; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/language/workspace/language/language-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/language/workspace/language/language-workspace.element.ts index ddcb9fa94a..3f3b64048a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/language/workspace/language/language-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/language/workspace/language/language-workspace.element.ts @@ -29,7 +29,7 @@ export class UmbLanguageWorkspaceElement extends UmbLitElement { path: 'edit/:unique', component: this.#createElement, setup: (_component, info) => { - this.removeControllerByAlias('_observeIsNew'); + this.removeControllerByAlias('isNewRedirectController'); this.#languageWorkspaceContext.load(info.match.params.unique); }, }, diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/media-type-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/media-type-workspace-editor.element.ts index 3358ac83af..73824dd956 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/media-type-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/media-type-workspace-editor.element.ts @@ -55,7 +55,7 @@ export class UmbMediaTypeWorkspaceEditorElement extends UmbLitElement { // TODO: Would be good with a more general way to bring focus to the name input. (this.shadowRoot?.querySelector('#name') as HTMLElement)?.focus(); } - this.removeControllerByAlias('_observeIsNew'); + this.removeControllerByAlias('isNewRedirectController'); }, '_observeIsNew', ); diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/views/design/media-type-workspace-view-edit-property.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/views/design/media-type-workspace-view-edit-property.element.ts index 5a5f2a0731..4c42684238 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/views/design/media-type-workspace-view-edit-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/views/design/media-type-workspace-view-edit-property.element.ts @@ -94,9 +94,6 @@ export class UmbMediaTypeWorkspacePropertyElement extends UmbLitElement { return { data: { documentTypeId: mediaTypeId }, value: propertyData }; //TODO: Should we have a separate modal for mediaTypes? }) .onSubmit((result) => { - if (!result.dataType) { - throw new Error('No dataType found on property'); - } this._partialUpdate(result as UmbPropertyTypeModel); }) .observeRouteBuilder((routeBuilder) => {