add submittable workspace data manager
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
export * from './components/index.js';
|
||||
export * from './contexts/index.js';
|
||||
export * from './controllers/index.js';
|
||||
export * from './data-manager/index.js';
|
||||
export * from './modals/index.js';
|
||||
export * from './paths.js';
|
||||
export * from './submittable/index.js';
|
||||
export * from './workspace-property-dataset/index.js';
|
||||
export * from './workspace.element.js';
|
||||
export * from './paths.js';
|
||||
|
||||
export type * from './conditions/index.js';
|
||||
export type * from './types.js';
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './submittable-workspace-data-manager.js';
|
||||
export * from './submittable-workspace-context-base.js';
|
||||
@@ -0,0 +1,164 @@
|
||||
import { UmbWorkspaceRouteManager } from '../controllers/workspace-route-manager.controller.js';
|
||||
import { UMB_WORKSPACE_CONTEXT } from '../contexts/tokens/workspace.context-token.js';
|
||||
import type { UmbSubmittableWorkspaceContext } from '../contexts/tokens/submittable-workspace-context.interface.js';
|
||||
import { UmbSubmittableWorkspaceDataManager } from './submittable-workspace-data-manager.js';
|
||||
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
|
||||
import { UmbBooleanState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import type { UmbModalContext } from '@umbraco-cms/backoffice/modal';
|
||||
import { UMB_MODAL_CONTEXT } from '@umbraco-cms/backoffice/modal';
|
||||
import type { Observable } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
import type { UmbValidationController } from '@umbraco-cms/backoffice/validation';
|
||||
import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity';
|
||||
|
||||
export abstract class UmbSubmittableWorkspaceContextBase<WorkspaceDataModelType extends UmbEntityModel>
|
||||
extends UmbContextBase<UmbSubmittableWorkspaceContextBase<WorkspaceDataModelType>>
|
||||
implements UmbSubmittableWorkspaceContext
|
||||
{
|
||||
protected readonly _data = new UmbSubmittableWorkspaceDataManager<WorkspaceDataModelType>(this);
|
||||
|
||||
public readonly workspaceAlias: string;
|
||||
|
||||
// TODO: We could make a base type for workspace modal data, and use this here: As well as a base for the result, to make sure we always include the unique (instead of the object type)
|
||||
public readonly modalContext?: UmbModalContext<{ preset: object }>;
|
||||
|
||||
//public readonly validation = new UmbValidationContext(this);
|
||||
#validationContexts: Array<UmbValidationController> = [];
|
||||
|
||||
/**
|
||||
* Appends a validation context to the workspace.
|
||||
* @param context
|
||||
*/
|
||||
addValidationContext(context: UmbValidationController) {
|
||||
this.#validationContexts.push(context);
|
||||
}
|
||||
|
||||
#submitPromise: Promise<void> | undefined;
|
||||
#submitResolve: (() => void) | undefined;
|
||||
#submitReject: (() => void) | undefined;
|
||||
|
||||
abstract readonly unique: Observable<string | null | undefined>;
|
||||
|
||||
#isNew = new UmbBooleanState(undefined);
|
||||
isNew = this.#isNew.asObservable();
|
||||
|
||||
readonly routes = new UmbWorkspaceRouteManager(this);
|
||||
|
||||
/*
|
||||
Concept notes: [NL]
|
||||
Considerations are, if we bring a dirty state (observable) we need to maintain it all the time.
|
||||
This might be too heavy process, so we might want to consider just having a get dirty state method.
|
||||
*/
|
||||
//#isDirty = new UmbBooleanState(undefined);
|
||||
//isDirty = this.#isNew.asObservable();
|
||||
|
||||
constructor(host: UmbControllerHost, workspaceAlias: string) {
|
||||
super(host, UMB_WORKSPACE_CONTEXT.toString());
|
||||
this.workspaceAlias = workspaceAlias;
|
||||
// TODO: Consider if we can move this consumption to #resolveSubmit, just as a getContext, but it depends if others use the modalContext prop.. [NL]
|
||||
this.consumeContext(UMB_MODAL_CONTEXT, (context) => {
|
||||
(this.modalContext as UmbModalContext) = context;
|
||||
});
|
||||
}
|
||||
|
||||
protected resetState() {
|
||||
//this.validation.reset();
|
||||
this.#validationContexts.forEach((context) => context.reset());
|
||||
this.#isNew.setValue(undefined);
|
||||
}
|
||||
|
||||
getIsNew() {
|
||||
return this.#isNew.getValue();
|
||||
}
|
||||
|
||||
protected setIsNew(isNew: boolean) {
|
||||
this.#isNew.setValue(isNew);
|
||||
}
|
||||
|
||||
/**
|
||||
* If a Workspace has multiple validation contexts, then this method can be overwritten to return the correct one.
|
||||
* @returns Promise that resolves to void when the validation is complete.
|
||||
*/
|
||||
async validate(): Promise<Array<void>> {
|
||||
//return this.validation.validate();
|
||||
return Promise.all(this.#validationContexts.map((context) => context.validate()));
|
||||
}
|
||||
|
||||
async requestSubmit(): Promise<void> {
|
||||
return this.validateAndSubmit(
|
||||
() => this.submit(),
|
||||
() => this.invalidSubmit(),
|
||||
);
|
||||
}
|
||||
|
||||
protected async validateAndSubmit(onValid: () => Promise<void>, onInvalid: () => Promise<void>): Promise<void> {
|
||||
if (this.#submitPromise) {
|
||||
return this.#submitPromise;
|
||||
}
|
||||
this.#submitPromise = new Promise<void>((resolve, reject) => {
|
||||
this.#submitResolve = resolve;
|
||||
this.#submitReject = reject;
|
||||
});
|
||||
this.validate().then(
|
||||
async () => {
|
||||
onValid().then(this.#completeSubmit, this.#rejectSubmit);
|
||||
},
|
||||
async () => {
|
||||
onInvalid().then(this.#resolveSubmit, this.#rejectSubmit);
|
||||
},
|
||||
);
|
||||
|
||||
return this.#submitPromise;
|
||||
}
|
||||
|
||||
#rejectSubmit = () => {
|
||||
if (this.#submitPromise) {
|
||||
// TODO: Capture the validation contexts messages on open, and then reset to them in this case. [NL]
|
||||
|
||||
this.#submitReject?.();
|
||||
this.#submitPromise = undefined;
|
||||
this.#submitResolve = undefined;
|
||||
this.#submitReject = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
#resolveSubmit = () => {
|
||||
// Resolve the submit promise:
|
||||
this.#submitResolve?.();
|
||||
this.#submitPromise = undefined;
|
||||
this.#submitResolve = undefined;
|
||||
this.#submitReject = undefined;
|
||||
|
||||
// If we do not want to close a modal when saving something with errors, then move this part down to #completeSubmit method. [NL]
|
||||
if (this.modalContext) {
|
||||
this.modalContext?.setValue(this.getData());
|
||||
this.modalContext?.submit();
|
||||
}
|
||||
};
|
||||
|
||||
#completeSubmit = () => {
|
||||
this.#resolveSubmit();
|
||||
|
||||
// Calling reset on the validation context here. [NL]
|
||||
// TODO: Capture the validation messages on open, and then reset to that.
|
||||
//this.validation.reset();
|
||||
};
|
||||
|
||||
//abstract getIsDirty(): Promise<boolean>;
|
||||
abstract getUnique(): string | undefined;
|
||||
abstract getEntityType(): string;
|
||||
abstract getData(): WorkspaceDataModelType | undefined;
|
||||
protected abstract submit(): Promise<void>;
|
||||
protected invalidSubmit(): Promise<void> {
|
||||
return Promise.reject();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @deprecated Use UmbSubmittableWorkspaceContextBase instead — Will be removed before RC.
|
||||
* Rename `save` to `submit` and return a promise that resolves to true when save is complete.
|
||||
* TODO: Delete before RC.
|
||||
*/
|
||||
export abstract class UmbEditableWorkspaceContextBase<
|
||||
WorkspaceDataModelType,
|
||||
> extends UmbSubmittableWorkspaceContextBase<WorkspaceDataModelType> {}
|
||||
@@ -0,0 +1,107 @@
|
||||
import type { UmbWorkspaceDataManager } from '../data-manager/workspace-data-manager.interface.js';
|
||||
import { jsonStringComparison, UmbObjectState } 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';
|
||||
|
||||
export class UmbSubmittableWorkspaceDataManager<ModelType extends UmbEntityModel>
|
||||
extends UmbControllerBase
|
||||
implements UmbWorkspaceDataManager<ModelType>
|
||||
{
|
||||
#persisted = new UmbObjectState<ModelType | undefined>(undefined);
|
||||
#current = new UmbObjectState<ModelType | undefined>(undefined);
|
||||
|
||||
public readonly current = this.#current.asObservable();
|
||||
|
||||
constructor(host: UmbControllerHost) {
|
||||
super(host);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets persisted data
|
||||
* @returns {(ModelType | undefined)}
|
||||
* @memberof UmbSubmittableWorkspaceDataManager
|
||||
*/
|
||||
getPersistedData() {
|
||||
return this.#persisted.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the persisted data
|
||||
* @param {(ModelType | undefined)} data
|
||||
* @memberof UmbSubmittableWorkspaceDataManager
|
||||
*/
|
||||
setPersistedData(data: ModelType | undefined) {
|
||||
this.#persisted.setValue(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the persisted data
|
||||
* @param {Partial<ModelType>} partialData
|
||||
* @memberof UmbSubmittableWorkspaceDataManager
|
||||
*/
|
||||
updatePersistedData(partialData: Partial<ModelType>) {
|
||||
this.#persisted.update(partialData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current data
|
||||
* @returns {(ModelType | undefined)}
|
||||
* @memberof UmbSubmittableWorkspaceDataManager
|
||||
*/
|
||||
getCurrentData() {
|
||||
return this.#current.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current data
|
||||
* @param {(ModelType | undefined)} data
|
||||
* @memberof UmbSubmittableWorkspaceDataManager
|
||||
*/
|
||||
setCurrentData(data: ModelType | undefined) {
|
||||
this.#current.setValue(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the current data
|
||||
* @param {Partial<ModelType>} partialData
|
||||
* @memberof UmbSubmittableWorkspaceDataManager
|
||||
*/
|
||||
updateCurrentData(partialData: Partial<ModelType>) {
|
||||
this.#current.update(partialData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there are unpersisted changes
|
||||
* @returns {*}
|
||||
* @memberof UmbSubmittableWorkspaceDataManager
|
||||
*/
|
||||
hasUnpersistedChanges() {
|
||||
const persisted = this.#persisted.getValue();
|
||||
const current = this.#current.getValue();
|
||||
return jsonStringComparison(persisted, current) === false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the current data to the persisted data
|
||||
* @memberof UmbSubmittableWorkspaceDataManager
|
||||
*/
|
||||
resetCurrentData() {
|
||||
this.#current.setValue(this.#persisted.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the data
|
||||
* @memberof UmbSubmittableWorkspaceDataManager
|
||||
*/
|
||||
clearData() {
|
||||
this.#persisted.setValue(undefined);
|
||||
this.#current.setValue(undefined);
|
||||
}
|
||||
|
||||
override destroy() {
|
||||
this.#persisted.destroy();
|
||||
this.#current.destroy();
|
||||
super.destroy();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user