Merge branch 'main' into feature/rich-text-editor

This commit is contained in:
Nathan Woulfe
2023-03-30 09:46:55 +10:00
326 changed files with 2080 additions and 1135 deletions

View File

@@ -35,6 +35,8 @@
"local-rules/bad-type-import": "error",
"local-rules/no-direct-api-import": "warn",
"local-rules/prefer-import-aliases": "error",
"local-rules/enforce-element-suffix-on-element-class-name": "error",
"local-rules/prefer-umbraco-cms-imports": "error",
"@typescript-eslint/no-non-null-assertion": "off"
},
"settings": {

View File

@@ -4,7 +4,7 @@ import logoImg from '/umbraco_logomark_white.svg';
import loginImg from '/login.jpeg';
@customElement('umb-auth-layout')
export class UmbAuthLayout extends LitElement {
export class UmbAuthLayoutElement extends LitElement {
static styles: CSSResultGroup = [
css`
#background {
@@ -69,6 +69,6 @@ export class UmbAuthLayout extends LitElement {
declare global {
interface HTMLElementTagNameMap {
'umb-auth-layout': UmbAuthLayout;
'umb-auth-layout': UmbAuthLayoutElement;
}
}

View File

@@ -6,7 +6,7 @@ import { ifDefined } from 'lit/directives/if-defined.js';
import './auth-layout.element';
@customElement('umb-login')
export default class UmbLogin extends LitElement {
export default class UmbLoginElement extends LitElement {
static styles: CSSResultGroup = [
UUITextStyles,
css`
@@ -113,6 +113,6 @@ export default class UmbLogin extends LitElement {
declare global {
interface HTMLElementTagNameMap {
'umb-login': UmbLogin;
'umb-login': UmbLoginElement;
}
}

View File

@@ -1,16 +1,16 @@
import { expect, fixture, html } from '@open-wc/testing';
import { defaultA11yConfig } from '@umbraco-cms/internal/test-utils';
import UmbLogin from './login.element';
import UmbLoginElement from './login.element';
describe('UmbLogin', () => {
let element: UmbLogin;
let element: UmbLoginElement;
beforeEach(async () => {
element = await fixture(html`<umb-login></umb-login>`);
});
it('is defined with its own instance', () => {
expect(element).to.be.instanceOf(UmbLogin);
expect(element).to.be.instanceOf(UmbLoginElement);
});
it('passes the a11y audit', async () => {

View File

@@ -20,18 +20,21 @@ module.exports = {
create: function (context) {
return {
ImportDeclaration: function (node) {
if (node.source.parent.importKind !== 'type' && (node.source.value.endsWith('/models') || node.source.value === 'router-slot/model')) {
if (
node.source.parent.importKind !== 'type' &&
(node.source.value.endsWith('/models') || node.source.value === 'router-slot/model')
) {
const sourceCode = context.getSourceCode();
const nodeSource = sourceCode.getText(node);
context.report({
node,
message: 'Use `import type` instead of `import`.',
fix: fixer => fixer.replaceText(node, nodeSource.replace('import', 'import type')),
fix: (fixer) => fixer.replaceText(node, nodeSource.replace('import', 'import type')),
});
}
},
};
}
},
},
/** @type {import('eslint').Rule.RuleModule} */
@@ -39,9 +42,10 @@ module.exports = {
meta: {
type: 'suggestion',
docs: {
description: 'Ensures that any API resources from the `@umbraco-cms/backend-api` module are not used directly. Instead you should use the `tryExecuteAndNotify` function from the `@umbraco-cms/resources` module.',
description:
'Ensures that any API resources from the `@umbraco-cms/backend-api` module are not used directly. Instead you should use the `tryExecuteAndNotify` function from the `@umbraco-cms/resources` module.',
category: 'Best Practices',
recommended: true
recommended: true,
},
fixable: 'code',
schema: [],
@@ -50,19 +54,30 @@ module.exports = {
return {
// If methods called on *Resource classes are not already wrapped with `await tryExecuteAndNotify()`, then we should suggest to wrap them.
CallExpression: function (node) {
if (node.callee.type === 'MemberExpression' && node.callee.object.type === 'Identifier' && node.callee.object.name.endsWith('Resource') && node.callee.property.type === 'Identifier' && node.callee.property.name !== 'constructor') {
const hasTryExecuteAndNotify = node.parent && node.parent.callee && (node.parent.callee.name === 'tryExecute' || node.parent.callee.name === 'tryExecuteAndNotify');
if (
node.callee.type === 'MemberExpression' &&
node.callee.object.type === 'Identifier' &&
node.callee.object.name.endsWith('Resource') &&
node.callee.property.type === 'Identifier' &&
node.callee.property.name !== 'constructor'
) {
const hasTryExecuteAndNotify =
node.parent &&
node.parent.callee &&
(node.parent.callee.name === 'tryExecute' || node.parent.callee.name === 'tryExecuteAndNotify');
if (!hasTryExecuteAndNotify) {
context.report({
node,
message: 'Wrap this call with `tryExecuteAndNotify()`. Make sure to `await` the result.',
fix: fixer => [fixer.insertTextBefore(node, 'tryExecuteAndNotify(this, '), fixer.insertTextAfter(node, ')')],
fix: (fixer) => [
fixer.insertTextBefore(node, 'tryExecuteAndNotify(this, '),
fixer.insertTextAfter(node, ')'),
],
});
}
}
}
},
};
},
},
@@ -71,9 +86,10 @@ module.exports = {
meta: {
type: 'suggestion',
docs: {
description: 'Ensures that the application does not rely on file system paths for imports. Instead, use import aliases or relative imports. This also solves a problem where GitHub fails on the test runner step.',
description:
'Ensures that the application does not rely on file system paths for imports. Instead, use import aliases or relative imports. This also solves a problem where GitHub fails on the test runner step.',
category: 'Best Practices',
recommended: true
recommended: true,
},
schema: [],
},
@@ -83,11 +99,76 @@ module.exports = {
if (node.source.value.startsWith('src/')) {
context.report({
node,
message: 'Prefer using import aliases or relative imports instead of absolute imports. Example: `import { MyComponent } from "src/components/MyComponent";` should be `import { MyComponent } from "@components/MyComponent";`'
message:
'Prefer using import aliases or relative imports instead of absolute imports. Example: `import { MyComponent } from "src/components/MyComponent";` should be `import { MyComponent } from "@components/MyComponent";`',
});
}
},
};
},
},
/** @type {import('eslint').Rule.RuleModule} */
'enforce-element-suffix-on-element-class-name': {
meta: {
type: 'suggestion',
docs: {
description: 'Enforce Element class name to end with "Element".',
category: 'Naming',
recommended: true,
},
},
create: function (context) {
return {
ClassDeclaration(node) {
// check if the class extends HTMLElement, LitElement, or UmbLitElement
const isExtendingElement =
node.superClass && ['HTMLElement', 'LitElement', 'UmbLitElement'].includes(node.superClass.name);
// check if the class name ends with 'Element'
const isClassNameValid = node.id.name.endsWith('Element');
if (isExtendingElement && !isClassNameValid) {
context.report({
node,
message: "Element class name should end with 'Element'.",
// There us no fixer on purpose because it's not safe to rename the class. We want to do that trough the refactoring tool.
});
}
},
};
},
},
// TODO: Its not bullet proof, but it will catch most/some cases.
/** @type {import('eslint').Rule.RuleModule} */
'prefer-umbraco-cms-imports': {
meta: {
type: 'suggestion',
docs: {
description: 'Replace relative imports to libs/... with @umbraco-cms/backoffice/...',
category: 'Best Practices',
recommended: true,
},
fixable: 'code',
schema: [],
},
create: function (context) {
const libsRegex = /(\.\.\/)*libs\/(.*)/;
return {
ImportDeclaration: function (node) {
const sourceValue = node.source.value;
if (sourceValue.startsWith('libs/') || libsRegex.test(sourceValue)) {
const importPath = sourceValue.replace(libsRegex, (match, p1, p2) => {
return `@umbraco-cms/backoffice/${p2}`;
});
context.report({
node,
message: `Use import alias @umbraco-cms/backoffice instead of relative path "${sourceValue}".`,
fix: function (fixer) {
return fixer.replaceTextRange(node.source.range, `'${importPath}'`);
},
});
}
},
};
},
},
};

View File

@@ -1,10 +1,10 @@
import { UmbContextToken } from '../token/context-token';
import { UmbContextConsumer } from './context-consumer';
import { UmbContextCallback } from './context-request.event';
import type { UmbControllerHostInterface, UmbControllerInterface } from '@umbraco-cms/backoffice/controller';
import type { UmbControllerHostElement, UmbControllerInterface } from '@umbraco-cms/backoffice/controller';
export class UmbContextConsumerController<T = unknown>
extends UmbContextConsumer<UmbControllerHostInterface, T>
extends UmbContextConsumer<UmbControllerHostElement, T>
implements UmbControllerInterface
{
public get unique() {
@@ -12,7 +12,7 @@ export class UmbContextConsumerController<T = unknown>
}
constructor(
host: UmbControllerHostInterface,
host: UmbControllerHostElement,
contextAlias: string | UmbContextToken<T>,
callback: UmbContextCallback<T>
) {

View File

@@ -36,6 +36,10 @@ export class UmbContextConsumer<HostType extends EventTarget = EventTarget, T =
}
protected _onResponse = (instance: T) => {
// TODO: check that this check is not giving us any problems:
if (this._instance === instance) {
return;
}
this._instance = instance;
this._callback?.(instance);
this._promiseResolver?.(instance);

View File

@@ -1,16 +1,16 @@
import { UmbContextToken } from '../token/context-token';
import { UmbContextProvider } from './context-provider';
import type { UmbControllerHostInterface, UmbControllerInterface } from '@umbraco-cms/backoffice/controller';
import type { UmbControllerHostElement, UmbControllerInterface } from '@umbraco-cms/backoffice/controller';
export class UmbContextProviderController<T = unknown>
extends UmbContextProvider<UmbControllerHostInterface>
extends UmbContextProvider<UmbControllerHostElement>
implements UmbControllerInterface
{
public get unique() {
return this._contextAlias.toString();
}
constructor(host: UmbControllerHostInterface, contextAlias: string | UmbContextToken<T>, instance: T) {
constructor(host: UmbControllerHostElement, contextAlias: string | UmbContextToken<T>, instance: T) {
super(host, contextAlias, instance);
// If this API is already provided with this alias? Then we do not want to register this controller:

View File

@@ -1,9 +1,7 @@
import { UmbControllerInterface } from './controller.interface';
import type { HTMLElementConstructor } from '@umbraco-cms/backoffice/models';
export declare class UmbControllerHostInterface extends HTMLElement {
//#controllers:UmbController[];
//#attached:boolean;
export declare class UmbControllerHostElement extends HTMLElement {
hasController(controller: UmbControllerInterface): boolean;
getControllers(filterMethod: (ctrl: UmbControllerInterface) => boolean): UmbControllerInterface[];
addController(controller: UmbControllerInterface): void;
@@ -101,7 +99,7 @@ export const UmbControllerHostMixin = <T extends HTMLElementConstructor>(superCl
}
}
return UmbContextConsumerClass as unknown as HTMLElementConstructor<UmbControllerHostInterface> & T;
return UmbContextConsumerClass as unknown as HTMLElementConstructor<UmbControllerHostElement> & T;
};
declare global {

View File

@@ -1,15 +1,15 @@
import { UmbControllerHostInterface } from './controller-host.mixin';
import { UmbControllerHostElement } from './controller-host.mixin';
import { UmbControllerInterface } from './controller.interface';
export abstract class UmbController implements UmbControllerInterface {
protected host?: UmbControllerHostInterface;
protected host?: UmbControllerHostElement;
private _alias?: string;
public get unique() {
return this._alias;
}
constructor(host: UmbControllerHostInterface, alias?: string) {
constructor(host: UmbControllerHostElement, alias?: string) {
this.host = host;
this._alias = alias;
this.host.addController(this);

View File

@@ -1,6 +1,6 @@
import { expect } from '@open-wc/testing';
import { customElement } from 'lit/decorators.js';
import { UmbControllerHostInterface, UmbControllerHostMixin } from './controller-host.mixin';
import { UmbControllerHostElement, UmbControllerHostMixin } from './controller-host.mixin';
import { UmbContextProviderController } from '@umbraco-cms/backoffice/context-api';
class MyClass {
@@ -11,13 +11,13 @@ class MyClass {
export class MyHostElement extends UmbControllerHostMixin(HTMLElement) {}
describe('UmbContextProvider', () => {
type NewType = UmbControllerHostInterface;
type NewType = UmbControllerHostElement;
let hostElement: NewType;
const contextInstance = new MyClass();
beforeEach(() => {
hostElement = document.createElement('test-my-controller-host') as UmbControllerHostInterface;
hostElement = document.createElement('test-my-controller-host') as UmbControllerHostElement;
});
describe('Destroyed controllers is gone from host', () => {

View File

@@ -2,7 +2,7 @@ import { Observable } from 'rxjs';
import type { HTMLElementConstructor } from '@umbraco-cms/backoffice/models';
import { UmbControllerHostInterface, UmbControllerHostMixin } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement, UmbControllerHostMixin } from '@umbraco-cms/backoffice/controller';
import {
UmbContextToken,
UmbContextCallback,
@@ -16,7 +16,7 @@ interface ResolvedContexts {
[key: string]: any;
}
export declare class UmbElementMixinInterface extends UmbControllerHostInterface {
export declare class UmbElementMixinInterface extends UmbControllerHostElement {
observe<T>(source: Observable<T>, callback: (_value: T) => void, unique?: string): UmbObserverController<T>;
provideContext<R = unknown>(alias: string | UmbContextToken<R>, instance: R): UmbContextProviderController<R>;
consumeContext<R = unknown>(

View File

@@ -1,18 +1,18 @@
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
import { umbExtensionsRegistry, createExtensionClass } from '@umbraco-cms/backoffice/extensions-api';
import { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
export interface UmbAction<RepositoryType = unknown> {
host: UmbControllerHostInterface;
host: UmbControllerHostElement;
repository: RepositoryType;
execute(): Promise<void>;
}
export class UmbActionBase<RepositoryType> {
host: UmbControllerHostInterface;
host: UmbControllerHostElement;
repository?: RepositoryType;
constructor(host: UmbControllerHostInterface, repositoryAlias: string) {
constructor(host: UmbControllerHostElement, repositoryAlias: string) {
this.host = host;
// TODO: unsure a method can't be called before everything is initialized

View File

@@ -1,8 +1,8 @@
import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export class UmbCopyEntityAction<T extends { copy(): Promise<void> }> extends UmbEntityActionBase<T> {
constructor(host: UmbControllerHostInterface, repositoryAlias: string, unique: string) {
constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) {
super(host, repositoryAlias, unique);
}

View File

@@ -1,15 +1,14 @@
import { UMB_CONFIRM_MODAL_TOKEN } from '../../../../src/backoffice/shared/modals/confirm';
import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action';
import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/modal';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN, UMB_CONFIRM_MODAL } from '@umbraco-cms/backoffice/modal';
export class UmbDeleteEntityAction<
T extends { delete(unique: string): Promise<void>; requestItems(uniques: Array<string>): any }
> extends UmbEntityActionBase<T> {
#modalContext?: UmbModalContext;
constructor(host: UmbControllerHostInterface, repositoryAlias: string, unique: string) {
constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) {
super(host, repositoryAlias, unique);
new UmbContextConsumerController(this.host, UMB_MODAL_CONTEXT_TOKEN, (instance) => {
@@ -25,7 +24,7 @@ export class UmbDeleteEntityAction<
if (data) {
const item = data[0];
const modalHandler = this.#modalContext.open(UMB_CONFIRM_MODAL_TOKEN, {
const modalHandler = this.#modalContext.open(UMB_CONFIRM_MODAL, {
headline: `Delete ${item.name}`,
content: 'Are you sure you want to delete this item?',
color: 'danger',

View File

@@ -1,8 +1,8 @@
import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export class UmbMoveEntityAction<T extends { move(): Promise<void> }> extends UmbEntityActionBase<T> {
constructor(host: UmbControllerHostInterface, repositoryAlias: string, unique: string) {
constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) {
super(host, repositoryAlias, unique);
}

View File

@@ -1,10 +1,10 @@
import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export class UmbSortChildrenOfEntityAction<
T extends { sortChildrenOf(): Promise<void> }
> extends UmbEntityActionBase<T> {
constructor(host: UmbControllerHostInterface, repositoryAlias: string, unique: string) {
constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) {
super(host, repositoryAlias, unique);
}

View File

@@ -1,15 +1,14 @@
import { UMB_CONFIRM_MODAL_TOKEN } from '../../../../src/backoffice/shared/modals/confirm';
import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action';
import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/modal';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN, UMB_CONFIRM_MODAL } from '@umbraco-cms/backoffice/modal';
export class UmbTrashEntityAction<
T extends { trash(unique: Array<string>): Promise<void>; requestTreeItems(uniques: Array<string>): any }
> extends UmbEntityActionBase<T> {
#modalContext?: UmbModalContext;
constructor(host: UmbControllerHostInterface, repositoryAlias: string, unique: string) {
constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) {
super(host, repositoryAlias, unique);
new UmbContextConsumerController(this.host, UMB_MODAL_CONTEXT_TOKEN, (instance) => {
@@ -25,7 +24,7 @@ export class UmbTrashEntityAction<
if (data) {
const item = data[0];
const modalHandler = this.#modalContext?.open(UMB_CONFIRM_MODAL_TOKEN, {
const modalHandler = this.#modalContext?.open(UMB_CONFIRM_MODAL, {
headline: `Trash ${item.name}`,
content: 'Are you sure you want to move this item to the recycle bin?',
color: 'danger',

View File

@@ -1,5 +1,5 @@
import { UmbAction, UmbActionBase } from './action';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export interface UmbEntityAction<RepositoryType> extends UmbAction<RepositoryType> {
unique: string;
@@ -8,7 +8,7 @@ export interface UmbEntityAction<RepositoryType> extends UmbAction<RepositoryTyp
export class UmbEntityActionBase<RepositoryType> extends UmbActionBase<RepositoryType> {
unique: string;
constructor(host: UmbControllerHostInterface, repositoryAlias: string, unique: string) {
constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) {
super(host, repositoryAlias);
this.unique = unique;
}

View File

@@ -1,5 +1,5 @@
import { UmbAction, UmbActionBase } from './action';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export interface UmbEntityBulkAction<RepositoryType = unknown> extends UmbAction<RepositoryType> {
selection: Array<string>;
@@ -9,7 +9,7 @@ export interface UmbEntityBulkAction<RepositoryType = unknown> extends UmbAction
export class UmbEntityBulkActionBase<RepositoryType = unknown> extends UmbActionBase<RepositoryType> {
selection: Array<string>;
constructor(host: UmbControllerHostInterface, repositoryAlias: string, selection: Array<string>) {
constructor(host: UmbControllerHostElement, repositoryAlias: string, selection: Array<string>) {
super(host, repositoryAlias);
this.selection = selection;
}

View File

@@ -1,7 +1,7 @@
import type { UmbExtensionRegistry } from './registry/extension.registry';
import type { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export type UmbEntrypointOnInit = (host: UmbControllerHostInterface, extensionRegistry: UmbExtensionRegistry) => void;
export type UmbEntrypointOnInit = (host: UmbControllerHostElement, extensionRegistry: UmbExtensionRegistry) => void;
/**
* Interface containing supported life-cycle functions for ESModule entrypoints

View File

@@ -1,12 +1,12 @@
import type { ManifestEntrypoint } from './models';
import { hasInitExport, loadExtension, UmbExtensionRegistry } from '@umbraco-cms/backoffice/extensions-api';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export class UmbEntryPointExtensionInitializer {
#rootHost;
#extensionRegistry;
constructor(rootHost: UmbControllerHostInterface, extensionRegistry: UmbExtensionRegistry) {
constructor(rootHost: UmbControllerHostElement, extensionRegistry: UmbExtensionRegistry) {
this.#rootHost = rootHost;
this.#extensionRegistry = extensionRegistry;
// TODO: change entrypoint extension to be entryPoint:

View File

@@ -1,4 +1,6 @@
export * from './modal.context';
export * from './modal-handler';
export * from './token/modal-token';
export * from './modal-route-registration';
export * from './modal-route-registration.controller';
export * from './token';
export * from './modal.interfaces';

View File

@@ -10,13 +10,13 @@ import { UmbModalConfig, UmbModalType } from './modal.context';
import { UmbModalToken } from './token/modal-token';
import { createExtensionElement, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api';
import { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
import type { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
import type { ManifestModal } from '@umbraco-cms/backoffice/extensions-registry';
/**
* Type which omits the real submit method, and replaces it with a submit method which accepts an optional argument depending on the generic type.
*/
export type UmbModalHandler<ModalData = unknown, ModalResult = unknown> = Omit<
export type UmbModalHandler<ModalData extends object = object, ModalResult = any> = Omit<
UmbModalHandlerClass<ModalData, ModalResult>,
'submit'
> &
@@ -38,15 +38,15 @@ type OptionalSubmitArgumentIfUndefined<T> = T extends undefined
};
//TODO consider splitting this into two separate handlers
export class UmbModalHandlerClass<ModalData, ModalResult> {
export class UmbModalHandlerClass<ModalData extends object = object, ModalResult = unknown> {
private _submitPromise: Promise<ModalResult>;
private _submitResolver?: (value: ModalResult) => void;
private _submitRejecter?: () => void;
#host: UmbControllerHostInterface;
#host: UmbControllerHostElement;
public modalElement: UUIModalDialogElement | UUIModalSidebarElement;
#innerElement = new BehaviorSubject<any | undefined>(undefined);
#innerElement = new BehaviorSubject<HTMLElement | undefined>(undefined);
public readonly innerElement = this.#innerElement.asObservable();
#modalElement?: UUIModalSidebarElement | UUIDialogElement;
@@ -56,7 +56,7 @@ export class UmbModalHandlerClass<ModalData, ModalResult> {
public size: UUIModalSidebarSize = 'small';
constructor(
host: UmbControllerHostInterface,
host: UmbControllerHostElement,
modalAlias: string | UmbModalToken<ModalData, ModalResult>,
data?: ModalData,
config?: UmbModalConfig
@@ -106,7 +106,7 @@ export class UmbModalHandlerClass<ModalData, ModalResult> {
const innerElement = (await createExtensionElement(manifest)) as any;
if (innerElement) {
innerElement.data = data; //
innerElement.data = data;
//innerElement.observable = this.#dataObservable;
innerElement.modalHandler = this;
}
@@ -114,7 +114,7 @@ export class UmbModalHandlerClass<ModalData, ModalResult> {
return innerElement;
}
// note, this methods argument is not defined correctly here, but requires to be fix by appending the OptionalSubmitArgumentIfUndefined type when newing up this class.
// note, this methods is private argument is not defined correctly here, but requires to be fix by appending the OptionalSubmitArgumentIfUndefined type when newing up this class.
private submit(result?: ModalResult) {
this._submitResolver?.(result as ModalResult);
this.modalElement.close();
@@ -140,22 +140,25 @@ export class UmbModalHandlerClass<ModalData, ModalResult> {
async (manifest) => {
if (manifest) {
const innerElement = await this.#createInnerElement(manifest, data);
if (innerElement) {
this.#appendInnerElement(innerElement);
} else {
this.#removeInnerElement();
return;
}
}
this.#removeInnerElement();
}
);
}
#appendInnerElement(element: any) {
#appendInnerElement(element: HTMLElement) {
this.#modalElement?.appendChild(element);
this.#innerElement.next(element);
}
#removeInnerElement() {
if (this.#innerElement.getValue()) {
this.#modalElement?.removeChild(this.#innerElement.getValue());
const innerElement = this.#innerElement.getValue();
if (innerElement) {
this.#modalElement?.removeChild(innerElement);
this.#innerElement.next(undefined);
}
}

View File

@@ -0,0 +1,88 @@
// TODO: Be aware here we import a class from src!
import { UMB_ROUTE_CONTEXT_TOKEN } from '../router/route.context';
import { UmbModalRouteRegistration } from './modal-route-registration';
import type { UmbControllerHostElement, UmbControllerInterface } from '@umbraco-cms/backoffice/controller';
import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api';
import { UmbModalConfig, UmbModalToken } from '@umbraco-cms/backoffice/modal';
export class UmbModalRouteRegistrationController<D extends object = object, R = any>
extends UmbModalRouteRegistration<D, R>
implements UmbControllerInterface
{
//#host: UmbControllerHostInterface;
#configuredPath: string;
#uniqueParts: Map<string, string | undefined>;
#routeContext?: typeof UMB_ROUTE_CONTEXT_TOKEN.TYPE;
#modalRegistration?: UmbModalRouteRegistration;
public get unique() {
return undefined;
}
constructor(
host: UmbControllerHostElement,
alias: UmbModalToken<D, R> | string,
path: string,
uniqueParts?: Map<string, string | undefined> | null,
modalConfig?: UmbModalConfig
) {
super(alias, path, modalConfig);
//this.#host = host;
this.#configuredPath = path;
this.#uniqueParts = uniqueParts || new Map();
new UmbContextConsumerController(host, UMB_ROUTE_CONTEXT_TOKEN, (_routeContext) => {
this.#routeContext = _routeContext;
this._registererModal();
});
}
setUniqueIdentifier(identifier: string, value: string | undefined) {
if (!this.#uniqueParts.has(identifier)) {
throw new Error(
`Identifier ${identifier} was not registered at the construction of the modal registration controller, it has to be.`
);
}
this.#uniqueParts.set(identifier, value);
this._registererModal();
}
private _registererModal() {
if (!this.#routeContext) return;
if (this.#modalRegistration) {
this.#routeContext.unregisterModal(this.#modalRegistration);
this.#modalRegistration = undefined;
}
const pathParts = Array.from(this.#uniqueParts.values());
// Check if there is any undefined values of unique map:
if (pathParts.some((value) => value === undefined)) return;
// Add the configured part of the path:
pathParts.push(this.#configuredPath);
// Make this the path of the modal registration:
this._setPath(pathParts.join('/'));
this.#modalRegistration = this.#routeContext.registerModal(this);
}
hostConnected() {
if (!this.#modalRegistration) {
this._registererModal();
}
}
hostDisconnected(): void {
if (this.#modalRegistration) {
this.#routeContext?.unregisterModal(this.#modalRegistration);
this.#modalRegistration = undefined;
}
}
public destroy(): void {
this.hostDisconnected();
}
}

View File

@@ -0,0 +1,115 @@
import type { Params } from 'router-slot';
import { v4 as uuidv4 } from 'uuid';
import { UmbModalHandler } from './modal-handler';
import { UmbModalConfig, UmbModalContext } from './modal.context';
import { UmbModalToken } from './token/modal-token';
export type UmbModalRouteBuilder = (params: { [key: string]: string | number }) => string;
export class UmbModalRouteRegistration<UmbModalTokenData extends object = object, UmbModalTokenResult = any> {
#key: string;
#path: string;
#modalAlias: UmbModalToken<UmbModalTokenData, UmbModalTokenResult> | string;
#modalConfig?: UmbModalConfig;
#onSetupCallback?: (routingInfo: Params) => UmbModalTokenData | false;
#onSubmitCallback?: (data: UmbModalTokenResult) => void;
#onRejectCallback?: () => void;
#modalHandler: UmbModalHandler<UmbModalTokenData, UmbModalTokenResult> | undefined;
#routeBuilder?: UmbModalRouteBuilder;
#urlBuilderCallback: ((urlBuilder: UmbModalRouteBuilder) => void) | undefined;
// Notice i removed the key in the transferring to this class.
constructor(
modalAlias: UmbModalToken<UmbModalTokenData, UmbModalTokenResult> | string,
path: string,
modalConfig?: UmbModalConfig
) {
this.#key = modalConfig?.key || uuidv4();
this.#modalAlias = modalAlias;
this.#path = path;
this.#modalConfig = { ...modalConfig, key: this.#key };
}
public get key() {
return this.#key;
}
public get alias() {
return this.#modalAlias;
}
public get path() {
return this.#path;
}
protected _setPath(path: string) {
this.#path = path;
}
public get modalConfig() {
return this.#modalConfig;
}
/**
* Returns true if the modal is currently active.
*/
public get active() {
return !!this.#modalHandler;
}
public open(params: { [key: string]: string | number }) {
if (this.active) return;
window.history.pushState({}, '', this.#routeBuilder?.(params));
}
/**
* Returns the modal handler if the modal is currently active. Otherwise its undefined.
*/
public get modalHandler() {
return this.#modalHandler;
}
public observeRouteBuilder(callback: (urlBuilder: UmbModalRouteBuilder) => void) {
this.#urlBuilderCallback = callback;
return this;
}
public _internal_setRouteBuilder(urlBuilder: UmbModalRouteBuilder) {
this.#routeBuilder = urlBuilder;
this.#urlBuilderCallback?.(urlBuilder);
}
public onSetup(callback: (routingInfo: Params) => UmbModalTokenData | false) {
this.#onSetupCallback = callback;
return this;
}
public onSubmit(callback: (data: UmbModalTokenResult) => void) {
this.#onSubmitCallback = callback;
return this;
}
public onReject(callback: () => void) {
this.#onRejectCallback = callback;
return this;
}
#onSubmit = (data: UmbModalTokenResult) => {
this.#onSubmitCallback?.(data);
this.#modalHandler = undefined;
};
#onReject = () => {
this.#onRejectCallback?.();
this.#modalHandler = undefined;
};
routeSetup(modalContext: UmbModalContext, params: Params) {
const modalData = this.#onSetupCallback ? this.#onSetupCallback(params) : undefined;
if (modalData !== false) {
this.#modalHandler = modalContext.open(this.#modalAlias, modalData, this.modalConfig);
this.#modalHandler.onSubmit().then(this.#onSubmit, this.#onReject);
return this.#modalHandler;
}
return null;
}
}

View File

@@ -6,7 +6,7 @@ import { BehaviorSubject } from 'rxjs';
import { UmbModalHandler, UmbModalHandlerClass } from './modal-handler';
import type { UmbModalToken } from './token/modal-token';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export type UmbModalType = 'dialog' | 'sidebar';
@@ -19,12 +19,12 @@ export interface UmbModalConfig {
// TODO: we should find a way to easily open a modal without adding custom methods to this context. It would result in a better separation of concerns.
// TODO: move all layouts into their correct "silo" folders. User picker should live with users etc.
export class UmbModalContext {
host: UmbControllerHostInterface;
host: UmbControllerHostElement;
// TODO: Investigate if we can get rid of HTML elements in our store, so we can use one of our states.
#modals = new BehaviorSubject(<Array<UmbModalHandler<any, any>>>[]);
#modals = new BehaviorSubject(<Array<UmbModalHandler>>[]);
public readonly modals = this.#modals.asObservable();
constructor(host: UmbControllerHostInterface) {
constructor(host: UmbControllerHostElement) {
this.host = host;
}
@@ -75,7 +75,7 @@ export class UmbModalContext {
* @return {*} {UmbModalHandler}
* @memberof UmbModalContext
*/
public open<ModalData = unknown, ModalResult = unknown>(
public open<ModalData extends object = object, ModalResult = unknown>(
modalAlias: string | UmbModalToken<ModalData, ModalResult>,
data?: ModalData,
config?: UmbModalConfig

View File

@@ -8,7 +8,7 @@ export interface UmbAllowedDocumentTypesModalResult {
documentTypeKey: string;
}
export const UMB_ALLOWED_DOCUMENT_TYPES_MODAL_TOKEN = new UmbModalToken<
export const UMB_ALLOWED_DOCUMENT_TYPES_MODAL = new UmbModalToken<
UmbAllowedDocumentTypesModalData,
UmbAllowedDocumentTypesModalResult
>('Umb.Modal.AllowedDocumentTypes', {

View File

@@ -0,0 +1,9 @@
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
export interface UmbChangePasswordModalData {
requireOldPassword: boolean;
}
export const UMB_CHANGE_PASSWORD_MODAL = new UmbModalToken<UmbChangePasswordModalData>('Umb.Modal.ChangePassword', {
type: 'dialog',
});

View File

@@ -10,9 +10,6 @@ export interface UmbConfirmModalData {
export type UmbConfirmModalResult = undefined;
export const UMB_CONFIRM_MODAL_TOKEN = new UmbModalToken<UmbConfirmModalData, UmbConfirmModalResult>(
'Umb.Modal.Confirm',
{
export const UMB_CONFIRM_MODAL = new UmbModalToken<UmbConfirmModalData, UmbConfirmModalResult>('Umb.Modal.Confirm', {
type: 'dialog',
}
);
});

View File

@@ -12,7 +12,7 @@ export interface UmbCreateDictionaryModalResult {
name?: string;
}
export const UMB_CREATE_DICTIONARY_MODAL_TOKEN = new UmbModalToken<
export const UMB_CREATE_DICTIONARY_MODAL = new UmbModalToken<
UmbCreateDictionaryModalData,
UmbCreateDictionaryModalResult
>('Umb.Modal.CreateDictionary', {

View File

@@ -1,6 +1,6 @@
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
export const UMB_INVITE_USER_MODAL_TOKEN = new UmbModalToken('Umb.Modal.InviteUser', {
export const UMB_CREATE_USER_MODAL = new UmbModalToken('Umb.Modal.CreateUser', {
type: 'dialog',
size: 'small',
});

View File

@@ -1,6 +1,6 @@
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
export const UMB_CURRENT_USER_MODAL_TOKEN = new UmbModalToken('Umb.Modal.CurrentUser', {
export const UMB_CURRENT_USER_MODAL = new UmbModalToken('Umb.Modal.CurrentUser', {
type: 'sidebar',
size: 'small',
});

View File

@@ -5,10 +5,7 @@ export interface UmbContextDebuggerModalData {
content: TemplateResult | string;
}
export const UMB_CONTEXT_DEBUGGER_MODAL_TOKEN = new UmbModalToken<UmbContextDebuggerModalData>(
'Umb.Modal.ContextDebugger',
{
export const UMB_CONTEXT_DEBUGGER_MODAL = new UmbModalToken<UmbContextDebuggerModalData>('Umb.Modal.ContextDebugger', {
type: 'sidebar',
size: 'small',
}
);
});

View File

@@ -9,10 +9,10 @@ export interface UmbDocumentPickerModalResult {
selection: Array<string>;
}
export const UMB_DOCUMENT_PICKER_MODAL_TOKEN = new UmbModalToken<
UmbDocumentPickerModalData,
UmbDocumentPickerModalResult
>('Umb.Modal.DocumentPicker', {
export const UMB_DOCUMENT_PICKER_MODAL = new UmbModalToken<UmbDocumentPickerModalData, UmbDocumentPickerModalResult>(
'Umb.Modal.DocumentPicker',
{
type: 'sidebar',
size: 'small',
});
}
);

View File

@@ -28,7 +28,7 @@ export interface UmbEmbeddedMediaModalResult extends UmbEmbeddedMediaModalData {
originalHeight: number;
};
export const UMB_EMBEDDED_MEDIA_MODAL_TOKEN = new UmbModalToken<UmbEmbeddedMediaModalData, UmbEmbeddedMediaModalResult>(
export const UMB_EMBEDDED_MEDIA_MODAL = new UmbModalToken<UmbEmbeddedMediaModalData, UmbEmbeddedMediaModalResult>(
'Umb.Modal.EmbeddedMedia',
{
type: 'sidebar',

View File

@@ -9,7 +9,7 @@ export interface UmbCreateDocumentModalResultData {
fields?: UmbExamineFieldsSettingsModalData;
}
export const UMB_EXAMINE_FIELDS_SETTINGS_MODAL_TOKEN = new UmbModalToken<
export const UMB_EXAMINE_FIELDS_SETTINGS_MODAL = new UmbModalToken<
UmbExamineFieldsSettingsModalData,
UmbCreateDocumentModalResultData
>('Umb.Modal.ExamineFieldsSettings', {

View File

@@ -8,7 +8,7 @@ export interface UmbExportDictionaryModalResult {
includeChildren?: boolean;
}
export const UMB_EXPORT_DICTIONARY_MODAL_TOKEN = new UmbModalToken<
export const UMB_EXPORT_DICTIONARY_MODAL = new UmbModalToken<
UmbExportDictionaryModalData,
UmbExportDictionaryModalResult
>('Umb.Modal.ExportDictionary', {

View File

@@ -10,7 +10,7 @@ export interface UmbIconPickerModalResult {
icon: string | undefined;
}
export const UMB_ICON_PICKER_MODAL_TOKEN = new UmbModalToken<UmbIconPickerModalData, UmbIconPickerModalResult>(
export const UMB_ICON_PICKER_MODAL = new UmbModalToken<UmbIconPickerModalData, UmbIconPickerModalResult>(
'Umb.Modal.IconPicker',
{
type: 'sidebar',

View File

@@ -11,7 +11,7 @@ export interface UmbImportDictionaryModalResult {
parentKey?: string;
}
export const UMB_IMPORT_DICTIONARY_MODAL_TOKEN = new UmbModalToken<
export const UMB_IMPORT_DICTIONARY_MODAL = new UmbModalToken<
UmbImportDictionaryModalData,
UmbImportDictionaryModalResult
>('Umb.Modal.ImportDictionary', {

View File

@@ -0,0 +1,24 @@
export * from './modal-token';
export * from './allowed-document-types-modal.token';
export * from './change-password-modal.token';
export * from './confirm-modal.token';
export * from './create-dictionary-modal.token';
export * from './create-user-modal.token';
export * from './current-user-modal.token';
export * from './debug-modal.token';
export * from './document-picker-modal.token';
export * from './embedded-media-modal.token';
export * from './examine-fields-settings-modal.token';
export * from './export-dictionary-modal.token';
export * from './icon-picker-modal.token';
export * from './import-dictionary-modal.token';
export * from './invite-user-modal.token';
export * from './language-picker-modal.token';
export * from './link-picker-modal.token';
export * from './media-picker-modal.token';
export * from './property-editor-ui-picker-modal.token';
export * from './property-settings-modal.token';
export * from './search-modal.token';
export * from './section-picker-modal.token';
export * from './user-group-picker-modal.token';
export * from './user-picker-modal.token';

View File

@@ -1,6 +1,6 @@
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
export const UMB_CREATE_USER_MODAL_TOKEN = new UmbModalToken('Umb.Modal.CreateUser', {
export const UMB_INVITE_USER_MODAL = new UmbModalToken('Umb.Modal.InviteUser', {
type: 'dialog',
size: 'small',
});

View File

@@ -11,10 +11,10 @@ export interface UmbLanguagePickerModalResult {
selection: Array<string>;
}
export const UMB_LANGUAGE_PICKER_MODAL_TOKEN = new UmbModalToken<
UmbLanguagePickerModalData,
UmbLanguagePickerModalResult
>('Umb.Modal.LanguagePicker', {
export const UMB_LANGUAGE_PICKER_MODAL = new UmbModalToken<UmbLanguagePickerModalData, UmbLanguagePickerModalResult>(
'Umb.Modal.LanguagePicker',
{
type: 'sidebar',
size: 'small',
});
}
);

View File

@@ -2,11 +2,12 @@ import type { UUIModalSidebarSize } from '@umbraco-ui/uui';
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
export interface UmbLinkPickerModalData {
index: number | null;
link: UmbLinkPickerLink;
config: UmbLinkPickerConfig;
}
export type UmbLinkPickerModalResult = UmbLinkPickerLink;
export type UmbLinkPickerModalResult = { index: number | null; link: UmbLinkPickerLink };
export interface UmbLinkPickerLink {
icon?: string | null;
@@ -26,7 +27,7 @@ export interface UmbLinkPickerConfig {
overlaySize?: UUIModalSidebarSize;
}
export const UMB_LINK_PICKER_MODAL_TOKEN = new UmbModalToken<UmbLinkPickerModalData, UmbLinkPickerModalResult>(
export const UMB_LINK_PICKER_MODAL = new UmbModalToken<UmbLinkPickerModalData, UmbLinkPickerModalResult>(
'Umb.Modal.LinkPicker',
{
type: 'sidebar',

View File

@@ -9,7 +9,7 @@ export interface UmbMediaPickerModalResult {
selection: Array<string>;
}
export const UMB_MEDIA_PICKER_MODAL_TOKEN = new UmbModalToken<UmbMediaPickerModalData, UmbMediaPickerModalResult>(
export const UMB_MEDIA_PICKER_MODAL = new UmbModalToken<UmbMediaPickerModalData, UmbMediaPickerModalResult>(
'Umb.Modal.MediaPicker',
{
type: 'sidebar',

View File

@@ -1,6 +1,6 @@
import { UmbModalConfig } from '../modal.context';
export class UmbModalToken<Data = unknown, Result = unknown> {
export class UmbModalToken<Data extends object = object, Result = unknown> {
/**
* Get the data type of the token's data.
*

View File

@@ -9,7 +9,7 @@ export type UmbPropertyEditorUIPickerModalResult = {
selection: Array<string>;
};
export const UMB_PROPERTY_EDITOR_UI_PICKER_MODAL_TOKEN = new UmbModalToken<
export const UMB_PROPERTY_EDITOR_UI_PICKER_MODAL = new UmbModalToken<
UmbPropertyEditorUIPickerModalData,
UmbPropertyEditorUIPickerModalResult
>('Umb.Modal.PropertyEditorUIPicker', {

View File

@@ -17,7 +17,7 @@ export interface UmbPropertySettingsModalResult {
};
}
export const UMB_PROPERTY_SETTINGS_MODAL_TOKEN = new UmbModalToken<undefined, UmbPropertySettingsModalResult>(
export const UMB_PROPERTY_SETTINGS_MODAL = new UmbModalToken<object, UmbPropertySettingsModalResult>(
'Umb.Modal.PropertySettings',
{
type: 'sidebar',

View File

@@ -0,0 +1,3 @@
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
export const UMB_SEARCH_MODAL = new UmbModalToken('Umb.Modal.Search');

View File

@@ -5,7 +5,7 @@ export interface UmbSectionPickerModalData {
selection: string[];
}
export const UMB_SECTION_PICKER_MODAL_TOKEN = new UmbModalToken<UmbSectionPickerModalData>('Umb.Modal.SectionPicker', {
export const UMB_SECTION_PICKER_MODAL = new UmbModalToken<UmbSectionPickerModalData>('Umb.Modal.SectionPicker', {
type: 'sidebar',
size: 'small',
});

View File

@@ -1,7 +1,7 @@
import type { UserDetails } from '@umbraco-cms/backoffice/models';
import { UmbModalToken, UmbPickerModalData } from '@umbraco-cms/backoffice/modal';
export const UMB_USER_GROUP_PICKER_MODAL_TOKEN = new UmbModalToken<UmbPickerModalData<UserDetails>>(
export const UMB_USER_GROUP_PICKER_MODAL = new UmbModalToken<UmbPickerModalData<UserDetails>>(
'Umb.Modal.UserGroupPicker',
{
type: 'sidebar',

View File

@@ -1,7 +1,7 @@
import type { UserDetails } from '@umbraco-cms/backoffice/models';
import { UmbModalToken, UmbPickerModalData } from '@umbraco-cms/backoffice/modal';
export const UMB_USER_PICKER_MODAL_TOKEN = new UmbModalToken<UmbPickerModalData<UserDetails>>('Umb.Modal.UserPicker', {
export const UMB_USER_PICKER_MODAL = new UmbModalToken<UmbPickerModalData<UserDetails>>('Umb.Modal.UserPicker', {
type: 'sidebar',
size: 'small',
});

View File

@@ -1,5 +1,6 @@
export * from './observer.controller';
export * from './observer';
export * from './basic-state';
export * from './boolean-state';
export * from './number-state';
export * from './string-state';

View File

@@ -1,6 +1,6 @@
import { Observable } from 'rxjs';
import { UmbObserver } from './observer';
import { UmbControllerInterface, UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerInterface, UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export class UmbObserverController<T = unknown> extends UmbObserver<T> implements UmbControllerInterface {
_alias?: string;
@@ -8,7 +8,7 @@ export class UmbObserverController<T = unknown> extends UmbObserver<T> implement
return this._alias;
}
constructor(host: UmbControllerHostInterface, source: Observable<T>, callback: (_value: T) => void, alias?: string) {
constructor(host: UmbControllerHostElement, source: Observable<T>, callback: (_value: T) => void, alias?: string) {
super(source, callback);
this._alias = alias;

View File

@@ -17,7 +17,8 @@ export class UmbObserver<T> {
}
hostDisconnected() {
this.#subscription.unsubscribe();
// No cause then it cant re-connect, if the same element just was moved in DOM.
//this.#subscription.unsubscribe();
}
destroy(): void {

View File

@@ -5,7 +5,7 @@ import {
UMB_NOTIFICATION_CONTEXT_TOKEN,
} from '@umbraco-cms/backoffice/notification';
import { ApiError, CancelablePromise, ProblemDetailsModel } from '@umbraco-cms/backoffice/backend-api';
import { UmbController, UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbController, UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api';
import type { DataSourceResponse } from '@umbraco-cms/backoffice/repository';
@@ -14,7 +14,7 @@ export class UmbResourceController extends UmbController {
#notificationContext?: UmbNotificationContext;
constructor(host: UmbControllerHostInterface, promise: Promise<any>, alias?: string) {
constructor(host: UmbControllerHostElement, promise: Promise<any>, alias?: string) {
super(host, alias);
this.#promise = promise;

View File

@@ -1,10 +1,10 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { UmbResourceController } from './resource.controller';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
import type { UmbNotificationOptions } from '@umbraco-cms/backoffice/notification';
export function tryExecuteAndNotify<T>(
host: UmbControllerHostInterface,
host: UmbControllerHostElement,
resource: Promise<T>,
options?: UmbNotificationOptions<any>
) {

View File

@@ -0,0 +1,3 @@
export * from './route-location.interface';
export * from './route.context';
export * from './route.interface';

View File

@@ -0,0 +1,143 @@
import type { IRoutingInfo, ISlashOptions } from 'router-slot';
import { UmbRoute } from './route.interface';
import {
UmbContextConsumerController,
UmbContextProviderController,
UmbContextToken,
} from '@umbraco-cms/backoffice/context-api';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
import { UMB_MODAL_CONTEXT_TOKEN, UmbModalRouteRegistration } from '@umbraco-cms/backoffice/modal';
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;
#contextRoutes: UmbRoute[] = [];
#routerBasePath?: string;
#activeModalPath?: string;
constructor(host: UmbControllerHostElement, private _onGotModals: (contextRoutes: any) => void) {
new UmbContextProviderController(host, UMB_ROUTE_CONTEXT_TOKEN, this);
new UmbContextConsumerController(host, UMB_MODAL_CONTEXT_TOKEN, (context) => {
this.#modalContext = context;
this.#generateContextRoutes();
});
}
public registerModal(registration: UmbModalRouteRegistration) {
this.#modalRegistrations.push(registration);
this.#generateNewUrlBuilder(registration);
this.#generateContextRoutes();
return registration;
}
public unregisterModal(registrationToken: ReturnType<typeof this.registerModal>) {
const index = this.#modalRegistrations.indexOf(registrationToken);
if (index === -1) return;
this.#modalRegistrations.splice(index, 1);
this.#generateContextRoutes();
}
#getModalRoutePath(modalRegistration: UmbModalRouteRegistration) {
return `/modal/${modalRegistration.alias.toString()}/${modalRegistration.path}`;
}
#generateRoute(modalRegistration: UmbModalRouteRegistration): UmbRoute {
return {
path: this.#getModalRoutePath(modalRegistration),
component: EmptyDiv,
setup: (component: HTMLElement, info: IRoutingInfo<any, any>) => {
if (!this.#modalContext) return;
const modalHandler = modalRegistration.routeSetup(this.#modalContext, info.match.params);
if (modalHandler) {
modalHandler.onSubmit().then(
() => {
this.#removeModalPath(info);
},
() => {
this.#removeModalPath(info);
}
);
}
},
};
}
#removeModalPath(info: IRoutingInfo) {
if (window.location.href.includes(info.match.fragments.consumed)) {
window.history.pushState({}, '', window.location.href.split(info.match.fragments.consumed)[0]);
}
}
#generateContextRoutes() {
this.#contextRoutes = this.#modalRegistrations.map((modalRegistration) => {
return this.#generateRoute(modalRegistration);
});
// Add an empty route, so there is a route for the router to react on when no modals are open.
this.#contextRoutes.push({
path: '',
component: EmptyDiv,
});
// TODO: Should we await one frame, to ensure we don't call back too much?.
this._onGotModals(this.#contextRoutes);
}
public _internal_routerGotBasePath(routerBasePath: string) {
if (this.#routerBasePath === routerBasePath) return;
this.#routerBasePath = routerBasePath;
this.#generateNewUrlBuilders();
}
// Also notice each registration should now hold its handler when its active.
public _internal_modalRouterChanged(activeModalPath: string | undefined) {
if (this.#activeModalPath === activeModalPath) return;
if (this.#activeModalPath) {
// If if there is a modal using the old path.
const activeModal = this.#modalRegistrations.find(
(registration) => this.#getModalRoutePath(registration) === this.#activeModalPath
);
if (activeModal) {
this.#modalContext?.close(activeModal.key);
}
}
this.#activeModalPath = activeModalPath;
}
#generateNewUrlBuilders() {
this.#modalRegistrations.forEach(this.#generateNewUrlBuilder);
}
#generateNewUrlBuilder = (modalRegistration: UmbModalRouteRegistration) => {
if (!this.#routerBasePath) return;
const routeBasePath = this.#routerBasePath.endsWith('/') ? this.#routerBasePath : this.#routerBasePath + '/';
const localPath = `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;
};
modalRegistration._internal_setRouteBuilder(urlBuilder);
};
}
export const UMB_ROUTE_CONTEXT_TOKEN = new UmbContextToken<UmbRouteContext>('UmbRouterContext');

View File

@@ -0,0 +1,3 @@
import type { IRoute } from 'router-slot/model';
export type UmbRoute = IRoute;

View File

@@ -1,8 +1,8 @@
import { UmbContextProviderController } from '@umbraco-cms/backoffice/context-api';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export class UmbStoreBase {
constructor(protected _host: UmbControllerHostInterface, public readonly storeAlias: string) {
constructor(protected _host: UmbControllerHostElement, public readonly storeAlias: string) {
new UmbContextProviderController(_host, storeAlias, this);
}
}

View File

@@ -1,10 +1,10 @@
import { UmbWorkspaceContextInterface } from '../../context/workspace-context.interface';
import { UmbWorkspaceActionBase } from '../workspace-action-base';
import type { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
// TODO: add interface for repo/partial repo/save-repo
export class UmbSaveWorkspaceAction extends UmbWorkspaceActionBase<UmbWorkspaceContextInterface> {
constructor(host: UmbControllerHostInterface) {
constructor(host: UmbControllerHostElement) {
super(host);
}

View File

@@ -1,16 +1,16 @@
import type { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api';
export interface UmbWorkspaceAction<T = unknown> {
host: UmbControllerHostInterface;
host: UmbControllerHostElement;
workspaceContext?: T;
execute(): Promise<void>;
}
export class UmbWorkspaceActionBase<WorkspaceType> {
host: UmbControllerHostInterface;
host: UmbControllerHostElement;
workspaceContext?: WorkspaceType;
constructor(host: UmbControllerHostInterface) {
constructor(host: UmbControllerHostElement) {
this.host = host;
new UmbContextConsumerController(this.host, 'umbWorkspaceContext', (instance: WorkspaceType) => {

View File

@@ -1,8 +1,8 @@
import { Observable } from 'rxjs';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export interface UmbWorkspaceContextInterface<T = unknown> {
host: UmbControllerHostInterface;
host: UmbControllerHostElement;
repository: any; // TODO: add type
isNew: Observable<boolean>;
getIsNew(): boolean;

View File

@@ -30,8 +30,8 @@
"build": "tsc && vite build --mode staging",
"build:libs": "npm run wc-analyze && npm run wc-analyze:vscode && rollup -c rollup-libs.config.js && node utils/move-libs.js",
"build:for:static": "tsc && vite build",
"build:for:cms": "tsc && vite build -c vite.cms.config.ts && npm run build:libs",
"build:for:cms:watch": "vite build -c vite.cms.config.ts --watch",
"build:for:cms": "tsc && npm run build:libs && vite build -c vite.cms.config.ts",
"build:for:cms:watch": "tsc && npm run build:libs && vite build -c vite.cms.config.ts --watch",
"preview": "vite preview --open",
"test": "web-test-runner --coverage",
"test:watch": "web-test-runner --watch",

View File

@@ -4,6 +4,7 @@ import './core/css/custom-properties.css';
import 'element-internals-polyfill';
import './core/router/router-slot.element';
import './core/router/variant-router-slot.element';
import './core/notification/layouts/default';
import './core/modal/modal-element.element';
@@ -12,7 +13,6 @@ import { css, html } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { UmbIconStore } from './core/stores/icon/icon.store';
import type { Guard, IRoute } from '@umbraco-cms/internal/router';
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
@@ -20,7 +20,7 @@ import { OpenAPI, RuntimeLevelModel, ServerResource } from '@umbraco-cms/backoff
import { umbDebugContextEventType } from '@umbraco-cms/backoffice/context-api';
@customElement('umb-app')
export class UmbApp extends UmbLitElement {
export class UmbAppElement extends UmbLitElement {
static styles = css`
:host {
overflow: hidden;
@@ -156,6 +156,6 @@ export class UmbApp extends UmbLitElement {
declare global {
interface HTMLElementTagNameMap {
'umb-app': UmbApp;
'umb-app': UmbAppElement;
}
}

View File

@@ -2,8 +2,7 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { css, html, nothing } from 'lit';
import { customElement, state, query, property } from 'lit/decorators.js';
import { UUIButtonState, UUIPaginationElement, UUIPaginationEvent } from '@umbraco-ui/uui';
import { UMB_CONFIRM_MODAL_TOKEN } from '../../../shared/modals/confirm';
import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/modal';
import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN, UMB_CONFIRM_MODAL } from '@umbraco-cms/backoffice/modal';
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
import {
RedirectManagementResource,
@@ -136,7 +135,7 @@ export class UmbDashboardRedirectManagementElement extends UmbLitElement {
}
private _removeRedirectHandler(data: RedirectUrlResponseModel) {
const modalHandler = this._modalContext?.open(UMB_CONFIRM_MODAL_TOKEN, {
const modalHandler = this._modalContext?.open(UMB_CONFIRM_MODAL, {
headline: 'Delete',
content: html`
<div style="width:300px">
@@ -167,7 +166,7 @@ export class UmbDashboardRedirectManagementElement extends UmbLitElement {
}
private _disableRedirectHandler() {
const modalHandler = this._modalContext?.open(UMB_CONFIRM_MODAL_TOKEN, {
const modalHandler = this._modalContext?.open(UMB_CONFIRM_MODAL, {
headline: 'Disable URL tracker',
content: html`Are you sure you want to disable the URL tracker?`,
color: 'danger',

View File

@@ -2,7 +2,7 @@ import type { DocumentBlueprintDetails } from '@umbraco-cms/backoffice/models';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { ArrayState } from '@umbraco-cms/backoffice/observable-api';
import { UmbStoreBase } from '@umbraco-cms/backoffice/store';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
/**
* @export
@@ -14,7 +14,7 @@ export class UmbDocumentBlueprintStore extends UmbStoreBase {
// TODO: use the right type:
#data = new ArrayState<DocumentBlueprintDetails>([], (x) => x.key);
constructor(host: UmbControllerHostInterface) {
constructor(host: UmbControllerHostElement) {
super(host, UMB_DOCUMENT_BLUEPRINT_STORE_CONTEXT_TOKEN.toString());
}

View File

@@ -1,6 +1,6 @@
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/store';
import type { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export const UMB_DOCUMENT_BLUEPRINT_TREE_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbDocumentBlueprintTreeStore>(
'UmbDocumentBlueprintTreeStore'
@@ -13,7 +13,7 @@ export const UMB_DOCUMENT_BLUEPRINT_TREE_STORE_CONTEXT_TOKEN = new UmbContextTok
* @description - Tree Data Store for Document Blueprints
*/
export class UmbDocumentBlueprintTreeStore extends UmbEntityTreeStore {
constructor(host: UmbControllerHostInterface) {
constructor(host: UmbControllerHostElement) {
super(host, UMB_DOCUMENT_BLUEPRINT_TREE_STORE_CONTEXT_TOKEN.toString());
}
}

View File

@@ -3,7 +3,7 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { customElement, state } from 'lit/decorators.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { UmbDocumentTypeRepository } from '../../repository/document-type.repository';
import { UmbAllowedDocumentTypesModalData, UmbAllowedDocumentTypesModalResult } from '.';
import { UmbAllowedDocumentTypesModalData, UmbAllowedDocumentTypesModalResult } from '@umbraco-cms/backoffice/modal';
import { UmbModalBaseElement } from '@umbraco-cms/internal/modal';
import { DocumentTypeTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';

View File

@@ -3,7 +3,7 @@ import { UmbDocumentTypeServerDataSource } from './sources/document-type.server.
import { UmbDocumentTypeTreeStore, UMB_DOCUMENT_TYPE_TREE_STORE_CONTEXT_TOKEN } from './document-type.tree.store';
import { UmbDocumentTypeStore, UMB_DOCUMENT_TYPE_STORE_CONTEXT_TOKEN } from './document-type.store';
import type { UmbTreeDataSource, UmbTreeRepository, UmbDetailRepository } from '@umbraco-cms/backoffice/repository';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api';
import { ProblemDetailsModel, DocumentTypeResponseModel } from '@umbraco-cms/backoffice/backend-api';
import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification';
@@ -13,7 +13,7 @@ type ItemType = DocumentTypeResponseModel;
export class UmbDocumentTypeRepository implements UmbTreeRepository<ItemType>, UmbDetailRepository<ItemType> {
#init!: Promise<unknown>;
#host: UmbControllerHostInterface;
#host: UmbControllerHostElement;
#treeSource: UmbTreeDataSource;
#treeStore?: UmbDocumentTypeTreeStore;
@@ -23,7 +23,7 @@ export class UmbDocumentTypeRepository implements UmbTreeRepository<ItemType>, U
#notificationContext?: UmbNotificationContext;
constructor(host: UmbControllerHostInterface) {
constructor(host: UmbControllerHostElement) {
this.#host = host;
// TODO: figure out how spin up get the correct data source

View File

@@ -2,7 +2,7 @@ import { DocumentTypeResponseModel } from '@umbraco-cms/backoffice/backend-api';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { ArrayState } from '@umbraco-cms/backoffice/observable-api';
import { UmbStoreBase } from '@umbraco-cms/backoffice/store';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
/**
* @export
@@ -15,10 +15,10 @@ export class UmbDocumentTypeStore extends UmbStoreBase {
/**
* Creates an instance of UmbDocumentTypeStore.
* @param {UmbControllerHostInterface} host
* @param {UmbControllerHostElement} host
* @memberof UmbDocumentTypeStore
*/
constructor(host: UmbControllerHostInterface) {
constructor(host: UmbControllerHostElement) {
super(host, UMB_DOCUMENT_TYPE_STORE_CONTEXT_TOKEN.toString());
}
@@ -50,6 +50,4 @@ export class UmbDocumentTypeStore extends UmbStoreBase {
}
}
export const UMB_DOCUMENT_TYPE_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbDocumentTypeStore>(
'UmbDocumentTypeStore'
);
export const UMB_DOCUMENT_TYPE_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbDocumentTypeStore>('UmbDocumentTypeStore');

View File

@@ -1,6 +1,6 @@
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/store';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
/**
* @export
@@ -12,10 +12,10 @@ import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
export class UmbDocumentTypeTreeStore extends UmbEntityTreeStore {
/**
* Creates an instance of UmbDocumentTypeTreeStore.
* @param {UmbControllerHostInterface} host
* @param {UmbControllerHostElement} host
* @memberof UmbDocumentTypeTreeStore
*/
constructor(host: UmbControllerHostInterface) {
constructor(host: UmbControllerHostElement) {
super(host, UMB_DOCUMENT_TYPE_TREE_STORE_CONTEXT_TOKEN.toString());
}
}

View File

@@ -4,7 +4,7 @@ import {
ProblemDetailsModel,
DocumentTypeResponseModel,
} from '@umbraco-cms/backoffice/backend-api';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
/**
@@ -14,14 +14,14 @@ import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
* @implements {RepositoryDetailDataSource}
*/
export class UmbDocumentTypeServerDataSource implements UmbDataSource<DocumentTypeResponseModel> {
#host: UmbControllerHostInterface;
#host: UmbControllerHostElement;
/**
* Creates an instance of UmbDocumentServerDataSource.
* @param {UmbControllerHostInterface} host
* @param {UmbControllerHostElement} host
* @memberof UmbDocumentServerDataSource
*/
constructor(host: UmbControllerHostInterface) {
constructor(host: UmbControllerHostElement) {
this.#host = host;
}

View File

@@ -1,6 +1,6 @@
import type { UmbTreeDataSource } from '@umbraco-cms/backoffice/repository';
import { ProblemDetailsModel, DocumentTypeResource } from '@umbraco-cms/backoffice/backend-api';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
/**
@@ -10,7 +10,7 @@ import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
* @implements {DocumentTreeDataSource}
*/
export class DocumentTypeTreeServerDataSource implements UmbTreeDataSource {
#host: UmbControllerHostInterface;
#host: UmbControllerHostElement;
// TODO: how do we handle trashed items?
async trashItems(keys: Array<string>) {
@@ -43,10 +43,10 @@ export class DocumentTypeTreeServerDataSource implements UmbTreeDataSource {
/**
* Creates an instance of DocumentTreeServerDataSource.
* @param {UmbControllerHostInterface} host
* @param {UmbControllerHostElement} host
* @memberof DocumentTreeServerDataSource
*/
constructor(host: UmbControllerHostInterface) {
constructor(host: UmbControllerHostElement) {
this.#host = host;
}

View File

@@ -2,11 +2,10 @@ import { UUIInputElement, UUIInputEvent } from '@umbraco-ui/uui';
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { css, html } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { UMB_ICON_PICKER_MODAL_TOKEN } from '../../../shared/modals/icon-picker';
import { UmbWorkspaceDocumentTypeContext } from './document-type-workspace.context';
import type { DocumentTypeResponseModel } from '@umbraco-cms/backoffice/backend-api';
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/modal';
import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN, UMB_ICON_PICKER_MODAL } from '@umbraco-cms/backoffice/modal';
@customElement('umb-document-type-workspace-edit')
export class UmbDocumentTypeWorkspaceEditElement extends UmbLitElement {
@@ -83,7 +82,7 @@ export class UmbDocumentTypeWorkspaceEditElement extends UmbLitElement {
}
private async _handleIconClick() {
const modalHandler = this._modalContext?.open(UMB_ICON_PICKER_MODAL_TOKEN);
const modalHandler = this._modalContext?.open(UMB_ICON_PICKER_MODAL);
modalHandler?.onSubmit().then((saved) => {
if (saved.icon) this.#workspaceContext?.setIcon(saved.icon);

View File

@@ -2,7 +2,7 @@ import { UmbWorkspaceContext } from '../../../shared/components/workspace/worksp
import { UmbEntityWorkspaceContextInterface } from '../../../shared/components/workspace/workspace-context/workspace-entity-context.interface';
import { UmbDocumentTypeRepository } from '../repository/document-type.repository';
import type { DocumentTypeResponseModel } from '@umbraco-cms/backoffice/backend-api';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
import { ObjectState } from '@umbraco-cms/backoffice/observable-api';
type EntityType = DocumentTypeResponseModel;
@@ -14,7 +14,7 @@ export class UmbWorkspaceDocumentTypeContext
data = this.#data.asObservable();
name = this.#data.getObservablePart((data) => data?.name);
constructor(host: UmbControllerHostInterface) {
constructor(host: UmbControllerHostElement) {
super(host, new UmbDocumentTypeRepository(host));
}

View File

@@ -1,9 +1,9 @@
import { UmbDocumentRepository } from '../repository/document.repository';
import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export class UmbCreateDocumentBlueprintEntityAction extends UmbEntityActionBase<UmbDocumentRepository> {
constructor(host: UmbControllerHostInterface, repositoryAlias: string, unique: string) {
constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) {
super(host, repositoryAlias, unique);
}

View File

@@ -1,14 +1,17 @@
import { UMB_ALLOWED_DOCUMENT_TYPES_MODAL_TOKEN } from '../../../document-types/modals/allowed-document-types';
import type { UmbDocumentRepository } from '../../repository/document.repository';
import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/modal';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
import {
UmbModalContext,
UMB_MODAL_CONTEXT_TOKEN,
UMB_ALLOWED_DOCUMENT_TYPES_MODAL,
} from '@umbraco-cms/backoffice/modal';
import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api';
export class UmbCreateDocumentEntityAction extends UmbEntityActionBase<UmbDocumentRepository> {
#modalContext?: UmbModalContext;
constructor(host: UmbControllerHostInterface, repositoryAlias: string, unique: string) {
constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) {
super(host, repositoryAlias, unique);
new UmbContextConsumerController(this.host, UMB_MODAL_CONTEXT_TOKEN, (instance) => {
@@ -24,7 +27,7 @@ export class UmbCreateDocumentEntityAction extends UmbEntityActionBase<UmbDocume
const { data } = await this.repository.requestByKey(this.unique);
if (data && data.contentTypeKey) {
const modalHandler = this.#modalContext?.open(UMB_ALLOWED_DOCUMENT_TYPES_MODAL_TOKEN, {
const modalHandler = this.#modalContext?.open(UMB_ALLOWED_DOCUMENT_TYPES_MODAL, {
key: data.contentTypeKey,
});

View File

@@ -1,9 +1,9 @@
import { UmbDocumentRepository } from '../repository/document.repository';
import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export class UmbDocumentCultureAndHostnamesEntityAction extends UmbEntityActionBase<UmbDocumentRepository> {
constructor(host: UmbControllerHostInterface, repositoryAlias: string, unique: string) {
constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) {
super(host, repositoryAlias, unique);
}

View File

@@ -1,9 +1,9 @@
import { UmbDocumentRepository } from '../repository/document.repository';
import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export class UmbDocumentPermissionsEntityAction extends UmbEntityActionBase<UmbDocumentRepository> {
constructor(host: UmbControllerHostInterface, repositoryAlias: string, unique: string) {
constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) {
super(host, repositoryAlias, unique);
}

View File

@@ -1,9 +1,9 @@
import { UmbDocumentRepository } from '../repository/document.repository';
import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export class UmbDocumentPublicAccessEntityAction extends UmbEntityActionBase<UmbDocumentRepository> {
constructor(host: UmbControllerHostInterface, repositoryAlias: string, unique: string) {
constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) {
super(host, repositoryAlias, unique);
}

View File

@@ -1,9 +1,9 @@
import { UmbDocumentRepository } from '../repository/document.repository';
import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export class UmbPublishDocumentEntityAction extends UmbEntityActionBase<UmbDocumentRepository> {
constructor(host: UmbControllerHostInterface, repositoryAlias: string, unique: string) {
constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) {
super(host, repositoryAlias, unique);
}

View File

@@ -1,9 +1,9 @@
import { UmbDocumentRepository } from '../repository/document.repository';
import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export class UmbRollbackDocumentEntityAction extends UmbEntityActionBase<UmbDocumentRepository> {
constructor(host: UmbControllerHostInterface, repositoryAlias: string, unique: string) {
constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) {
super(host, repositoryAlias, unique);
}

View File

@@ -1,9 +1,9 @@
import { UmbDocumentRepository } from '../repository/document.repository';
import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export class UmbUnpublishDocumentEntityAction extends UmbEntityActionBase<UmbDocumentRepository> {
constructor(host: UmbControllerHostInterface, repositoryAlias: string, unique: string) {
constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) {
super(host, repositoryAlias, unique);
}

View File

@@ -1,9 +1,9 @@
import { UmbDocumentRepository } from '../../repository/document.repository';
import { UmbEntityBulkActionBase } from '@umbraco-cms/backoffice/entity-action';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export class UmbDocumentCopyEntityBulkAction extends UmbEntityBulkActionBase<UmbDocumentRepository> {
constructor(host: UmbControllerHostInterface, repositoryAlias: string, selection: Array<string>) {
constructor(host: UmbControllerHostElement, repositoryAlias: string, selection: Array<string>) {
super(host, repositoryAlias, selection);
}

View File

@@ -1,9 +1,9 @@
import { UmbDocumentRepository } from '../../repository/document.repository';
import { UmbEntityBulkActionBase } from '@umbraco-cms/backoffice/entity-action';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export class UmbDocumentMoveEntityBulkAction extends UmbEntityBulkActionBase<UmbDocumentRepository> {
constructor(host: UmbControllerHostInterface, repositoryAlias: string, selection: Array<string>) {
constructor(host: UmbControllerHostElement, repositoryAlias: string, selection: Array<string>) {
super(host, repositoryAlias, selection);
}

View File

@@ -2,7 +2,7 @@ import { css, html } from 'lit';
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { customElement, state } from 'lit/decorators.js';
import type { UmbTreeElement } from '../../../../shared/components/tree/tree.element';
import { UmbDocumentPickerModalData, UmbDocumentPickerModalResult } from '.';
import { UmbDocumentPickerModalData, UmbDocumentPickerModalResult } from '@umbraco-cms/backoffice/modal';
import { UmbModalBaseElement } from '@umbraco-cms/internal/modal';
// TODO: make use of UmbPickerLayoutBase

View File

@@ -5,7 +5,7 @@ import { Meta, Story } from '@storybook/web-components';
import { html } from 'lit';
import type { UmbDocumentPickerModalElement } from './document-picker-modal.element';
import type { UmbDocumentPickerModalData } from './index';
import type { UmbDocumentPickerModalData } from '@umbraco-cms/backoffice/modal';
export default {
title: 'API/Modals/Layouts/Content Picker',

View File

@@ -3,7 +3,7 @@ import { UmbDocumentStore, UMB_DOCUMENT_STORE_CONTEXT_TOKEN } from './document.s
import { UmbDocumentTreeStore, UMB_DOCUMENT_TREE_STORE_CONTEXT_TOKEN } from './document.tree.store';
import { DocumentTreeServerDataSource } from './sources/document.tree.server.data';
import type { UmbTreeDataSource, UmbTreeRepository, UmbDetailRepository } from '@umbraco-cms/backoffice/repository';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api';
import { ProblemDetailsModel, DocumentResponseModel } from '@umbraco-cms/backoffice/backend-api';
import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification';
@@ -13,7 +13,7 @@ type ItemType = DocumentResponseModel;
export class UmbDocumentRepository implements UmbTreeRepository<ItemType>, UmbDetailRepository<ItemType> {
#init!: Promise<unknown>;
#host: UmbControllerHostInterface;
#host: UmbControllerHostElement;
#treeSource: UmbTreeDataSource;
#treeStore?: UmbDocumentTreeStore;
@@ -23,7 +23,7 @@ export class UmbDocumentRepository implements UmbTreeRepository<ItemType>, UmbDe
#notificationContext?: UmbNotificationContext;
constructor(host: UmbControllerHostInterface) {
constructor(host: UmbControllerHostElement) {
this.#host = host;
// TODO: figure out how spin up get the correct data source

View File

@@ -2,7 +2,7 @@ import { DocumentResponseModel } from '@umbraco-cms/backoffice/backend-api';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { ArrayState } from '@umbraco-cms/backoffice/observable-api';
import { UmbStoreBase } from '@umbraco-cms/backoffice/store';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
/**
* @export
@@ -15,10 +15,10 @@ export class UmbDocumentStore extends UmbStoreBase {
/**
* Creates an instance of UmbDocumentDetailStore.
* @param {UmbControllerHostInterface} host
* @param {UmbControllerHostElement} host
* @memberof UmbDocumentDetailStore
*/
constructor(host: UmbControllerHostInterface) {
constructor(host: UmbControllerHostElement) {
super(host, UMB_DOCUMENT_STORE_CONTEXT_TOKEN.toString());
}

View File

@@ -1,6 +1,6 @@
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/store';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
/**
* @export
@@ -11,10 +11,10 @@ import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
export class UmbDocumentTreeStore extends UmbEntityTreeStore {
/**
* Creates an instance of UmbDocumentTreeStore.
* @param {UmbControllerHostInterface} host
* @param {UmbControllerHostElement} host
* @memberof UmbDocumentTreeStore
*/
constructor(host: UmbControllerHostInterface) {
constructor(host: UmbControllerHostElement) {
super(host, UMB_DOCUMENT_TREE_STORE_CONTEXT_TOKEN.toString());
}
}

View File

@@ -1,8 +1,7 @@
import { UmbDocumentRepository } from '../repository/document.repository';
import { UmbDocumentStore } from './document.store';
import { UmbDocumentTreeStore } from './document.tree.store';
import { ManifestRepository } from 'libs/extensions-registry/repository.models';
import { ManifestStore, ManifestTreeStore } from '@umbraco-cms/backoffice/extensions-registry';
import type { ManifestRepository, ManifestStore, ManifestTreeStore } from '@umbraco-cms/backoffice/extensions-registry';
export const DOCUMENT_REPOSITORY_ALIAS = 'Umb.Repository.Document';

View File

@@ -6,7 +6,7 @@ import {
DocumentResponseModel,
ContentStateModel,
} from '@umbraco-cms/backoffice/backend-api';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
/**
@@ -16,14 +16,14 @@ import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
* @implements {RepositoryDetailDataSource}
*/
export class UmbDocumentServerDataSource implements UmbDataSource<DocumentResponseModel> {
#host: UmbControllerHostInterface;
#host: UmbControllerHostElement;
/**
* Creates an instance of UmbDocumentServerDataSource.
* @param {UmbControllerHostInterface} host
* @param {UmbControllerHostElement} host
* @memberof UmbDocumentServerDataSource
*/
constructor(host: UmbControllerHostInterface) {
constructor(host: UmbControllerHostElement) {
this.#host = host;
}

View File

@@ -1,6 +1,6 @@
import type { UmbTreeDataSource } from '@umbraco-cms/backoffice/repository';
import { ProblemDetailsModel, DocumentResource } from '@umbraco-cms/backoffice/backend-api';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
/**
@@ -10,7 +10,7 @@ import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
* @implements {DocumentTreeDataSource}
*/
export class DocumentTreeServerDataSource implements UmbTreeDataSource {
#host: UmbControllerHostInterface;
#host: UmbControllerHostElement;
// TODO: how do we handle trashed items?
async trashItems(keys: Array<string>) {
@@ -43,10 +43,10 @@ export class DocumentTreeServerDataSource implements UmbTreeDataSource {
/**
* Creates an instance of DocumentTreeServerDataSource.
* @param {UmbControllerHostInterface} host
* @param {UmbControllerHostElement} host
* @memberof DocumentTreeServerDataSource
*/
constructor(host: UmbControllerHostInterface) {
constructor(host: UmbControllerHostElement) {
this.#host = host;
}

View File

@@ -1,10 +1,10 @@
import { UmbTreeItemContextBase } from '../../../../shared/components/tree/tree-item-base/tree-item-base.context';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
import { DocumentTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
// TODO get unique method from an document repository static method
export class UmbDocumentTreeItemContext extends UmbTreeItemContextBase<DocumentTreeItemResponseModel> {
constructor(host: UmbControllerHostInterface) {
constructor(host: UmbControllerHostElement) {
super(host, (x: DocumentTreeItemResponseModel) => x.key);
}
}

View File

@@ -1,9 +1,9 @@
import { UmbDocumentWorkspaceContext } from '../document-workspace.context';
import { UmbWorkspaceActionBase } from '@umbraco-cms/backoffice/workspace';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export class UmbDocumentSaveAndPreviewWorkspaceAction extends UmbWorkspaceActionBase<UmbDocumentWorkspaceContext> {
constructor(host: UmbControllerHostInterface) {
constructor(host: UmbControllerHostElement) {
super(host);
}

View File

@@ -1,9 +1,9 @@
import { UmbDocumentWorkspaceContext } from '../document-workspace.context';
import { UmbWorkspaceActionBase } from '@umbraco-cms/backoffice/workspace';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export class UmbDocumentSaveAndPublishWorkspaceAction extends UmbWorkspaceActionBase<UmbDocumentWorkspaceContext> {
constructor(host: UmbControllerHostInterface) {
constructor(host: UmbControllerHostElement) {
super(host);
}

View File

@@ -1,9 +1,9 @@
import { UmbDocumentWorkspaceContext } from '../document-workspace.context';
import { UmbWorkspaceActionBase } from '@umbraco-cms/backoffice/workspace';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller';
export class UmbSaveAndScheduleDocumentWorkspaceAction extends UmbWorkspaceActionBase<UmbDocumentWorkspaceContext> {
constructor(host: UmbControllerHostInterface) {
constructor(host: UmbControllerHostElement) {
super(host);
}

Some files were not shown because too many files have changed in this diff Show More