Proff of concept for navigating to edit path when created

This commit is contained in:
Niels Lyngsø
2023-04-04 15:48:36 +02:00
parent 4a83bfa41d
commit 42f901aa41
11 changed files with 93 additions and 65 deletions

View File

@@ -5,6 +5,7 @@ export declare class UmbControllerHostElement extends HTMLElement {
hasController(controller: UmbControllerInterface): boolean;
getControllers(filterMethod: (ctrl: UmbControllerInterface) => boolean): UmbControllerInterface[];
addController(controller: UmbControllerInterface): void;
removeControllerByUnique(unique: UmbControllerInterface['unique']): void;
removeController(controller: UmbControllerInterface): void;
}
@@ -43,13 +44,7 @@ export const UmbControllerHostMixin = <T extends HTMLElementConstructor>(superCl
*/
addController(ctrl: UmbControllerInterface): void {
// Check if there is one already with same unique
if (ctrl.unique) {
this.#controllers.forEach((x) => {
if (x.unique === ctrl.unique) {
this.removeController(x);
}
});
}
this.removeControllerByUnique(ctrl.unique);
this.#controllers.push(ctrl);
if (this.#attached) {
@@ -57,6 +52,20 @@ export const UmbControllerHostMixin = <T extends HTMLElementConstructor>(superCl
}
}
/**
* Remove a controller from this element, by its unique/alias.
* @param {unknown} unique/alias
*/
removeControllerByUnique(unique: UmbControllerInterface['unique']): void {
if (unique) {
this.#controllers.forEach((x) => {
if (x.unique === unique) {
this.removeController(x);
}
});
}
}
/**
* Remove a controller from this element.
* Notice this will also destroy the controller.

View File

@@ -0,0 +1,21 @@
import type { ISlashOptions } from '@umbraco-cms/internal/router';
const PARAM_IDENTIFIER = /:([^\\/]+)/g;
function stripSlash(path: string): string {
return slashify(path, { start: false, end: false });
}
function slashify(path: string, { start = true, end = true }: Partial<ISlashOptions> = {}): string {
path = start && !path.startsWith('/') ? `/${path}` : !start && path.startsWith('/') ? path.slice(1) : path;
return end && !path.endsWith('/') ? `${path}/` : !end && path.endsWith('/') ? path.slice(0, path.length - 1) : path;
}
export function generateRoutePathBuilder(path: string) {
return (params: { [key: string]: string | number }) =>
stripSlash(
path.replace(PARAM_IDENTIFIER, (substring: string, ...args: string[]) => {
return params[args[0]].toString();
})
);
}

View File

@@ -1,3 +1,4 @@
export * from './route-location.interface';
export * from './route.context';
export * from './route.interface';
export * from './generate-route-path-builder.function';

View File

@@ -1,5 +1,6 @@
import type { IRoutingInfo, ISlashOptions } from 'router-slot';
import { UmbRoute } from './route.interface';
import { generateRoutePathBuilder } from '.';
import {
UmbContextConsumerController,
UmbContextProviderController,
@@ -10,17 +11,6 @@ import { UMB_MODAL_CONTEXT_TOKEN, UmbModalRouteRegistration } from '@umbraco-cms
const EmptyDiv = document.createElement('div');
const PARAM_IDENTIFIER = /:([^\\/]+)/g;
function stripSlash(path: string): string {
return slashify(path, { start: false, end: false });
}
function slashify(path: string, { start = true, end = true }: Partial<ISlashOptions> = {}): string {
path = start && !path.startsWith('/') ? `/${path}` : !start && path.startsWith('/') ? path.slice(1) : path;
return end && !path.endsWith('/') ? `${path}/` : !end && path.endsWith('/') ? path.slice(0, path.length - 1) : path;
}
export class UmbRouteContext {
#modalRegistrations: UmbModalRouteRegistration[] = [];
#modalContext?: typeof UMB_MODAL_CONTEXT_TOKEN.TYPE;
@@ -125,16 +115,9 @@ export class UmbRouteContext {
if (!this.#routerBasePath) return;
const routeBasePath = this.#routerBasePath.endsWith('/') ? this.#routerBasePath : this.#routerBasePath + '/';
const localPath = `modal/${modalRegistration.alias.toString()}/${modalRegistration.path}`;
const localPath = routeBasePath + `modal/${modalRegistration.alias.toString()}/${modalRegistration.path}`;
const urlBuilder = (params: { [key: string]: string | number }) => {
const localRoutePath = stripSlash(
localPath.replace(PARAM_IDENTIFIER, (substring: string, ...args: string[]) => {
return params[args[0]].toString();
})
);
return routeBasePath + localRoutePath;
};
const urlBuilder = generateRoutePathBuilder(localPath);
modalRegistration._internal_setRouteBuilder(urlBuilder);
};

View File

@@ -6,6 +6,9 @@ import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controlle
export class UmbSaveWorkspaceAction extends UmbWorkspaceActionBase<UmbWorkspaceContextInterface> {
constructor(host: UmbControllerHostElement) {
super(host);
// TODO: Could we make change label depending on the state?
// So its called 'Create' when the workspace is new and 'Save' when the workspace is not new.
}
/* TODO: we need a solution for all actions to notify the system that is has been executed.
@@ -14,35 +17,7 @@ export class UmbSaveWorkspaceAction extends UmbWorkspaceActionBase<UmbWorkspaceC
*/
async execute() {
if (!this.workspaceContext) return;
// TODO: it doesn't get the updated value
const data = this.workspaceContext.getData();
// TODO: handle errors
if (!data) return;
this.workspaceContext.getIsNew() ? this.#create(data) : this.#update(data);
}
async #create(data: any) {
if (!this.workspaceContext) return;
// TODO: preferably the actions dont talk directly with repository, but instead with its context.
// We just need to consider how third parties can extend the system.
const { error } = await this.workspaceContext.repository.create(data);
// TODO: this is temp solution to bubble validation errors to the UI
if (error) {
if (error.type === 'validation') {
this.workspaceContext.setValidationErrors?.(error.errors);
}
} else {
this.workspaceContext.setValidationErrors?.(undefined);
// TODO: do not make it the buttons responsibility to set the workspace to not new.
this.workspaceContext.setIsNew(false);
}
}
#update(data: any) {
if (!this.workspaceContext) return;
this.workspaceContext.repository?.save(data);
this.workspaceContext.save();
}
}

View File

@@ -4,12 +4,13 @@ import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export interface UmbWorkspaceContextInterface<DataType = unknown> {
host: UmbControllerHostElement;
repository: any; // TODO: add type
isNew: Observable<boolean>;
getIsNew(): boolean;
isNew: Observable<boolean | undefined>;
getIsNew(): boolean | undefined;
setIsNew(value: boolean): void;
// TODO: should we consider another name than entity type. File system files are not entities but still have this type.
getEntityType(): string;
getData(): DataType | undefined;
save(): Promise<void>;
destroy(): void;
// TODO: temp solution to bubble validation errors to the UI
setValidationErrors?(errorMap: any): void;