Merge branch 'v15/feature/discard-changes' into v15/fix/extend-entity-detail-workspace-base
This commit is contained in:
@@ -2,8 +2,8 @@ import type { UmbController } from '@umbraco-cms/backoffice/controller-api';
|
||||
import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity';
|
||||
|
||||
export interface UmbWorkspaceDataManager<ModelType extends UmbEntityModel> 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;
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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<ModelType>}
|
||||
* @template ModelType
|
||||
*/
|
||||
export class UmbEntityWorkspaceDataManager<ModelType extends UmbEntityModel>
|
||||
extends UmbControllerBase
|
||||
implements UmbWorkspaceDataManager<ModelType>
|
||||
@@ -11,22 +17,24 @@ export class UmbEntityWorkspaceDataManager<ModelType extends UmbEntityModel>
|
||||
#persisted = new UmbObjectState<ModelType | undefined>(undefined);
|
||||
#current = new UmbObjectState<ModelType | undefined>(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<ReturnType>(mappingFunction: MappingFunction<ModelType | undefined, ReturnType>) {
|
||||
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<ModelType extends UmbEntityModel>
|
||||
* @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<ModelType extends UmbEntityModel>
|
||||
* @param {Partial<ModelType>} partialData
|
||||
* @memberof UmbSubmittableWorkspaceDataManager
|
||||
*/
|
||||
updatePersistedData(partialData: Partial<ModelType>) {
|
||||
updatePersisted(partialData: Partial<ModelType>) {
|
||||
this.#persisted.update(partialData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an observable part of the persisted data
|
||||
* @template ReturnType
|
||||
* @param {(MappingFunction<ModelType | undefined, ReturnType>)} mappingFunction
|
||||
* @returns {*}
|
||||
* @memberof UmbEntityWorkspaceDataManager
|
||||
*/
|
||||
createObservablePartOfPersisted<ReturnType>(mappingFunction: MappingFunction<ModelType | undefined, ReturnType>) {
|
||||
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<ModelType extends UmbEntityModel>
|
||||
* @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<ModelType extends UmbEntityModel>
|
||||
* @param {Partial<ModelType>} partialData
|
||||
* @memberof UmbSubmittableWorkspaceDataManager
|
||||
*/
|
||||
updateCurrentData(partialData: Partial<ModelType>) {
|
||||
updateCurrent(partialData: Partial<ModelType>) {
|
||||
this.#current.update(partialData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an observable part of the current data
|
||||
* @template ReturnType
|
||||
* @param {(MappingFunction<ModelType | undefined, ReturnType>)} mappingFunction
|
||||
* @returns {*}
|
||||
* @memberof UmbEntityWorkspaceDataManager
|
||||
*/
|
||||
createObservablePartOfCurrent<ReturnType>(mappingFunction: MappingFunction<ModelType | undefined, ReturnType>) {
|
||||
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<ModelType extends UmbEntityModel>
|
||||
* 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<ModelType extends UmbEntityModel>
|
||||
* Clears the data
|
||||
* @memberof UmbSubmittableWorkspaceDataManager
|
||||
*/
|
||||
clearData() {
|
||||
clear() {
|
||||
this.#persisted.setValue(undefined);
|
||||
this.#current.setValue(undefined);
|
||||
}
|
||||
|
||||
@@ -45,12 +45,12 @@ export class UmbDataTypeWorkspaceContext
|
||||
extends UmbEntityDetailWorkspaceContextBase<EntityType, UmbDataTypeDetailRepository>
|
||||
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<PropertyEditorSettingsProperty>([], (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<UmbDataTypePropertyModel>;
|
||||
// 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<ReturnType = unknown>(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<ReturnType = unknown>(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 });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<UmbUserStartNodesModel | undefined>(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 extends keyof EntityType>(propertyName: PropertyName, value: EntityType[PropertyName]) {
|
||||
this._data.updateCurrentData({ [propertyName]: value });
|
||||
this._data.updateCurrent({ [propertyName]: value });
|
||||
}
|
||||
|
||||
// TODO: implement upload progress
|
||||
|
||||
Reference in New Issue
Block a user