fix editable workspace + form context
This commit is contained in:
@@ -60,7 +60,21 @@ export class UmbInputNumberRangeElement extends UmbFormControlMixin(UmbLitElemen
|
||||
}
|
||||
|
||||
protected getFormElement() {
|
||||
return this;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.addValidator(
|
||||
'customError',
|
||||
() => {
|
||||
return 'The low value must be less than the high value';
|
||||
},
|
||||
() => {
|
||||
return this._minValue !== undefined && this._maxValue !== undefined && this._minValue > this._maxValue;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
protected firstUpdated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void {
|
||||
|
||||
@@ -39,7 +39,11 @@ import type { ManifestLocalization } from './localization.model.js';
|
||||
import type { ManifestTree } from './tree.model.js';
|
||||
import type { ManifestTreeItem } from './tree-item.model.js';
|
||||
import type { ManifestUserProfileApp } from './user-profile-app.model.js';
|
||||
import type { ManifestWorkspace, ManifestWorkspaceRoutableKind } from './workspace.model.js';
|
||||
import type {
|
||||
ManifestWorkspace,
|
||||
ManifestWorkspaceRoutableKind,
|
||||
ManifestWorkspaceEditableKind,
|
||||
} from './workspace.model.js';
|
||||
import type { ManifestWorkspaceAction, ManifestWorkspaceActionDefaultKind } from './workspace-action.model.js';
|
||||
import type { ManifestWorkspaceActionMenuItem } from './workspace-action-menu-item.model.js';
|
||||
import type { ManifestWorkspaceContext } from './workspace-context.model.js';
|
||||
@@ -114,7 +118,7 @@ export type ManifestPropertyActions = ManifestPropertyAction | ManifestPropertyA
|
||||
|
||||
export type ManifestWorkspaceActions = ManifestWorkspaceAction | ManifestWorkspaceActionDefaultKind;
|
||||
|
||||
export type ManifestWorkspaces = ManifestWorkspace | ManifestWorkspaceRoutableKind;
|
||||
export type ManifestWorkspaces = ManifestWorkspace | ManifestWorkspaceRoutableKind | ManifestWorkspaceRoutableKind;
|
||||
export type ManifestWorkspaceViews = ManifestWorkspaceView | ManifestWorkspaceViewContentTypeDesignEditorKind;
|
||||
|
||||
export type ManifestTypes =
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { UmbRoutableWorkspaceContext } from '../../workspace/contexts/tokens/routable-workspace-context.interface.js';
|
||||
import type { UmbEditableWorkspaceContext } from '../../workspace/contexts/tokens/editable-workspace-context.interface.js';
|
||||
import type { UmbWorkspaceContext } from '../../workspace/contexts/tokens/workspace-context.interface.js';
|
||||
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import type { ManifestElementAndApi } from '@umbraco-cms/backoffice/extension-api';
|
||||
@@ -24,3 +25,11 @@ export interface ManifestWorkspaceRoutableKind
|
||||
}
|
||||
|
||||
export interface MetaWorkspaceRoutableKind extends MetaWorkspace {}
|
||||
|
||||
export interface ManifestWorkspaceEditableKind
|
||||
extends ManifestWorkspace<MetaWorkspaceEditableKind, UmbControllerHostElement, UmbEditableWorkspaceContext> {
|
||||
type: 'workspace';
|
||||
kind: 'routable';
|
||||
}
|
||||
|
||||
export interface MetaWorkspaceEditableKind extends MetaWorkspace {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { UmbFormContext } from '../context/form.context.js';
|
||||
import { type PropertyValueMap, customElement, html } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { type PropertyValueMap, customElement, html, css } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
|
||||
@customElement('umb-form')
|
||||
@@ -19,4 +19,12 @@ export class UmbFormElement extends UmbLitElement {
|
||||
</form>
|
||||
</uui-form>`;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
css`
|
||||
form {
|
||||
display: contents;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ export class UmbFormContext extends UmbContextBase<UmbFormContext> {
|
||||
|
||||
constructor(host: UmbControllerHost) {
|
||||
super(host, UMB_FORM_CONTEXT);
|
||||
console.log('providing it self as', UMB_FORM_CONTEXT, this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -20,6 +21,7 @@ export class UmbFormContext extends UmbContextBase<UmbFormContext> {
|
||||
* @param element {HTMLFormElement | null} - The Form element to be used for this context.
|
||||
*/
|
||||
setFormElement(element: HTMLFormElement | null) {
|
||||
console.log('setFormElement', element, this);
|
||||
if (this.#formElement === element) return;
|
||||
if (this.#formElement) {
|
||||
this.#formElement.removeEventListener('submit', this.onSubmit);
|
||||
@@ -46,25 +48,29 @@ export class UmbFormContext extends UmbContextBase<UmbFormContext> {
|
||||
*/
|
||||
requestSubmit() {
|
||||
// We do not call requestSubmit here, as we want the form to submit, and then we will handle the validation as part of the submit event handling.
|
||||
this.#formElement?.submit();
|
||||
this.#formElement?.requestSubmit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Triggered by the form, when it fires a submit event
|
||||
*/
|
||||
onSubmit = (event: SubmitEvent) => {
|
||||
console.log('onSubmit', event);
|
||||
event?.preventDefault();
|
||||
//this.dispatchEvent(new CustomEvent('submit-requested'));
|
||||
|
||||
// Check client validation:
|
||||
const isClientValid = this.#formElement?.checkValidity();
|
||||
|
||||
console.log('isClientValid', isClientValid);
|
||||
// ask validation managers to validate the form.
|
||||
|
||||
const isValid = isClientValid ?? false;
|
||||
|
||||
if (!isValid) {
|
||||
// Fire invalid..
|
||||
// TODO: consider naming it something like submit failed?
|
||||
this.dispatchEvent(new CustomEvent('invalid'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export * from './context/index.js';
|
||||
export * from './component/form.element.js';
|
||||
|
||||
@@ -15,6 +15,7 @@ export * from './entity-action/index.js';
|
||||
export * from './entity-bulk-action/index.js';
|
||||
export * from './extension-registry/index.js';
|
||||
export * from './id/index.js';
|
||||
export * from './form/index.js';
|
||||
export * from './menu/index.js';
|
||||
export * from './modal/index.js';
|
||||
export * from './notification/index.js';
|
||||
|
||||
@@ -23,6 +23,7 @@ export abstract class UmbSaveableWorkspaceContextBase<WorkspaceDataModelType>
|
||||
#form?: typeof UMB_FORM_CONTEXT.TYPE;
|
||||
#savePromise: Promise<void> | undefined;
|
||||
#saveResolve: (() => void) | undefined;
|
||||
#saveReject: (() => void) | undefined;
|
||||
|
||||
abstract readonly unique: Observable<string | null | undefined>;
|
||||
|
||||
@@ -46,13 +47,17 @@ export abstract class UmbSaveableWorkspaceContextBase<WorkspaceDataModelType>
|
||||
this.consumeContext(UMB_MODAL_CONTEXT, (context) => {
|
||||
(this.modalContext as UmbModalContext) = context;
|
||||
});
|
||||
console.log('about to consume form context', UMB_FORM_CONTEXT);
|
||||
this.consumeContext(UMB_FORM_CONTEXT, (context) => {
|
||||
console.log('consume form context', context);
|
||||
if (this.#form === context) return;
|
||||
if (this.#form) {
|
||||
this.#form.removeEventListener('submit', this.#performSubmitBind);
|
||||
this.#form.removeEventListener('invalid', this.#invalidForm);
|
||||
}
|
||||
this.#form = context;
|
||||
this.#form.addEventListener('submit', this.#performSubmitBind);
|
||||
this.#form.addEventListener('invalid', this.#invalidForm);
|
||||
this._gotFormContext(context);
|
||||
});
|
||||
}
|
||||
@@ -69,9 +74,41 @@ export abstract class UmbSaveableWorkspaceContextBase<WorkspaceDataModelType>
|
||||
this.#isNew.setValue(isNew);
|
||||
}
|
||||
|
||||
requestSubmit(): Promise<void> {
|
||||
if (this.#savePromise) {
|
||||
return this.#savePromise;
|
||||
}
|
||||
if (!this.#form) {
|
||||
throw new Error('Form context not available');
|
||||
}
|
||||
this.#savePromise = new Promise<void>((resolve, reject) => {
|
||||
this.#saveResolve = resolve;
|
||||
this.#saveReject = reject;
|
||||
});
|
||||
|
||||
console.log('REQUEST SUBMIT', this.#form);
|
||||
this.#form.requestSubmit();
|
||||
|
||||
return this.#savePromise;
|
||||
}
|
||||
|
||||
#invalidForm = (event: Event) => {
|
||||
console.log('workspace context got invalid form', event);
|
||||
if (this.#savePromise) {
|
||||
this.#saveReject?.();
|
||||
this.#savePromise = undefined;
|
||||
this.#saveResolve = undefined;
|
||||
this.#saveReject = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
protected submitComplete(data: WorkspaceDataModelType | undefined) {
|
||||
// Resolve the save promise:
|
||||
this.#saveResolve?.();
|
||||
// TODO: We need a way to fail the save promise..
|
||||
this.#savePromise = undefined;
|
||||
this.#saveResolve = undefined;
|
||||
this.#saveReject = undefined;
|
||||
|
||||
if (this.modalContext) {
|
||||
if (data) {
|
||||
@@ -87,20 +124,6 @@ export abstract class UmbSaveableWorkspaceContextBase<WorkspaceDataModelType>
|
||||
abstract getUnique(): string | undefined;
|
||||
abstract getEntityType(): string;
|
||||
abstract getData(): WorkspaceDataModelType | undefined;
|
||||
requestSubmit(): Promise<void> {
|
||||
if (this.#savePromise) {
|
||||
return this.#savePromise;
|
||||
}
|
||||
if (!this.#form) {
|
||||
throw new Error('Form context not available');
|
||||
}
|
||||
this.#form.requestSubmit();
|
||||
|
||||
this.#savePromise = new Promise<void>((resolve) => {
|
||||
this.#saveResolve = resolve;
|
||||
});
|
||||
return this.#savePromise;
|
||||
}
|
||||
|
||||
#performSubmitBind: () => void;
|
||||
protected abstract submit(): void;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import type { UmbRoutableWorkspaceContext } from '../../index.js';
|
||||
|
||||
export interface UmbEditableWorkspaceContext extends UmbRoutableWorkspaceContext {}
|
||||
@@ -0,0 +1,10 @@
|
||||
import type { UmbEditableWorkspaceContext } from './editable-workspace-context.interface.js';
|
||||
import type { UmbWorkspaceContext } from './workspace-context.interface.js';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
|
||||
export const UMB_EDITABLE_WORKSPACE_CONTEXT = new UmbContextToken<UmbWorkspaceContext, UmbEditableWorkspaceContext>(
|
||||
'UmbWorkspaceContext',
|
||||
undefined,
|
||||
// TODO: Make proper discriminator:
|
||||
(context): context is UmbEditableWorkspaceContext => 'routes' in context,
|
||||
);
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from './collection-workspace.context-token.js';
|
||||
export * from './editable-workspace.context-token.js';
|
||||
export * from './entity-workspace.context-token.js';
|
||||
export * from './publishable-workspace.context-token.js';
|
||||
export * from './routable-workspace.context-token.js';
|
||||
@@ -6,6 +7,7 @@ export * from './saveable-workspace.context-token.js';
|
||||
export * from './variant-workspace.context-token.js';
|
||||
export * from './workspace.context-token.js';
|
||||
export type * from './collection-workspace-context.interface.js';
|
||||
export type * from './editable-workspace-context.interface.js';
|
||||
export type * from './entity-workspace-context.interface.js';
|
||||
export type * from './invariant-dataset-workspace-context.interface.js';
|
||||
export type * from './property-structure-workspace-context.interface.js';
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import type { UmbSaveableWorkspaceContext } from '../../contexts/tokens/saveable-workspace-context.interface.js';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { html, customElement, state, css, type PropertyValueMap } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import type { UmbRoute } from '@umbraco-cms/backoffice/router';
|
||||
import { UmbExtensionsApiInitializer } from '@umbraco-cms/backoffice/extension-api';
|
||||
import { UmbFormContext } from '@umbraco-cms/backoffice/form';
|
||||
|
||||
@customElement('umb-editable-workspace')
|
||||
export class UmbEditableWorkspaceElement extends UmbLitElement {
|
||||
readonly #formContext = new UmbFormContext(this);
|
||||
|
||||
@state()
|
||||
_routes: UmbRoute[] = [];
|
||||
|
||||
@@ -16,11 +19,28 @@ export class UmbEditableWorkspaceElement extends UmbLitElement {
|
||||
new UmbExtensionsApiInitializer(this, umbExtensionsRegistry, 'workspaceContext', [api]);
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`<umb-form>
|
||||
<umb-router-slot .routes="${this._routes}"></umb-router-slot>
|
||||
</umb-form>`;
|
||||
protected firstUpdated(_changedProperties: PropertyValueMap<unknown> | Map<PropertyKey, unknown>): void {
|
||||
super.firstUpdated(_changedProperties);
|
||||
|
||||
this.#formContext.setFormElement(this.shadowRoot!.querySelector<HTMLFormElement>('form'));
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`<uui-form>
|
||||
<form>
|
||||
<uui-input name="tester" required></uui-input>
|
||||
<umb-router-slot .routes="${this._routes}"></umb-router-slot>
|
||||
</form>
|
||||
</uui-form>`;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
css`
|
||||
form {
|
||||
display: contents;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
export default UmbEditableWorkspaceElement;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { manifest as editableKindManifest } from './editable/editable-workspace.kind.js';
|
||||
import { manifest as routableKindManifest } from './routable/routable-workspace.kind.js';
|
||||
|
||||
export const manifests = [routableKindManifest];
|
||||
export const manifests = [routableKindManifest, editableKindManifest];
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property
|
||||
import type {
|
||||
UmbInvariantDatasetWorkspaceContext,
|
||||
UmbRoutableWorkspaceContext,
|
||||
UmbEditableWorkspaceContext,
|
||||
} from '@umbraco-cms/backoffice/workspace';
|
||||
import {
|
||||
UmbSaveableWorkspaceContextBase,
|
||||
@@ -33,7 +34,7 @@ import { UmbRequestReloadStructureForEntityEvent } from '@umbraco-cms/backoffice
|
||||
type EntityType = UmbDataTypeDetailModel;
|
||||
export class UmbDataTypeWorkspaceContext
|
||||
extends UmbSaveableWorkspaceContextBase<EntityType>
|
||||
implements UmbInvariantDatasetWorkspaceContext, UmbRoutableWorkspaceContext
|
||||
implements UmbInvariantDatasetWorkspaceContext, UmbRoutableWorkspaceContext, UmbEditableWorkspaceContext
|
||||
{
|
||||
//
|
||||
public readonly repository: UmbDataTypeDetailRepository = new UmbDataTypeDetailRepository(this);
|
||||
@@ -315,6 +316,8 @@ export class UmbDataTypeWorkspaceContext
|
||||
}
|
||||
|
||||
async submit() {
|
||||
console.log('SUBMIT');
|
||||
|
||||
if (!this.#currentData.value) return;
|
||||
if (!this.#currentData.value.unique) return;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ const DATA_TYPE_WORKSPACE_ALIAS = 'Umb.Workspace.DataType';
|
||||
|
||||
const workspace: ManifestWorkspaces = {
|
||||
type: 'workspace',
|
||||
kind: 'routable',
|
||||
kind: 'editable',
|
||||
alias: DATA_TYPE_WORKSPACE_ALIAS,
|
||||
name: 'Data Type Workspace',
|
||||
api: () => import('./data-type-workspace.context.js'),
|
||||
|
||||
Reference in New Issue
Block a user