diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/data-manager/workspace-data-manager.interface.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/data-manager/workspace-data-manager.interface.ts index d9c497b44d..3f3a3d9685 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/data-manager/workspace-data-manager.interface.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/data-manager/workspace-data-manager.interface.ts @@ -2,8 +2,8 @@ import type { UmbController } from '@umbraco-cms/backoffice/controller-api'; import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; export interface UmbWorkspaceDataManager extends UmbController { - getPersistedData(): ModelType | undefined; - getCurrentData(): ModelType | undefined; - setPersistedData(data: ModelType | undefined): void; - setCurrentData(data: ModelType | undefined): void; + getPersisted(): ModelType | undefined; + getCurrent(): ModelType | undefined; + setPersisted(data: ModelType | undefined): void; + setCurrent(data: ModelType | undefined): void; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity-detail/entity-detail-workspace-base.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity-detail/entity-detail-workspace-base.ts index f18d1dbbd1..4d9b9fad62 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity-detail/entity-detail-workspace-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity-detail/entity-detail-workspace-base.ts @@ -68,11 +68,11 @@ export abstract class UmbEntityDetailWorkspaceContextBase< } getData() { - return this._data.getCurrentData(); + return this._data.getCurrent(); } getUnique() { - return this._data.getCurrentData()?.unique; + return this._data.getCurrent()?.unique; } async load(unique: string) { @@ -85,8 +85,8 @@ export abstract class UmbEntityDetailWorkspaceContextBase< if (data) { this.setIsNew(false); - this._data.setPersistedData(data); - this._data.setCurrentData(data); + this._data.setPersisted(data); + this._data.setCurrent(data); } return response; @@ -98,7 +98,7 @@ export abstract class UmbEntityDetailWorkspaceContextBase< async submit() { await this.#init; - const currentData = this._data.getCurrentData(); + const currentData = this._data.getCurrent(); if (!currentData) { throw new Error('Data is not set'); @@ -115,7 +115,7 @@ export abstract class UmbEntityDetailWorkspaceContextBase< throw error?.message ?? 'Repository did not return data after create.'; } - this._data.setPersistedData(data); + this._data.setPersisted(data); // TODO: this might not be the right place to alert the tree, but it works for now const eventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); @@ -131,7 +131,7 @@ export abstract class UmbEntityDetailWorkspaceContextBase< throw error?.message ?? 'Repository did not return data after create.'; } - this._data.setPersistedData(data); + this._data.setPersisted(data); const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); const event = new UmbRequestReloadStructureForEntityEvent({ @@ -156,8 +156,8 @@ export abstract class UmbEntityDetailWorkspaceContextBase< data = { ...data, ...this.modalContext.data.preset }; } this.setIsNew(true); - this._data.setPersistedData(data); - this._data.setCurrentData(data); + this._data.setPersisted(data); + this._data.setCurrent(data); return data; } @@ -182,7 +182,7 @@ export abstract class UmbEntityDetailWorkspaceContextBase< #onWillNavigate = async (e: CustomEvent) => { const newUrl = e.detail.url; - if (this._checkWillNavigateAway(newUrl) && this._data.hasUnpersistedChanges()) { + if (this._checkWillNavigateAway(newUrl) && this._data.getHasUnpersistedChanges()) { e.preventDefault(); const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); const modal = modalManager.open(this, UMB_DISCARD_CHANGES_MODAL); @@ -191,7 +191,7 @@ export abstract class UmbEntityDetailWorkspaceContextBase< // navigate to the new url when discarding changes await modal.onSubmit(); // Reset the current data so we don't end in a endless loop of asking to discard changes. - this._data.resetCurrentData(); + this._data.resetCurrent(); history.pushState({}, '', e.detail.url); return true; } catch { @@ -204,7 +204,7 @@ export abstract class UmbEntityDetailWorkspaceContextBase< override resetState() { super.resetState(); - this._data.clearData(); + this._data.clear(); } #checkIfInitialized() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity/entity-workspace-data-manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity/entity-workspace-data-manager.ts index f28161666d..ab21d9476a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity/entity-workspace-data-manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity/entity-workspace-data-manager.ts @@ -2,8 +2,14 @@ import type { UmbWorkspaceDataManager } from '../data-manager/workspace-data-man import { jsonStringComparison, UmbObjectState, type MappingFunction } from '@umbraco-cms/backoffice/observable-api'; import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +/** + * Manages the workspace data for an entity. + * @class UmbEntityWorkspaceDataManager + * @augments {UmbControllerBase} + * @implements {UmbWorkspaceDataManager} + * @template ModelType + */ export class UmbEntityWorkspaceDataManager extends UmbControllerBase implements UmbWorkspaceDataManager @@ -11,22 +17,24 @@ export class UmbEntityWorkspaceDataManager #persisted = new UmbObjectState(undefined); #current = new UmbObjectState(undefined); + /** + * Observable of the persisted data + * @memberof UmbEntityWorkspaceDataManager + */ + public readonly persisted = this.#persisted.asObservable(); + + /** + * Observable of the current data + * @memberof UmbEntityWorkspaceDataManager + */ public readonly current = this.#current.asObservable(); - constructor(host: UmbControllerHost) { - super(host); - } - - createObservablePart(mappingFunction: MappingFunction) { - return this.#current.asObservablePart(mappingFunction); - } - /** * Gets persisted data * @returns {(ModelType | undefined)} * @memberof UmbSubmittableWorkspaceDataManager */ - getPersistedData() { + getPersisted() { return this.#persisted.getValue(); } @@ -35,7 +43,7 @@ export class UmbEntityWorkspaceDataManager * @param {(ModelType | undefined)} data * @memberof UmbSubmittableWorkspaceDataManager */ - setPersistedData(data: ModelType | undefined) { + setPersisted(data: ModelType | undefined) { this.#persisted.setValue(data); } @@ -44,16 +52,27 @@ export class UmbEntityWorkspaceDataManager * @param {Partial} partialData * @memberof UmbSubmittableWorkspaceDataManager */ - updatePersistedData(partialData: Partial) { + updatePersisted(partialData: Partial) { this.#persisted.update(partialData); } + /** + * Creates an observable part of the persisted data + * @template ReturnType + * @param {(MappingFunction)} mappingFunction + * @returns {*} + * @memberof UmbEntityWorkspaceDataManager + */ + createObservablePartOfPersisted(mappingFunction: MappingFunction) { + return this.#persisted.asObservablePart(mappingFunction); + } + /** * Gets the current data * @returns {(ModelType | undefined)} * @memberof UmbSubmittableWorkspaceDataManager */ - getCurrentData() { + getCurrent() { return this.#current.getValue(); } @@ -62,7 +81,7 @@ export class UmbEntityWorkspaceDataManager * @param {(ModelType | undefined)} data * @memberof UmbSubmittableWorkspaceDataManager */ - setCurrentData(data: ModelType | undefined) { + setCurrent(data: ModelType | undefined) { this.#current.setValue(data); } @@ -71,16 +90,27 @@ export class UmbEntityWorkspaceDataManager * @param {Partial} partialData * @memberof UmbSubmittableWorkspaceDataManager */ - updateCurrentData(partialData: Partial) { + updateCurrent(partialData: Partial) { this.#current.update(partialData); } + /** + * Creates an observable part of the current data + * @template ReturnType + * @param {(MappingFunction)} mappingFunction + * @returns {*} + * @memberof UmbEntityWorkspaceDataManager + */ + createObservablePartOfCurrent(mappingFunction: MappingFunction) { + return this.#current.asObservablePart(mappingFunction); + } + /** * Checks if there are unpersisted changes * @returns {*} * @memberof UmbSubmittableWorkspaceDataManager */ - hasUnpersistedChanges() { + getHasUnpersistedChanges() { const persisted = this.#persisted.getValue(); const current = this.#current.getValue(); return jsonStringComparison(persisted, current) === false; @@ -90,7 +120,7 @@ export class UmbEntityWorkspaceDataManager * Resets the current data to the persisted data * @memberof UmbSubmittableWorkspaceDataManager */ - resetCurrentData() { + resetCurrent() { this.#current.setValue(this.#persisted.getValue()); } @@ -98,7 +128,7 @@ export class UmbEntityWorkspaceDataManager * Clears the data * @memberof UmbSubmittableWorkspaceDataManager */ - clearData() { + clear() { this.#persisted.setValue(undefined); this.#current.setValue(undefined); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace.context.ts index 14d528f590..590ce04c26 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace.context.ts @@ -45,12 +45,12 @@ export class UmbDataTypeWorkspaceContext extends UmbEntityDetailWorkspaceContextBase implements UmbInvariantDatasetWorkspaceContext, UmbRoutableWorkspaceContext { - readonly name = this._data.createObservablePart((data) => data?.name); - readonly unique = this._data.createObservablePart((data) => data?.unique); - readonly entityType = this._data.createObservablePart((data) => data?.entityType); + readonly name = this._data.createObservablePartOfCurrent((data) => data?.name); + readonly unique = this._data.createObservablePartOfCurrent((data) => data?.unique); + readonly entityType = this._data.createObservablePartOfCurrent((data) => data?.entityType); - readonly propertyEditorUiAlias = this._data.createObservablePart((data) => data?.editorUiAlias); - readonly propertyEditorSchemaAlias = this._data.createObservablePart((data) => data?.editorAlias); + readonly propertyEditorUiAlias = this._data.createObservablePartOfCurrent((data) => data?.editorUiAlias); + readonly propertyEditorSchemaAlias = this._data.createObservablePartOfCurrent((data) => data?.editorAlias); #properties = new UmbArrayState([], (x) => x.alias).sortBy( (a, b) => (a.weight || 0) - (b.weight || 0), @@ -239,7 +239,7 @@ export class UmbDataTypeWorkspaceContext #transferConfigDefaultData() { if (!this.#propertyEditorSchemaSettingsDefaultData || !this.#propertyEditorUISettingsDefaultData) return; - const data = this._data.getCurrentData(); + const data = this._data.getCurrent(); if (!data) return; this.#settingsDefaultData = [ @@ -248,8 +248,8 @@ export class UmbDataTypeWorkspaceContext ] satisfies Array; // We check for satisfied type, because we will be directly transferring them to become value. Future note, if they are not satisfied, we need to transfer alias and value. [NL] - this._data.updatePersistedData({ values: this.#settingsDefaultData }); - this._data.updateCurrentData({ values: this.#settingsDefaultData }); + this._data.updatePersisted({ values: this.#settingsDefaultData }); + this._data.updateCurrent({ values: this.#settingsDefaultData }); } public getPropertyDefaultValue(alias: string) { @@ -261,27 +261,27 @@ export class UmbDataTypeWorkspaceContext } getName() { - return this._data.getCurrentData()?.name; + return this._data.getCurrent()?.name; } setName(name: string | undefined) { - this._data.updateCurrentData({ name }); + this._data.updateCurrent({ name }); } getPropertyEditorSchemaAlias() { - return this._data.getCurrentData()?.editorAlias; + return this._data.getCurrent()?.editorAlias; } setPropertyEditorSchemaAlias(alias?: string) { - this._data.updateCurrentData({ editorAlias: alias }); + this._data.updateCurrent({ editorAlias: alias }); } getPropertyEditorUiAlias() { - return this._data.getCurrentData()?.editorUiAlias; + return this._data.getCurrent()?.editorUiAlias; } setPropertyEditorUiAlias(alias?: string) { - this._data.updateCurrentData({ editorUiAlias: alias }); + this._data.updateCurrent({ editorUiAlias: alias }); } /** @@ -292,14 +292,14 @@ export class UmbDataTypeWorkspaceContext */ async propertyValueByAlias(propertyAlias: string) { await this._getDataPromise; - return this._data.createObservablePart( + return this._data.createObservablePartOfCurrent( (data) => data?.values?.find((x) => x.alias === propertyAlias)?.value as ReturnType, ); } getPropertyValue(propertyAlias: string) { return ( - (this._data.getCurrentData()?.values?.find((x) => x.alias === propertyAlias)?.value as ReturnType) ?? + (this._data.getCurrent()?.values?.find((x) => x.alias === propertyAlias)?.value as ReturnType) ?? (this.getPropertyDefaultValue(propertyAlias) as ReturnType) ); } @@ -309,11 +309,11 @@ export class UmbDataTypeWorkspaceContext await this._getDataPromise; const entry = { alias: alias, value: value }; - const currentData = this._data.getCurrentData(); + const currentData = this._data.getCurrent(); if (currentData) { // TODO: make a partial update method for array of data, (idea/concept, use if this case is getting common) const newDataSet = appendToFrozenArray(currentData.values || [], entry, (x) => x.alias); - this._data.updateCurrentData({ values: newDataSet }); + this._data.updateCurrent({ values: newDataSet }); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/language/workspace/language/language-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/language/workspace/language/language-workspace.context.ts index 73edd09bc7..1caf0e7b16 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/language/workspace/language/language-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/language/workspace/language/language-workspace.context.ts @@ -19,8 +19,8 @@ export class UmbLanguageWorkspaceContext readonly data = this._data.current; - readonly unique = this._data.createObservablePart((data) => data?.unique); - readonly name = this._data.createObservablePart((data) => data?.name); + readonly unique = this._data.createObservablePartOfCurrent((data) => data?.unique); + readonly name = this._data.createObservablePartOfCurrent((data) => data?.name); constructor(host: UmbControllerHost) { super(host, { @@ -55,23 +55,23 @@ export class UmbLanguageWorkspaceContext } setName(name: string) { - this._data.updateCurrentData({ name }); + this._data.updateCurrent({ name }); } setCulture(unique: string) { - this._data.updateCurrentData({ unique }); + this._data.updateCurrent({ unique }); } setMandatory(isMandatory: boolean) { - this._data.updateCurrentData({ isMandatory }); + this._data.updateCurrent({ isMandatory }); } setDefault(isDefault: boolean) { - this._data.updateCurrentData({ isDefault }); + this._data.updateCurrent({ isDefault }); } setFallbackCulture(unique: string) { - this._data.updateCurrentData({ fallbackIsoCode: unique }); + this._data.updateCurrent({ fallbackIsoCode: unique }); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/user-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/user-workspace.context.ts index f009758c3c..0aa79554f2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/user-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/user-workspace.context.ts @@ -22,14 +22,20 @@ export class UmbUserWorkspaceContext public readonly configRepository = new UmbUserConfigRepository(this); readonly data = this._data.current; - readonly state = this._data.createObservablePart((x) => x?.state); - readonly unique = this._data.createObservablePart((x) => x?.unique); - readonly kind = this._data.createObservablePart((x) => x?.kind); - readonly userGroupUniques = this._data.createObservablePart((x) => x?.userGroupUniques || []); - readonly documentStartNodeUniques = this._data.createObservablePart((data) => data?.documentStartNodeUniques || []); - readonly hasDocumentRootAccess = this._data.createObservablePart((data) => data?.hasDocumentRootAccess || false); - readonly mediaStartNodeUniques = this._data.createObservablePart((data) => data?.mediaStartNodeUniques || []); - readonly hasMediaRootAccess = this._data.createObservablePart((data) => data?.hasMediaRootAccess || false); + readonly state = this._data.createObservablePartOfCurrent((x) => x?.state); + readonly unique = this._data.createObservablePartOfCurrent((x) => x?.unique); + readonly kind = this._data.createObservablePartOfCurrent((x) => x?.kind); + readonly userGroupUniques = this._data.createObservablePartOfCurrent((x) => x?.userGroupUniques || []); + readonly documentStartNodeUniques = this._data.createObservablePartOfCurrent( + (data) => data?.documentStartNodeUniques || [], + ); + readonly hasDocumentRootAccess = this._data.createObservablePartOfCurrent( + (data) => data?.hasDocumentRootAccess || false, + ); + readonly mediaStartNodeUniques = this._data.createObservablePartOfCurrent( + (data) => data?.mediaStartNodeUniques || [], + ); + readonly hasMediaRootAccess = this._data.createObservablePartOfCurrent((data) => data?.hasMediaRootAccess || false); #calculatedStartNodes = new UmbObjectState(undefined); readonly calculatedStartNodes = this.#calculatedStartNodes.asObservable(); @@ -82,15 +88,15 @@ export class UmbUserWorkspaceContext history.pushState(null, '', 'section/user-management'); return; } - this._data.updateCurrentData({ state: user.state, avatarUrls: user.avatarUrls }); + this._data.updateCurrent({ state: user.state, avatarUrls: user.avatarUrls }); } getState(): UmbUserStateEnum | null | undefined { - return this._data.getCurrentData()?.state; + return this._data.getCurrent()?.state; } updateProperty(propertyName: PropertyName, value: EntityType[PropertyName]) { - this._data.updateCurrentData({ [propertyName]: value }); + this._data.updateCurrent({ [propertyName]: value }); } // TODO: implement upload progress