From 2fab18fadaf0f91cd0db7daedab5cc29741004a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 9 Jun 2023 22:10:28 +0200 Subject: [PATCH] templates render correctly --- .../input-template/input-template.element.ts | 17 ++++---- .../templates/repository/manifests.ts | 18 ++++++++- .../sources/template.item.server.data.ts | 39 +++++++++++++++++++ .../repository/template-item.store.ts | 36 +++++++++++++++++ .../repository/template.repository.ts | 26 ++++++++++--- 5 files changed, 120 insertions(+), 16 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/sources/template.item.server.data.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/template-item.store.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/components/input-template/input-template.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/components/input-template/input-template.element.ts index 36d6a03718..cda5e0039d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/components/input-template/input-template.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/components/input-template/input-template.element.ts @@ -9,7 +9,7 @@ import { UMB_MODAL_MANAGER_CONTEXT_TOKEN, } from '@umbraco-cms/backoffice/modal'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; -import { TemplateResponseModel } from '@umbraco-cms/backoffice/backend-api'; +import { ItemResponseModelBaseModel, TemplateResponseModel } from '@umbraco-cms/backoffice/backend-api'; @customElement('umb-input-template') export class UmbInputTemplateElement extends FormControlMixin(UmbLitElement) { @@ -49,12 +49,12 @@ export class UmbInputTemplateElement extends FormControlMixin(UmbLitElement) { @property({ type: String, attribute: 'min-message' }) maxMessage = 'This field exceeds the allowed amount of items'; - _selectedIds: Array = []; - @property({ type: Array }) + _selectedIds: Array = []; + @property({ type: Array }) public get selectedIds() { return this._selectedIds; } - public set selectedIds(newKeys: Array) { + public set selectedIds(newKeys: Array) { this._selectedIds = newKeys; this.#observePickedTemplates(); } @@ -74,7 +74,7 @@ export class UmbInputTemplateElement extends FormControlMixin(UmbLitElement) { private _templateRepository: UmbTemplateRepository = new UmbTemplateRepository(this); @state() - _pickedTemplates: TemplateResponseModel[] = []; + _pickedTemplates: ItemResponseModelBaseModel[] = []; constructor() { super(); @@ -86,13 +86,13 @@ export class UmbInputTemplateElement extends FormControlMixin(UmbLitElement) { async #observePickedTemplates() { this.observe( - await this._templateRepository.itemsLegacy(this._selectedIds), + (await this._templateRepository.requestItems(this._selectedIds)).asObservable(), (data) => { const oldValue = this._pickedTemplates; this._pickedTemplates = data; this.requestUpdate('_pickedTemplates', oldValue); }, - '_pickedTemplates' + '_observeTemplates' ); } @@ -112,11 +112,12 @@ export class UmbInputTemplateElement extends FormControlMixin(UmbLitElement) { const modalContext = this._modalContext?.open(UMB_TEMPLATE_PICKER_MODAL, { multiple: true, selection: [...this.selectedIds], + pickableFilter: (template: TemplateResponseModel) => template.id !== null, }); modalContext?.onSubmit().then((data) => { if (!data.selection) return; - this.selectedIds = data.selection; + this.selectedIds = data.selection.filter((x) => x !== null) as Array; this.dispatchEvent(new CustomEvent('change')); }); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/manifests.ts index 042cbce709..6ee22e480d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/manifests.ts @@ -1,7 +1,13 @@ import { UmbTemplateRepository } from '../repository/template.repository.js'; import { UmbTemplateTreeStore } from './template.tree.store.js'; import { UmbTemplateStore } from './template.store.js'; -import { ManifestStore, ManifestTreeStore, ManifestRepository } from '@umbraco-cms/backoffice/extension-registry'; +import { UmbTemplateItemStore } from './template-item.store.js'; +import { + ManifestStore, + ManifestTreeStore, + ManifestRepository, + ManifestItemStore, +} from '@umbraco-cms/backoffice/extension-registry'; export const TEMPLATE_REPOSITORY_ALIAS = 'Umb.Repository.Template'; @@ -14,6 +20,7 @@ const repository: ManifestRepository = { export const TEMPLATE_STORE_ALIAS = 'Umb.Store.Template'; export const TEMPLATE_TREE_STORE_ALIAS = 'Umb.Store.TemplateTree'; +export const TEMPLATE_ITEM_STORE_ALIAS = 'Umb.Store.TemplateItem'; const store: ManifestStore = { type: 'store', @@ -29,4 +36,11 @@ const treeStore: ManifestTreeStore = { class: UmbTemplateTreeStore, }; -export const manifests = [repository, store, treeStore]; +const itemStore: ManifestItemStore = { + type: 'itemStore', + alias: TEMPLATE_ITEM_STORE_ALIAS, + name: 'Template Item Store', + class: UmbTemplateItemStore, +}; + +export const manifests = [repository, store, treeStore, itemStore]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/sources/template.item.server.data.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/sources/template.item.server.data.ts new file mode 100644 index 0000000000..22ae84f8f0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/sources/template.item.server.data.ts @@ -0,0 +1,39 @@ +import type { UmbItemDataSource } from '@umbraco-cms/backoffice/repository'; +import { TemplateItemResponseModel, TemplateResource } from '@umbraco-cms/backoffice/backend-api'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; +import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; + +/** + * A data source for Data Type items that fetches data from the server + * @export + * @class UmbTemplateItemServerDataSource + * @implements {DocumentTreeDataSource} + */ +export class UmbTemplateItemServerDataSource implements UmbItemDataSource { + #host: UmbControllerHostElement; + + /** + * Creates an instance of UmbTemplateItemServerDataSource. + * @param {UmbControllerHostElement} host + * @memberof UmbTemplateItemServerDataSource + */ + constructor(host: UmbControllerHostElement) { + this.#host = host; + } + + /** + * Fetches the items for the given ids from the server + * @param {Array} ids + * @return {*} + * @memberof UmbTemplateItemServerDataSource + */ + async getItems(ids: Array) { + if (!ids) throw new Error('Ids are missing'); + return tryExecuteAndNotify( + this.#host, + TemplateResource.getTemplateItem({ + id: ids, + }) + ); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/template-item.store.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/template-item.store.ts new file mode 100644 index 0000000000..5eeac72c38 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/template-item.store.ts @@ -0,0 +1,36 @@ +import { TemplateItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; +import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; +import { UmbItemStore, UmbStoreBase } from '@umbraco-cms/backoffice/store'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; + +/** + * @export + * @class UmbTemplateItemStore + * @extends {UmbStoreBase} + * @description - Data Store for Template items + */ + +export class UmbTemplateItemStore + extends UmbStoreBase + implements UmbItemStore +{ + /** + * Creates an instance of UmbTemplateItemStore. + * @param {UmbControllerHostElement} host + * @memberof UmbTemplateItemStore + */ + constructor(host: UmbControllerHostElement) { + super( + host, + UMB_TEMPLATE_ITEM_STORE_CONTEXT_TOKEN.toString(), + new UmbArrayState([], (x) => x.id) + ); + } + + items(ids: Array) { + return this._data.getObservablePart((items) => items.filter((item) => ids.includes(item.id ?? ''))); + } +} + +export const UMB_TEMPLATE_ITEM_STORE_CONTEXT_TOKEN = new UmbContextToken('UmbTemplateItemStore'); diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/template.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/template.repository.ts index dbf7a2212f..6b68cf7219 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/template.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/template.repository.ts @@ -2,9 +2,12 @@ import { UmbTemplateTreeStore, UMB_TEMPLATE_TREE_STORE_CONTEXT_TOKEN } from './t import { UmbTemplateStore, UMB_TEMPLATE_STORE_CONTEXT_TOKEN } from './template.store.js'; import { UmbTemplateTreeServerDataSource } from './sources/template.tree.server.data.js'; import { UmbTemplateDetailServerDataSource } from './sources/template.detail.server.data.js'; +import { UMB_TEMPLATE_ITEM_STORE_CONTEXT_TOKEN, UmbTemplateItemStore } from './template-item.store.js'; +import { UmbTemplateItemServerDataSource } from './sources/template.item.server.data.js'; import { Observable } from '@umbraco-cms/backoffice/external/rxjs'; import type { UmbDetailRepository, + UmbItemDataSource, UmbItemRepository, UmbTreeDataSource, UmbTreeRepository, @@ -32,7 +35,9 @@ export class UmbTemplateRepository #treeDataSource: UmbTreeDataSource; #detailDataSource: UmbTemplateDetailServerDataSource; + #itemSource: UmbItemDataSource; + #itemStore?: UmbTemplateItemStore; #treeStore?: UmbTemplateTreeStore; #store?: UmbTemplateStore; @@ -43,8 +48,13 @@ export class UmbTemplateRepository this.#treeDataSource = new UmbTemplateTreeServerDataSource(this.#host); this.#detailDataSource = new UmbTemplateDetailServerDataSource(this.#host); + this.#itemSource = new UmbTemplateItemServerDataSource(this.#host); this.#init = Promise.all([ + new UmbContextConsumerController(this.#host, UMB_TEMPLATE_ITEM_STORE_CONTEXT_TOKEN, (instance) => { + this.#itemStore = instance; + }), + new UmbContextConsumerController(this.#host, UMB_TEMPLATE_TREE_STORE_CONTEXT_TOKEN, (instance) => { this.#treeStore = instance; }), @@ -147,17 +157,21 @@ export class UmbTemplateRepository this.#store?.append(data); } - return { data, error }; + return { data, error, asObservable: () => this.#treeStore!.items([id]) }; } - async requestItems(id: string[]) { + // ITEMS: + async requestItems(ids: Array) { + if (!ids) throw new Error('Ids are missing'); await this.#init; - if (!id) { - throw new Error('Id is missing'); + const { data, error } = await this.#itemSource.getItems(ids); + + if (data) { + this.#itemStore?.appendItems(data); } - const { data, error } = await this.#detailDataSource.getItem(id); - return { data, error }; + + return { data, error, asObservable: () => this.#itemStore!.items(ids) }; } async items(uniques: string[]): Promise> {