diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/partial-view/item.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/partial-view/item.handlers.ts index abb84379ba..9869404c04 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/handlers/partial-view/item.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/handlers/partial-view/item.handlers.ts @@ -5,9 +5,10 @@ import { umbracoPath } from '@umbraco-cms/backoffice/utils'; export const itemHandlers = [ rest.get(umbracoPath(`${UMB_SLUG}/item`), (req, res, ctx) => { - const paths = req.url.searchParams.getAll('paths'); + const paths = req.url.searchParams.getAll('path'); if (!paths) return res(ctx.status(400, 'no body found')); - const items = umbPartialViewMockDB.item.getItems(paths); + const decodedPaths = paths.map((path) => decodeURI(path)); + const items = umbPartialViewMockDB.item.getItems(decodedPaths); return res(ctx.status(200), ctx.json(items)); }), ]; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/script/item.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/script/item.handlers.ts index 9af1b7bc39..34e725d86e 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/handlers/script/item.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/handlers/script/item.handlers.ts @@ -5,9 +5,10 @@ import { umbracoPath } from '@umbraco-cms/backoffice/utils'; export const itemHandlers = [ rest.get(umbracoPath(`${UMB_SLUG}/item`), (req, res, ctx) => { - const paths = req.url.searchParams.getAll('paths'); + const paths = req.url.searchParams.getAll('path'); if (!paths) return res(ctx.status(400, 'no body found')); - const items = umbScriptMockDb.item.getItems(paths); + const decodedPaths = paths.map((path) => decodeURI(path)); + const items = umbScriptMockDb.item.getItems(decodedPaths); return res(ctx.status(200), ctx.json(items)); }), ]; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/stylesheet/item.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/stylesheet/item.handlers.ts index b1f29d39bb..5406b602bc 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/handlers/stylesheet/item.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/handlers/stylesheet/item.handlers.ts @@ -5,9 +5,10 @@ import { umbracoPath } from '@umbraco-cms/backoffice/utils'; export const itemHandlers = [ rest.get(umbracoPath(`${UMB_SLUG}/item`), (req, res, ctx) => { - const paths = req.url.searchParams.getAll('paths'); + const paths = req.url.searchParams.getAll('path'); if (!paths) return res(ctx.status(400, 'no body found')); - const items = umbStylesheetMockDb.item.getItems(paths); + const decodedPaths = paths.map((path) => decodeURI(path)); + const items = umbStylesheetMockDb.item.getItems(decodedPaths); return res(ctx.status(200), ctx.json(items)); }), ]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/tree-picker/tree-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/tree-picker/tree-picker-modal.element.ts index 8d0b5425d6..8de85023a7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/tree-picker/tree-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/tree-picker/tree-picker-modal.element.ts @@ -50,7 +50,11 @@ export class UmbTreePickerModalElement
- +
`; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/modal.interfaces.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/modal.interfaces.ts index e3a9520916..f6b81a7e1e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/modal.interfaces.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/modal.interfaces.ts @@ -1,8 +1,8 @@ -export interface UmbPickerModalData { +export interface UmbPickerModalData { multiple?: boolean; hideTreeRoot?: boolean; - filter?: (item: ItemType) => boolean; - pickableFilter?: (item: ItemType) => boolean; + filter?: (item: TreeItemType) => boolean; + pickableFilter?: (item: TreeItemType) => boolean; } export interface UmbPickerModalValue { selection: Array; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tiny-mce/config/stylesheets/property-editor-ui-tiny-mce-stylesheets-configuration.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tiny-mce/config/stylesheets/property-editor-ui-tiny-mce-stylesheets-configuration.element.ts index 931c3074d8..e22e70d8d0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tiny-mce/config/stylesheets/property-editor-ui-tiny-mce-stylesheets-configuration.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tiny-mce/config/stylesheets/property-editor-ui-tiny-mce-stylesheets-configuration.element.ts @@ -1,9 +1,10 @@ import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import { css, customElement, html, property, state } from '@umbraco-cms/backoffice/external/lit'; +import { css, customElement, html, property } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; -import { UmbStylesheetDetailRepository } from '@umbraco-cms/backoffice/stylesheet'; -import { StylesheetOverviewResponseModel } from '@umbraco-cms/backoffice/backend-api'; -import { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor'; +import { + UmbPropertyEditorConfigCollection, + UmbPropertyValueChangeEvent, +} from '@umbraco-cms/backoffice/property-editor'; import { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry'; /** @@ -20,30 +21,8 @@ export class UmbPropertyEditorUITinyMceStylesheetsConfigurationElement @property({ type: Object, attribute: false }) public config?: UmbPropertyEditorConfigCollection; - @state() - stylesheetList: Array> = []; - - #repository; - - constructor() { - super(); - this.#repository = new UmbStylesheetDetailRepository(this); - - this.#getAllStylesheets(); - } - async #getAllStylesheets() { - const { data } = await this.#repository.getAll(); - if (!data) return; - - const styles = data.items; - - this.stylesheetList = styles.map((stylesheet) => ({ - ...stylesheet, - selected: this.value?.some((path) => path === stylesheet.path), - })); - } - #onChange(event: CustomEvent) { + debugger; const checkbox = event.target as HTMLInputElement; if (checkbox.checked) { @@ -56,36 +35,14 @@ export class UmbPropertyEditorUITinyMceStylesheetsConfigurationElement this.value = this.value.filter((v) => v !== checkbox.value); } - this.dispatchEvent(new CustomEvent('property-value-change')); + this.dispatchEvent(new UmbPropertyValueChangeEvent()); } render() { - return html`
    - ${this.stylesheetList.map( - (stylesheet) => - html`
  • - - ${stylesheet.name} - -
  • `, - )} -
`; + return html``; } - static styles = [ - UmbTextStyles, - css` - ul { - list-style: none; - padding: 0; - margin: 0; - } - `, - ]; + static styles = [UmbTextStyles, css``]; } export default UmbPropertyEditorUITinyMceStylesheetsConfigurationElement; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/repository/repository-items.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/repository/repository-items.manager.ts index 9d0806d8c8..6fc12ad5af 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/repository/repository-items.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/repository/repository-items.manager.ts @@ -72,8 +72,7 @@ export class UmbRepositoryItemsManager extends UmbBaseController { // TODO: Test if its just some items that is gone now, if so then just filter them out. (maybe use code from #removeItem) // This is where this.#getUnique comes in play. Unless that can come from the repository, but that collides with the idea of having a multi-type repository. If that happens. - - const { asObservable } = await this.repository.requestItems(this.getUniques()); + const { data, asObservable } = await this.repository.requestItems(this.getUniques()); if (asObservable) { this.observe(asObservable(), (data) => this.#items.next(data), '_observeRequestedItems'); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/store/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/store/index.ts index 7f58158607..9b03c755d5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/store/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/store/index.ts @@ -1,10 +1,13 @@ -export * from './item-store.interface.js'; export * from './store-base.js'; export * from './store.interface.js'; export * from './store.js'; export * from './entity-item.store.js'; export * from './file-system-item.store.js'; -export { UmbStoreConnector } from './store-connector.js'; export { UmbDetailStoreBase } from './detail-store-base.js'; export type { UmbDetailStore } from './detail-store.interface.js'; + +export { UmbItemStoreBase } from './item-store-base.js'; +export type { UmbItemStore } from './item-store.interface.js'; + +export { UmbStoreConnector } from './store-connector.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/store/item-store-base.ts b/src/Umbraco.Web.UI.Client/src/packages/core/store/item-store-base.ts new file mode 100644 index 0000000000..a09a5e7fd6 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/store/item-store-base.ts @@ -0,0 +1,28 @@ +import { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { UmbItemStore, UmbStoreBase } from '@umbraco-cms/backoffice/store'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; + +/** + * @export + * @class UmbItemStoreBase + * @extends {UmbStoreBase} + * @description - Data Store for items with a unique property + */ + +export abstract class UmbItemStoreBase + extends UmbStoreBase + implements UmbItemStore +{ + /** + * Creates an instance of UmbItemStoreBase. + * @param {UmbControllerHost} host + * @memberof UmbItemStoreBase + */ + constructor(host: UmbControllerHost, storeAlias: string) { + super(host, storeAlias, new UmbArrayState([], (x) => x.unique)); + } + + items(uniques: Array) { + return this._data.asObservablePart((items) => items.filter((item) => uniques.includes(item.unique))); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/store/item-store.interface.ts b/src/Umbraco.Web.UI.Client/src/packages/core/store/item-store.interface.ts index 408617c842..0427a65879 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/store/item-store.interface.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/store/item-store.interface.ts @@ -2,6 +2,6 @@ import { UmbStore } from './store.interface.js'; import type { Observable } from '@umbraco-cms/backoffice/external/rxjs'; import type { UmbApi } from '@umbraco-cms/backoffice/extension-api'; -export interface UmbItemStore extends UmbStore, UmbApi { +export interface UmbItemStore extends UmbStore, UmbApi { items: (uniques: Array) => Observable>; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/collection/repository/stylesheet-collection.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/collection/repository/stylesheet-collection.repository.ts index 66404f2c9d..3cfee0de5d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/collection/repository/stylesheet-collection.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/collection/repository/stylesheet-collection.repository.ts @@ -1,34 +1,24 @@ import { UmbStylesheetCollectionFilterModel, UmbStylesheetCollectionItemModel } from '../types.js'; -import { UmbStylesheetDetailStore, UMB_STYLESHEET_DETAIL_STORE_CONTEXT } from '../../repository/index.js'; import { UmbStylesheetCollectionServerDataSource } from './stylesheet-collection.server.data-source.js'; import { UmbCollectionDataSource, UmbCollectionRepository } from '@umbraco-cms/backoffice/repository'; import { type UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbBaseController } from '@umbraco-cms/backoffice/class-api'; export class UmbStylesheetCollectionRepository extends UmbBaseController implements UmbCollectionRepository { - #init; - - #detailStore?: UmbStylesheetDetailStore; #collectionSource: UmbCollectionDataSource; constructor(host: UmbControllerHost) { super(host); this.#collectionSource = new UmbStylesheetCollectionServerDataSource(this._host); - - this.#init = this.consumeContext(UMB_STYLESHEET_DETAIL_STORE_CONTEXT, (instance) => { - this.#detailStore = instance; - }).asPromise(); } - async requestCollection(filter: UmbStylesheetCollectionFilterModel = { take: 100, skip: 0 }) { - await this.#init; - - const { data, error } = await this.#collectionSource.getCollection(filter); - - if (data) { - this.#detailStore?.appendItems(data.items); - } - - return { data, error, asObservable: () => this.#detailStore!.all() }; + /** + * Requests the stylesheet collection + * @param {UmbStylesheetCollectionFilterModel} [filter={ take: 100, skip: 0 }] + * @return {*} + * @memberof UmbStylesheetCollectionRepository + */ + requestCollection(filter: UmbStylesheetCollectionFilterModel = { take: 100, skip: 0 }) { + return this.#collectionSource.getCollection(filter); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/collection/repository/stylesheet-collection.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/collection/repository/stylesheet-collection.server.data-source.ts index 57cda012e5..fb4f7e78a8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/collection/repository/stylesheet-collection.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/collection/repository/stylesheet-collection.server.data-source.ts @@ -1,3 +1,4 @@ +import { UmbServerFilePathUniqueSerializer } from '@umbraco-cms/backoffice/server-file-system'; import { UmbStylesheetCollectionFilterModel, UmbStylesheetCollectionItemModel } from '../types.js'; import type { UmbCollectionDataSource } from '@umbraco-cms/backoffice/repository'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; @@ -14,6 +15,7 @@ export class UmbStylesheetCollectionServerDataSource implements UmbCollectionDataSource { #host: UmbControllerHost; + #serverFilePathUniqueSerializer = new UmbServerFilePathUniqueSerializer(); /** * Creates an instance of UmbStylesheetCollectionServerDataSource. @@ -24,7 +26,26 @@ export class UmbStylesheetCollectionServerDataSource this.#host = host; } - getCollection(filter: UmbStylesheetCollectionFilterModel) { - return tryExecuteAndNotify(this.#host, StylesheetResource.getStylesheetAll(filter)); + /** + * Gets the stylesheet collection items from the server + * @param {UmbStylesheetCollectionFilterModel} filter + * @return {*} + * @memberof UmbStylesheetCollectionServerDataSource + */ + async getCollection(filter: UmbStylesheetCollectionFilterModel) { + const { data, error } = await tryExecuteAndNotify(this.#host, StylesheetResource.getStylesheetOverview(filter)); + + if (data) { + const items: Array = data.items.map((item) => { + return { + name: item.name, + unique: this.#serverFilePathUniqueSerializer.toUnique(item.path), + }; + }); + + return { data: { items, total: data.total } }; + } + + return { error }; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/collection/types.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/collection/types.ts index d04c8fb3f5..ade7c382f5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/collection/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/collection/types.ts @@ -12,5 +12,5 @@ export interface UmbStylesheetCollectionFilterModel { export interface UmbStylesheetCollectionItemModel { name: string; - path: string; + unique: string; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/components/index.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/components/index.ts index d10ea30039..3307b2aa54 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/components/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/components/index.ts @@ -1,5 +1,7 @@ +import './stylesheet-input/stylesheet-input.element.js'; import './stylesheet-rule-input/stylesheet-rule-input.element.js'; import './stylesheet-rule-ref/stylesheet-rule-ref.element.js'; +export * from './stylesheet-input/stylesheet-input.element.js'; export * from './stylesheet-rule-input/stylesheet-rule-input.element.js'; export * from './stylesheet-rule-ref/stylesheet-rule-ref.element.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/components/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/components/manifests.ts index fc795a1da1..0af23cccca 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/components/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/components/manifests.ts @@ -1,3 +1,3 @@ import { manifests as stylesheetRuleInputManifests } from './stylesheet-rule-input/manifests.js'; -export const manifests = [...stylesheetRuleInputManifests]; +export const manifests = [...stylesheetPickerModalManifests, ...stylesheetRuleInputManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/components/stylesheet-input/stylesheet-input.context.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/components/stylesheet-input/stylesheet-input.context.ts new file mode 100644 index 0000000000..6f42004d9c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/components/stylesheet-input/stylesheet-input.context.ts @@ -0,0 +1,14 @@ +import { UMB_STYLESHEET_ITEM_REPOSITORY_ALIAS } from '../../repository/index.js'; +import { UmbStylesheetItemModel } from '../../types.js'; +import { UMB_STYLESHEET_PICKER_MODAL } from './stylesheet-picker-modal.token.js'; +import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; + +export class UmbStylesheetPickerContext extends UmbPickerInputContext { + constructor(host: UmbControllerHostElement) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + // TODO: Item and tree item types collide + super(host, UMB_STYLESHEET_ITEM_REPOSITORY_ALIAS, UMB_STYLESHEET_PICKER_MODAL, (item) => item.unique); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/components/stylesheet-input/stylesheet-input.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/components/stylesheet-input/stylesheet-input.element.ts new file mode 100644 index 0000000000..da82cd4f03 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/components/stylesheet-input/stylesheet-input.element.ts @@ -0,0 +1,136 @@ +import { UmbStylesheetItemModel } from '../../types.js'; +import { UmbStylesheetPickerContext } from './stylesheet-input.context.js'; +import { css, html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; +import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui'; +import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; +import { splitStringToArray } from '@umbraco-cms/backoffice/utils'; + +@customElement('umb-stylesheet-input') +export class UmbStylesheetInputElement extends FormControlMixin(UmbLitElement) { + /** + * This is a minimum amount of selected items in this input. + * @type {number} + * @attr + * @default 0 + */ + @property({ type: Number }) + public get min(): number { + return this.#pickerContext.min; + } + public set min(value: number) { + this.#pickerContext.min = value; + } + + /** + * Min validation message. + * @type {boolean} + * @attr + * @default + */ + @property({ type: String, attribute: 'min-message' }) + minMessage = 'This field need more items'; + + /** + * This is a maximum amount of selected items in this input. + * @type {number} + * @attr + * @default Infinity + */ + @property({ type: Number }) + public get max(): number { + return this.#pickerContext.max; + } + public set max(value: number) { + this.#pickerContext.max = value; + } + + /** + * Max validation message. + * @type {boolean} + * @attr + * @default + */ + @property({ type: String, attribute: 'min-message' }) + maxMessage = 'This field exceeds the allowed amount of items'; + + public get selectedIds(): Array { + return this.#pickerContext.getSelection(); + } + public set selectedIds(ids: Array) { + this.#pickerContext.setSelection(ids); + } + + @property() + public set value(idsString: string) { + // Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection. + this.selectedIds = splitStringToArray(idsString); + } + + @state() + private _items?: Array; + + #pickerContext = new UmbStylesheetPickerContext(this); + + constructor() { + super(); + + this.addValidator( + 'rangeUnderflow', + () => this.minMessage, + () => !!this.min && this.#pickerContext.getSelection().length < this.min, + ); + + this.addValidator( + 'rangeOverflow', + () => this.maxMessage, + () => !!this.max && this.#pickerContext.getSelection().length > this.max, + ); + + this.observe(this.#pickerContext.selection, (selection) => (super.value = selection.join(','))); + this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems)); + } + + protected getFormElement() { + return undefined; + } + + render() { + return html` + ${this._items?.map((item) => this._renderItem(item))} + this.#pickerContext.openPicker()} label="open" + >Add + `; + } + + private _renderItem(item: UmbStylesheetItemModel) { + if (!item.unique) return; + return html` + + + this.#pickerContext.requestRemoveItem(item.unique!)} + label="Remove Data Type ${item.name}" + >Remove + + + `; + } + + static styles = [ + css` + #add-button { + width: 100%; + } + `, + ]; +} + +export default UmbStylesheetInputElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-stylesheet-input': UmbStylesheetInputElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/components/stylesheet-input/stylesheet-picker-modal.token.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/components/stylesheet-input/stylesheet-picker-modal.token.ts new file mode 100644 index 0000000000..9b689e9818 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/components/stylesheet-input/stylesheet-picker-modal.token.ts @@ -0,0 +1,18 @@ +import { UmbStylesheetTreeItemModel } from '../../tree/types.js'; +import { UmbModalToken, UmbPickerModalValue, UmbTreePickerModalData } from '@umbraco-cms/backoffice/modal'; + +export type UmbStylesheetPickerModalData = UmbTreePickerModalData; +export type UmbStylesheetPickerModalValue = UmbPickerModalValue; + +export const UMB_STYLESHEET_PICKER_MODAL = new UmbModalToken< + UmbStylesheetPickerModalData, + UmbStylesheetPickerModalValue +>('Umb.Modal.TreePicker', { + modal: { + type: 'sidebar', + size: 'small', + }, + data: { + treeAlias: 'Umb.Tree.Stylesheet', + }, +}); diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/repository/item/stylesheet-item.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/repository/item/stylesheet-item.repository.ts index 9cc0cc8198..d8a770162f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/repository/item/stylesheet-item.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/repository/item/stylesheet-item.repository.ts @@ -1,10 +1,10 @@ +import { UmbStylesheetItemModel } from '../../types.js'; import { UmbStylesheetItemServerDataSource } from './stylesheet-item.server.data-source.js'; import { UMB_STYLESHEET_ITEM_STORE_CONTEXT } from './stylesheet-item.store.js'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { StylesheetItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; import { UmbItemRepositoryBase } from '@umbraco-cms/backoffice/repository'; -export class UmbStylesheetItemRepository extends UmbItemRepositoryBase { +export class UmbStylesheetItemRepository extends UmbItemRepositoryBase { constructor(host: UmbControllerHost) { super(host, UmbStylesheetItemServerDataSource, UMB_STYLESHEET_ITEM_STORE_CONTEXT); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/repository/item/stylesheet-item.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/repository/item/stylesheet-item.server.data-source.ts index 2c65c2a56c..adccd19b47 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/repository/item/stylesheet-item.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/repository/item/stylesheet-item.server.data-source.ts @@ -1,7 +1,10 @@ +import { UmbServerFilePathUniqueSerializer } from '@umbraco-cms/backoffice/server-file-system'; +import { UMB_STYLESHEET_ENTITY_TYPE, UMB_STYLESHEET_FOLDER_ENTITY_TYPE } from '../../entity.js'; +import { UmbStylesheetItemModel } from '../../types.js'; import type { UmbItemDataSource } from '@umbraco-cms/backoffice/repository'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; -import { StylesheetItemResponseModel, StylesheetResource } from '@umbraco-cms/backoffice/backend-api'; +import { StylesheetResource } from '@umbraco-cms/backoffice/backend-api'; /** * A data source for stylesheet items that fetches data from the server @@ -9,8 +12,9 @@ import { StylesheetItemResponseModel, StylesheetResource } from '@umbraco-cms/ba * @class UmbStylesheetItemServerDataSource * @implements {UmbItemDataSource} */ -export class UmbStylesheetItemServerDataSource implements UmbItemDataSource { +export class UmbStylesheetItemServerDataSource implements UmbItemDataSource { #host: UmbControllerHost; + #serverFilePathUniqueSerializer = new UmbServerFilePathUniqueSerializer(); /** * Creates an instance of UmbStylesheetItemServerDataSource. @@ -22,19 +26,42 @@ export class UmbStylesheetItemServerDataSource implements UmbItemDataSource} paths + * Fetches the items for the given uniques from the server + * @param {Array} uniques * @return {*} * @memberof UmbStylesheetItemServerDataSource */ - async getItems(paths: Array) { - if (!paths) throw new Error('Paths are missing'); + async getItems(uniques: Array) { + if (!uniques) throw new Error('Uniques are missing'); - return tryExecuteAndNotify( + const paths = uniques + .map((unique) => { + const serverPath = this.#serverFilePathUniqueSerializer.toServerPath(unique); + return serverPath ? encodeURI(serverPath) : null; + }) + .filter((x) => x !== null) as string[]; + + const { data, error } = await tryExecuteAndNotify( this.#host, StylesheetResource.getStylesheetItem({ path: paths, }), ); + + if (data) { + const items: Array = data.map((item) => { + return { + entityType: item.isFolder ? UMB_STYLESHEET_FOLDER_ENTITY_TYPE : UMB_STYLESHEET_ENTITY_TYPE, + unique: this.#serverFilePathUniqueSerializer.toUnique(item.path), + parentUnique: item.parent ? this.#serverFilePathUniqueSerializer.toUnique(item.parent.path) : null, + name: item.name, + isFolder: item.isFolder, + }; + }); + + return { data: items }; + } + + return { error }; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/repository/item/stylesheet-item.store.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/repository/item/stylesheet-item.store.ts index 661cc27988..e6e463676f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/repository/item/stylesheet-item.store.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/repository/item/stylesheet-item.store.ts @@ -1,16 +1,16 @@ -import type { StylesheetItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; +import { UmbStylesheetItemModel } from '../../types.js'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; -import { UmbFileSystemItemStore } from '@umbraco-cms/backoffice/store'; +import { UmbItemStoreBase } from '@umbraco-cms/backoffice/store'; /** * @export * @class UmbStylesheetItemStore - * @extends {UmbFileSystemItemStore} + * @extends {UmbItemStoreBase} * @description - Data Store for Stylesheet items */ -export class UmbStylesheetItemStore extends UmbFileSystemItemStore { +export class UmbStylesheetItemStore extends UmbItemStoreBase { /** * Creates an instance of UmbStylesheetItemStore. * @param {UmbControllerHostElement} host diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/types.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/types.ts index 3e78f68010..91c8e771aa 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/types.ts @@ -1,4 +1,4 @@ -import { UmbStylesheetEntityType } from './entity.js'; +import { UmbStylesheetEntityType, UmbStylesheetFolderEntityType } from './entity.js'; export interface UmbStylesheetDetailModel { entityType: UmbStylesheetEntityType; @@ -9,6 +9,14 @@ export interface UmbStylesheetDetailModel { content: string; } +export interface UmbStylesheetItemModel { + entityType: UmbStylesheetEntityType | UmbStylesheetFolderEntityType; + unique: string; + parentUnique: string | null; + name: string; + isFolder: boolean; +} + export interface UmbStylesheetRule { name: string; selector: string; 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 index dbe169ea3b..260cad4dfa 100644 --- 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 @@ -11,10 +11,7 @@ import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; * @description - Data Store for Template items */ -export class UmbTemplateItemStore - extends UmbStoreBase - implements UmbItemStore -{ +export class UmbTemplateItemStore extends UmbStoreBase { /** * Creates an instance of UmbTemplateItemStore. * @param {UmbControllerHostElement} host diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/repository/user-group-item.store.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/repository/user-group-item.store.ts index 4b8731794d..a91a199546 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/repository/user-group-item.store.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/repository/user-group-item.store.ts @@ -11,10 +11,8 @@ import type { UserGroupItemResponseModel } from '@umbraco-cms/backoffice/backend * @description - Data Store for user group items */ -export class UmbUserGroupItemStore - extends UmbStoreBase - implements UmbItemStore -{ +// TODO: add UmbItemStoreInterface when changed to uniques +export class UmbUserGroupItemStore extends UmbStoreBase { /** * Creates an instance of UmbUserGroupItemStore. * @param {UmbControllerHostElement} host diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/repository/item/user-item.store.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/repository/item/user-item.store.ts index a14bbf062d..93c0daf2d3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/repository/item/user-item.store.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/repository/item/user-item.store.ts @@ -11,10 +11,8 @@ import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; * @description - Data Store for user items */ -export class UmbUserItemStore - extends UmbStoreBase - implements UmbItemStore -{ +// TODO: add UmbItemStoreInterface when changed to uniques +export class UmbUserItemStore extends UmbStoreBase { /** * Creates an instance of UmbUserItemStore. * @param {UmbControllerHostElement} host