diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts index 8a56c75eb5..db01d03642 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts @@ -32,6 +32,7 @@ import './users'; import './packages'; import './search'; import './shared'; +import { UmbLanguageStore } from './settings/languages/language.store'; @defineElement('umb-backoffice') export class UmbBackofficeElement extends UmbLitElement { @@ -71,6 +72,7 @@ export class UmbBackofficeElement extends UmbLitElement { this.provideContext('umbCurrentUserHistoryStore', new UmbCurrentUserHistoryStore()); this.provideContext('umbDictionaryStore', new UmbDictionaryStore(this)); this.provideContext('umbDocumentBlueprintStore', new UmbDocumentBlueprintStore(this)); + this.provideContext('umbLanguageStore', new UmbLanguageStore(this)); } render() { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/language.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/language.store.ts new file mode 100644 index 0000000000..b10d51a866 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/language.store.ts @@ -0,0 +1,41 @@ +import { map, Observable } from 'rxjs'; +import { UmbDataStoreBase } from '../../../core/stores/store'; +import type { DataTypeDetails, LanguageDetails } from '@umbraco-cms/models'; +import { DataTypeResource, FolderTreeItem } from '@umbraco-cms/backend-api'; +import { tryExecuteAndNotify } from '@umbraco-cms/resources'; + +export type UmbLanguageStoreItemType = LanguageDetails; + +// TODO: research how we write names of global consts. +export const STORE_ALIAS = 'umbLanguageStore'; + +/** + * @export + * @class UmbLanguageStore + * @extends {UmbDataStoreBase} + * @description - Data Store for languages + */ +export class UmbLanguageStore extends UmbDataStoreBase { + public readonly storeAlias = STORE_ALIAS; + + /** + * @description - Request a Data Type by key. The Data Type is added to the store and is returned as an Observable. + * @param {string} key + * @return {*} {(Observable)} + * @memberof UmbDataTypesStore + */ + getByKey(key: string): Observable { + // TODO: use backend cli when available. + fetch(`/umbraco/management/api/v1/language/${key}`) + .then((res) => res.json()) + .then((data) => { + this.updateItems([data]); + }); + + return this.items.pipe(map((dataTypes) => dataTypes.find((dataType) => dataType.key === key) || null)); + } + + save(): Promise { + return new Promise((resolve, reject) => ''); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language-root/language-root-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language-root/language-root-workspace.element.ts index 9dd037ce4a..73ead03877 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language-root/language-root-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language-root/language-root-workspace.element.ts @@ -1,5 +1,6 @@ import { Language, LanguageResource } from '@umbraco-cms/backend-api'; import { UmbLitElement } from '@umbraco-cms/element'; +import { LanguageDetails } from '@umbraco-cms/models'; import { tryExecuteAndNotify } from '@umbraco-cms/resources'; import { UUITextStyles } from '@umbraco-ui/uui-css'; import { css, html, LitElement } from 'lit'; @@ -37,7 +38,7 @@ export class UmbLanguageRootWorkspaceElement extends UmbLitElement { ]; @state() - private _languages: Array = [ + private _languages: Array = [ { id: 1, name: 'English', @@ -114,10 +115,11 @@ export class UmbLanguageRootWorkspaceElement extends UmbLitElement { this._getLanguageData(); } + //TODO: Move this code to the language store private async _getLanguageData() { const { data } = await tryExecuteAndNotify(this, LanguageResource.getLanguage({ skip: 0, take: 10 })); if (data) { - this._languages = data.items; + this._languages = data.items as Array; this._createTableItems(this._languages); console.log('LANGS', this._languages); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/language-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/language-workspace.context.ts new file mode 100644 index 0000000000..61dc7e80f4 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/language-workspace.context.ts @@ -0,0 +1,65 @@ +import type { UmbDataTypeStore, UmbDataTypeStoreItemType } from 'src/backoffice/settings/data-types/data-type.store'; +import type { DataTypeDetails, LanguageDetails } from '@umbraco-cms/models'; +import { UmbControllerHostInterface } from 'src/core/controller/controller-host.mixin'; +import { UmbWorkspaceContentContext } from 'src/backoffice/shared/components/workspace/workspace-content/workspace-content.context'; +import { UmbLanguageStore, UmbLanguageStoreItemType } from '../../language.store'; +import { UniqueBehaviorSubject } from 'src/core/observable-api/unique-behavior-subject'; +import { UmbContextConsumerController } from 'src/core/context-api/consume/context-consumer.controller'; +import { UmbObserverController } from '@umbraco-cms/observable-api'; + +const DefaultLanguageData: UmbLanguageStoreItemType = { + id: 0, + key: '', + name: '', + isoCode: '', + isDefault: false, + isMandatory: false, +}; + +export class UmbWorkspaceLanguageContext { + public host: UmbControllerHostInterface; + + private _entityKey!: string; + + private _data; + public readonly data; + + private _store: UmbLanguageStore | null = null; + protected _storeObserver?: UmbObserverController; + + constructor(host: UmbControllerHostInterface, entityKey: string) { + this.host = host; + this._entityKey = entityKey; + + this._data = new UniqueBehaviorSubject(DefaultLanguageData); + this.data = this._data.asObservable(); + + new UmbContextConsumerController(host, 'umbLanguageStore', (_instance: UmbLanguageStore) => { + this._store = _instance; + if (!this._store) { + // TODO: make sure to break the application in a good way. + return; + } + + this._observeStore(); + }); + } + + private _observeStore(): void { + if (!this._store) { + return; + } + this._storeObserver?.destroy(); + this._storeObserver = new UmbObserverController(this.host, this._store.getByKey(this._entityKey), (content) => { + if (!content) return; // TODO: Handle nicely if there is no content data. + this.update(content as any); + }); + } + + public getData() { + return this._data.getValue(); + } + public update(data: Partial) { + this._data.next({ ...this.getData(), ...data }); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/language-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/language-workspace.element.ts index 39fb6e0e21..ea8ccdb058 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/language-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/language-workspace.element.ts @@ -1,10 +1,13 @@ import { Language } from '@umbraco-cms/backend-api'; +import { UmbLitElement } from '@umbraco-cms/element'; +import { LanguageDetails } from '@umbraco-cms/models'; import { UUITextStyles } from '@umbraco-ui/uui-css'; -import { css, html, LitElement } from 'lit'; +import { css, html, LitElement, nothing } from 'lit'; import { customElement, property } from 'lit/decorators.js'; +import { UmbWorkspaceLanguageContext } from './language-workspace.context'; @customElement('umb-language-workspace') -export class UmbLanguageWorkspaceElement extends LitElement { +export class UmbLanguageWorkspaceElement extends UmbLitElement { static styles = [ UUITextStyles, css` @@ -36,15 +39,37 @@ export class UmbLanguageWorkspaceElement extends LitElement { ]; @property() - language: Language = { - id: 1, - name: 'English', - isoCode: 'en-us', - isDefault: true, - isMandatory: true, - }; + language?: LanguageDetails; + + private _entityKey!: string; + @property() + public get entityKey(): string { + return this._entityKey; + } + public set entityKey(value: string) { + this._entityKey = value; + if (this._entityKey && !this._languageWorkspaceContext) { + this.provideLanguageWorkspaceContext(); + } + } + + private _languageWorkspaceContext?: UmbWorkspaceLanguageContext; + + constructor() { + super(); + } + + public provideLanguageWorkspaceContext() { + this._languageWorkspaceContext = new UmbWorkspaceLanguageContext(this, this._entityKey); + this.provideContext('umbWorkspaceContext', this._languageWorkspaceContext); + this._languageWorkspaceContext.data.subscribe((language) => { + this.language = language; + }); + } render() { + if (!this.language) return nothing; + return html`