From 26f594332ef61a68e38b5af6277d4d0d5c802a76 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 22 Aug 2024 09:21:48 +0200 Subject: [PATCH 01/34] Update manifests.ts --- .../block-list/property-editors/block-list-editor/manifests.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/manifests.ts index c3d07105cc..e734bfaad1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/manifests.ts @@ -14,6 +14,7 @@ export const manifests: Array = [ propertyEditorSchemaAlias: UMB_BLOCK_LIST_PROPERTY_EDITOR_ALIAS, icon: 'icon-thumbnail-list', group: 'lists', + supportsReadOnly: true, settings: { properties: [ { From 0ffbf5b36a3c71b5bb885e6f48678dccbd938abf Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 22 Aug 2024 09:21:56 +0200 Subject: [PATCH 02/34] add readonly prop --- .../property-editor-ui-block-list.element.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts index 9e263cf849..00cd9340d9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts @@ -113,6 +113,15 @@ export class UmbPropertyEditorUIBlockListElement } } + /** + * Sets the input to readonly mode, meaning value cannot be changed but still able to read and select its content. + * @type {boolean} + * @attr + * @default false + */ + @property({ type: Boolean, reflect: true }) + readonly = false; + @state() private _limitMin?: number; @state() From 66a9f5353b03b653fc5a5f61b09db08804949969 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 22 Aug 2024 09:49:34 +0200 Subject: [PATCH 03/34] disable sorting when readonly --- .../property-editor-ui-block-list.element.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts index 00cd9340d9..62ad4e56ac 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts @@ -120,7 +120,19 @@ export class UmbPropertyEditorUIBlockListElement * @default false */ @property({ type: Boolean, reflect: true }) - readonly = false; + public get readonly() { + return this.#readonly; + } + public set readonly(value) { + this.#readonly = value; + + if (this.#readonly) { + this.#sorter.disable(); + } else { + this.#sorter.enable(); + } + } + #readonly = false; @state() private _limitMin?: number; From 5699936722d1674a9ae7b2262cef90cd82fc6fc5 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 22 Aug 2024 09:53:00 +0200 Subject: [PATCH 04/34] remove inline create button when readonly --- .../property-editor-ui-block-list.element.ts | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts index 62ad4e56ac..7fa69fc27f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts @@ -4,7 +4,7 @@ import type { UmbBlockListLayoutModel, UmbBlockListValueModel } from '../../type import type { UmbBlockListEntryElement } from '../../components/block-list-entry/index.js'; import { UMB_BLOCK_LIST_PROPERTY_EDITOR_ALIAS } from './manifests.js'; import { UmbLitElement, umbDestroyOnDisconnect } from '@umbraco-cms/backoffice/lit-element'; -import { html, customElement, property, state, repeat, css } from '@umbraco-cms/backoffice/external/lit'; +import { html, customElement, property, state, repeat, css, nothing } from '@umbraco-cms/backoffice/external/lit'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import type { UmbPropertyEditorUiElement, UmbBlockTypeBaseModel } from '@umbraco-cms/backoffice/extension-registry'; import { @@ -244,15 +244,14 @@ export class UmbPropertyEditorUIBlockListElement return html` ${repeat( this._layouts, (x) => x.contentUdi, - (layoutEntry, index) => - html` - - `, + (layoutEntry, index) => html` + ${this.#renderInlineCreateButton(index)} + + + `, )} @@ -265,6 +264,13 @@ export class UmbPropertyEditorUIBlockListElement `; } + #renderInlineCreateButton(index: number) { + if (this.readonly) return nothing; + return html``; + } + static override styles = [ UmbTextStyles, From 3d3e76dd8110c2c800ce6e638af9a0360abce569 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 22 Aug 2024 09:55:20 +0200 Subject: [PATCH 05/34] remove create button when readonly --- .../property-editor-ui-block-list.element.ts | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts index 7fa69fc27f..1c8f611360 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts @@ -233,14 +233,6 @@ export class UmbPropertyEditorUIBlockListElement } override render() { - let createPath: string | undefined; - if (this._blocks?.length === 1) { - const elementKey = this._blocks[0].contentElementTypeKey; - createPath = - this._catalogueRouteBuilder?.({ view: 'create', index: -1 }) + 'modal/umb-modal-workspace/create/' + elementKey; - } else { - createPath = this._catalogueRouteBuilder?.({ view: 'create', index: -1 }); - } return html` ${repeat( this._layouts, (x) => x.contentUdi, @@ -254,7 +246,7 @@ export class UmbPropertyEditorUIBlockListElement `, )} - + ${this.#renderCreateButton()} `; } + #renderCreateButton() { + if (this.readonly) return nothing; + + let createPath: string | undefined; + if (this._blocks?.length === 1) { + const elementKey = this._blocks[0].contentElementTypeKey; + createPath = + this._catalogueRouteBuilder?.({ view: 'create', index: -1 }) + 'modal/umb-modal-workspace/create/' + elementKey; + } else { + createPath = this._catalogueRouteBuilder?.({ view: 'create', index: -1 }); + } + + return html` + + `; + } + static override styles = [ UmbTextStyles, From 523a3b49779e6284cfe3281e14c5361c9693967c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 22 Aug 2024 09:56:26 +0200 Subject: [PATCH 06/34] remove paste button when readonly --- .../property-editor-ui-block-list.element.ts | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts index 1c8f611360..b4cc38059d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts @@ -245,15 +245,7 @@ export class UmbPropertyEditorUIBlockListElement `, )} - - ${this.#renderCreateButton()} - - - - `; + ${this.#renderCreateButton()} ${this.#renderPasteButton()} `; } #renderInlineCreateButton(index: number) { @@ -280,6 +272,18 @@ export class UmbPropertyEditorUIBlockListElement `; } + #renderPasteButton() { + if (this.readonly) return nothing; + return html` + + + + `; + } + static override styles = [ UmbTextStyles, From c031d293c625490f57e8076267bbe221d4a616f5 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 22 Aug 2024 10:16:56 +0200 Subject: [PATCH 07/34] split block-list-entry actions into multiple renders --- .../block-list-entry.element.ts | 66 +++++++++++-------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-entry/block-list-entry.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-entry/block-list-entry.element.ts index 6433e33864..d0641cf0e3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-entry/block-list-entry.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-entry/block-list-entry.element.ts @@ -251,33 +251,7 @@ export class UmbBlockListEntryElement extends UmbLitElement implements UmbProper >${this._inlineEditingMode ? this.#renderInlineBlock() : this.#renderRefBlock()} - ${this._showContentEdit && this._workspaceEditContentPath - ? html` - - ${this._contentInvalid - ? html`!` - : nothing} - ` - : nothing} - ${this._hasSettings && this._workspaceEditSettingsPath - ? html` - - ${this._settingsInvalid - ? html`!` - : nothing} - ` - : nothing} - this.#context.requestDelete()}> - - + ${this.#renderEditContentAction()} ${this.#renderEditSettingsAction()} ${this.#renderDeleteAction()} ${!this._showContentEdit && this._contentInvalid ? html`!` @@ -285,6 +259,44 @@ export class UmbBlockListEntryElement extends UmbLitElement implements UmbProper `; } + #renderEditContentAction() { + return html` ${this._showContentEdit && this._workspaceEditContentPath + ? html` + + ${this._contentInvalid + ? html`!` + : nothing} + ` + : nothing}`; + } + + #renderEditSettingsAction() { + return html` + ${this._hasSettings && this._workspaceEditSettingsPath + ? html` + + ${this._settingsInvalid + ? html`!` + : nothing} + ` + : nothing} + `; + } + + #renderDeleteAction() { + return html` this.#context.requestDelete()}> + + `; + } + override render() { return this.#renderBlock(); } From f48e18c46d82a672fedfd468fcf02a0f94f5115b Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 22 Aug 2024 10:20:20 +0200 Subject: [PATCH 08/34] accept readonly prop --- .../block-list-entry/block-list-entry.element.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-entry/block-list-entry.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-entry/block-list-entry.element.ts index d0641cf0e3..3da65903c0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-entry/block-list-entry.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-entry/block-list-entry.element.ts @@ -48,6 +48,15 @@ export class UmbBlockListEntryElement extends UmbLitElement implements UmbProper } private _contentUdi?: string | undefined; + /** + * Sets the element to readonly mode, meaning value cannot be changed but still able to read and select its content. + * @type {boolean} + * @attr + * @default false + */ + @property({ type: Boolean, reflect: true }) + public readonly = false; + #context = new UmbBlockListEntryContext(this); @state() From e19ed12c0c6a2c5204eeaaef832d203ece8cd5e9 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 22 Aug 2024 10:20:33 +0200 Subject: [PATCH 09/34] remove delete action when readonly --- .../components/block-list-entry/block-list-entry.element.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-entry/block-list-entry.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-entry/block-list-entry.element.ts index 3da65903c0..b7ee9dd6dc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-entry/block-list-entry.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-entry/block-list-entry.element.ts @@ -301,6 +301,7 @@ export class UmbBlockListEntryElement extends UmbLitElement implements UmbProper } #renderDeleteAction() { + if (this.readonly) return nothing; return html` this.#context.requestDelete()}> `; From 4dc38334755e1f66a2bebf36f958138bd93dddb8 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 22 Aug 2024 10:21:13 +0200 Subject: [PATCH 10/34] pass readonly to block-list-entry --- .../block-list-editor/property-editor-ui-block-list.element.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts index b4cc38059d..d8244b94db 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts @@ -241,6 +241,7 @@ export class UmbPropertyEditorUIBlockListElement `, From b283a0a4e8d4e88ffafe45353386b1c1b69f5652 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 22 Aug 2024 13:36:44 +0200 Subject: [PATCH 11/34] add read only state manager --- .../block/block/workspace/block-workspace.context.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts index c94569ca8a..d60cd50116 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts @@ -10,7 +10,7 @@ import { UmbClassState, UmbObjectState, UmbStringState } from '@umbraco-cms/back import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { ManifestWorkspace } from '@umbraco-cms/backoffice/extension-registry'; import { UMB_MODAL_CONTEXT } from '@umbraco-cms/backoffice/modal'; -import { decodeFilePath } from '@umbraco-cms/backoffice/utils'; +import { decodeFilePath, UmbReadOnlyVariantStateManager } from '@umbraco-cms/backoffice/utils'; import { UMB_BLOCK_ENTRIES_CONTEXT, UMB_BLOCK_MANAGER_CONTEXT, @@ -59,6 +59,9 @@ export class UmbBlockWorkspaceContext(undefined); readonly variantId = this.#variantId.asObservable(); + #readOnlyState = new UmbReadOnlyVariantStateManager(this); + public readonly readOnlyState = this.#readOnlyState; + constructor(host: UmbControllerHost, workspaceArgs: { manifest: ManifestWorkspace }) { super(host, workspaceArgs.manifest.alias); const manifest = workspaceArgs.manifest; From 4c479209162f27f44a289719116830fed383beb8 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 22 Aug 2024 13:37:19 +0200 Subject: [PATCH 12/34] set all block content to read only if the outer property is read only --- .../workspace/block-workspace.context.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts index d60cd50116..570207b26e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts @@ -94,6 +94,25 @@ export class UmbBlockWorkspaceContext { this.#variantId.setValue(variantId); }); + + // If the current property is readonly all inner block content should also be readonly. + this.observe(context.isReadOnly, (isReadOnly) => { + const unique = 'UMB_PROPERTY'; + const variantId = this.#variantId.getValue(); + if (variantId === undefined) return; + + if (isReadOnly) { + const state = { + unique, + variantId, + message: '', + }; + + this.#readOnlyState?.addState(state); + } else { + this.#readOnlyState?.removeState(unique); + } + }); }); this.observe(this.variantId, (variantId) => { From 94b7af1f70fe29fe3b561415506cf47a4d49fd10 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 22 Aug 2024 13:37:46 +0200 Subject: [PATCH 13/34] update state based on manager --- .../block-element-property-dataset.context.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-property-dataset.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-property-dataset.context.ts index c7451f7806..4db36b5497 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-property-dataset.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-element-property-dataset.context.ts @@ -1,5 +1,6 @@ import { UMB_BLOCK_ELEMENT_PROPERTY_DATASET_CONTEXT } from './block-element-property-dataset.context-token.js'; import type { UmbBlockElementManager } from './block-element-manager.js'; +import { UMB_BLOCK_WORKSPACE_CONTEXT } from './block-workspace.context-token.js'; import type { UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property'; import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; @@ -36,6 +37,16 @@ export class UmbBlockElementPropertyDatasetContext extends UmbControllerBase imp super(host, UMB_PROPERTY_DATASET_CONTEXT.toString()); this.#elementManager = elementManager; + this.consumeContext(UMB_BLOCK_WORKSPACE_CONTEXT, (workspace) => { + this.observe( + workspace.readOnlyState.isOn, + (value) => { + this.#currentVariantCultureIsReadOnly.setValue(value); + }, + 'umbObserveReadOnlyStates', + ); + }); + this.provideContext(UMB_BLOCK_ELEMENT_PROPERTY_DATASET_CONTEXT, this); } From 837fc769efaaaca483d5e009657724dc6091100a Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 23 Aug 2024 11:30:50 +0200 Subject: [PATCH 14/34] add pickable filter prop --- ...ocument-variant-language-picker.element.ts | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts index de6c4da99f..48a89d1403 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts @@ -29,28 +29,41 @@ export class UmbDocumentVariantLanguagePickerElement extends UmbLitElement { @state() _selection: Array = []; + /** + * A filter function that determines if an item is pickableFilter or not. + * @memberof UmbDocumentVariantLanguagePickerElement + * @returns {boolean} - True if the item is pickableFilter, false otherwise. + */ + public pickableFilter: (item: UmbDocumentVariantOptionModel) => boolean = () => true; + override render() { return this.variantLanguageOptions.length ? repeat( this.variantLanguageOptions, (option) => option.unique, - (option) => html` - this.selectionManager.select(option.unique)} - @deselected=${() => this.selectionManager.deselect(option.unique)} - ?selected=${this._selection.includes(option.unique)}> - - ${UmbDocumentVariantLanguagePickerElement.renderLabel(option)} - - `, + (option) => html` ${this.#renderItem(option)} `, ) : html` There are no available variants `; } + #renderItem(option: UmbDocumentVariantOptionModel) { + const pickable = this.pickableFilter(option); + return html` + this.selectionManager.select(option.unique)} + @deselected=${() => this.selectionManager.deselect(option.unique)} + ?selected=${this._selection.includes(option.unique)}> + + ${UmbDocumentVariantLanguagePickerElement.renderLabel(option)} + + `; + } + static renderLabel(option: UmbDocumentVariantOptionModel) { return html`
From 6b6b93be0a431be8fcbb05729a0909b626d82d6a Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 23 Aug 2024 11:31:23 +0200 Subject: [PATCH 15/34] observe the readonly variants --- .../save-modal/document-save-modal.element.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/save-modal/document-save-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/save-modal/document-save-modal.element.ts index cee6274984..1b5d736dd0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/save-modal/document-save-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/save-modal/document-save-modal.element.ts @@ -1,4 +1,5 @@ import type { UmbDocumentVariantOptionModel } from '../../types.js'; +import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from '../../workspace/document-workspace.context-token.js'; import type { UmbDocumentSaveModalData, UmbDocumentSaveModalValue } from './document-save-modal.token.js'; import { css, customElement, html, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal'; @@ -17,6 +18,23 @@ export class UmbDocumentSaveModalElement extends UmbModalBaseElement< @state() _options: Array = []; + @state() + _readOnlyCultures: Array = []; + + constructor() { + super(); + + this.consumeContext(UMB_DOCUMENT_WORKSPACE_CONTEXT, (context) => { + this.observe( + context.readOnlyState.states, + (states) => { + this._readOnlyCultures = states.map((s) => s.variantId.culture); + }, + 'umbObserveReadOnlyStates', + ); + }); + } + override firstUpdated() { this.#configureSelectionManager(); } From 63a8d236b5ff33cd2394a2ffb55093068b406f5a Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 23 Aug 2024 11:31:50 +0200 Subject: [PATCH 16/34] disable the readonly languages --- .../modals/save-modal/document-save-modal.element.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/save-modal/document-save-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/save-modal/document-save-modal.element.ts index 1b5d736dd0..315d1da569 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/save-modal/document-save-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/save-modal/document-save-modal.element.ts @@ -63,6 +63,10 @@ export class UmbDocumentSaveModalElement extends UmbModalBaseElement< this.modalContext?.reject(); } + #userCanPickLanguageVariant = (option: UmbDocumentVariantOptionModel) => { + return this._readOnlyCultures.includes(option.culture) === false; + }; + override render() { return html`

@@ -71,7 +75,8 @@ export class UmbDocumentSaveModalElement extends UmbModalBaseElement< + .variantLanguageOptions=${this._options} + .pickableFilter=${this.#userCanPickLanguageVariant}>

From 97e38d33ef85a88954c966b34077b872f9d94971 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 23 Aug 2024 11:43:21 +0200 Subject: [PATCH 17/34] use language name in save dialog --- .../modals/shared/document-variant-language-picker.element.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts index 48a89d1403..e53fb30b94 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts @@ -66,9 +66,7 @@ export class UmbDocumentVariantLanguagePickerElement extends UmbLitElement { static renderLabel(option: UmbDocumentVariantOptionModel) { return html`
- - ${option.variant?.segment ? option.variant.segment + ' - ' : ''}${option.variant?.name ?? option.language.name} - + ${option.language.name}
${UmbDocumentVariantLanguagePickerElement.renderVariantStatus(option)}
${option.language.isMandatory && option.variant?.state !== UmbDocumentVariantState.PUBLISHED ? html`
From 39f4aad6c391e04b0c8078bac06efa00b023747b Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 23 Aug 2024 11:50:20 +0200 Subject: [PATCH 18/34] filter pickable languages to publish --- .../document-publish-modal.element.ts | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/publish-modal/document-publish-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/publish-modal/document-publish-modal.element.ts index 24cc03526e..49075f8c87 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/publish-modal/document-publish-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/publish-modal/document-publish-modal.element.ts @@ -1,3 +1,4 @@ +import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from '../../workspace/index.js'; import { UmbDocumentVariantState, type UmbDocumentVariantOptionModel } from '../../types.js'; import type { UmbDocumentPublishModalData, UmbDocumentPublishModalValue } from './document-publish-modal.token.js'; import { css, customElement, html, state } from '@umbraco-cms/backoffice/external/lit'; @@ -17,6 +18,23 @@ export class UmbDocumentPublishModalElement extends UmbModalBaseElement< @state() _options: Array = []; + @state() + _readOnlyCultures: Array = []; + + constructor() { + super(); + + this.consumeContext(UMB_DOCUMENT_WORKSPACE_CONTEXT, (context) => { + this.observe( + context.readOnlyState.states, + (states) => { + this._readOnlyCultures = states.map((s) => s.variantId.culture); + }, + 'umbObserveReadOnlyStates', + ); + }); + } + override firstUpdated() { this.#configureSelectionManager(); } @@ -46,6 +64,10 @@ export class UmbDocumentPublishModalElement extends UmbModalBaseElement< }); } + #userCanPickLanguageVariant = (option: UmbDocumentVariantOptionModel) => { + return this._readOnlyCultures.includes(option.culture) === false; + }; + #submit() { this.value = { selection: this.#selectionManager.getSelection() }; this.modalContext?.submit(); @@ -62,7 +84,8 @@ export class UmbDocumentPublishModalElement extends UmbModalBaseElement<

+ .variantLanguageOptions=${this._options} + .pickableFilter=${this.#userCanPickLanguageVariant}>

All new variants will be saved.

From 264345b874b74f0ce0331531a28afacf0e51344a Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 23 Aug 2024 13:20:46 +0200 Subject: [PATCH 19/34] add method to get states --- .../packages/core/utils/state-manager/state.manager.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/utils/state-manager/state.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/utils/state-manager/state.manager.ts index af6e8247c5..890f31b6e2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/utils/state-manager/state.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/utils/state-manager/state.manager.ts @@ -76,6 +76,15 @@ export class UmbStateManager extends UmbC this._states.setValue(this._states.getValue().filter((x) => !uniques.includes(x.unique))); } + /** + * Get all states from the state manager + * @returns {StateType[]} {StateType[]} All states in the state manager + * @memberof UmbStateManager + */ + getStates() { + return this._states.getValue(); + } + /** * Clear all states from the state manager * @memberof UmbStateManager From cd2beb196ca6a8020770736056050d4118bf04c9 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 23 Aug 2024 13:21:03 +0200 Subject: [PATCH 20/34] remove logic from save modal --- .../save-modal/document-save-modal.element.ts | 24 +------------------ 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/save-modal/document-save-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/save-modal/document-save-modal.element.ts index 315d1da569..337c8867d1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/save-modal/document-save-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/save-modal/document-save-modal.element.ts @@ -1,5 +1,4 @@ import type { UmbDocumentVariantOptionModel } from '../../types.js'; -import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from '../../workspace/document-workspace.context-token.js'; import type { UmbDocumentSaveModalData, UmbDocumentSaveModalValue } from './document-save-modal.token.js'; import { css, customElement, html, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal'; @@ -18,23 +17,6 @@ export class UmbDocumentSaveModalElement extends UmbModalBaseElement< @state() _options: Array = []; - @state() - _readOnlyCultures: Array = []; - - constructor() { - super(); - - this.consumeContext(UMB_DOCUMENT_WORKSPACE_CONTEXT, (context) => { - this.observe( - context.readOnlyState.states, - (states) => { - this._readOnlyCultures = states.map((s) => s.variantId.culture); - }, - 'umbObserveReadOnlyStates', - ); - }); - } - override firstUpdated() { this.#configureSelectionManager(); } @@ -63,10 +45,6 @@ export class UmbDocumentSaveModalElement extends UmbModalBaseElement< this.modalContext?.reject(); } - #userCanPickLanguageVariant = (option: UmbDocumentVariantOptionModel) => { - return this._readOnlyCultures.includes(option.culture) === false; - }; - override render() { return html`

@@ -76,7 +54,7 @@ export class UmbDocumentSaveModalElement extends UmbModalBaseElement< + .pickableFilter=${this.data?.pickableFilter}>

From b1055bbb2abbbac4ff4f1296b88a8232e70372b0 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 23 Aug 2024 13:21:18 +0200 Subject: [PATCH 21/34] add pickable filter option to modal --- .../src/packages/documents/documents/modals/types.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/types.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/types.ts index d131490619..d3e91cdf89 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/types.ts @@ -2,6 +2,7 @@ import type { UmbDocumentVariantOptionModel } from '../types.js'; export interface UmbDocumentVariantPickerData { options: Array; + pickableFilter?: (variantOption: UmbDocumentVariantOptionModel) => boolean; } export interface UmbDocumentVariantPickerValue { From a32b3a5b8ffb9f92deff00c5b234125604b0ebd1 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 23 Aug 2024 13:21:45 +0200 Subject: [PATCH 22/34] add fallback filter --- ...ocument-variant-language-picker.element.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts index e53fb30b94..0ce8782c5c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts @@ -34,7 +34,22 @@ export class UmbDocumentVariantLanguagePickerElement extends UmbLitElement { * @memberof UmbDocumentVariantLanguagePickerElement * @returns {boolean} - True if the item is pickableFilter, false otherwise. */ - public pickableFilter: (item: UmbDocumentVariantOptionModel) => boolean = () => true; + + @property({ attribute: false }) + public get pickableFilter(): ((item: UmbDocumentVariantOptionModel) => boolean) | undefined { + return this.#pickableFilter; + } + public set pickableFilter(value: ((item: UmbDocumentVariantOptionModel) => boolean) | undefined) { + this.#pickableFilter = value; + + if (this.#pickableFilter) { + this.#pickableFilter; + } else { + this.#pickableFilter = () => true; + } + } + + #pickableFilter: ((item: UmbDocumentVariantOptionModel) => boolean) | undefined; override render() { return this.variantLanguageOptions.length @@ -49,7 +64,7 @@ export class UmbDocumentVariantLanguagePickerElement extends UmbLitElement { } #renderItem(option: UmbDocumentVariantOptionModel) { - const pickable = this.pickableFilter(option); + const pickable = this.#pickableFilter(option); return html` Date: Fri, 23 Aug 2024 13:22:00 +0200 Subject: [PATCH 23/34] pass pickable filter to modals --- .../workspace/document-workspace.context.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts index 9186d6db4b..628daff443 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts @@ -25,7 +25,7 @@ import { } from '../paths.js'; import { UMB_DOCUMENTS_SECTION_PATH } from '../../section/paths.js'; import { UmbDocumentPreviewRepository } from '../repository/preview/index.js'; -import { sortVariants } from '../utils.js'; + import { UMB_DOCUMENT_WORKSPACE_ALIAS } from './manifests.js'; import { UmbEntityContext } from '@umbraco-cms/backoffice/entity'; import { UMB_INVARIANT_CULTURE, UmbVariantId } from '@umbraco-cms/backoffice/variant'; @@ -104,7 +104,7 @@ export class UmbDocumentWorkspaceContext /*#blueprint = new UmbObjectState(undefined); public readonly blueprint = this.#blueprint.asObservable();*/ - readOnlyState = new UmbReadOnlyVariantStateManager(this); + public readOnlyState = new UmbReadOnlyVariantStateManager(this); public isLoaded() { return this.#getDataPromise; @@ -161,7 +161,7 @@ export class UmbDocumentWorkspaceContext } return [] as Array; }, - ).pipe(map((results) => results.sort(sortVariants))); + ); // TODO: this should be set up for all entity workspace contexts in a base class #entityContext = new UmbEntityContext(this); @@ -637,6 +637,11 @@ export class UmbDocumentWorkspaceContext } } + #readOnlyLanguageVariantsFilter = (option: UmbDocumentVariantOptionModel) => { + const readOnlyCultures = this.readOnlyState.getStates().map((s) => s.variantId.culture); + return readOnlyCultures.includes(option.culture) === false; + }; + async #handleSaveAndPreview() { const unique = this.getUnique(); if (!unique) throw new Error('Unique is missing'); @@ -681,6 +686,7 @@ export class UmbDocumentWorkspaceContext .open(this, UMB_DOCUMENT_PUBLISH_MODAL, { data: { options, + pickableFilter: this.#readOnlyLanguageVariantsFilter, }, value: { selection: selected }, }) @@ -786,6 +792,7 @@ export class UmbDocumentWorkspaceContext .open(this, UMB_DOCUMENT_SAVE_MODAL, { data: { options, + pickableFilter: this.#readOnlyLanguageVariantsFilter, }, value: { selection: selected }, }) @@ -833,6 +840,7 @@ export class UmbDocumentWorkspaceContext .open(this, UMB_DOCUMENT_SCHEDULE_MODAL, { data: { options, + pickableFilter: this.#readOnlyLanguageVariantsFilter, }, value: { selection: selected.map((unique) => ({ unique, schedule: {} })) }, }) @@ -873,6 +881,7 @@ export class UmbDocumentWorkspaceContext .open(this, UMB_DOCUMENT_PUBLISH_WITH_DESCENDANTS_MODAL, { data: { options, + pickableFilter: this.#readOnlyLanguageVariantsFilter, }, value: { selection: selected }, }) From 63b67ec8450e7d1539baea681652280ac2eba6a9 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 23 Aug 2024 14:26:45 +0200 Subject: [PATCH 24/34] remove unused --- .../documents/documents/workspace/document-workspace.context.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts index 628daff443..70591fc131 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts @@ -46,7 +46,7 @@ import { } from '@umbraco-cms/backoffice/observable-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbLanguageCollectionRepository, type UmbLanguageDetailModel } from '@umbraco-cms/backoffice/language'; -import { type Observable, firstValueFrom, map } from '@umbraco-cms/backoffice/external/rxjs'; +import { type Observable, firstValueFrom } from '@umbraco-cms/backoffice/external/rxjs'; import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; import { UmbRequestReloadChildrenOfEntityEvent, From 21429121c9542d2347d5a32eac67fc6c8dbfc0e3 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 23 Aug 2024 14:27:06 +0200 Subject: [PATCH 25/34] pass filter --- .../document-publish-modal.element.ts | 24 +------------------ ...-publish-with-descendants-modal.element.ts | 3 ++- ...ocument-variant-language-picker.element.ts | 18 ++------------ .../document-unpublish-modal.element.ts | 3 ++- 4 files changed, 7 insertions(+), 41 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/publish-modal/document-publish-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/publish-modal/document-publish-modal.element.ts index 49075f8c87..f17353719b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/publish-modal/document-publish-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/publish-modal/document-publish-modal.element.ts @@ -1,4 +1,3 @@ -import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from '../../workspace/index.js'; import { UmbDocumentVariantState, type UmbDocumentVariantOptionModel } from '../../types.js'; import type { UmbDocumentPublishModalData, UmbDocumentPublishModalValue } from './document-publish-modal.token.js'; import { css, customElement, html, state } from '@umbraco-cms/backoffice/external/lit'; @@ -18,23 +17,6 @@ export class UmbDocumentPublishModalElement extends UmbModalBaseElement< @state() _options: Array = []; - @state() - _readOnlyCultures: Array = []; - - constructor() { - super(); - - this.consumeContext(UMB_DOCUMENT_WORKSPACE_CONTEXT, (context) => { - this.observe( - context.readOnlyState.states, - (states) => { - this._readOnlyCultures = states.map((s) => s.variantId.culture); - }, - 'umbObserveReadOnlyStates', - ); - }); - } - override firstUpdated() { this.#configureSelectionManager(); } @@ -64,10 +46,6 @@ export class UmbDocumentPublishModalElement extends UmbModalBaseElement< }); } - #userCanPickLanguageVariant = (option: UmbDocumentVariantOptionModel) => { - return this._readOnlyCultures.includes(option.culture) === false; - }; - #submit() { this.value = { selection: this.#selectionManager.getSelection() }; this.modalContext?.submit(); @@ -85,7 +63,7 @@ export class UmbDocumentPublishModalElement extends UmbModalBaseElement< + .pickableFilter=${this.data?.pickableFilter}>

All new variants will be saved.

diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/publish-with-descendants-modal/document-publish-with-descendants-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/publish-with-descendants-modal/document-publish-with-descendants-modal.element.ts index 23a3a49e2c..1c1899711c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/publish-with-descendants-modal/document-publish-with-descendants-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/publish-with-descendants-modal/document-publish-with-descendants-modal.element.ts @@ -82,7 +82,8 @@ export class UmbDocumentPublishWithDescendantsModalElement extends UmbModalBaseE + .variantLanguageOptions=${this._options} + .pickableFilter=${this.data?.pickableFilter}> boolean) | undefined { - return this.#pickableFilter; - } - public set pickableFilter(value: ((item: UmbDocumentVariantOptionModel) => boolean) | undefined) { - this.#pickableFilter = value; - - if (this.#pickableFilter) { - this.#pickableFilter; - } else { - this.#pickableFilter = () => true; - } - } - - #pickableFilter: ((item: UmbDocumentVariantOptionModel) => boolean) | undefined; + public pickableFilter?: (item: UmbDocumentVariantOptionModel) => boolean; override render() { return this.variantLanguageOptions.length @@ -64,7 +50,7 @@ export class UmbDocumentVariantLanguagePickerElement extends UmbLitElement { } #renderItem(option: UmbDocumentVariantOptionModel) { - const pickable = this.#pickableFilter(option); + const pickable = this.pickableFilter ? this.pickableFilter(option) : () => true; return html` + .variantLanguageOptions=${this._options} + .pickableFilter=${this.data?.pickableFilter}>

From 9871a68830950c44b36368dbbe5ce1cfed95858e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 23 Aug 2024 14:27:24 +0200 Subject: [PATCH 26/34] implement readonly for schedule --- .../document-schedule-modal.element.ts | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/schedule-modal/document-schedule-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/schedule-modal/document-schedule-modal.element.ts index aa4b3e1575..643285640c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/schedule-modal/document-schedule-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/schedule-modal/document-schedule-modal.element.ts @@ -101,21 +101,28 @@ export class UmbDocumentScheduleModalElement extends UmbModalBaseElement< return repeat( this._options, (option) => option.unique, - (option) => html` - this.#selectionManager.select(option.unique)} - @deselected=${() => this.#selectionManager.deselect(option.unique)} - ?selected=${this.#isSelected(option.unique)}> - - ${UmbDocumentVariantLanguagePickerElement.renderLabel(option)} - - ${when(this.#isSelected(option.unique), () => this.#renderPublishDateInput(option))} - `, + (option) => this.#renderItem(option), ); } + #renderItem(option: UmbDocumentVariantOptionModel) { + const pickable = this.data?.pickableFilter ? this.data.pickableFilter(option) : () => true; + + return html` + this.#selectionManager.select(option.unique)} + @deselected=${() => this.#selectionManager.deselect(option.unique)} + ?selected=${this.#isSelected(option.unique)}> + + ${UmbDocumentVariantLanguagePickerElement.renderLabel(option)} + + ${when(this.#isSelected(option.unique), () => this.#renderPublishDateInput(option))} + `; + } + #renderPublishDateInput(option: UmbDocumentVariantOptionModel) { return html`

From da73550d6a89dab9ee8911ee6c728e9137f52a49 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 30 Aug 2024 14:01:21 +0200 Subject: [PATCH 27/34] Update document-workspace.context.ts --- .../documents/workspace/document-workspace.context.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts index 70591fc131..74b0629683 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts @@ -46,7 +46,7 @@ import { } from '@umbraco-cms/backoffice/observable-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbLanguageCollectionRepository, type UmbLanguageDetailModel } from '@umbraco-cms/backoffice/language'; -import { type Observable, firstValueFrom } from '@umbraco-cms/backoffice/external/rxjs'; +import { type Observable, firstValueFrom, map } from '@umbraco-cms/backoffice/external/rxjs'; import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; import { UmbRequestReloadChildrenOfEntityEvent, @@ -68,6 +68,7 @@ import type { UmbContentWorkspaceContext } from '@umbraco-cms/backoffice/content import type { UmbDocumentTypeDetailModel } from '@umbraco-cms/backoffice/document-type'; import { UmbIsTrashedEntityContext } from '@umbraco-cms/backoffice/recycle-bin'; import { UmbReadOnlyVariantStateManager } from '@umbraco-cms/backoffice/utils'; +import { sortVariants } from '../utils.js'; type EntityType = UmbDocumentDetailModel; export class UmbDocumentWorkspaceContext @@ -161,7 +162,7 @@ export class UmbDocumentWorkspaceContext } return [] as Array; }, - ); + ).pipe(map((results) => results.sort(sortVariants))); // TODO: this should be set up for all entity workspace contexts in a base class #entityContext = new UmbEntityContext(this); From 24e532b98e4b2ba73f9708b8bf22dfc37eafdd14 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 30 Aug 2024 14:08:57 +0200 Subject: [PATCH 28/34] more explicit unique --- .../packages/block/block/workspace/block-workspace.context.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts index 29fa469df3..dddd143138 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts @@ -98,7 +98,7 @@ export class UmbBlockWorkspaceContext { - const unique = 'UMB_PROPERTY'; + const unique = 'UMB_PROPERTY_CONTEXT'; const variantId = this.#variantId.getValue(); if (variantId === undefined) return; From a565489e406219b3fa36bf198b4a7212dd973245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 30 Aug 2024 21:27:03 +0200 Subject: [PATCH 29/34] one prop for read only state --- .../block/block/workspace/block-workspace.context.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts index dddd143138..19e304d8db 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts @@ -60,8 +60,7 @@ export class UmbBlockWorkspaceContext(undefined); readonly variantId = this.#variantId.asObservable(); - #readOnlyState = new UmbReadOnlyVariantStateManager(this); - public readonly readOnlyState = this.#readOnlyState; + public readonly readOnlyState = new UmbReadOnlyVariantStateManager(this); constructor(host: UmbControllerHost, workspaceArgs: { manifest: ManifestWorkspace }) { super(host, workspaceArgs.manifest.alias); @@ -109,9 +108,9 @@ export class UmbBlockWorkspaceContext Date: Mon, 2 Sep 2024 13:14:06 +0200 Subject: [PATCH 30/34] move type, refactor logic --- .../context/block-grid-entries.context.ts | 108 +++++++++--------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-entries.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-entries.context.ts index ebbec1134f..6c5ce9d51b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-entries.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-entries.context.ts @@ -20,6 +20,14 @@ import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/rou import { pathFolderName } from '@umbraco-cms/backoffice/utils'; import type { UmbNumberRangeValueType } from '@umbraco-cms/backoffice/models'; +interface UmbBlockGridAreaTypeInvalidRuleType { + groupKey?: string; + key?: string; + name: string; + amount: number; + minRequirement: number; + maxRequirement: number; +} export class UmbBlockGridEntriesContext extends UmbBlockEntriesContext< typeof UMB_BLOCK_GRID_MANAGER_CONTEXT, @@ -455,14 +463,7 @@ export class UmbBlockGridEntriesContext } } - #invalidBlockTypeLimits?: Array<{ - groupKey?: string; - key?: string; - name: string; - amount: number; - minRequirement: number; - maxRequirement: number; - }>; + #invalidBlockTypeLimits?: Array; getInvalidBlockTypeLimits() { return this.#invalidBlockTypeLimits ?? []; @@ -476,57 +477,56 @@ export class UmbBlockGridEntriesContext const layoutEntries = this._layoutEntries.getValue(); - this.#invalidBlockTypeLimits = []; + this.#invalidBlockTypeLimits = this.#areaType.specifiedAllowance + .map((rule) => { + const minAllowed = rule.minAllowed || 0; + const maxAllowed = rule.maxAllowed || 0; - const hasInvalidRules = this.#areaType.specifiedAllowance.some((rule) => { - const minAllowed = rule.minAllowed || 0; - const maxAllowed = rule.maxAllowed || 0; + // For block groups: + if (rule.groupKey) { + const groupElementTypeKeys = + this._manager + ?.getBlockTypes() + .filter((blockType) => blockType.groupKey === rule.groupKey && blockType.allowInAreas === true) + .map((x) => x.contentElementTypeKey) ?? []; + const groupAmount = layoutEntries.filter((entry) => { + const contentTypeKey = this._manager!.getContentTypeKeyOf(entry.contentUdi); + return contentTypeKey ? groupElementTypeKeys.indexOf(contentTypeKey) !== -1 : false; + }).length; - // For block groups: - if (rule.groupKey) { - const groupElementTypeKeys = - this._manager - ?.getBlockTypes() - .filter((blockType) => blockType.groupKey === rule.groupKey && blockType.allowInAreas === true) - .map((x) => x.contentElementTypeKey) ?? []; - const groupAmount = layoutEntries.filter((entry) => { - const contentTypeKey = this._manager!.getContentTypeKeyOf(entry.contentUdi); - return contentTypeKey ? groupElementTypeKeys.indexOf(contentTypeKey) !== -1 : false; - }).length; - - if (groupAmount < minAllowed || (maxAllowed > 0 && groupAmount > maxAllowed)) { - this.#invalidBlockTypeLimits!.push({ - groupKey: rule.groupKey, - name: this._manager!.getBlockGroupName(rule.groupKey) ?? '?', - amount: groupAmount, - minRequirement: minAllowed, - maxRequirement: maxAllowed, - }); - return true; + if (groupAmount < minAllowed || (maxAllowed > 0 && groupAmount > maxAllowed)) { + return { + groupKey: rule.groupKey, + name: this._manager!.getBlockGroupName(rule.groupKey) ?? '?', + amount: groupAmount, + minRequirement: minAllowed, + maxRequirement: maxAllowed, + }; + } } - } - // For specific elementTypes: - else if (rule.elementTypeKey) { - const amount = layoutEntries.filter((entry) => { - const contentTypeKey = this._manager!.getContentOf(entry.contentUdi)?.contentTypeKey; - return contentTypeKey === rule.elementTypeKey; - }).length; - if (amount < minAllowed || (maxAllowed > 0 ? amount > maxAllowed : false)) { - this.#invalidBlockTypeLimits!.push({ - key: rule.elementTypeKey, - name: this._manager!.getContentTypeNameOf(rule.elementTypeKey) ?? '?', - amount: amount, - minRequirement: minAllowed, - maxRequirement: maxAllowed, - }); - return true; + // For specific elementTypes: + else if (rule.elementTypeKey) { + const amount = layoutEntries.filter((entry) => { + const contentTypeKey = this._manager!.getContentOf(entry.contentUdi)?.contentTypeKey; + return contentTypeKey === rule.elementTypeKey; + }).length; + if (amount < minAllowed || (maxAllowed > 0 ? amount > maxAllowed : false)) { + return { + key: rule.elementTypeKey, + name: this._manager!.getContentTypeNameOf(rule.elementTypeKey) ?? '?', + amount: amount, + minRequirement: minAllowed, + maxRequirement: maxAllowed, + }; + } } - } - // Lets fail cause the rule was bad. - console.error('Invalid block type limit rule.', rule); - return false; - }); + // Lets fail cause the rule was bad. + console.error('Invalid block type limit rule.', rule); + return undefined; + }) + .filter((x) => x !== undefined) as Array; + const hasInvalidRules = this.#invalidBlockTypeLimits.length > 0; return hasInvalidRules === false; } From d8774bc495790e4303515e97007e299de304b189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 2 Sep 2024 14:13:25 +0200 Subject: [PATCH 31/34] notes for maybe future feature --- .../packages/core/validation/mixins/form-control.mixin.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/validation/mixins/form-control.mixin.ts b/src/Umbraco.Web.UI.Client/src/packages/core/validation/mixins/form-control.mixin.ts index e4f45a5518..e10264f44e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/validation/mixins/form-control.mixin.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/validation/mixins/form-control.mixin.ts @@ -164,7 +164,10 @@ export function UmbFormControlMixin< super(...args); this._internals = this.attachInternals(); - this.addEventListener('blur', () => { + this.addEventListener('blur', (e) => { + /*if (e.composedPath().some((x) => x === this)) { + return; + }*/ this.pristine = false; this.checkValidity(); }); From 5d8e0a969df13f25fd8f3d97c53187ae162a199c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 2 Sep 2024 14:13:38 +0200 Subject: [PATCH 32/34] avoid removing pristine on focus, instead on blur --- .../data-type-flow-input/data-type-flow-input.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/data-type/components/data-type-flow-input/data-type-flow-input.element.ts b/src/Umbraco.Web.UI.Client/src/packages/data-type/components/data-type-flow-input/data-type-flow-input.element.ts index e6579bf1f6..df1cc59049 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/data-type/components/data-type-flow-input/data-type-flow-input.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/data-type/components/data-type-flow-input/data-type-flow-input.element.ts @@ -101,7 +101,7 @@ export class UmbInputDataTypeElement extends UmbFormControlMixin(UmbLitElement, label="Select Property Editor" look="placeholder" color="default" - @focus=${() => { + @blur=${() => { this.pristine = false; }} .href=${this._createRoute}> From 9c84fabed3d22613e98f619a7da61655e70fb98c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 2 Sep 2024 14:13:48 +0200 Subject: [PATCH 33/34] fix rule validation --- .../block/block-grid/context/block-grid-entries.context.ts | 4 +++- .../workspace/block-grid-type-workspace.modal-token.ts | 2 +- .../packages/block/block/context/block-manager.context.ts | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-entries.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-entries.context.ts index 6c5ce9d51b..21ef577a45 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-entries.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-entries.context.ts @@ -490,7 +490,7 @@ export class UmbBlockGridEntriesContext .filter((blockType) => blockType.groupKey === rule.groupKey && blockType.allowInAreas === true) .map((x) => x.contentElementTypeKey) ?? []; const groupAmount = layoutEntries.filter((entry) => { - const contentTypeKey = this._manager!.getContentTypeKeyOf(entry.contentUdi); + const contentTypeKey = this._manager!.getContentTypeKeyOfContentUdi(entry.contentUdi); return contentTypeKey ? groupElementTypeKeys.indexOf(contentTypeKey) !== -1 : false; }).length; @@ -503,6 +503,7 @@ export class UmbBlockGridEntriesContext maxRequirement: maxAllowed, }; } + return undefined; } // For specific elementTypes: else if (rule.elementTypeKey) { @@ -519,6 +520,7 @@ export class UmbBlockGridEntriesContext maxRequirement: maxAllowed, }; } + return undefined; } // Lets fail cause the rule was bad. diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/workspace/block-grid-type-workspace.modal-token.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/workspace/block-grid-type-workspace.modal-token.ts index f45bce646e..19d76caa88 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/workspace/block-grid-type-workspace.modal-token.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/workspace/block-grid-type-workspace.modal-token.ts @@ -14,7 +14,7 @@ export const UMB_BLOCK_GRID_TYPE_WORKSPACE_MODAL = new UmbModalToken< type: 'sidebar', size: 'large', }, - data: { entityType: UMB_BLOCK_GRID_TYPE, preset: { allowAtRoot: true } }, + data: { entityType: UMB_BLOCK_GRID_TYPE, preset: { allowAtRoot: true, allowInAreas: true } }, }, // Recast the type, so the entityType data prop is not required: ) as UmbModalToken, UmbWorkspaceModalValue>; diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-manager.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-manager.context.ts index df113d9b81..f44da55be5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-manager.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-manager.context.ts @@ -139,6 +139,9 @@ export abstract class UmbBlockManagerContext< this.#contentTypes.appendOne(data); } + getContentTypeKeyOfContentUdi(contentUdi: string) { + return this.getContentOf(contentUdi)?.contentTypeKey; + } contentTypeOf(contentTypeKey: string) { return this.#contentTypes.asObservablePart((source) => source.find((x) => x.unique === contentTypeKey)); } @@ -148,9 +151,6 @@ export abstract class UmbBlockManagerContext< getContentTypeNameOf(contentTypeKey: string) { return this.#contentTypes.getValue().find((x) => x.unique === contentTypeKey)?.name; } - getContentTypeKeyOf(contentTypeKey: string) { - return this.#contentTypes.getValue().find((x) => x.unique === contentTypeKey)?.unique; - } getContentTypeHasProperties(contentTypeKey: string) { const properties = this.#contentTypes.getValue().find((x) => x.unique === contentTypeKey)?.properties; return properties ? properties.length > 0 : false; From 671b56e36f3c028faffc6296cf05533566215f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 2 Sep 2024 14:21:44 +0200 Subject: [PATCH 34/34] remove unused argument --- .../src/packages/core/validation/mixins/form-control.mixin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/validation/mixins/form-control.mixin.ts b/src/Umbraco.Web.UI.Client/src/packages/core/validation/mixins/form-control.mixin.ts index e10264f44e..e3b13b79be 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/validation/mixins/form-control.mixin.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/validation/mixins/form-control.mixin.ts @@ -164,7 +164,7 @@ export function UmbFormControlMixin< super(...args); this._internals = this.attachInternals(); - this.addEventListener('blur', (e) => { + this.addEventListener('blur', () => { /*if (e.composedPath().some((x) => x === this)) { return; }*/