From fe32ef093f8b9e6b944c0742de6d6ce8cdbe7bee Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 20 Aug 2024 12:40:11 +0200 Subject: [PATCH 01/16] limit UI when readonly --- .../input-document/input-document.element.ts | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts index 6c07e8834a..f7febe5dd3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts @@ -1,5 +1,14 @@ import { UmbDocumentPickerContext } from './input-document.context.js'; -import { classMap, css, customElement, html, property, repeat, state } from '@umbraco-cms/backoffice/external/lit'; +import { + classMap, + css, + customElement, + html, + nothing, + property, + repeat, + state, +} from '@umbraco-cms/backoffice/external/lit'; import { splitStringToArray } from '@umbraco-cms/backoffice/utils'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; @@ -103,6 +112,15 @@ export class UmbInputDocumentElement extends UmbFormControlMixin 0 ? this.selection.join(',') : undefined; } + /** + * 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 _editDocumentPath = ''; @@ -173,7 +191,8 @@ export class UmbInputDocumentElement extends UmbFormControlMixin + label=${this.localize.term('general_choose')} + ?disabled=${this.readonly}> `; } @@ -193,11 +212,14 @@ export class UmbInputDocumentElement extends UmbFormControlMixin + ${this.#renderIcon(item)} ${this.#renderIsTrashed(item)} - ${this.#renderOpenButton(item)} - this.#onRemove(item)} label=${this.localize.term('general_remove')}> + ${this.#renderOpenButton(item)} ${this.#renderRemoveButton(item)} `; @@ -213,8 +235,16 @@ export class UmbInputDocumentElement extends UmbFormControlMixinTrashed`; } + #renderRemoveButton(item: UmbDocumentItemModel) { + if (this.readonly) return nothing; + return html` + this.#onRemove(item)} label=${this.localize.term('general_remove')}> + `; + } + #renderOpenButton(item: UmbDocumentItemModel) { - if (!this.showOpenButton) return; + if (this.readonly) return nothing; + if (!this.showOpenButton) return nothing; return html` Date: Tue, 20 Aug 2024 12:59:50 +0200 Subject: [PATCH 02/16] enable and disable the sorter based on readonly state --- .../components/input-document/input-document.element.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts index f7febe5dd3..bb96ad3ea3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts @@ -119,7 +119,14 @@ export class UmbInputDocumentElement extends UmbFormControlMixin Date: Tue, 20 Aug 2024 12:59:56 +0200 Subject: [PATCH 03/16] add jsdocs --- .../src/packages/core/sorter/sorter.controller.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) 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 7afe497382..a188b37f85 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 @@ -294,6 +294,11 @@ export class UmbSorterController Date: Tue, 20 Aug 2024 14:20:27 +0200 Subject: [PATCH 04/16] remove draggable attribute from element when sorter is disabled --- .../src/packages/core/sorter/sorter.controller.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) 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 a188b37f85..72e7855b73 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 @@ -260,6 +260,8 @@ export class UmbSorterController(); + public get identifier() { return this.#config.identifier; } @@ -313,6 +315,7 @@ export class UmbSorterController { const containerEl = (this.#config.containerSelector @@ -376,6 +381,7 @@ export class UmbSorterController this.destroyItem(item)); } _itemDraggedOver = (e: DragEvent) => { @@ -453,6 +461,9 @@ export class UmbSorterController x !== element); } #setupPlaceholderStyle() { From a826e9fd9f1935aefb5f1ac5fd506cf2dad4e9a5 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 20 Aug 2024 20:15:26 +0200 Subject: [PATCH 05/16] set document name to read only --- .../workspace-split-view-variant-selector.element.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts index 63bfd697a8..c814b65b3b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts @@ -225,6 +225,7 @@ export class UmbWorkspaceSplitViewVariantSelectorElement extends UmbLitElement { .value=${this._name ?? ''} @input=${this.#handleInput} required + ?readonly=${this.#isReadOnly(this._activeVariant?.culture || null)} ${umbBindToValidation(this, `$.variants[${UmbDataPathVariantQuery(this._variantId)}].name`, this._name ?? '')} ${umbFocus()} > From 820eda01923aec5ca6d5b746315d359ed5b3224e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 20 Aug 2024 20:43:07 +0200 Subject: [PATCH 06/16] set dictionary translation to readonly when the user does not have access --- ...orkspace-view-dictionary-editor.element.ts | 68 ++++++++++++++----- 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/dictionary/workspace/views/workspace-view-dictionary-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/dictionary/workspace/views/workspace-view-dictionary-editor.element.ts index 2378ca1073..ddabdf4cc2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/dictionary/workspace/views/workspace-view-dictionary-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/dictionary/workspace/views/workspace-view-dictionary-editor.element.ts @@ -5,26 +5,50 @@ import { UUITextareaEvent } from '@umbraco-cms/backoffice/external/uui'; import { css, html, customElement, state, repeat, ifDefined, unsafeHTML } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbLanguageCollectionRepository, type UmbLanguageDetailModel } from '@umbraco-cms/backoffice/language'; +import { UMB_CURRENT_USER_CONTEXT } from '@umbraco-cms/backoffice/current-user'; @customElement('umb-workspace-view-dictionary-editor') export class UmbWorkspaceViewDictionaryEditorElement extends UmbLitElement { @state() private _dictionary?: UmbDictionaryDetailModel; - #languageCollectionRepository = new UmbLanguageCollectionRepository(this); - @state() private _languages: Array = []; - #workspaceContext!: typeof UMB_DICTIONARY_WORKSPACE_CONTEXT.TYPE; + @state() + private _currentUserLanguageAccess?: Array = []; - override async connectedCallback() { - super.connectedCallback(); + @state() + private _currentUserHasAccessToAllLanguages?: boolean = false; + + #languageCollectionRepository = new UmbLanguageCollectionRepository(this); + #workspaceContext!: typeof UMB_DICTIONARY_WORKSPACE_CONTEXT.TYPE; + #currentUserContext?: typeof UMB_CURRENT_USER_CONTEXT.TYPE; + + constructor() { + super(); this.consumeContext(UMB_DICTIONARY_WORKSPACE_CONTEXT, (_instance) => { this.#workspaceContext = _instance; this.#observeDictionary(); }); + + this.consumeContext(UMB_CURRENT_USER_CONTEXT, (context) => { + this.#currentUserContext = context; + this.#observeCurrentUserLanguageAccess(); + }); + } + + #observeCurrentUserLanguageAccess() { + if (!this.#currentUserContext) return; + + this.observe(this.#currentUserContext.languages, (languages) => { + this._currentUserLanguageAccess = languages; + }); + + this.observe(this.#currentUserContext.hasAccessToAllLanguages, (hasAccess) => { + this._currentUserHasAccessToAllLanguages = hasAccess; + }); } override async firstUpdated() { @@ -40,19 +64,11 @@ export class UmbWorkspaceViewDictionaryEditorElement extends UmbLitElement { }); } - #renderTranslation(language: UmbLanguageDetailModel) { - if (!language.unique) return; - - const translation = this._dictionary?.translations?.find((x) => x.isoCode === language.unique); - - return html` - - `; + #isReadOnly(culture: string | null) { + if (!this.#currentUserContext) return true; + if (!culture) return false; + if (this._currentUserHasAccessToAllLanguages) return false; + return !this._currentUserLanguageAccess?.includes(culture); } #onTextareaChange(e: Event) { @@ -78,6 +94,22 @@ export class UmbWorkspaceViewDictionaryEditorElement extends UmbLitElement { `; } + #renderTranslation(language: UmbLanguageDetailModel) { + if (!language.unique) return; + + const translation = this._dictionary?.translations?.find((x) => x.isoCode === language.unique); + + return html` + + `; + } + static override styles = [ css` :host { From 0b7006203d9ae68bac95fd4e0a811431a6d6064d Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 21 Aug 2024 10:09:12 +0200 Subject: [PATCH 07/16] Update workspace-split-view-variant-selector.element.ts --- .../workspace-split-view-variant-selector.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts index c814b65b3b..d5d9766a6b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts @@ -225,7 +225,7 @@ export class UmbWorkspaceSplitViewVariantSelectorElement extends UmbLitElement { .value=${this._name ?? ''} @input=${this.#handleInput} required - ?readonly=${this.#isReadOnly(this._activeVariant?.culture || null)} + ?readonly=${this.#isReadOnly(this._activeVariant?.culture ?? null)} ${umbBindToValidation(this, `$.variants[${UmbDataPathVariantQuery(this._variantId)}].name`, this._name ?? '')} ${umbFocus()} > From 0f7e461a9aff1b29cf42ea74ff9a9821c71795c8 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 21 Aug 2024 11:36:50 +0200 Subject: [PATCH 08/16] remove console log --- .../src/packages/core/sorter/sorter.controller.ts | 1 - 1 file changed, 1 deletion(-) 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 72e7855b73..3520456400 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 @@ -315,7 +315,6 @@ export class UmbSorterController Date: Wed, 21 Aug 2024 11:56:11 +0200 Subject: [PATCH 09/16] start on sorter controller tests --- .../core/sorter/sorter.controller.test.ts | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.test.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.test.ts b/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.test.ts new file mode 100644 index 0000000000..5ce872340b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.test.ts @@ -0,0 +1,82 @@ +import { UmbSorterController } from './sorter.controller.js'; +import { aTimeout, expect, fixture, html } from '@open-wc/testing'; +import { customElement } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '../lit-element/lit-element.element.js'; + +@customElement('test-my-sorter') +class UmbSorterTestElement extends UmbLitElement { + model: Array = ['1', '2', '3']; + + sorter = new UmbSorterController(this, { + getUniqueOfElement: (element) => { + return element.id; + }, + getUniqueOfModel: (modelEntry) => { + return modelEntry; + }, + identifier: 'Umb.SorterIdentifier.Test', + itemSelector: 'li', + containerSelector: 'ul', + onChange: ({ model }) => { + this.model = model; + }, + }); + + getAllItems() { + return Array.from(this.shadowRoot!.querySelectorAll('li')); + } + + override render() { + return html`
    +
  • Item 1
  • +
  • Item 2
  • +
  • Item 3
  • +
`; + } +} + +describe('UmbSorterController', () => { + let element: UmbSorterTestElement; + + beforeEach(async () => { + element = await fixture(html``); + await aTimeout(10); + }); + + it('is defined with its own instance', () => { + expect(element).to.be.instanceOf(UmbSorterTestElement); + }); + + describe('Set up', () => { + it('should find all items', () => { + const items = element.getAllItems(); + expect(items.length).to.equal(3); + }); + + it('sets all allowed draggable items to draggable', () => { + const items = element.getAllItems(); + items.forEach((item) => { + expect(item.draggable).to.be.true; + }); + }); + }); + + describe('disable', () => { + it('sets all items to non draggable', () => { + element.sorter.disable(); + const items = element.getAllItems(); + items.forEach((item) => { + expect(item.draggable).to.be.false; + }); + }); + }); + + describe('enable', () => { + it('sets all items to draggable', () => { + const items = element.getAllItems(); + items.forEach((item) => { + expect(item.draggable).to.be.true; + }); + }); + }); +}); From b5d3f84e38ec7a4946aa3c81ea81e0258dd1d052 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 21 Aug 2024 12:47:10 +0200 Subject: [PATCH 10/16] add tests for disabled items --- .../core/sorter/sorter.controller.test.ts | 54 ++++++++++++++----- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.test.ts b/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.test.ts index 5ce872340b..1bb49a8c9a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.test.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.test.ts @@ -5,7 +5,7 @@ import { UmbLitElement } from '../lit-element/lit-element.element.js'; @customElement('test-my-sorter') class UmbSorterTestElement extends UmbLitElement { - model: Array = ['1', '2', '3']; + model: Array = ['1', '2', '3', '4']; sorter = new UmbSorterController(this, { getUniqueOfElement: (element) => { @@ -15,23 +15,33 @@ class UmbSorterTestElement extends UmbLitElement { return modelEntry; }, identifier: 'Umb.SorterIdentifier.Test', - itemSelector: 'li', - containerSelector: 'ul', + itemSelector: '.item', + containerSelector: '#container', + disabledItemSelector: '.disabled', onChange: ({ model }) => { this.model = model; }, }); getAllItems() { - return Array.from(this.shadowRoot!.querySelectorAll('li')); + return Array.from(this.shadowRoot!.querySelectorAll('.item')) as HTMLElement[]; + } + + getSortableItems() { + return Array.from(this.shadowRoot!.querySelectorAll('.item:not(.disabled')) as HTMLElement[]; + } + + getDisabledItems() { + return Array.from(this.shadowRoot!.querySelectorAll('.item.disabled')) as HTMLElement[]; } override render() { - return html`
    -
  • Item 1
  • -
  • Item 2
  • -
  • Item 3
  • -
`; + return html`
+
Item 1
+
Item 2
+
Item 3
+
Item 4
+
`; } } @@ -50,15 +60,24 @@ describe('UmbSorterController', () => { describe('Set up', () => { it('should find all items', () => { const items = element.getAllItems(); - expect(items.length).to.equal(3); + expect(items.length).to.equal(4); }); it('sets all allowed draggable items to draggable', () => { - const items = element.getAllItems(); + const items = element.getSortableItems(); + expect(items.length).to.equal(3); items.forEach((item) => { expect(item.draggable).to.be.true; }); }); + + it('sets all disabled items non draggable', () => { + const items = element.getDisabledItems(); + expect(items.length).to.equal(1); + items.forEach((item) => { + expect(item.draggable).to.be.false; + }); + }); }); describe('disable', () => { @@ -72,11 +91,20 @@ describe('UmbSorterController', () => { }); describe('enable', () => { - it('sets all items to draggable', () => { - const items = element.getAllItems(); + it('sets all allowed items to draggable', () => { + const items = element.getSortableItems(); + expect(items.length).to.equal(3); items.forEach((item) => { expect(item.draggable).to.be.true; }); }); + + it('sets all disabled items non draggable', () => { + const items = element.getDisabledItems(); + expect(items.length).to.equal(1); + items.forEach((item) => { + expect(item.draggable).to.be.false; + }); + }); }); }); From 77b68e8d03cea822c36d7b16540ed59e2015e26b Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 21 Aug 2024 13:07:01 +0200 Subject: [PATCH 11/16] Update sorter.controller.test.ts --- .../core/sorter/sorter.controller.test.ts | 63 ++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.test.ts b/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.test.ts index 1bb49a8c9a..4b68007e03 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.test.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.test.ts @@ -55,9 +55,70 @@ describe('UmbSorterController', () => { it('is defined with its own instance', () => { expect(element).to.be.instanceOf(UmbSorterTestElement); + expect(element.sorter).to.be.instanceOf(UmbSorterController); }); - describe('Set up', () => { + describe('Public API', () => { + describe('methods', () => { + it('has a enable method', () => { + expect(element.sorter).to.have.property('enable').that.is.a('function'); + }); + + it('has a disable method', () => { + expect(element.sorter).to.have.property('disable').that.is.a('function'); + }); + + it('has a setModel method', () => { + expect(element.sorter).to.have.property('setModel').that.is.a('function'); + }); + + it('has a hasItem method', () => { + expect(element.sorter).to.have.property('hasItem').that.is.a('function'); + }); + + it('has a getItem method', () => { + expect(element.sorter).to.have.property('getItem').that.is.a('function'); + }); + + it('has a setupItem method', () => { + expect(element.sorter).to.have.property('setupItem').that.is.a('function'); + }); + + it('has a destroyItem method', () => { + expect(element.sorter).to.have.property('destroyItem').that.is.a('function'); + }); + + it('has a hasOtherItemsThan method', () => { + expect(element.sorter).to.have.property('hasOtherItemsThan').that.is.a('function'); + }); + + it('has a moveItemInModel method', () => { + expect(element.sorter).to.have.property('moveItemInModel').that.is.a('function'); + }); + + it('has a updateAllowIndication method', () => { + expect(element.sorter).to.have.property('updateAllowIndication').that.is.a('function'); + }); + + it('has a removeAllowIndication method', () => { + expect(element.sorter).to.have.property('removeAllowIndication').that.is.a('function'); + }); + + it('has a notifyDisallowed method', () => { + expect(element.sorter).to.have.property('notifyDisallowed').that.is.a('function'); + }); + + it('has a notifyRequestDrop method', () => { + expect(element.sorter).to.have.property('notifyRequestDrop').that.is.a('function'); + }); + + it('has a destroy method', () => { + expect(element.sorter).to.have.property('destroy').that.is.a('function'); + }); + }); + }); + + describe('Init', () => { it('should find all items', () => { const items = element.getAllItems(); expect(items.length).to.equal(4); From 92931c3770f6c66f85a33253e455ec098f242eae Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 21 Aug 2024 13:23:14 +0200 Subject: [PATCH 12/16] add getModel method --- .../src/packages/core/sorter/sorter.controller.ts | 9 +++++++++ 1 file changed, 9 insertions(+) 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 3520456400..3fb39166e1 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 @@ -329,6 +329,15 @@ export class UmbSorterController} + * @memberof UmbSorterController + */ + getModel(): Array { + return this.#model; + } + hasItem(unique: UniqueType) { return this.#model.find((x) => this.#config.getUniqueOfModel(x) === unique) !== undefined; } From d40ee05bdaf76e64490c87d750787147f64fe72b Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 21 Aug 2024 13:23:27 +0200 Subject: [PATCH 13/16] add tests for model methods --- .../core/sorter/sorter.controller.test.ts | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.test.ts b/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.test.ts index 4b68007e03..3595ec1376 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.test.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/sorter/sorter.controller.test.ts @@ -5,8 +5,6 @@ import { UmbLitElement } from '../lit-element/lit-element.element.js'; @customElement('test-my-sorter') class UmbSorterTestElement extends UmbLitElement { - model: Array = ['1', '2', '3', '4']; - sorter = new UmbSorterController(this, { getUniqueOfElement: (element) => { return element.id; @@ -168,4 +166,40 @@ describe('UmbSorterController', () => { }); }); }); + + describe('setModel & getModel', () => { + it('it sets the model', () => { + const model = ['1', '2', '3', '4']; + element.sorter.setModel(model); + expect(element.sorter.getModel()).to.deep.equal(model); + }); + }); + + describe('hasItem', () => { + beforeEach(() => { + element.sorter.setModel(['1', '2', '3', '4']); + }); + + it('returns true if item exists', () => { + expect(element.sorter.hasItem('1')).to.be.true; + }); + + it('returns false if item does not exist', () => { + expect(element.sorter.hasItem('5')).to.be.false; + }); + }); + + describe('getItem', () => { + beforeEach(() => { + element.sorter.setModel(['1', '2', '3', '4']); + }); + + it('returns the item if it exists', () => { + expect(element.sorter.getItem('1')).to.equal('1'); + }); + + it('returns undefined if item does not exist', () => { + expect(element.sorter.getItem('5')).to.be.undefined; + }); + }); }); From 363ec8c48d8524a58f824813765695acf4f7d840 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 21 Aug 2024 13:29:35 +0200 Subject: [PATCH 14/16] Update manifests.ts --- .../documents/property-editors/document-picker/manifests.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/manifests.ts index cfff881f56..93493b2efe 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/manifests.ts @@ -12,6 +12,7 @@ export const manifests: Array = [ propertyEditorSchemaAlias: 'Umbraco.ContentPicker', icon: 'icon-document', group: 'pickers', + supportsReadOnly: true, settings: { properties: [ { From a244700dcccfe1e98c216185a8dd0020bca2fbf9 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 21 Aug 2024 13:31:37 +0200 Subject: [PATCH 15/16] pass readonly to input --- .../property-editor-ui-document-picker.element.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts index 2d7dfbd6f4..5b85243363 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts @@ -26,6 +26,15 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl this._showOpenButton = config.getValueByAlias('showOpenButton') ?? false; } + /** + * 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 _min = 0; @@ -57,7 +66,8 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl .startNode=${startNode} .value=${this.value} ?showOpenButton=${this._showOpenButton} - @change=${this.#onChange}> + @change=${this.#onChange} + ?readonly=${this.readonly}> `; } From 1dcbed5bb110400aff21cb2549446b824eb56cce Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 21 Aug 2024 13:50:24 +0200 Subject: [PATCH 16/16] make linter happy --- .../components/input-document/input-document.element.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts index bb96ad3ea3..4c24fa30a3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts @@ -124,7 +124,12 @@ export class UmbInputDocumentElement extends UmbFormControlMixin