diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tags/repository/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tags/repository/manifests.ts new file mode 100644 index 0000000000..4eb7b6b7f3 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tags/repository/manifests.ts @@ -0,0 +1,23 @@ +import { UmbTagRepository } from './tag.repository'; +import { UmbTagStore } from './tag.store'; +import type { ManifestStore, ManifestRepository } from '@umbraco-cms/backoffice/extensions-registry'; + +export const TAG_REPOSITORY_ALIAS = 'Umb.Repository.Tags'; + +const repository: ManifestRepository = { + type: 'repository', + alias: TAG_REPOSITORY_ALIAS, + name: 'Tags Repository', + class: UmbTagRepository, +}; + +export const TAG_STORE_ALIAS = 'Umb.Store.Tags'; + +const store: ManifestStore = { + type: 'store', + alias: TAG_STORE_ALIAS, + name: 'Tags Store', + class: UmbTagStore, +}; + +export const manifests = [repository, store]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tags/repository/sources/tag.server.data.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tags/repository/sources/tag.server.data.ts new file mode 100644 index 0000000000..a9d60e0fb5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tags/repository/sources/tag.server.data.ts @@ -0,0 +1,44 @@ +import { v4 as uuidv4 } from 'uuid'; +import { TagResource } from '@umbraco-cms/backoffice/backend-api'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; +import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; + +/** + * A data source for the Tag that fetches data from the server + * @export + * @class UmbTagServerDataSource + * @implements {RepositoryDetailDataSource} + */ +export class UmbTagServerDataSource { + #host: UmbControllerHostElement; + + /** + * Creates an instance of UmbTagServerDataSource. + * @param {UmbControllerHostElement} host + * @memberof UmbTagServerDataSource + */ + constructor(host: UmbControllerHostElement) { + this.#host = host; + } + + /** + * Get a list of tags on the server + * @return {*} + * @memberof UmbTagServerDataSource + */ + async getCollection({ + query, + skip, + take, + tagGroup, + culture, + }: { + query: string; + skip: number; + take: number; + tagGroup?: string; + culture?: string; + }) { + return tryExecuteAndNotify(this.#host, TagResource.getTag({ query, skip, take, tagGroup, culture })); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tags/repository/tag.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tags/repository/tag.repository.ts new file mode 100644 index 0000000000..4c876de37f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tags/repository/tag.repository.ts @@ -0,0 +1,48 @@ +import { UmbTagServerDataSource } from './sources/tag.server.data'; +import { UmbTagStore, UMB_TAG_STORE_CONTEXT_TOKEN } from './tag.store'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; +import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; +import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification'; +import { TagResponseModel, ProblemDetailsModel } from '@umbraco-cms/backoffice/backend-api'; + +export class UmbTagRepository { + #init!: Promise; + + #host: UmbControllerHostElement; + + #dataSource: UmbTagServerDataSource; + #tagStore?: UmbTagStore; + + #notificationContext?: UmbNotificationContext; + + constructor(host: UmbControllerHostElement) { + this.#host = host; + + this.#dataSource = new UmbTagServerDataSource(this.#host); + + this.#init = Promise.all([ + new UmbContextConsumerController(this.#host, UMB_NOTIFICATION_CONTEXT_TOKEN, (instance) => { + this.#notificationContext = instance; + }), + + new UmbContextConsumerController(this.#host, UMB_TAG_STORE_CONTEXT_TOKEN, (instance) => { + this.#tagStore = instance; + }).asPromise(), + ]); + } + + async requestTags( + { query, skip, take, tagGroup, culture } = { query: '', skip: 0, take: 1000, tagGroup: '', culture: '' } + ) { + await this.#init; + + const { data, error } = await this.#dataSource.getCollection({ query, skip, take, tagGroup, culture }); + + if (data) { + // TODO: allow to append an array of items to the store + data.items.forEach((x) => this.#tagStore?.append(x)); + } + + return { data, error, asObservable: () => this.#tagStore!.data }; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/tags/repository/tag.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/tags/repository/tag.store.ts new file mode 100644 index 0000000000..d69b24df5c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/tags/repository/tag.store.ts @@ -0,0 +1,52 @@ +import type { PagedTagResponseModel, TagResponseModel } from '@umbraco-cms/backoffice/backend-api'; +import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; +import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbStoreBase } from '@umbraco-cms/backoffice/store'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; + +export const UMB_TAG_STORE_CONTEXT_TOKEN = new UmbContextToken('UmbTAGStore'); +/** + * @export + * @class UmbTagStore + * @extends {UmbStoreBase} + * @description - Data Store for Template Details + */ +export class UmbTagStore extends UmbStoreBase { + #data = new ArrayState([], (x) => x.id); + + /** + * Creates an instance of UmbTagStore. + * @param {UmbControllerHostElement} host + * @memberof UmbTagStore + */ + constructor(host: UmbControllerHostElement) { + super(host, UMB_TAG_STORE_CONTEXT_TOKEN.toString()); + } + + /** + * Append a tag to the store + * @param {TagResponseModel} TAG + * @memberof UmbTagStore + */ + append(TAG: TagResponseModel) { + this.#data.append([TAG]); + } + + /** + * Append a tag to the store + * @param {id} TAGResponseModel id. + * @memberof UmbTagStore + */ + byId(id: TagResponseModel['id']) { + return this.#data.getObservablePart((x) => x.find((y) => y.id === id)); + } + + /** + * Removes tag in the store with the given uniques + * @param {string[]} uniques + * @memberof UmbTagStore + */ + remove(uniques: Array) { + this.#data.remove(uniques); + } +}