From e66abe4071c38e50ae05a86140327f2ff7db45dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 6 Mar 2025 18:44:31 +0100 Subject: [PATCH 01/26] implement getContext rejecter + allow for resolving in undefined --- .../src/libs/class-api/class.interface.ts | 2 +- .../src/libs/class-api/class.mixin.ts | 16 ++++--- .../consume/context-consumer.test.ts | 43 +++++++++++++------ .../context-api/consume/context-consumer.ts | 21 ++++++--- 4 files changed, 59 insertions(+), 23 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/class-api/class.interface.ts b/src/Umbraco.Web.UI.Client/src/libs/class-api/class.interface.ts index 47aa54c406c2..ed89e002587e 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/class-api/class.interface.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/class-api/class.interface.ts @@ -64,5 +64,5 @@ export interface UmbClassInterface extends UmbControllerHost { */ getContext( alias: string | UmbContextToken, - ): Promise; + ): Promise; } diff --git a/src/Umbraco.Web.UI.Client/src/libs/class-api/class.mixin.ts b/src/Umbraco.Web.UI.Client/src/libs/class-api/class.mixin.ts index 0b1c893bcdb7..a81bfbe412b6 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/class-api/class.mixin.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/class-api/class.mixin.ts @@ -98,12 +98,18 @@ export const UmbClassMixin = >(superClas async getContext( contextAlias: string | UmbContextToken, - ): Promise { + ): Promise { const controller = new UmbContextConsumerController(this, contextAlias); - const promise = controller.asPromise().then((result) => { - controller.destroy(); - return result; - }); + const promise = controller + .asPromise() + .then((result) => { + controller.destroy(); + return result; + }) + .catch(() => { + controller.destroy(); + return undefined; + }); return promise; } diff --git a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.test.ts b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.test.ts index 5e110b74ae8b..6d5c743de468 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.test.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.test.ts @@ -59,19 +59,38 @@ describe('UmbContextConsumer', () => { const element = document.createElement('div'); document.body.appendChild(element); - const localConsumer = new UmbContextConsumer( - element, - testContextAlias, - (_instance: UmbTestContextConsumerClass | undefined) => { - if (_instance) { - expect(_instance.prop).to.eq('value from provider'); - done(); - localConsumer.hostDisconnected(); - provider.hostDisconnected(); - } - }, - ); + const localConsumer = new UmbContextConsumer(element, testContextAlias, (_instance: undefined) => { + if (_instance) { + expect(_instance.prop).to.eq('value from provider'); + done(); + localConsumer.hostDisconnected(); + provider.hostDisconnected(); + } + }); + localConsumer.hostConnected(); + }); + + it('works with asPromise for UmbContextProvider', (done) => { + const provider = new UmbContextProvider(document.body, testContextAlias, new UmbTestContextConsumerClass()); + provider.hostConnected(); + + const element = document.createElement('div'); + document.body.appendChild(element); + + const localConsumer = new UmbContextConsumer(element, testContextAlias); localConsumer.hostConnected(); + localConsumer + .asPromise() + .then((instance) => { + expect(instance.prop).to.eq('value from provider'); + localConsumer.hostDisconnected(); + provider.hostDisconnected(); + done(); + }) + .catch(() => { + expect.fail('Promise should not reject'); + done(); + }); }); it('works with host as a method', (done) => { diff --git a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts index 0230a3f1fd8e..9556eee35668 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts @@ -14,8 +14,9 @@ export class UmbContextConsumer; - #promise?: Promise; - #promiseResolver?: (instance: ResultType) => void; + #promise?: Promise; + #promiseResolver?: (instance: ResultType | undefined) => void; + #promiseRejecter?: (instance: ResultType | undefined) => void; #instance?: ResultType; get instance() { @@ -102,6 +103,8 @@ export class UmbContextConsumer { + public asPromise(): Promise { return ( this.#promise ?? - (this.#promise = new Promise((resolve) => { + (this.#promise = new Promise((resolve, reject) => { if (this.#instance) { + this.#promiseResolver = undefined; + this.#promiseRejecter = undefined; resolve(this.#instance); } else { this.#promiseResolver = resolve; + this.#promiseRejecter = reject; } })) ); @@ -129,7 +135,7 @@ export class UmbContextConsumer { const event = new UmbContextRequestEventImplementation( this.#contextAlias, this.#apiAlias, @@ -137,6 +143,10 @@ export class UmbContextConsumer Date: Thu, 6 Mar 2025 19:42:07 +0100 Subject: [PATCH 02/26] fix test --- .../consume/context-consumer.test.ts | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.test.ts b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.test.ts index 6d5c743de468..169d0e60dffa 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.test.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.test.ts @@ -59,14 +59,18 @@ describe('UmbContextConsumer', () => { const element = document.createElement('div'); document.body.appendChild(element); - const localConsumer = new UmbContextConsumer(element, testContextAlias, (_instance: undefined) => { - if (_instance) { - expect(_instance.prop).to.eq('value from provider'); - done(); - localConsumer.hostDisconnected(); - provider.hostDisconnected(); - } - }); + const localConsumer = new UmbContextConsumer( + element, + testContextAlias, + (_instance) => { + if (_instance) { + expect(_instance.prop).to.eq('value from provider'); + done(); + localConsumer.hostDisconnected(); + provider.hostDisconnected(); + } + }, + ); localConsumer.hostConnected(); }); @@ -77,12 +81,12 @@ describe('UmbContextConsumer', () => { const element = document.createElement('div'); document.body.appendChild(element); - const localConsumer = new UmbContextConsumer(element, testContextAlias); + const localConsumer = new UmbContextConsumer(element, testContextAlias); localConsumer.hostConnected(); localConsumer .asPromise() .then((instance) => { - expect(instance.prop).to.eq('value from provider'); + expect(instance?.prop).to.eq('value from provider'); localConsumer.hostDisconnected(); provider.hostDisconnected(); done(); @@ -118,10 +122,10 @@ describe('UmbContextConsumer', () => { it('works with host method returning undefined', async () => { const element = undefined; - const localConsumer = new UmbContextConsumer( + const localConsumer = new UmbContextConsumer( () => element, testContextAlias, - (_instance: UmbTestContextConsumerClass | undefined) => { + (_instance) => { if (_instance) { expect.fail('Callback should not be called when never permitted'); } @@ -177,14 +181,18 @@ describe('UmbContextConsumer', () => { const element = document.createElement('div'); document.body.appendChild(element); - const localConsumer = new UmbContextConsumer(element, testContextAliasAndApiAlias, (_instance) => { - if (_instance) { - expect((_instance as UmbTestContextConsumerClass).prop).to.eq('value from provider'); - localConsumer.hostDisconnected(); - provider.hostDisconnected(); - done(); - } - }); + const localConsumer = new UmbContextConsumer( + element, + testContextAliasAndApiAlias, + (_instance) => { + if (_instance) { + expect(_instance.prop).to.eq('value from provider'); + localConsumer.hostDisconnected(); + provider.hostDisconnected(); + done(); + } + }, + ); localConsumer.hostConnected(); }); From 5d10b3708b74f69f8db93c4d8e14b0f57abe6d43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 6 Mar 2025 19:42:14 +0100 Subject: [PATCH 03/26] timeout concept --- .../libs/context-api/consume/context-consumer.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts index 9556eee35668..b8c8c4ebd21b 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts @@ -5,6 +5,10 @@ import { UmbContextRequestEventImplementation } from './context-request.event.js type HostElementMethod = () => Element | undefined; +type AsPromiseOptionsType = { + preventTimeout?: boolean; +}; + /** * @class UmbContextConsumer */ @@ -111,10 +115,11 @@ export class UmbContextConsumer { + public asPromise(options?: AsPromiseOptionsType): Promise { return ( this.#promise ?? (this.#promise = new Promise((resolve, reject) => { @@ -124,7 +129,7 @@ export class UmbContextConsumer 0 && this.#promiseRejecter) { + await new Promise((resolve) => requestAnimationFrame(resolve)); + } // If we still have the rejecter, it means that the context was not found immediately, so lets reject the promise. this.#promiseRejecter?.(undefined); } From 3687892c249eae7d104ecf289b8801bd4d0e9239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 6 Mar 2025 21:48:35 +0100 Subject: [PATCH 04/26] adjustments --- .../context-api/consume/context-consumer.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts index b8c8c4ebd21b..d9f8ac6294f3 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts @@ -11,6 +11,9 @@ type AsPromiseOptionsType = { /** * @class UmbContextConsumer + * @description The context consumer class, used to consume a context from a host element. + * Notice it is not recommended to use this class directly, but rather use the `consumeContext` method from a `UmbElement` or `UmbElementMixin` or `UmbControllerBase` or `UmbClassMixin`. + * Alternatively, you can use the `UmbContextConsumerController` to consume a context from a host element. But this does require that you can implement one of the Class Mixins mentioned above. */ export class UmbContextConsumer { protected _retrieveHost: HostElementMethod; @@ -19,8 +22,8 @@ export class UmbContextConsumer; #promise?: Promise; - #promiseResolver?: (instance: ResultType | undefined) => void; - #promiseRejecter?: (instance: ResultType | undefined) => void; + #promiseResolver?: (instance: ResultType) => void; + #promiseRejecter?: (instance?: ResultType) => void; #instance?: ResultType; get instance() { @@ -88,7 +91,7 @@ export class UmbContextConsumer 0 && this.#promiseRejecter) { await new Promise((resolve) => requestAnimationFrame(resolve)); } - // If we still have the rejecter, it means that the context was not found immediately, so lets reject the promise. - this.#promiseRejecter?.(undefined); + // If we still have the rejecter, it means that the context was not found immediately, so lets reject the promise. [NL] + this.#promiseRejecter?.(); } public hostConnected(): void { @@ -180,7 +183,7 @@ export class UmbContextConsumer { // Does seem a bit unnecessary, we could just assume the type via type casting... From e3024a52e8f9ea77df49c08a0857d6e66fa6b2dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 6 Mar 2025 22:09:45 +0100 Subject: [PATCH 05/26] adapt implementation --- .../src/libs/class-api/class.interface.ts | 2 ++ .../src/libs/class-api/class.mixin.ts | 4 +++- .../context-api/consume/context-consumer.ts | 10 ++++---- .../src/libs/element-api/element.mixin.ts | 23 ++++++++++++++----- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/class-api/class.interface.ts b/src/Umbraco.Web.UI.Client/src/libs/class-api/class.interface.ts index ed89e002587e..a70f20916eea 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/class-api/class.interface.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/class-api/class.interface.ts @@ -1,5 +1,6 @@ import type { UmbContextCallback, + UmbContextConsumerAsPromiseOptionsType, UmbContextConsumerController, UmbContextProviderController, UmbContextToken, @@ -64,5 +65,6 @@ export interface UmbClassInterface extends UmbControllerHost { */ getContext( alias: string | UmbContextToken, + options?: UmbContextConsumerAsPromiseOptionsType, ): Promise; } diff --git a/src/Umbraco.Web.UI.Client/src/libs/class-api/class.mixin.ts b/src/Umbraco.Web.UI.Client/src/libs/class-api/class.mixin.ts index a81bfbe412b6..607cca29c1cc 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/class-api/class.mixin.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/class-api/class.mixin.ts @@ -11,6 +11,7 @@ import { type UmbContextCallback, UmbContextConsumerController, UmbContextProviderController, + type UmbContextConsumerAsPromiseOptionsType, } from '@umbraco-cms/backoffice/context-api'; import { type ObserverCallback, UmbObserverController, simpleHashCode } from '@umbraco-cms/backoffice/observable-api'; @@ -98,10 +99,11 @@ export const UmbClassMixin = >(superClas async getContext( contextAlias: string | UmbContextToken, + options?: UmbContextConsumerAsPromiseOptionsType, ): Promise { const controller = new UmbContextConsumerController(this, contextAlias); const promise = controller - .asPromise() + .asPromise(options) .then((result) => { controller.destroy(); return result; diff --git a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts index d9f8ac6294f3..2a17e5b3e1dc 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts @@ -5,7 +5,7 @@ import { UmbContextRequestEventImplementation } from './context-request.event.js type HostElementMethod = () => Element | undefined; -type AsPromiseOptionsType = { +export type UmbContextConsumerAsPromiseOptionsType = { preventTimeout?: boolean; }; @@ -118,11 +118,11 @@ export class UmbContextConsumer { + public asPromise(options?: UmbContextConsumerAsPromiseOptionsType): Promise { return ( this.#promise ?? (this.#promise = new Promise((resolve, reject) => { @@ -152,8 +152,8 @@ export class UmbContextConsumer 0 && this.#promiseRejecter) { await new Promise((resolve) => requestAnimationFrame(resolve)); } diff --git a/src/Umbraco.Web.UI.Client/src/libs/element-api/element.mixin.ts b/src/Umbraco.Web.UI.Client/src/libs/element-api/element.mixin.ts index 9b46710c58b4..83f7c29cea96 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/element-api/element.mixin.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/element-api/element.mixin.ts @@ -3,7 +3,11 @@ import { UmbLocalizationController } from '@umbraco-cms/backoffice/localization- import type { Observable } from '@umbraco-cms/backoffice/external/rxjs'; import type { HTMLElementConstructor } from '@umbraco-cms/backoffice/extension-api'; import { type UmbControllerAlias, UmbControllerHostElementMixin } from '@umbraco-cms/backoffice/controller-api'; -import type { UmbContextToken, UmbContextCallback } from '@umbraco-cms/backoffice/context-api'; +import type { + UmbContextToken, + UmbContextCallback, + UmbContextConsumerAsPromiseOptionsType, +} from '@umbraco-cms/backoffice/context-api'; import { UmbContextConsumerController, UmbContextProviderController } from '@umbraco-cms/backoffice/context-api'; import type { ObserverCallback } from '@umbraco-cms/backoffice/observable-api'; import { UmbObserverController, simpleHashCode } from '@umbraco-cms/backoffice/observable-api'; @@ -74,12 +78,19 @@ export const UmbElementMixin = (superClass: T) async getContext( contextAlias: string | UmbContextToken, - ): Promise { + options?: UmbContextConsumerAsPromiseOptionsType, + ): Promise { const controller = new UmbContextConsumerController(this, contextAlias); - const promise = controller.asPromise().then((result) => { - controller.destroy(); - return result; - }); + const promise = controller + .asPromise(options) + .then((result) => { + controller.destroy(); + return result; + }) + .catch(() => { + controller.destroy(); + return undefined; + }); return promise; } } From 4481d872f9011a4d621df72007bcb201f47b14ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 6 Mar 2025 22:41:28 +0100 Subject: [PATCH 06/26] ability to set timeoutFrame for faster test --- .../src/libs/context-api/consume/context-consumer.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts index 2a17e5b3e1dc..9c7578a8a9b8 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts @@ -7,6 +7,7 @@ type HostElementMethod = () => Element | undefined; export type UmbContextConsumerAsPromiseOptionsType = { preventTimeout?: boolean; + timeoutFrames?: number; }; /** @@ -24,6 +25,7 @@ export class UmbContextConsumer; #promiseResolver?: (instance: ResultType) => void; #promiseRejecter?: (instance?: ResultType) => void; + #timeoutFrames?: number; #instance?: ResultType; get instance() { @@ -131,6 +133,7 @@ export class UmbContextConsumer 0 && this.#promiseRejecter) { await new Promise((resolve) => requestAnimationFrame(resolve)); } From bb5cb1a0ac5eefe3143f170f72681e99ff42a328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 7 Mar 2025 08:11:29 +0100 Subject: [PATCH 07/26] update --- .../consume/context-consumer.test.ts | 120 ++++++++++++------ .../context-api/consume/context-consumer.ts | 4 +- 2 files changed, 84 insertions(+), 40 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.test.ts b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.test.ts index 169d0e60dffa..9d1ec0224392 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.test.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.test.ts @@ -52,22 +52,28 @@ describe('UmbContextConsumer', () => { }); describe('Simple implementation', () => { + let element: HTMLElement; + beforeEach(() => { + element = document.createElement('div'); + document.body.appendChild(element); + }); + afterEach(() => { + document.body.removeChild(element); + }); + it('works with UmbContextProvider', (done) => { const provider = new UmbContextProvider(document.body, testContextAlias, new UmbTestContextConsumerClass()); provider.hostConnected(); - const element = document.createElement('div'); - document.body.appendChild(element); - const localConsumer = new UmbContextConsumer( element, testContextAlias, (_instance) => { if (_instance) { expect(_instance.prop).to.eq('value from provider'); - done(); localConsumer.hostDisconnected(); provider.hostDisconnected(); + done(); } }, ); @@ -78,13 +84,10 @@ describe('UmbContextConsumer', () => { const provider = new UmbContextProvider(document.body, testContextAlias, new UmbTestContextConsumerClass()); provider.hostConnected(); - const element = document.createElement('div'); - document.body.appendChild(element); - const localConsumer = new UmbContextConsumer(element, testContextAlias); localConsumer.hostConnected(); localConsumer - .asPromise() + .asPromise({ timeoutFrames: 10 }) // Just limiting the time out to make sure the other tests are working as expected. [NL] .then((instance) => { expect(instance?.prop).to.eq('value from provider'); localConsumer.hostDisconnected(); @@ -93,26 +96,63 @@ describe('UmbContextConsumer', () => { }) .catch(() => { expect.fail('Promise should not reject'); + }); + }); + + it('gets rejected when using asPromise that does not resolve', (done) => { + const localConsumer = new UmbContextConsumer(element, testContextAlias); + + localConsumer + .asPromise({ timeoutFrames: 10 }) + .then((instance) => { + expect.fail('Promise should reject'); + }) + .catch(() => { + localConsumer.hostDisconnected(); + localConsumer.destroy(); done(); }); + localConsumer.hostConnected(); + }); + + it('never gets rejected when using asPromise that is set not to timeout and never will resolve', (done) => { + const localConsumer = new UmbContextConsumer(element, testContextAlias); + localConsumer.hostConnected(); + + const timeout = setTimeout(() => { + localConsumer.hostDisconnected(); + done(); + }, 200); + + try { + localConsumer + .asPromise({ preventTimeout: true, timeoutFrames: 10 }) + .then((instance) => { + clearTimeout(timeout); + expect.fail('Promise should not resolve'); + }) + .catch(() => { + clearTimeout(timeout); + expect.fail('Promise should not reject'); + }); + } catch (e) { + console.log('e', e); + } }); it('works with host as a method', (done) => { const provider = new UmbContextProvider(document.body, testContextAlias, new UmbTestContextConsumerClass()); provider.hostConnected(); - const element = document.createElement('div'); - document.body.appendChild(element); - const localConsumer = new UmbContextConsumer( () => element, testContextAlias, (_instance: UmbTestContextConsumerClass | undefined) => { if (_instance) { expect(_instance.prop).to.eq('value from provider'); - done(); localConsumer.hostDisconnected(); provider.hostDisconnected(); + done(); } }, ); @@ -120,10 +160,10 @@ describe('UmbContextConsumer', () => { }); it('works with host method returning undefined', async () => { - const element = undefined; + const notExistingElement = undefined; const localConsumer = new UmbContextConsumer( - () => element, + () => notExistingElement, testContextAlias, (_instance) => { if (_instance) { @@ -170,6 +210,15 @@ describe('UmbContextConsumer', () => { }); describe('Implementation with Api Alias', () => { + let element: HTMLElement; + beforeEach(() => { + element = document.createElement('div'); + document.body.appendChild(element); + }); + afterEach(() => { + document.body.removeChild(element); + }); + it('responds when api alias matches', (done) => { const provider = new UmbContextProvider( document.body, @@ -178,9 +227,6 @@ describe('UmbContextConsumer', () => { ); provider.hostConnected(); - const element = document.createElement('div'); - document.body.appendChild(element); - const localConsumer = new UmbContextConsumer( element, testContextAliasAndApiAlias, @@ -204,9 +250,6 @@ describe('UmbContextConsumer', () => { ); provider.hostConnected(); - const element = document.createElement('div'); - document.body.appendChild(element); - const localConsumer = new UmbContextConsumer(element, testContextAliasAndNotExistingApiAlias, () => { expect(false).to.be.true; }); @@ -222,6 +265,15 @@ describe('UmbContextConsumer', () => { }); describe('Implementation with discriminator method', () => { + let element: HTMLElement; + beforeEach(() => { + element = document.createElement('div'); + document.body.appendChild(element); + }); + afterEach(() => { + document.body.removeChild(element); + }); + type A = { prop: string }; function discriminator(instance: unknown): instance is A { @@ -235,16 +287,20 @@ describe('UmbContextConsumer', () => { } it('discriminator determines the instance type', (done) => { + const provider = new UmbContextProvider(document.body, testContextAlias, new UmbTestContextConsumerClass()); + const localConsumer = new UmbContextConsumer( - document.body, + element, new UmbContextToken(testContextAlias, undefined, discriminator), (instance: A) => { expect(instance.prop).to.eq('value from provider'); - done(); + provider.destroy(); localConsumer.destroy(); + done(); }, ); localConsumer.hostConnected(); + provider.hostConnected(); // This bit of code is not really a test but it serves as a TypeScript type test, making sure the given type is matches the one given from the Discriminator method. type TestType = Exclude extends A ? true : never; @@ -256,17 +312,14 @@ describe('UmbContextConsumer', () => { const provider = new UmbContextProvider(document.body, testContextAlias, new UmbTestContextConsumerClass()); provider.hostConnected(); - const element = document.createElement('div'); - document.body.appendChild(element); - const localConsumer = new UmbContextConsumer( element, new UmbContextToken(testContextAlias, undefined, discriminator), (_instance) => { expect(_instance.prop).to.eq('value from provider'); - done(); localConsumer.hostDisconnected(); provider.hostDisconnected(); + done(); }, ); localConsumer.hostConnected(); @@ -276,9 +329,6 @@ describe('UmbContextConsumer', () => { const provider = new UmbContextProvider(document.body, testContextAlias, new UmbTestContextConsumerClass()); provider.hostConnected(); - const element = document.createElement('div'); - document.body.appendChild(element); - const localConsumer = new UmbContextConsumer( element, new UmbContextToken(testContextAlias, undefined, badDiscriminator), @@ -290,9 +340,9 @@ describe('UmbContextConsumer', () => { // Wait for to ensure the above request didn't succeed: Promise.resolve().then(() => { - done(); localConsumer.hostDisconnected(); provider.hostDisconnected(); + done(); }); }); @@ -300,9 +350,6 @@ describe('UmbContextConsumer', () => { const provider = new UmbContextProvider(document.body, testContextAlias, new UmbTestContextConsumerClass()); provider.hostConnected(); - const element = document.createElement('div'); - document.body.appendChild(element); - const alternativeProvider = new UmbContextProvider( element, testContextAlias, @@ -321,9 +368,9 @@ describe('UmbContextConsumer', () => { // Wait for to ensure the above request didn't succeed: Promise.resolve().then(() => { - done(); localConsumer.hostDisconnected(); provider.hostDisconnected(); + done(); }); }); @@ -331,9 +378,6 @@ describe('UmbContextConsumer', () => { const provider = new UmbContextProvider(document.body, testContextAlias, new UmbTestContextConsumerClass()); provider.hostConnected(); - const element = document.createElement('div'); - document.body.appendChild(element); - const alternativeProvider = new UmbContextProvider( element, testContextAlias, @@ -346,9 +390,9 @@ describe('UmbContextConsumer', () => { new UmbContextToken(testContextAlias, undefined, discriminator), (_instance) => { expect(_instance.prop).to.eq('value from provider'); - done(); localConsumer.hostDisconnected(); provider.hostDisconnected(); + done(); }, ); localConsumer.passContextAliasMatches(); diff --git a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts index 9c7578a8a9b8..045e49c4c330 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts @@ -155,8 +155,8 @@ export class UmbContextConsumer 0 && this.#promiseRejecter) { await new Promise((resolve) => requestAnimationFrame(resolve)); } From fccbf6bf43527c1507a6ce4a93563539bb7ca0a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 7 Mar 2025 08:11:43 +0100 Subject: [PATCH 08/26] make sure provider only provides when connected --- .../src/libs/context-api/provide/context-provider.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/context-api/provide/context-provider.ts b/src/Umbraco.Web.UI.Client/src/libs/context-api/provide/context-provider.ts index 10ddd09b6311..8ac0fd6795a8 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/context-api/provide/context-provider.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/context-api/provide/context-provider.ts @@ -40,15 +40,15 @@ export class UmbContextProvider Date: Fri, 7 Mar 2025 08:12:47 +0100 Subject: [PATCH 09/26] make sure action apis can fail without resolving --- .../core/entity-action/default/entity-action.element.ts | 7 ++++++- .../kinds/default/property-action.element.ts | 6 +++++- .../default/workspace-action-menu-item.element.ts | 6 +++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/default/entity-action.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/default/entity-action.element.ts index 23899406129a..96407a4bac22 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/default/entity-action.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/default/entity-action.element.ts @@ -49,8 +49,13 @@ export class UmbEntityActionDefaultElement< async #onClickLabel(event: UUIMenuItemEvent) { if (!this._href) { event.stopPropagation(); - await this.#api?.execute(); + try { + await this.#api?.execute(); + } catch (error) { + return; + } } + console.log('success'); this.dispatchEvent(new UmbActionExecutedEvent()); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-action/kinds/default/property-action.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-action/kinds/default/property-action.element.ts index 55d2da24bf6e..dabebb5d8d82 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-action/kinds/default/property-action.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-action/kinds/default/property-action.element.ts @@ -34,7 +34,11 @@ export class UmbPropertyActionElement< async #onClickLabel(event: UUIMenuItemEvent) { if (!this._href) { event.stopPropagation(); - await this.#api?.execute(); + try { + await this.#api?.execute(); + } catch (error) { + return; + } } this.dispatchEvent(new UmbActionExecutedEvent()); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-action-menu-item/default/workspace-action-menu-item.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-action-menu-item/default/workspace-action-menu-item.element.ts index f1994d1e8ea2..c85f9498bc52 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-action-menu-item/default/workspace-action-menu-item.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-action-menu-item/default/workspace-action-menu-item.element.ts @@ -34,7 +34,11 @@ export class UmbWorkspaceActionMenuItemElement< async #onClickLabel(event: UUIMenuItemEvent) { if (!this._href) { event.stopPropagation(); - await this.#api?.execute(); + try { + await this.#api?.execute(); + } catch (error) { + return; + } } this.dispatchEvent(new UmbActionExecutedEvent()); } From bb5a0395585a07e7e6c9ca20b8eaa7efc2cc9eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 7 Mar 2025 08:13:45 +0100 Subject: [PATCH 10/26] make sure to await the arrival of the UMB_AUTH_CONTEXT --- .../src/apps/app/app-auth.controller.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/apps/app/app-auth.controller.ts b/src/Umbraco.Web.UI.Client/src/apps/app/app-auth.controller.ts index 2d7f4928083f..3726dcd65760 100644 --- a/src/Umbraco.Web.UI.Client/src/apps/app/app-auth.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/apps/app/app-auth.controller.ts @@ -7,13 +7,14 @@ import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; import { setStoredPath } from '@umbraco-cms/backoffice/utils'; export class UmbAppAuthController extends UmbControllerBase { + #retrievedModal: Promise; #authContext?: typeof UMB_AUTH_CONTEXT.TYPE; #isFirstCheck = true; constructor(host: UmbControllerHost) { super(host); - this.consumeContext(UMB_AUTH_CONTEXT, (context) => { + this.#retrievedModal = this.consumeContext(UMB_AUTH_CONTEXT, (context) => { this.#authContext = context; // Observe the user's authorization state and start the authorization flow if the user is not authorized @@ -24,7 +25,7 @@ export class UmbAppAuthController extends UmbControllerBase { }, '_authState', ); - }); + }).asPromise(); } /** @@ -32,6 +33,7 @@ export class UmbAppAuthController extends UmbControllerBase { * If not, the authorization flow is started. */ async isAuthorized(): Promise { + await this.#retrievedModal; if (!this.#authContext) { throw new Error('[Fatal] Auth context is not available'); } @@ -63,6 +65,7 @@ export class UmbAppAuthController extends UmbControllerBase { * @param userLoginState */ async makeAuthorizationRequest(userLoginState: UmbUserLoginState = 'loggingIn'): Promise { + await this.#retrievedModal; if (!this.#authContext) { throw new Error('[Fatal] Auth context is not available'); } @@ -111,6 +114,7 @@ export class UmbAppAuthController extends UmbControllerBase { } async #showLoginModal(userLoginState: UmbUserLoginState): Promise { + await this.#retrievedModal; if (!this.#authContext) { throw new Error('[Fatal] Auth context is not available'); } @@ -118,6 +122,9 @@ export class UmbAppAuthController extends UmbControllerBase { // Show the provider selection screen const authModalKey = 'umbAuthModal'; const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); + if (!modalManager) { + throw new Error('[Fatal] Modal manager is not available'); + } const selected = await modalManager .open(this._host, UMB_MODAL_APP_AUTH, { From 71ca072341e9f8c09193e57358c5201ced1e9075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 7 Mar 2025 08:13:59 +0100 Subject: [PATCH 11/26] no need to be async --- .../backoffice/components/backoffice-header-logo.element.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/apps/backoffice/components/backoffice-header-logo.element.ts b/src/Umbraco.Web.UI.Client/src/apps/backoffice/components/backoffice-header-logo.element.ts index 03af4fdac547..2c0f0d8ecf16 100644 --- a/src/Umbraco.Web.UI.Client/src/apps/backoffice/components/backoffice-header-logo.element.ts +++ b/src/Umbraco.Web.UI.Client/src/apps/backoffice/components/backoffice-header-logo.element.ts @@ -47,7 +47,7 @@ export class UmbBackofficeHeaderLogoElement extends UmbLitElement { }); } - protected override async firstUpdated() { + protected override firstUpdated() { this.#isAdmin(); } @@ -88,6 +88,7 @@ export class UmbBackofficeHeaderLogoElement extends UmbLitElement { async #openSystemInformation() { const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); + if (!modalManager) return; modalManager .open(this, UMB_SYSINFO_MODAL) .onSubmit() @@ -97,6 +98,7 @@ export class UmbBackofficeHeaderLogoElement extends UmbLitElement { async #openNewVersion() { if (!this._serverUpgradeCheck) return; const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); + if (!modalManager) return; modalManager .open(this, UMB_NEWVERSION_MODAL, { data: { From fdbcd6d4cf386cf973d1a440c59bc3bc4fc69dee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 7 Mar 2025 08:14:19 +0100 Subject: [PATCH 12/26] consume to stay up to date --- .../src/apps/backoffice/backoffice.context.ts | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/apps/backoffice/backoffice.context.ts b/src/Umbraco.Web.UI.Client/src/apps/backoffice/backoffice.context.ts index 13ce2e72f886..7cbe0f48adb5 100644 --- a/src/Umbraco.Web.UI.Client/src/apps/backoffice/backoffice.context.ts +++ b/src/Umbraco.Web.UI.Client/src/apps/backoffice/backoffice.context.ts @@ -34,29 +34,26 @@ export class UmbBackofficeContext extends UmbContextBase { }); }); - this.#init(); - } - - async #init() { - const userContext = await this.getContext(UMB_CURRENT_USER_CONTEXT); - this.observe( - userContext.allowedSections, - (allowedSections) => { - if (!allowedSections) return; - // TODO: Please be aware that we re-initialize this initializer based on user permissions. I suggest we should solve this specific case should be improved by the ability to change the filter [NL] - new UmbExtensionsManifestInitializer( - this, - umbExtensionsRegistry, - 'section', - (manifest) => allowedSections.includes(manifest.alias), - async (sections) => { - this.#allowedSections.setValue([...sections]); - }, - 'umbAllowedSectionsManifestInitializer', - ); - }, - 'umbAllowedSectionsObserver', - ); + this.consumeContext(UMB_CURRENT_USER_CONTEXT, (userContext) => { + this.observe( + userContext.allowedSections, + (allowedSections) => { + if (!allowedSections) return; + // TODO: Please be aware that we re-initialize this initializer based on user permissions. I suggest we should solve this specific case should be improved by the ability to change the filter [NL] + new UmbExtensionsManifestInitializer( + this, + umbExtensionsRegistry, + 'section', + (manifest) => allowedSections.includes(manifest.alias), + async (sections) => { + this.#allowedSections.setValue([...sections]); + }, + 'umbAllowedSectionsManifestInitializer', + ); + }, + 'umbAllowedSectionsObserver', + ); + }); } async #getVersion() { From 3459a1bbef3a8ad3f950681ee0e12da807ebb37a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 7 Mar 2025 11:16:10 +0100 Subject: [PATCH 13/26] one rendering cycle approach --- .../context-api/consume/context-consumer.test.ts | 9 +++++---- .../libs/context-api/consume/context-consumer.ts | 16 ++++++++-------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.test.ts b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.test.ts index 9d1ec0224392..57f9f0339b64 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.test.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.test.ts @@ -82,12 +82,11 @@ describe('UmbContextConsumer', () => { it('works with asPromise for UmbContextProvider', (done) => { const provider = new UmbContextProvider(document.body, testContextAlias, new UmbTestContextConsumerClass()); - provider.hostConnected(); const localConsumer = new UmbContextConsumer(element, testContextAlias); localConsumer.hostConnected(); localConsumer - .asPromise({ timeoutFrames: 10 }) // Just limiting the time out to make sure the other tests are working as expected. [NL] + .asPromise() .then((instance) => { expect(instance?.prop).to.eq('value from provider'); localConsumer.hostDisconnected(); @@ -97,13 +96,15 @@ describe('UmbContextConsumer', () => { .catch(() => { expect.fail('Promise should not reject'); }); + + provider.hostConnected(); }); it('gets rejected when using asPromise that does not resolve', (done) => { const localConsumer = new UmbContextConsumer(element, testContextAlias); localConsumer - .asPromise({ timeoutFrames: 10 }) + .asPromise() .then((instance) => { expect.fail('Promise should reject'); }) @@ -126,7 +127,7 @@ describe('UmbContextConsumer', () => { try { localConsumer - .asPromise({ preventTimeout: true, timeoutFrames: 10 }) + .asPromise({ preventTimeout: true }) .then((instance) => { clearTimeout(timeout); expect.fail('Promise should not resolve'); diff --git a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts index 045e49c4c330..35d0870ca0d2 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts @@ -7,7 +7,6 @@ type HostElementMethod = () => Element | undefined; export type UmbContextConsumerAsPromiseOptionsType = { preventTimeout?: boolean; - timeoutFrames?: number; }; /** @@ -25,7 +24,6 @@ export class UmbContextConsumer; #promiseResolver?: (instance: ResultType) => void; #promiseRejecter?: (instance?: ResultType) => void; - #timeoutFrames?: number; #instance?: ResultType; get instance() { @@ -133,7 +131,6 @@ export class UmbContextConsumer { + public request(): void { const event = new UmbContextRequestEventImplementation( this.#contextAlias, this.#apiAlias, @@ -155,13 +152,16 @@ export class UmbContextConsumer 0 && this.#promiseRejecter) { await new Promise((resolve) => requestAnimationFrame(resolve)); } - // If we still have the rejecter, it means that the context was not found immediately, so lets reject the promise. [NL] - this.#promiseRejecter?.(); + */ + requestAnimationFrame(() => { + // If we still have the rejecter, it means that the context was not found immediately, so lets reject the promise. [NL] + this.#promiseRejecter?.(); + }); } public hostConnected(): void { From 91049f2f20d3491cbb4a8f7fc33ceae2636ea635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 7 Mar 2025 11:24:40 +0100 Subject: [PATCH 14/26] adjusting context consumption part 1 --- .../incrementor-workspace-action.ts | 5 +++- .../apps/app/api-interceptor.controller.ts | 3 +++ .../src/apps/app/app-auth.controller.ts | 6 ++--- .../backoffice-header-logo.element.ts | 5 +++- .../src/apps/preview/preview.context.ts | 24 +++++++++---------- .../input-manifest/input-manifest.element.ts | 3 +++ ...nt-type-workspace-editor-header.element.ts | 3 +++ .../is-current-user-an-admin.function.ts | 4 ++-- 8 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/examples/workspace-context-counter/incrementor-workspace-action.ts b/src/Umbraco.Web.UI.Client/examples/workspace-context-counter/incrementor-workspace-action.ts index 940436c57900..04bfb72cac1e 100644 --- a/src/Umbraco.Web.UI.Client/examples/workspace-context-counter/incrementor-workspace-action.ts +++ b/src/Umbraco.Web.UI.Client/examples/workspace-context-counter/incrementor-workspace-action.ts @@ -1,11 +1,14 @@ +import { EXAMPLE_COUNTER_CONTEXT } from './counter-workspace-context.js'; import { UmbWorkspaceActionBase, type UmbWorkspaceAction } from '@umbraco-cms/backoffice/workspace'; -import { EXAMPLE_COUNTER_CONTEXT } from './counter-workspace-context'; // The Example Incrementor Workspace Action Controller: export class ExampleIncrementorWorkspaceAction extends UmbWorkspaceActionBase implements UmbWorkspaceAction { // This method is executed override async execute() { const context = await this.getContext(EXAMPLE_COUNTER_CONTEXT); + if (!context) { + throw new Error('Could not get the counter context'); + } context.increment(); } } diff --git a/src/Umbraco.Web.UI.Client/src/apps/app/api-interceptor.controller.ts b/src/Umbraco.Web.UI.Client/src/apps/app/api-interceptor.controller.ts index 874c96c2b060..8c7bbcf6e838 100644 --- a/src/Umbraco.Web.UI.Client/src/apps/app/api-interceptor.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/apps/app/api-interceptor.controller.ts @@ -29,6 +29,9 @@ export class UmbApiInterceptorController extends UmbControllerBase { if (!isUmbNotifications(notifications)) return response; this.getContext(UMB_NOTIFICATION_CONTEXT).then((notificationContext) => { + if (notificationContext === undefined) { + throw new Error('Notification context is not available'); + } for (const notification of notifications) { notificationContext.peek(extractUmbNotificationColor(notification.type), { data: { headline: notification.category, message: notification.message }, diff --git a/src/Umbraco.Web.UI.Client/src/apps/app/app-auth.controller.ts b/src/Umbraco.Web.UI.Client/src/apps/app/app-auth.controller.ts index 3726dcd65760..6b1ee082df77 100644 --- a/src/Umbraco.Web.UI.Client/src/apps/app/app-auth.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/apps/app/app-auth.controller.ts @@ -33,7 +33,7 @@ export class UmbAppAuthController extends UmbControllerBase { * If not, the authorization flow is started. */ async isAuthorized(): Promise { - await this.#retrievedModal; + await this.#retrievedModal.catch(() => undefined); if (!this.#authContext) { throw new Error('[Fatal] Auth context is not available'); } @@ -65,7 +65,7 @@ export class UmbAppAuthController extends UmbControllerBase { * @param userLoginState */ async makeAuthorizationRequest(userLoginState: UmbUserLoginState = 'loggingIn'): Promise { - await this.#retrievedModal; + await this.#retrievedModal.catch(() => undefined); if (!this.#authContext) { throw new Error('[Fatal] Auth context is not available'); } @@ -114,7 +114,7 @@ export class UmbAppAuthController extends UmbControllerBase { } async #showLoginModal(userLoginState: UmbUserLoginState): Promise { - await this.#retrievedModal; + await this.#retrievedModal.catch(() => undefined); if (!this.#authContext) { throw new Error('[Fatal] Auth context is not available'); } diff --git a/src/Umbraco.Web.UI.Client/src/apps/backoffice/components/backoffice-header-logo.element.ts b/src/Umbraco.Web.UI.Client/src/apps/backoffice/components/backoffice-header-logo.element.ts index 2c0f0d8ecf16..5c7cbe4484d9 100644 --- a/src/Umbraco.Web.UI.Client/src/apps/backoffice/components/backoffice-header-logo.element.ts +++ b/src/Umbraco.Web.UI.Client/src/apps/backoffice/components/backoffice-header-logo.element.ts @@ -88,7 +88,10 @@ export class UmbBackofficeHeaderLogoElement extends UmbLitElement { async #openSystemInformation() { const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - if (!modalManager) return; + if (!modalManager) { + throw new Error('Modal manager not found'); + } + modalManager .open(this, UMB_SYSINFO_MODAL) .onSubmit() diff --git a/src/Umbraco.Web.UI.Client/src/apps/preview/preview.context.ts b/src/Umbraco.Web.UI.Client/src/apps/preview/preview.context.ts index 03e928fa82da..0e8bc63bd747 100644 --- a/src/Umbraco.Web.UI.Client/src/apps/preview/preview.context.ts +++ b/src/Umbraco.Web.UI.Client/src/apps/preview/preview.context.ts @@ -24,24 +24,22 @@ export class UmbPreviewContext extends UmbContextBase { constructor(host: UmbControllerHost) { super(host, UMB_PREVIEW_CONTEXT); - this.#init(); - } - async #init() { - const appContext = await this.getContext(UMB_APP_CONTEXT); - this.#serverUrl = appContext.getServerUrl(); + this.consumeContext(UMB_APP_CONTEXT, (appContext) => { + this.#serverUrl = appContext.getServerUrl(); - const params = new URLSearchParams(window.location.search); + const params = new URLSearchParams(window.location.search); - this.#culture = params.get('culture'); - this.#unique = params.get('id'); + this.#culture = params.get('culture'); + this.#unique = params.get('id'); - if (!this.#unique) { - console.error('No unique ID found in query string.'); - return; - } + if (!this.#unique) { + console.error('No unique ID found in query string.'); + return; + } - this.#setPreviewUrl(); + this.#setPreviewUrl(); + }); } #configureWebSocket() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-manifest/input-manifest.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-manifest/input-manifest.element.ts index 9a32e987527c..271dfe993c98 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-manifest/input-manifest.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-manifest/input-manifest.element.ts @@ -33,6 +33,9 @@ export class UmbInputManifestElement extends UmbLitElement { async #onClick() { const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); + if (!modalManager) { + throw new Error('Modal manager not found.'); + } const modalContext = modalManager.open(this, UMB_ITEM_PICKER_MODAL, { data: { headline: `${this.localize.term('general_choose')}...`, diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/global-components/content-type-workspace-editor-header.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/global-components/content-type-workspace-editor-header.element.ts index fc3180ee1d17..16d15246524d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/global-components/content-type-workspace-editor-header.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/global-components/content-type-workspace-editor-header.element.ts @@ -51,6 +51,9 @@ export class UmbContentTypeWorkspaceEditorHeaderElement extends UmbLitElement { private async _handleIconClick() { const [alias, color] = this._icon?.replace('color-', '')?.split(' ') ?? []; const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); + if (!modalManager) { + throw new Error('Modal manager not found.'); + } const modalContext = modalManager.open(this, UMB_ICON_PICKER_MODAL, { value: { icon: alias, diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/utils/is-current-user-an-admin.function.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/utils/is-current-user-an-admin.function.ts index c39d1392971a..a858fda128b4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/utils/is-current-user-an-admin.function.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/utils/is-current-user-an-admin.function.ts @@ -8,8 +8,8 @@ import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; */ export const isCurrentUserAnAdmin = async (host: UmbControllerHost) => { const ctrl = new UmbContextConsumerController(host, UMB_CURRENT_USER_CONTEXT); - const currentUserContext = await ctrl.asPromise(); + const currentUserContext = await ctrl.asPromise().catch(() => undefined); ctrl.destroy(); - return currentUserContext!.isCurrentUserAdmin(); + return currentUserContext?.isCurrentUserAdmin() ?? false; }; From 3cf5d7806cac47065047f13d5232405b144d445b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 7 Mar 2025 21:12:31 +0100 Subject: [PATCH 15/26] implementation adjustments --- .../block-type-custom-view-guide.element.ts | 9 ++-- .../collection-create-action.element.ts | 6 ++- .../entity-actions-bundle.element.ts | 6 ++- .../common/create/create.action.ts | 13 +++--- ...create-option-action-list-modal.element.ts | 8 +++- .../duplicate-to/duplicate-to.action.ts | 7 +-- .../common/move-to/move-to.action.ts | 7 +-- .../entity-bulk-action.element.ts | 6 ++- .../confirm/confirm-modal.controller.ts | 31 +++---------- .../core/modal/context/modal.context.ts | 12 ++--- .../packages/core/modal/controller/index.ts | 1 + .../modal/controller/open-modal.controller.ts | 45 +++++++++++++++++++ .../src/packages/core/modal/index.ts | 1 + .../peek-error-notification.element.ts | 3 ++ .../core/picker-input/picker-input.context.ts | 6 +-- .../restore-from-recycle-bin-modal.element.ts | 7 +-- .../restore-from-recycle-bin.action.ts | 9 ++-- .../rename/rename-server-file.action.ts | 41 ++++++++--------- .../duplicate-to/duplicate-to.action.ts | 38 +++++++--------- .../entity-actions/move/move-to.action.ts | 6 +-- .../create-folder/create-folder.action.ts | 10 ++--- .../update-folder/update-folder.action.ts | 10 ++--- .../entity-detail-workspace-base.ts | 8 ++-- .../data-type-create-options-modal.element.ts | 2 +- ...-blueprint-options-create-modal.element.ts | 2 +- ...ument-type-create-options-modal.element.ts | 2 +- .../entity-bulk-action/publish.bulk-action.ts | 3 ++ .../unpublish.bulk-action.ts | 3 ++ ...media-type-create-options-modal.element.ts | 2 +- ...rtial-view-create-options-modal.element.ts | 2 +- .../script-create-options-modal.element.ts | 2 +- ...stylesheet-create-options-modal.element.ts | 2 +- 32 files changed, 168 insertions(+), 142 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/modal/controller/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/modal/controller/open-modal.controller.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/block-type-custom-view-guide/block-type-custom-view-guide.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/block-type-custom-view-guide/block-type-custom-view-guide.element.ts index 923339fc7175..1bc04243f49b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/block-type-custom-view-guide/block-type-custom-view-guide.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/block-type-custom-view-guide/block-type-custom-view-guide.element.ts @@ -6,7 +6,7 @@ import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registr import { stringOrStringArrayContains } from '@umbraco-cms/backoffice/utils'; import { UmbExtensionsManifestInitializer } from '@umbraco-cms/backoffice/extension-api'; import { UmbDocumentTypeDetailRepository } from '@umbraco-cms/backoffice/document-type'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { UMB_MODAL_MANAGER_CONTEXT, umbOpenModal } from '@umbraco-cms/backoffice/modal'; import type { ManifestBlockEditorCustomView } from '@umbraco-cms/backoffice/block-custom-view'; @customElement('umb-block-type-custom-view-guide') @@ -82,13 +82,10 @@ export class UmbBlockTypeCustomViewGuideElement extends UmbLitElement { }; async #viewManifest(manifest: ManifestBlockEditorCustomView) { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - modalManager.open(this, UMB_MANIFEST_VIEWER_MODAL, { data: manifest }); + umbOpenModal(this, UMB_MANIFEST_VIEWER_MODAL, { data: manifest }); } async #generateManifest() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const manifest: UmbExtensionManifest = { type: 'blockEditorCustomView', alias: 'Local.blockEditorCustomView.' + this.#contentTypeAlias, @@ -97,7 +94,7 @@ export class UmbBlockTypeCustomViewGuideElement extends UmbLitElement { forContentTypeAlias: this.#contentTypeAlias, forBlockEditor: this.#blockEditorType, }; - modalManager.open(this, UMB_MANIFEST_VIEWER_MODAL, { data: manifest }); + umbOpenModal(this, UMB_MANIFEST_VIEWER_MODAL, { data: manifest }); } override render() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/collection/action/create/collection-create-action.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/collection/action/create/collection-create-action.element.ts index fd80de09a252..0b721ec903df 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/collection/action/create/collection-create-action.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/collection/action/create/collection-create-action.element.ts @@ -42,7 +42,11 @@ export class UmbCollectionCreateActionButtonElement extends UmbLitElement { } if (!controller.api) throw new Error('No API found'); - await controller.api.execute(); + try { + await controller.api.execute(); + } catch (error) { + return; + } } constructor() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/entity-actions-bundle/entity-actions-bundle.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/entity-actions-bundle/entity-actions-bundle.element.ts index b873cd777116..db1fe6c6c8f3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/entity-actions-bundle/entity-actions-bundle.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/entity-actions-bundle/entity-actions-bundle.element.ts @@ -104,7 +104,11 @@ export class UmbEntityActionsBundleElement extends UmbLitElement { } event.stopPropagation(); - await this._firstActionApi?.execute(); + try { + await this._firstActionApi?.execute(); + } catch (error) { + return; + } } #onActionExecuted() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/common/create/create.action.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/common/create/create.action.ts index 9d869b0b979f..8f893b31eab2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/common/create/create.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/common/create/create.action.ts @@ -2,7 +2,7 @@ import { UmbEntityActionBase } from '../../entity-action-base.js'; import type { UmbEntityActionArgs } from '../../types.js'; import type { MetaEntityActionCreateKind } from './types.js'; import { UMB_ENTITY_CREATE_OPTION_ACTION_LIST_MODAL } from './modal/constants.js'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; import { @@ -24,9 +24,9 @@ export class UmbCreateEntityAction extends UmbEntityActionBase) { super(host, args); - /* This is wrapped in a promise to confirm whether only one option exists and to ensure - that the API for this option has been created. We both need to wait for any options to - be returned from the registry and for the API to be created. This is a custom promise implementation, + /* This is wrapped in a promise to confirm whether only one option exists and to ensure + that the API for this option has been created. We both need to wait for any options to + be returned from the registry and for the API to be created. This is a custom promise implementation, because using .asPromise() on the initializer does not wait for the async API creation in the callback.*/ this.#optionsInit = new Promise((resolve) => { new UmbExtensionsManifestInitializer( @@ -61,15 +61,12 @@ export class UmbCreateEntityAction extends UmbEntityActionBase this.#onOpen(event, controller)} + @open=${async (event: Event) => await this.#onOpen(event, controller).catch(() => undefined)} @click=${(event: Event) => this.#onNavigate(event, href)}> `; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-bulk-action/common/duplicate-to/duplicate-to.action.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-bulk-action/common/duplicate-to/duplicate-to.action.ts index d865a1768888..3ed6feda549b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-bulk-action/common/duplicate-to/duplicate-to.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-bulk-action/common/duplicate-to/duplicate-to.action.ts @@ -7,7 +7,7 @@ import { } from '@umbraco-cms/backoffice/entity-action'; import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; import { UMB_ENTITY_CONTEXT } from '@umbraco-cms/backoffice/entity'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UMB_TREE_PICKER_MODAL } from '@umbraco-cms/backoffice/tree'; import type { MetaEntityBulkActionDuplicateToKind } from '@umbraco-cms/backoffice/extension-registry'; @@ -15,9 +15,7 @@ export class UmbMediaDuplicateEntityBulkAction extends UmbEntityBulkActionBase undefined); if (!value?.selection?.length) return; const destinationUnique = value.selection[0]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-bulk-action/common/move-to/move-to.action.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-bulk-action/common/move-to/move-to.action.ts index f248afe4e85f..38d6b6cf03fc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-bulk-action/common/move-to/move-to.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-bulk-action/common/move-to/move-to.action.ts @@ -7,7 +7,7 @@ import { } from '@umbraco-cms/backoffice/entity-action'; import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; import { UMB_ENTITY_CONTEXT } from '@umbraco-cms/backoffice/entity'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UMB_TREE_PICKER_MODAL } from '@umbraco-cms/backoffice/tree'; import type { MetaEntityBulkActionMoveToKind } from '@umbraco-cms/backoffice/extension-registry'; @@ -15,9 +15,7 @@ export class UmbMediaMoveEntityBulkAction extends UmbEntityBulkActionBase undefined); if (!value?.selection?.length) return; const destinationUnique = value.selection[0]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-bulk-action/entity-bulk-action.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-bulk-action/entity-bulk-action.element.ts index 0478595f71fd..7bbe79772b74 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-bulk-action/entity-bulk-action.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-bulk-action/entity-bulk-action.element.ts @@ -26,7 +26,11 @@ export class UmbEntityBulkActionDefaultElement< async #onClick(event: PointerEvent) { if (!this.api) return; event.stopPropagation(); - await this.api.execute(); + try { + await this.api.execute(); + } catch (error) { + return; + } this.dispatchEvent(new UmbActionExecutedEvent()); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/confirm/confirm-modal.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/confirm/confirm-modal.controller.ts index 8deb91202bac..e896fbfa5dfc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/confirm/confirm-modal.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/confirm/confirm-modal.controller.ts @@ -1,38 +1,19 @@ import { UMB_MODAL_MANAGER_CONTEXT } from '../../context/index.js'; +import { UmbOpenModalController } from '../../index.js'; import { UMB_CONFIRM_MODAL, type UmbConfirmModalData } from './confirm-modal.token.js'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +/** @deprecated use `UmbConfirmModalData`, will be removed in v.17 */ // eslint-disable-next-line @typescript-eslint/no-empty-object-type export interface UmbConfirmModalArgs extends UmbConfirmModalData {} -export class UmbConfirmModalController extends UmbControllerBase { - async open(args: UmbConfirmModalArgs): Promise { - const modalManagerContext = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - - const modalContext = modalManagerContext.open(this, UMB_CONFIRM_MODAL, { - data: args, - }); - - const p = modalContext.onSubmit(); - p.catch(() => { - this.destroy(); - }); - await p; - - // This is a one time off, so we can destroy our selfs. - this.destroy(); - - return; - } -} - /** * * @param host {UmbControllerHost} - The host controller - * @param args {UmbConfirmModalArgs} - The data to pass to the modal - * @returns {UmbConfirmModalController} The modal controller instance + * @param args {UmbConfirmModalData} - The data to pass to the modal + * @returns {UmbOpenModalController} The modal controller instance */ -export function umbConfirmModal(host: UmbControllerHost, args: UmbConfirmModalArgs) { - return new UmbConfirmModalController(host).open(args); +export function umbConfirmModal(host: UmbControllerHost, data: UmbConfirmModalData) { + return new UmbOpenModalController(host).open(UMB_CONFIRM_MODAL, { data }); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts index aa468f7dd60e..c8af3838dbc3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts @@ -116,7 +116,7 @@ export class UmbModalContext< async _internal_removeCurrentModal() { const routeContext = await this.getContext(UMB_ROUTE_CONTEXT); - routeContext._internal_removeModalPath(this.#activeModalPath); + routeContext?._internal_removeModalPath(this.#activeModalPath); } forceResolve() { @@ -151,8 +151,9 @@ export class UmbModalContext< this._internal_removeCurrentModal(); return; } - this.#submitResolver?.(this.getValue()); + const resolver = this.#submitResolver; this.#markAsResolved(); + resolver?.(this.getValue()); // TODO: Could we clean up this class here? (Example destroy the value state, and other things?) } @@ -171,8 +172,9 @@ export class UmbModalContext< this._internal_removeCurrentModal(); return; } - this.#submitRejecter?.(reason); + const resolver = this.#submitRejecter; this.#markAsResolved(); + resolver?.(reason); // TODO: Could we clean up this class here? (Example destroy the value state, and other things?) } @@ -182,8 +184,8 @@ export class UmbModalContext< * @public * @memberof UmbModalContext */ - public onSubmit() { - return this.#submitPromise; + public async onSubmit() { + return await this.#submitPromise; } /** diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/controller/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/controller/index.ts new file mode 100644 index 000000000000..c924e43b5c48 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/controller/index.ts @@ -0,0 +1 @@ +export * from './open-modal.controller.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/controller/open-modal.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/controller/open-modal.controller.ts new file mode 100644 index 000000000000..7cffdb71b984 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/controller/open-modal.controller.ts @@ -0,0 +1,45 @@ +import { UMB_MODAL_MANAGER_CONTEXT, type UmbModalContextClassArgs, type UmbModalRejectReason } from '../index.js'; +import type { UmbModalToken } from '../token/modal-token.js'; +import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; + +export class UmbOpenModalController extends UmbControllerBase { + async open< + ModalData extends { [key: string]: any } = { [key: string]: any }, + ModalValue = unknown, + ModalAliasTypeAsToken extends UmbModalToken = UmbModalToken, + >( + modalAlias: UmbModalToken | string, + args: UmbModalContextClassArgs = {}, + ): Promise { + const modalManagerContext = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); + if (!modalManagerContext) { + this.destroy(); + throw new Error('Modal manager not found.'); + } + + const modalContext = modalManagerContext.open(this, modalAlias, args); + + return await modalContext.onSubmit().finally(() => { + this.destroy(); + }); + } +} + +/** + * + * @param host {UmbControllerHost} - The host controller + * @param args {UmbConfirmModalArgs} - The data to pass to the modal + * @returns {UmbConfirmModalController} The modal controller instance + */ +export function umbOpenModal< + ModalData extends { [key: string]: any } = { [key: string]: any }, + ModalValue = unknown, + ModalAliasTypeAsToken extends UmbModalToken = UmbModalToken, +>( + host: UmbControllerHost, + modalAlias: UmbModalToken | string, + args: UmbModalContextClassArgs = {}, +): Promise { + return new UmbOpenModalController(host).open(modalAlias, args); +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/index.ts index 5403700cff98..128bf4886bae 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/index.ts @@ -1,6 +1,7 @@ import './component/modal.element.js'; export * from './common/index.js'; +export * from './controller/index.js'; export * from './component/modal-base.element.js'; export * from './component/modal.element.js'; export * from './context/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error-notification.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error-notification.element.ts index 30c920b6be85..768581b6b64b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error-notification.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error-notification.element.ts @@ -13,6 +13,9 @@ export class UmbPeekErrorNotificationElement extends UmbLitElement { async #onClick() { const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); + if (!modalManager) { + throw new Error('Modal manager not found.'); + } modalManager.open(this, UMB_ERROR_VIEWER_MODAL, { data: this.data?.details }); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts index 057ba23d72b9..535b109e5ecd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts @@ -2,7 +2,7 @@ import { UMB_PICKER_INPUT_CONTEXT } from './picker-input.context-token.js'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; import { UmbRepositoryItemsManager } from '@umbraco-cms/backoffice/repository'; -import { UMB_MODAL_MANAGER_CONTEXT, umbConfirmModal } from '@umbraco-cms/backoffice/modal'; +import { umbConfirmModal, umbOpenModal } from '@umbraco-cms/backoffice/modal'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { UmbItemRepository } from '@umbraco-cms/backoffice/repository'; import type { UmbModalToken, UmbPickerModalData, UmbPickerModalValue } from '@umbraco-cms/backoffice/modal'; @@ -91,8 +91,7 @@ export class UmbPickerInputContext< async openPicker(pickerData?: Partial) { await this.#itemManager.init; - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, this.modalAlias, { + const modalValue = await umbOpenModal(this, this.modalAlias, { data: { multiple: this._max === 1 ? false : true, ...pickerData, @@ -102,7 +101,6 @@ export class UmbPickerInputContext< } as PickerModalValueType, }); - const modalValue = await modalContext?.onSubmit(); this.setSelection(modalValue.selection); this.getHostElement().dispatchEvent(new UmbChangeEvent()); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/recycle-bin/entity-action/restore-from-recycle-bin/modal/restore-from-recycle-bin-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/recycle-bin/entity-action/restore-from-recycle-bin/modal/restore-from-recycle-bin-modal.element.ts index 7a398e57aae5..c299d944ad54 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/recycle-bin/entity-action/restore-from-recycle-bin/modal/restore-from-recycle-bin-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/recycle-bin/entity-action/restore-from-recycle-bin/modal/restore-from-recycle-bin-modal.element.ts @@ -6,7 +6,7 @@ import type { import type { PropertyValueMap } from '@umbraco-cms/backoffice/external/lit'; import { html, customElement, state, css } from '@umbraco-cms/backoffice/external/lit'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import { UMB_MODAL_MANAGER_CONTEXT, UmbModalBaseElement } from '@umbraco-cms/backoffice/modal'; +import { UmbModalBaseElement, umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { createExtensionApiByAlias } from '@umbraco-cms/backoffice/extension-registry'; import type { UmbItemRepository } from '@umbraco-cms/backoffice/repository'; @@ -102,15 +102,12 @@ export class UmbRestoreFromRecycleBinModalElement extends UmbModalBaseElement< async #onSelectCustomDestination() { if (!this.data?.pickerModal) throw new Error('Cannot select a destination without a picker modal.'); - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modal = modalManager.open(this, this.data.pickerModal, { + const { selection } = await umbOpenModal(this, this.data.pickerModal, { data: { multiple: false, }, }); - const { selection } = await modal.onSubmit(); - if (selection.length > 0) { const unique = selection[0]; this.setDestination(unique); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/recycle-bin/entity-action/restore-from-recycle-bin/restore-from-recycle-bin.action.ts b/src/Umbraco.Web.UI.Client/src/packages/core/recycle-bin/entity-action/restore-from-recycle-bin/restore-from-recycle-bin.action.ts index 30b218649d9d..cd8e4ac1b2fc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/recycle-bin/entity-action/restore-from-recycle-bin/restore-from-recycle-bin.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/recycle-bin/entity-action/restore-from-recycle-bin/restore-from-recycle-bin.action.ts @@ -1,6 +1,6 @@ import { UMB_RESTORE_FROM_RECYCLE_BIN_MODAL } from './modal/restore-from-recycle-bin-modal.token.js'; import type { MetaEntityActionRestoreFromRecycleBinKind } from './types.js'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UmbEntityActionBase, UmbRequestReloadStructureForEntityEvent } from '@umbraco-cms/backoffice/entity-action'; import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; @@ -17,8 +17,7 @@ export class UmbRestoreFromRecycleBinEntityAction extends UmbEntityActionBase { override async execute() { if (!this.args.unique) throw new Error('Unique is required to rename an entity'); - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_RENAME_SERVER_FILE_MODAL, { + const res = await umbOpenModal(this, UMB_RENAME_SERVER_FILE_MODAL, { data: { unique: this.args.unique, renameRepositoryAlias: this.args.meta.renameRepositoryAlias, @@ -18,29 +17,25 @@ export class UmbRenameEntityAction extends UmbEntityActionBase( - this, - this.args.meta.duplicateRepositoryAlias, - ); - if (!duplicateRepository) throw new Error('Duplicate repository is not available'); + const duplicateRepository = await createExtensionApiByAlias( + this, + this.args.meta.duplicateRepositoryAlias, + ); + if (!duplicateRepository) throw new Error('Duplicate repository is not available'); - const { error } = await duplicateRepository.requestDuplicateTo({ - unique: this.args.unique, - destination: { unique: destinationUnique }, - }); - - if (!error) { - this.#reloadMenu(); - } - } catch (error) { - console.error(error); + const { error } = await duplicateRepository.requestDuplicateTo({ + unique: this.args.unique, + destination: { unique: destinationUnique }, + }); + + if (!error) { + this.#reloadMenu(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/entity-actions/move/move-to.action.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/entity-actions/move/move-to.action.ts index e6921c7c196d..18d88190c200 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/entity-actions/move/move-to.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/entity-actions/move/move-to.action.ts @@ -1,7 +1,7 @@ import type { UmbMoveRepository } from './move-repository.interface.js'; import type { MetaEntityActionMoveToKind } from './types.js'; import { UmbEntityActionBase, UmbRequestReloadStructureForEntityEvent } from '@umbraco-cms/backoffice/entity-action'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { createExtensionApiByAlias } from '@umbraco-cms/backoffice/extension-registry'; import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; import { UMB_TREE_PICKER_MODAL } from '@umbraco-cms/backoffice/tree'; @@ -11,15 +11,13 @@ export class UmbMoveToEntityAction extends UmbEntityActionBase { override async execute() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_FOLDER_CREATE_MODAL, { + await umbOpenModal(this, UMB_FOLDER_CREATE_MODAL, { data: { folderRepositoryAlias: this.args.meta.folderRepositoryAlias, parent: { @@ -17,9 +16,10 @@ export class UmbCreateFolderEntityAction extends UmbEntityActionBase { override async execute() { if (!this.args.unique) throw new Error('Unique is not available'); - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_FOLDER_UPDATE_MODAL, { + await umbOpenModal(this, UMB_FOLDER_UPDATE_MODAL, { data: { folderRepositoryAlias: this.args.meta.folderRepositoryAlias, unique: this.args.unique, }, }); - await modalContext.onSubmit(); - const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!actionEventContext) { + throw new Error('Event context not found.'); + } const event = new UmbRequestReloadStructureForEntityEvent({ unique: this.args.unique, entityType: this.args.entityType, diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity-detail/entity-detail-workspace-base.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity-detail/entity-detail-workspace-base.ts index 643181df69d0..f4184909e358 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity-detail/entity-detail-workspace-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity-detail/entity-detail-workspace-base.ts @@ -4,7 +4,7 @@ import type { UmbEntityDetailWorkspaceContextArgs, UmbEntityDetailWorkspaceConte import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbEntityContext, type UmbEntityModel, type UmbEntityUnique } from '@umbraco-cms/backoffice/entity'; -import { UMB_DISCARD_CHANGES_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { UMB_DISCARD_CHANGES_MODAL, umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; import { UmbEntityUpdatedEvent, @@ -316,6 +316,7 @@ export abstract class UmbEntityDetailWorkspaceContextBase< this._data.setCurrent(data); const eventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!eventContext) throw new Error('Event context not found.'); const event = new UmbRequestReloadChildrenOfEntityEvent({ entityType: parent.entityType, unique: parent.unique, @@ -337,6 +338,7 @@ export abstract class UmbEntityDetailWorkspaceContextBase< const entityType = this.getEntityType(); const eventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!eventContext) throw new Error('Event context not found.'); const event = new UmbRequestReloadStructureForEntityEvent({ unique, entityType }); eventContext.dispatchEvent(event); @@ -372,12 +374,10 @@ export abstract class UmbEntityDetailWorkspaceContextBase< This push will make the "willchangestate" event happen again and due to this somewhat "backward" behavior, we set an "allowNavigateAway"-flag to prevent the "discard-changes" functionality from running in a loop.*/ e.preventDefault(); - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modal = modalManager.open(this, UMB_DISCARD_CHANGES_MODAL); try { // navigate to the new url when discarding changes - await modal.onSubmit(); + await umbOpenModal(this, UMB_DISCARD_CHANGES_MODAL); this.#allowNavigateAway = true; history.pushState({}, '', e.detail.url); return true; diff --git a/src/Umbraco.Web.UI.Client/src/packages/data-type/entity-actions/create/modal/data-type-create-options-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/data-type/entity-actions/create/modal/data-type-create-options-modal.element.ts index a06c637c938e..67019a67b1f2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/data-type/entity-actions/create/modal/data-type-create-options-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/data-type/entity-actions/create/modal/data-type-create-options-modal.element.ts @@ -55,7 +55,7 @@ export class UmbDataTypeCreateOptionsModalElement extends UmbModalBaseElement { async execute() { const entityContext = await this.getContext(UMB_ENTITY_CONTEXT); + if (!entityContext) { + throw new Error('Entity context not found'); + } const entityType = entityContext.getEntityType(); const unique = entityContext.getUnique(); diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/entity-bulk-action/unpublish.bulk-action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/entity-bulk-action/unpublish.bulk-action.ts index d817030e8818..ff96a480c806 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/entity-bulk-action/unpublish.bulk-action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/entity-bulk-action/unpublish.bulk-action.ts @@ -14,6 +14,9 @@ import { UmbRequestReloadChildrenOfEntityEvent } from '@umbraco-cms/backoffice/e export class UmbDocumentUnpublishEntityBulkAction extends UmbEntityBulkActionBase { async execute() { const entityContext = await this.getContext(UMB_ENTITY_CONTEXT); + if (!entityContext) { + throw new Error('Entity context not found'); + } const entityType = entityContext.getEntityType(); const unique = entityContext.getUnique(); diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/create/modal/media-type-create-options-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/create/modal/media-type-create-options-modal.element.ts index 345512da5931..fb0f8555e761 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/create/modal/media-type-create-options-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/create/modal/media-type-create-options-modal.element.ts @@ -45,7 +45,7 @@ export class UmbMediaTypeCreateOptionsModalElement extends UmbModalBaseElement Date: Sat, 8 Mar 2025 20:18:11 +0100 Subject: [PATCH 16/26] correction patch 2 --- .../stylesheet-rule-input.element.ts | 16 +++----- .../input-template/input-template.element.ts | 9 ++--- .../query-builder-modal.element.ts | 38 +++++++++---------- .../plugins/tiny-mce-code-editor.plugin.ts | 8 ++-- .../plugins/tiny-mce-embeddedmedia.plugin.ts | 10 ++--- .../embedded-media.tiptap-toolbar-api.ts | 8 +--- .../toolbar/link.tiptap-toolbar-api.ts | 11 ++---- .../source-editor.tiptap-toolbar-api.ts | 10 ++--- .../change-user-password.action.ts | 12 +++--- .../current-user-header-app.element.ts | 5 +-- .../user/current-user/current-user.context.ts | 3 ++ ...nfigure-external-login-providers-action.ts | 5 +-- .../modals/external-login-modal.element.ts | 3 ++ .../configure-mfa-providers-action.ts | 5 +-- .../current-user-mfa-modal.element.ts | 22 ++++------- .../change-password-current-user.action.ts | 6 +-- .../user-group-workspace-editor.element.ts | 21 +++++----- .../create/modal/create-user-modal.element.ts | 11 ++---- .../user-entity-create-option-action-base.ts | 12 ++---- .../entity-actions/mfa/mfa-user.action.ts | 18 +++------ .../disable/disable.action.ts | 2 + .../enable/enable.action.ts | 2 + .../unlock/unlock.action.ts | 2 + .../invite-user.collection-action.ts | 6 +-- .../invite/invite-user-entity-action.ts | 6 +-- .../resend-invite/resend-invite.action.ts | 7 +--- 26 files changed, 106 insertions(+), 152 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/global-components/stylesheet-rule-input/stylesheet-rule-input.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/global-components/stylesheet-rule-input/stylesheet-rule-input.element.ts index 103e7f7a1be5..1741e9f661df 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/global-components/stylesheet-rule-input/stylesheet-rule-input.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/global-components/stylesheet-rule-input/stylesheet-rule-input.element.ts @@ -4,7 +4,7 @@ import { css, html, customElement, repeat, property } from '@umbraco-cms/backoff import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui'; @customElement('umb-stylesheet-rule-input') @@ -29,17 +29,11 @@ export class UmbStylesheetRuleInputElement extends UUIFormControlMixin(UmbLitEle } async #openRuleSettings(rule: UmbStylesheetRule | null = null) { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - - const value = { - rule: rule ? { name: rule.name, selector: rule.selector, styles: rule.styles } : null, - }; - - const modalContext = modalManager.open(this, UMB_STYLESHEET_RULE_SETTINGS_MODAL, { - value, + return await umbOpenModal(this, UMB_STYLESHEET_RULE_SETTINGS_MODAL, { + value: { + rule: rule ? { name: rule.name, selector: rule.selector, styles: rule.styles } : null, + }, }); - - return modalContext?.onSubmit(); } #appendRule = () => { diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/global-components/input-template/input-template.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/global-components/input-template/input-template.element.ts index db6f6815d2a5..d28fe7333e22 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/global-components/input-template/input-template.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/global-components/input-template/input-template.element.ts @@ -5,7 +5,7 @@ import { UmbTemplateItemRepository } from '../../repository/item/index.js'; import { UMB_TEMPLATE_PICKER_MODAL } from '../../modals/index.js'; import { css, html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/workspace'; import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; @@ -124,15 +124,12 @@ export class UmbInputTemplateElement extends UUIFormControlMixin(UmbLitElement, } async #openPicker() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_TEMPLATE_PICKER_MODAL, { + const value = await umbOpenModal(this, UMB_TEMPLATE_PICKER_MODAL, { data: { multiple: true, pickableFilter: (template) => template.unique !== null && !this._selection.includes(template.unique), }, - }); - - const value = await modalContext?.onSubmit().catch(() => undefined); + }).catch(() => undefined); if (!value?.selection) return; diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/modals/query-builder/query-builder-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/modals/query-builder/query-builder-modal.element.ts index a3e286347147..e9144f14b08d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/modals/query-builder/query-builder-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/modals/query-builder/query-builder-modal.element.ts @@ -8,7 +8,7 @@ import type { } from './query-builder-modal.token.js'; import type { UUIComboboxListElement } from '@umbraco-cms/backoffice/external/uui'; import { css, html, customElement, state, query, queryAll, ifDefined } from '@umbraco-cms/backoffice/external/lit'; -import { UmbModalBaseElement, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { UmbModalBaseElement, UMB_MODAL_MANAGER_CONTEXT, umbOpenModal } from '@umbraco-cms/backoffice/modal'; import type { TemplateQueryResultResponseModel, TemplateQuerySettingsResponseModel, @@ -90,24 +90,24 @@ export default class UmbTemplateQueryBuilderModalElement extends UmbModalBaseEle }; async #openDocumentPicker() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - modalManager - .open(this, UMB_DOCUMENT_PICKER_MODAL, { data: { hideTreeRoot: true } }) - .onSubmit() - .then((result) => { - const selection = result.selection[0]; - this.#updateQueryRequest({ rootDocument: selection ? { unique: selection } : null }); - - if (result.selection.length > 0 && result.selection[0] === null) { - this._selectedRootContentName = 'all pages'; - return; - } - - if (result.selection.length > 0) { - this.#getDocumentItem(result.selection as string[]); - return; - } - }); + const result = await umbOpenModal(this, UMB_DOCUMENT_PICKER_MODAL, { data: { hideTreeRoot: true } }).catch( + () => undefined, + ); + + if (!result) return; + + const selection = result.selection[0]; + this.#updateQueryRequest({ rootDocument: selection ? { unique: selection } : null }); + + if (result.selection.length > 0 && result.selection[0] === null) { + this._selectedRootContentName = 'all pages'; + return; + } + + if (result.selection.length > 0) { + this.#getDocumentItem(result.selection as string[]); + return; + } } async #getDocumentItem(ids: string[]) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/plugins/tiny-mce-code-editor.plugin.ts b/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/plugins/tiny-mce-code-editor.plugin.ts index f524840f51b9..b6609ade8e8d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/plugins/tiny-mce-code-editor.plugin.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/plugins/tiny-mce-code-editor.plugin.ts @@ -1,7 +1,7 @@ import { type TinyMcePluginArguments, UmbTinyMcePluginBase } from '../components/input-tiny-mce/tiny-mce-plugin.js'; import { UmbLocalizationController } from '@umbraco-cms/backoffice/localization-api'; import { UMB_CODE_EDITOR_MODAL } from '@umbraco-cms/backoffice/code-editor'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; export default class UmbTinyMceCodeEditorPlugin extends UmbTinyMcePluginBase { constructor(args: TinyMcePluginArguments) { @@ -16,16 +16,14 @@ export default class UmbTinyMceCodeEditorPlugin extends UmbTinyMcePluginBase { } async #showCodeEditor() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modal = modalManager.open(this, UMB_CODE_EDITOR_MODAL, { + const value = await umbOpenModal(this, UMB_CODE_EDITOR_MODAL, { data: { headline: 'Edit source code', content: this.editor.getContent() ?? '', language: 'html', }, - }); + }).catch(() => undefined); - const value = await modal.onSubmit().catch(() => undefined); if (!value) { return; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/plugins/tiny-mce-embeddedmedia.plugin.ts b/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/plugins/tiny-mce-embeddedmedia.plugin.ts index e451c9d6d7f1..75e16fa29ac7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/plugins/tiny-mce-embeddedmedia.plugin.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tiny-mce/plugins/tiny-mce-embeddedmedia.plugin.ts @@ -1,7 +1,7 @@ import { type TinyMcePluginArguments, UmbTinyMcePluginBase } from '../components/input-tiny-mce/tiny-mce-plugin.js'; import { UmbLocalizationController } from '@umbraco-cms/backoffice/localization-api'; import type { UmbEmbeddedMediaModalData, UmbEmbeddedMediaModalValue } from '@umbraco-cms/backoffice/embedded-media'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UMB_EMBEDDED_MEDIA_MODAL } from '@umbraco-cms/backoffice/embedded-media'; export default class UmbTinyMceEmbeddedMediaPlugin extends UmbTinyMcePluginBase { @@ -76,12 +76,10 @@ export default class UmbTinyMceEmbeddedMediaPlugin extends UmbTinyMcePluginBase } async #showModal(selectedElm: HTMLElement, embeddedMediaModalData: UmbEmbeddedMediaModalData) { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalHandler = modalManager.open(this, UMB_EMBEDDED_MEDIA_MODAL, { data: embeddedMediaModalData }); - - if (!modalHandler) return; + const result = await umbOpenModal(this, UMB_EMBEDDED_MEDIA_MODAL, { data: embeddedMediaModalData }).catch( + () => undefined, + ); - const result = await modalHandler.onSubmit(); if (!result) return; this.#insertInEditor(result, selectedElm); diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/embedded-media.tiptap-toolbar-api.ts b/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/embedded-media.tiptap-toolbar-api.ts index b691bb7c7a7c..d3a5509ab887 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/embedded-media.tiptap-toolbar-api.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/embedded-media.tiptap-toolbar-api.ts @@ -1,7 +1,7 @@ import { UmbTiptapToolbarElementApiBase } from '../base.js'; import { umbEmbeddedMedia } from '@umbraco-cms/backoffice/external/tiptap'; import { UMB_EMBEDDED_MEDIA_MODAL } from '@umbraco-cms/backoffice/embedded-media'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import type { Editor } from '@umbraco-cms/backoffice/external/tiptap'; export default class UmbTiptapToolbarEmbeddedMediaExtensionApi extends UmbTiptapToolbarElementApiBase { @@ -21,12 +21,8 @@ export default class UmbTiptapToolbarEmbeddedMediaExtensionApi extends UmbTiptap data.url = attrs['data-embed-url']; } - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalHandler = modalManager.open(this, UMB_EMBEDDED_MEDIA_MODAL, { data }); + const result = await umbOpenModal(this, UMB_EMBEDDED_MEDIA_MODAL, { data }).catch(() => undefined); - if (!modalHandler) return; - - const result = await modalHandler.onSubmit().catch(() => undefined); if (!result) return; editor?.commands.setEmbeddedMedia({ diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/link.tiptap-toolbar-api.ts b/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/link.tiptap-toolbar-api.ts index 0761ee50afda..a369af6a0f82 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/link.tiptap-toolbar-api.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/link.tiptap-toolbar-api.ts @@ -1,7 +1,7 @@ import { UmbTiptapToolbarElementApiBase } from '../base.js'; import { UmbLink } from '@umbraco-cms/backoffice/external/tiptap'; import { UMB_LINK_PICKER_MODAL } from '@umbraco-cms/backoffice/multi-url-picker'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import type { Editor } from '@umbraco-cms/backoffice/external/tiptap'; import type { UmbLinkPickerLink } from '@umbraco-cms/backoffice/multi-url-picker'; import type { UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui'; @@ -15,12 +15,9 @@ export default class UmbTiptapToolbarLinkExtensionApi extends UmbTiptapToolbarEl const overlaySize = this.configuration?.getValueByAlias('overlaySize') ?? 'small'; - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalHandler = modalManager.open(this, UMB_LINK_PICKER_MODAL, { data, value, modal: { size: overlaySize } }); - - if (!modalHandler) return; - - const result = await modalHandler.onSubmit().catch(() => undefined); + const result = await umbOpenModal(this, UMB_LINK_PICKER_MODAL, { data, value, modal: { size: overlaySize } }).catch( + () => undefined, + ); if (!result?.link) return; const linkAttrs = this.#parseLinkData(result.link); diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/source-editor.tiptap-toolbar-api.ts b/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/source-editor.tiptap-toolbar-api.ts index 0125fff1b6bf..3d5593ab059f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/source-editor.tiptap-toolbar-api.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/source-editor.tiptap-toolbar-api.ts @@ -1,6 +1,6 @@ import { UmbTiptapToolbarElementApiBase } from '../base.js'; import { UMB_CODE_EDITOR_MODAL } from '@umbraco-cms/backoffice/code-editor'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import type { Editor } from '@umbraco-cms/backoffice/external/tiptap'; import { UmbLocalizationController } from '@umbraco-cms/backoffice/localization-api'; @@ -10,19 +10,15 @@ export default class UmbTiptapToolbarSourceEditorExtensionApi extends UmbTiptapT override async execute(editor?: Editor) { if (!editor) return; - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modal = modalManager.open(this, UMB_CODE_EDITOR_MODAL, { + const data = await umbOpenModal(this, UMB_CODE_EDITOR_MODAL, { data: { headline: this.#localize.term('tiptap_sourceCodeEdit'), content: editor?.getHTML() ?? '', language: 'html', formatOnLoad: true, }, - }); + }).catch(() => undefined); - if (!modal) return; - - const data = await modal.onSubmit().catch(() => undefined); if (!data) return; editor?.commands.setContent(data.content, true); diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/change-password/entity-action/change-user-password.action.ts b/src/Umbraco.Web.UI.Client/src/packages/user/change-password/entity-action/change-user-password.action.ts index 6e836d9bf8a2..21cd10b963fc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/change-password/entity-action/change-user-password.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/change-password/entity-action/change-user-password.action.ts @@ -3,7 +3,7 @@ import { UmbChangeUserPasswordRepository } from '@umbraco-cms/backoffice/user'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { UmbEntityActionArgs } from '@umbraco-cms/backoffice/entity-action'; import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UMB_CURRENT_USER_CONTEXT, UmbCurrentUserRepository } from '@umbraco-cms/backoffice/current-user'; export class UmbChangeUserPasswordEntityAction extends UmbEntityActionBase { @@ -14,18 +14,18 @@ export class UmbChangeUserPasswordEntityAction extends UmbEntityActionBase undefined); const currentUserContext = await this.getContext(UMB_CURRENT_USER_CONTEXT); + if (!currentUserContext) { + throw new Error('Current user context is not available'); + } const isCurrentUser = await currentUserContext.isUserCurrentUser(this.args.unique); if (isCurrentUser) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/current-user-header-app.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/current-user-header-app.element.ts index 362d2d1e37fa..259424cc21e1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/current-user-header-app.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/current-user-header-app.element.ts @@ -1,7 +1,7 @@ import { UMB_CURRENT_USER_MODAL } from './modals/current-user/current-user-modal.token.js'; import type { CSSResultGroup } from '@umbraco-cms/backoffice/external/lit'; import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UMB_CURRENT_USER_CONTEXT, type UmbCurrentUserModel } from '@umbraco-cms/backoffice/current-user'; import { UmbHeaderAppButtonElement } from '@umbraco-cms/backoffice/components'; @@ -34,8 +34,7 @@ export class UmbCurrentUserHeaderAppElement extends UmbHeaderAppButtonElement { } async #handleUserClick() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - modalManager.open(this, UMB_CURRENT_USER_MODAL); + await umbOpenModal(this, UMB_CURRENT_USER_MODAL).catch(() => undefined); } override render() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/current-user.context.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/current-user.context.ts index 96c00fc17f7f..cdc944c907f5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/current-user.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/current-user.context.ts @@ -233,6 +233,9 @@ export class UmbCurrentUserContext extends UmbContextBase const url = new URL(window.location.href); const appContext = await this.getContext(UMB_APP_CONTEXT); + if (!appContext) { + throw new Error('App context not available'); + } const backofficePath = appContext.getBackofficePath(); if (url.pathname === backofficePath || url.pathname === ensurePathEndsWithSlash(backofficePath)) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/external-login/configure-external-login-providers-action.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/external-login/configure-external-login-providers-action.ts index 379f4e0a3b4a..b2cac5832e88 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/external-login/configure-external-login-providers-action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/external-login/configure-external-login-providers-action.ts @@ -1,7 +1,7 @@ import type { UmbCurrentUserAction, UmbCurrentUserActionArgs } from '../current-user-action.extension.js'; import { UMB_CURRENT_USER_EXTERNAL_LOGIN_MODAL } from './modals/external-login-modal.token.js'; import { UmbActionBase } from '@umbraco-cms/backoffice/action'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; export class UmbConfigureExternalLoginProvidersApi extends UmbActionBase> @@ -12,8 +12,7 @@ export class UmbConfigureExternalLoginProvidersApi } async execute() { - const modalManagerContext = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - await modalManagerContext.open(this, UMB_CURRENT_USER_EXTERNAL_LOGIN_MODAL).onSubmit(); + await umbOpenModal(this, UMB_CURRENT_USER_EXTERNAL_LOGIN_MODAL); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/external-login/modals/external-login-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/external-login/modals/external-login-modal.element.ts index a6c7cf07c91b..0048bb58e432 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/external-login/modals/external-login-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/external-login/modals/external-login-modal.element.ts @@ -168,6 +168,9 @@ export class UmbCurrentUserExternalLoginModalElement extends UmbLitElement { color: 'positive', }); const authContext = await this.getContext(UMB_AUTH_CONTEXT); + if (!authContext) { + throw new Error('Auth context is missing'); + } await authContext.linkLogin(item.providerSchemeName); } catch (error) { if (error instanceof Error) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/mfa-login/configure-mfa-providers-action.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/mfa-login/configure-mfa-providers-action.ts index e7a923d3b57d..993a4d823827 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/mfa-login/configure-mfa-providers-action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/mfa-login/configure-mfa-providers-action.ts @@ -1,7 +1,7 @@ import { UMB_CURRENT_USER_MFA_MODAL } from '../modals/current-user-mfa/current-user-mfa-modal.token.js'; import type { UmbCurrentUserAction, UmbCurrentUserActionArgs } from '../current-user-action.extension.js'; import { UmbActionBase } from '@umbraco-cms/backoffice/action'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; export class UmbConfigureMfaProvidersApi extends UmbActionBase> @@ -12,8 +12,7 @@ export class UmbConfigureMfaProvidersApi } async execute() { - const modalManagerContext = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - await modalManagerContext.open(this, UMB_CURRENT_USER_MFA_MODAL).onSubmit(); + await umbOpenModal(this, UMB_CURRENT_USER_MFA_MODAL); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/modals/current-user-mfa/current-user-mfa-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/modals/current-user-mfa/current-user-mfa-modal.element.ts index 5dc7fd0d0076..7c7fa88ced0e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/modals/current-user-mfa/current-user-mfa-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/modals/current-user-mfa/current-user-mfa-modal.element.ts @@ -4,7 +4,7 @@ import { UMB_CURRENT_USER_MFA_DISABLE_PROVIDER_MODAL } from '../current-user-mfa import type { UmbCurrentUserMfaProviderModel } from '../../types.js'; import { css, customElement, html, nothing, property, repeat, state, when } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; -import { UMB_MODAL_MANAGER_CONTEXT, type UmbModalContext } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal, type UmbModalContext } from '@umbraco-cms/backoffice/modal'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; import { mergeObservables } from '@umbraco-cms/backoffice/observable-api'; @@ -141,13 +141,9 @@ export class UmbCurrentUserMfaModalElement extends UmbLitElement { * @param item */ async #onProviderEnable(item: UmbMfaLoginProviderOption) { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - await modalManager - .open(this, UMB_CURRENT_USER_MFA_ENABLE_PROVIDER_MODAL, { - data: { providerName: item.providerName, displayName: item.displayName }, - }) - .onSubmit() - .catch(() => undefined); + await umbOpenModal(this, UMB_CURRENT_USER_MFA_ENABLE_PROVIDER_MODAL, { + data: { providerName: item.providerName, displayName: item.displayName }, + }).catch(() => undefined); } /** @@ -157,13 +153,9 @@ export class UmbCurrentUserMfaModalElement extends UmbLitElement { * @param item */ async #onProviderDisable(item: UmbMfaLoginProviderOption) { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - await modalManager - .open(this, UMB_CURRENT_USER_MFA_DISABLE_PROVIDER_MODAL, { - data: { providerName: item.providerName, displayName: item.displayName }, - }) - .onSubmit() - .catch(() => undefined); + await umbOpenModal(this, UMB_CURRENT_USER_MFA_DISABLE_PROVIDER_MODAL, { + data: { providerName: item.providerName, displayName: item.displayName }, + }).catch(() => undefined); } static override readonly styles = [ diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/profile/change-password-current-user.action.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/profile/change-password-current-user.action.ts index 6b830126fdc5..cdbda6f4c5b3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/profile/change-password-current-user.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/profile/change-password-current-user.action.ts @@ -3,7 +3,7 @@ import { UmbCurrentUserRepository } from '../repository/index.js'; import type { UmbCurrentUserAction, UmbCurrentUserActionArgs } from '../current-user-action.extension.js'; import { UmbActionBase } from '@umbraco-cms/backoffice/action'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UMB_CHANGE_PASSWORD_MODAL } from '@umbraco-cms/backoffice/user-change-password'; export class UmbChangePasswordCurrentUserAction extends UmbActionBase> @@ -32,8 +32,7 @@ export class UmbChangePasswordCurrentUserAction async execute() { if (!this.#unique) return; - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_CHANGE_PASSWORD_MODAL, { + const data = await umbOpenModal(this, UMB_CHANGE_PASSWORD_MODAL, { data: { user: { unique: this.#unique, @@ -41,7 +40,6 @@ export class UmbChangePasswordCurrentUserAction }, }); - const data = await modalContext.onSubmit(); const repository = new UmbCurrentUserRepository(this); await repository.changePassword(data.newPassword, data.oldPassword); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/user-group-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/user-group-workspace-editor.element.ts index e44a4a6a7cb1..b8a7de7a9af8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/user-group-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/user-group-workspace-editor.element.ts @@ -9,7 +9,7 @@ import type { UmbInputDocumentElement } from '@umbraco-cms/backoffice/document'; import type { UmbInputSectionElement } from '@umbraco-cms/backoffice/section'; import type { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import type { UmbInputMediaElement } from '@umbraco-cms/backoffice/media'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import type { UmbInputLanguageElement } from '@umbraco-cms/backoffice/language'; import { UMB_ICON_PICKER_MODAL } from '@umbraco-cms/backoffice/icon'; import type { UmbInputWithAliasElement } from '@umbraco-cms/backoffice/components'; @@ -177,21 +177,20 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { async #onIconClick() { const [alias, color] = this._icon?.replace('color-', '')?.split(' ') ?? []; - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_ICON_PICKER_MODAL, { + const result = await umbOpenModal(this, UMB_ICON_PICKER_MODAL, { value: { icon: alias, color: color, }, - }); + }).catch(() => undefined); - modalContext?.onSubmit().then((saved) => { - if (saved.icon && saved.color) { - this.#workspaceContext?.updateProperty('icon', `${saved.icon} color-${saved.color}`); - } else if (saved.icon) { - this.#workspaceContext?.updateProperty('icon', saved.icon); - } - }); + if (!result) return; + + if (result.icon && result.color) { + this.#workspaceContext?.updateProperty('icon', `${result.icon} color-${result.color}`); + } else if (result.icon) { + this.#workspaceContext?.updateProperty('icon', result.icon); + } } #onNameAndAliasChange(event: InputEvent & { target: UmbInputWithAliasElement }) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/create-user-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/create-user-modal.element.ts index cea24184d8a3..25154c920959 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/create-user-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/create-user-modal.element.ts @@ -4,6 +4,7 @@ import { UMB_CREATE_USER_SUCCESS_MODAL } from './create-user-success-modal.token import type { UmbCreateUserModalData } from './create-user-modal.token.js'; import type { UmbUserGroupInputElement } from '@umbraco-cms/backoffice/user-group'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { css, html, customElement, query } from '@umbraco-cms/backoffice/external/lit'; import { UmbModalBaseElement, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; import type { UmbReferenceByUnique } from '@umbraco-cms/backoffice/models'; @@ -56,21 +57,17 @@ export class UmbCreateUserModalElement extends UmbModalBaseElement { this._submitModal(); }) - .catch((reason) => { + .catch((reason: any) => { if (reason?.type === 'createAnotherUser') { this._form?.reset(); } else { diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/user-entity-create-option-action-base.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/user-entity-create-option-action-base.ts index ca55652d5acd..7b493db7f0ba 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/user-entity-create-option-action-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/user-entity-create-option-action-base.ts @@ -8,7 +8,7 @@ import { type MetaEntityCreateOptionAction, type UmbEntityCreateOptionActionArgs, } from '@umbraco-cms/backoffice/entity-create-option-action'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; export interface UmbUserEntityCreateOptionActionBaseArgs extends UmbEntityCreateOptionActionArgs { @@ -24,18 +24,13 @@ export abstract class UmbUserEntityCreateOptionActionBase extends UmbEntityCreat } override async execute() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - - const modalContext = modalManager.open(this, UMB_CREATE_USER_MODAL, { + await umbOpenModal(this, UMB_CREATE_USER_MODAL, { data: { user: { kind: this.#kind, }, }, - }); - - await modalContext - ?.onSubmit() + }) .then(() => { this.#requestReloadChildrenOfEntity(); }) @@ -48,6 +43,7 @@ export abstract class UmbUserEntityCreateOptionActionBase extends UmbEntityCreat async #requestReloadChildrenOfEntity() { const eventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!eventContext) throw new Error('Event context not found'); const event = new UmbRequestReloadChildrenOfEntityEvent({ entityType: this.args.entityType, unique: this.args.unique, diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/mfa/mfa-user.action.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/mfa/mfa-user.action.ts index a6bdc5f5f0b2..daf2c8cdffb4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/mfa/mfa-user.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/mfa/mfa-user.action.ts @@ -5,7 +5,7 @@ import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UMB_CURRENT_USER_CONTEXT } from '@umbraco-cms/backoffice/current-user'; import { firstValueFrom } from '@umbraco-cms/backoffice/external/rxjs'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; export class UmbMfaUserEntityAction extends UmbEntityActionBase { constructor(host: UmbControllerHost, args: UmbEntityActionArgs) { @@ -17,27 +17,21 @@ export class UmbMfaUserEntityAction extends UmbEntityActionBase { if (!unique) throw new Error('Unique is not available'); const currentUserContext = await this.getContext(UMB_CURRENT_USER_CONTEXT); + if (!currentUserContext) throw new Error('Current user context not found'); const currentUserModel = await firstValueFrom(currentUserContext.currentUser); if (!currentUserModel) throw new Error('Current user is not available'); // If you clicked on yourself, we can just use the current user modal - const modalManagerContext = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); if (currentUserModel.unique === unique) { - await modalManagerContext - .open(this, UMB_CURRENT_USER_MFA_MODAL) - .onSubmit() - .catch(() => undefined); + await umbOpenModal(this, UMB_CURRENT_USER_MFA_MODAL).catch(() => undefined); return; } // Otherwise we will show the generic mfa modal - await modalManagerContext - .open(this, UMB_USER_MFA_MODAL, { - data: { unique }, - }) - .onSubmit() - .catch(() => undefined); + await umbOpenModal(this, UMB_USER_MFA_MODAL, { + data: { unique }, + }).catch(() => undefined); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-bulk-actions/disable/disable.action.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-bulk-actions/disable/disable.action.ts index 44ee673a7717..354a69f8187f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-bulk-actions/disable/disable.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-bulk-actions/disable/disable.action.ts @@ -10,6 +10,7 @@ export class UmbDisableUserEntityBulkAction extends UmbEntityBulkActionBase { override async execute() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_INVITE_USER_MODAL); - await modalContext?.onSubmit(); + await umbOpenModal(this, UMB_INVITE_USER_MODAL); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/resend-invite/resend-invite.action.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/resend-invite/resend-invite.action.ts index 53fc3ae5fa67..c52108ded8a1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/resend-invite/resend-invite.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/resend-invite/resend-invite.action.ts @@ -3,7 +3,7 @@ import { UMB_RESEND_INVITE_TO_USER_MODAL } from '../../index.js'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { UmbEntityActionArgs } from '@umbraco-cms/backoffice/entity-action'; import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; export class UmbResendInviteToUserEntityAction extends UmbEntityActionBase { constructor(host: UmbControllerHost, args: UmbEntityActionArgs) { @@ -13,16 +13,13 @@ export class UmbResendInviteToUserEntityAction extends UmbEntityActionBase Date: Sun, 9 Mar 2025 20:37:37 +0100 Subject: [PATCH 17/26] correction patch 3 --- .../common/delete/delete.action.ts | 3 + .../entity-bulk-action/publish.bulk-action.ts | 45 ++++++----- .../save-and-publish.action.ts | 6 ++ .../save-and-schedule.action.ts | 3 + .../entity-action/unpublish.action.ts | 31 ++++---- .../unpublish.bulk-action.ts | 38 +++++----- .../modal/document-unpublish-modal.element.ts | 3 + .../workspace-action/unpublish.action.ts | 3 + .../document-publishing.workspace-context.ts | 76 +++++++++---------- .../rollback/entity-action/rollback.action.ts | 10 +-- .../rollback/modal/rollback-modal.element.ts | 3 + .../actions/save-and-preview.action.ts | 3 + .../workspace/document-workspace.context.ts | 3 + .../document-workspace-view-info.element.ts | 9 +-- .../unregister/unregister-extension.action.ts | 3 + .../log-viewer-search-input.element.ts | 20 ++--- .../input-markdown.element.ts | 48 +++++------- .../media-type-duplicate.repository.ts | 3 + .../media-type-export.repository.ts | 3 + .../import/media-type-import.action.ts | 11 +-- .../media-type-import.repository.ts | 3 + .../repository/media-type-move.repository.ts | 3 + .../collection/media-collection.element.ts | 3 + .../media/dropzone/dropzone-manager.class.ts | 8 +- .../entity-actions/create/create.action.ts | 7 +- .../repository/media-move.repository.ts | 3 + .../member-type-duplicate.repository.ts | 3 + .../entity-actions/create/create.action.ts | 6 +- .../tiny-mce-multi-url-picker.plugin.ts | 10 +-- .../layout/layout-configuration.element.ts | 7 +- .../property-editor-ui-icon-picker.element.ts | 7 +- .../bulk-delete-with-relation.action.ts | 8 +- .../bulk-trash-with-relation.action.ts | 8 +- .../delete/delete-with-relation.action.ts | 8 +- .../trash/trash-with-relation.action.ts | 8 +- .../views/section-view-examine-searchers.ts | 17 ++--- .../search/umb-search-header-app.element.ts | 5 +- .../sysinfo/repository/sysinfo.repository.ts | 4 + .../entity-actions/create/create.action.ts | 13 +--- ...rtial-view-create-options-modal.element.ts | 17 ++--- .../entity-actions/create/create.action.ts | 13 +--- .../entity-actions/create/create.action.ts | 7 +- .../change-user-password.action.ts | 1 + .../modals/external-login-modal.element.ts | 3 + 44 files changed, 238 insertions(+), 258 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/common/delete/delete.action.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/common/delete/delete.action.ts index 4fa014b07371..50186d74d75c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/common/delete/delete.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/common/delete/delete.action.ts @@ -60,6 +60,9 @@ export class UmbDeleteEntityAction< async #notify() { const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!actionEventContext) { + throw new Error('Action event context not found.'); + } const event = new UmbRequestReloadStructureForEntityEvent({ unique: this.args.unique, diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish/entity-bulk-action/publish.bulk-action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish/entity-bulk-action/publish.bulk-action.ts index 64a3db0e243f..5f9499f8e2c0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish/entity-bulk-action/publish.bulk-action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish/entity-bulk-action/publish.bulk-action.ts @@ -6,7 +6,7 @@ import { UmbPublishDocumentEntityAction } from '../entity-action/index.js'; import { UmbEntityBulkActionBase } from '@umbraco-cms/backoffice/entity-bulk-action'; import { UMB_APP_LANGUAGE_CONTEXT, UmbLanguageCollectionRepository } from '@umbraco-cms/backoffice/language'; import { UmbVariantId } from '@umbraco-cms/backoffice/variant'; -import { UMB_CONFIRM_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbConfirmModal, umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UmbLocalizationController } from '@umbraco-cms/backoffice/localization-api'; import { UMB_ENTITY_CONTEXT } from '@umbraco-cms/backoffice/entity'; import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; @@ -23,6 +23,9 @@ export class UmbDocumentPublishEntityBulkAction extends UmbEntityBulkActionBase< const unique = entityContext.getUnique(); const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); + if (!notificationContext) { + throw new Error('Notification context not found'); + } const localize = new UmbLocalizationController(this); if (!entityType) throw new Error('Entity type not found'); @@ -60,9 +63,10 @@ export class UmbDocumentPublishEntityBulkAction extends UmbEntityBulkActionBase< segment: null, })); - const modalManagerContext = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const eventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!eventContext) { + throw new Error('Event context not found'); + } const event = new UmbRequestReloadChildrenOfEntityEvent({ entityType, unique, @@ -71,17 +75,12 @@ export class UmbDocumentPublishEntityBulkAction extends UmbEntityBulkActionBase< // If there is only one language available, we can skip the modal and publish directly: if (options.length === 1) { const localizationController = new UmbLocalizationController(this._host); - const confirm = await modalManagerContext - .open(this, UMB_CONFIRM_MODAL, { - data: { - headline: localizationController.term('content_readyToPublish'), - content: localizationController.term('prompt_confirmListViewPublish'), - color: 'positive', - confirmLabel: localizationController.term('actions_publish'), - }, - }) - .onSubmit() - .catch(() => false); + const confirm = await umbConfirmModal(this, { + headline: localizationController.term('content_readyToPublish'), + content: localizationController.term('prompt_confirmListViewPublish'), + color: 'positive', + confirmLabel: localizationController.term('actions_publish'), + }).catch(() => false); if (confirm !== false) { const variantId = new UmbVariantId(options[0].language.unique, null); @@ -113,21 +112,21 @@ export class UmbDocumentPublishEntityBulkAction extends UmbEntityBulkActionBase< // TODO: Missing features to pre-select the variant that fits with the variant-id of the tree/collection? (Again only relevant if the action is executed from a Tree or Collection) [NL] const selection: Array = []; const context = await this.getContext(UMB_APP_LANGUAGE_CONTEXT); + if (!context) { + throw new Error('App language context not found'); + } const appCulture = context.getAppCulture(); // If the app language is one of the options, select it by default: if (appCulture && options.some((o) => o.unique === appCulture)) { selection.push(new UmbVariantId(appCulture, null).toString()); } - const result = await modalManagerContext - .open(this, UMB_DOCUMENT_PUBLISH_MODAL, { - data: { - options, - }, - value: { selection }, - }) - .onSubmit() - .catch(() => undefined); + const result = await umbOpenModal(this, UMB_DOCUMENT_PUBLISH_MODAL, { + data: { + options, + }, + value: { selection }, + }).catch(() => undefined); if (!result?.selection.length) return; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish/workspace-action/save-and-publish.action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish/workspace-action/save-and-publish.action.ts index 142e5393a5ad..ae617ef3785c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish/workspace-action/save-and-publish.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish/workspace-action/save-and-publish.action.ts @@ -34,12 +34,18 @@ export class UmbDocumentSaveAndPublishWorkspaceAction extends UmbWorkspaceAction async hasAdditionalOptions() { const workspaceContext = await this.getContext(UMB_DOCUMENT_WORKSPACE_CONTEXT); + if (!workspaceContext) { + throw new Error('The workspace context is missing'); + } const variantOptions = await this.observe(workspaceContext.variantOptions).asPromise(); return variantOptions?.length > 1; } override async execute() { const workspaceContext = await this.getContext(UMB_DOCUMENT_PUBLISHING_WORKSPACE_CONTEXT); + if (!workspaceContext) { + throw new Error('The workspace context is missing'); + } return workspaceContext.saveAndPublish(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/schedule-publish/workspace-action/save-and-schedule.action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/schedule-publish/workspace-action/save-and-schedule.action.ts index 14cec080ef5a..38a5c822e624 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/schedule-publish/workspace-action/save-and-schedule.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/schedule-publish/workspace-action/save-and-schedule.action.ts @@ -4,6 +4,9 @@ import { UmbWorkspaceActionBase } from '@umbraco-cms/backoffice/workspace'; export class UmbDocumentSaveAndScheduleWorkspaceAction extends UmbWorkspaceActionBase { override async execute() { const workspaceContext = await this.getContext(UMB_DOCUMENT_PUBLISHING_WORKSPACE_CONTEXT); + if (!workspaceContext) { + throw new Error('Publishing workspace context not found'); + } return workspaceContext.schedule(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/entity-action/unpublish.action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/entity-action/unpublish.action.ts index 5aa6e4125d15..cbce845f5993 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/entity-action/unpublish.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/entity-action/unpublish.action.ts @@ -10,7 +10,7 @@ import { } from '@umbraco-cms/backoffice/entity-action'; import { UmbVariantId } from '@umbraco-cms/backoffice/variant'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; import { UMB_CURRENT_USER_CONTEXT } from '@umbraco-cms/backoffice/current-user'; @@ -31,9 +31,11 @@ export class UmbUnpublishDocumentEntityAction extends UmbEntityActionBase if (!documentData) throw new Error('The document was not found'); const appLanguageContext = await this.getContext(UMB_APP_LANGUAGE_CONTEXT); + if (!appLanguageContext) throw new Error('The app language context is missing'); const appCulture = appLanguageContext.getAppCulture(); const currentUserContext = await this.getContext(UMB_CURRENT_USER_CONTEXT); + if (!currentUserContext) throw new Error('The current user context is missing'); const currentUserAllowedLanguages = currentUserContext.getLanguages(); const currentUserHasAccessToAllLanguages = currentUserContext.getHasAccessToAllLanguages(); @@ -69,22 +71,18 @@ export class UmbUnpublishDocumentEntityAction extends UmbEntityActionBase selection.push(options[0].unique); } - const modalManagerContext = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const result = await modalManagerContext - .open(this, UMB_DOCUMENT_UNPUBLISH_MODAL, { - data: { - documentUnique: this.args.unique, - options, - pickableFilter: (option) => { - if (!option.culture) return false; - if (currentUserHasAccessToAllLanguages) return true; - return currentUserAllowedLanguages.includes(option.culture); - }, + const result = await umbOpenModal(this, UMB_DOCUMENT_UNPUBLISH_MODAL, { + data: { + documentUnique: this.args.unique, + options, + pickableFilter: (option) => { + if (!option.culture) return false; + if (currentUserHasAccessToAllLanguages) return true; + return currentUserAllowedLanguages.includes(option.culture); }, - value: { selection }, - }) - .onSubmit() - .catch(() => undefined); + }, + value: { selection }, + }).catch(() => undefined); if (!result?.selection.length) return; @@ -96,6 +94,7 @@ export class UmbUnpublishDocumentEntityAction extends UmbEntityActionBase if (!error) { const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!actionEventContext) throw new Error('The action event context is missing'); const event = new UmbRequestReloadStructureForEntityEvent({ unique: this.args.unique, entityType: this.args.entityType, diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/entity-bulk-action/unpublish.bulk-action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/entity-bulk-action/unpublish.bulk-action.ts index ff96a480c806..ee369add5aad 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/entity-bulk-action/unpublish.bulk-action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/entity-bulk-action/unpublish.bulk-action.ts @@ -2,7 +2,7 @@ import { UmbUnpublishDocumentEntityAction } from '../entity-action/index.js'; import type { UmbDocumentVariantOptionModel } from '../../../types.js'; import { UMB_DOCUMENT_ENTITY_TYPE, UMB_DOCUMENT_UNPUBLISH_MODAL } from '../../../constants.js'; import { UmbDocumentPublishingRepository } from '../../repository/index.js'; -import { UMB_CONFIRM_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { UMB_MODAL_MANAGER_CONTEXT, umbConfirmModal, umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UmbEntityBulkActionBase } from '@umbraco-cms/backoffice/entity-bulk-action'; import { UMB_APP_LANGUAGE_CONTEXT, UmbLanguageCollectionRepository } from '@umbraco-cms/backoffice/language'; import { UmbVariantId } from '@umbraco-cms/backoffice/variant'; @@ -58,6 +58,9 @@ export class UmbDocumentUnpublishEntityBulkAction extends UmbEntityBulkActionBas const modalManagerContext = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); const eventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!eventContext) { + throw new Error('Event context not found'); + } const event = new UmbRequestReloadChildrenOfEntityEvent({ entityType, unique, @@ -66,17 +69,12 @@ export class UmbDocumentUnpublishEntityBulkAction extends UmbEntityBulkActionBas // If there is only one language available, we can skip the modal and unpublish directly: if (options.length === 1) { const localizationController = new UmbLocalizationController(this._host); - const confirm = await modalManagerContext - .open(this, UMB_CONFIRM_MODAL, { - data: { - headline: localizationController.term('actions_unpublish'), - content: localizationController.term('prompt_confirmListViewUnpublish'), - color: 'warning', - confirmLabel: localizationController.term('actions_unpublish'), - }, - }) - .onSubmit() - .catch(() => false); + const confirm = await umbConfirmModal(this, { + headline: localizationController.term('actions_unpublish'), + content: localizationController.term('prompt_confirmListViewUnpublish'), + color: 'warning', + confirmLabel: localizationController.term('actions_unpublish'), + }).catch(() => false); if (confirm !== false) { const variantId = new UmbVariantId(options[0].language.unique, null); @@ -95,21 +93,19 @@ export class UmbDocumentUnpublishEntityBulkAction extends UmbEntityBulkActionBas // TODO: Missing features to pre-select the variant that fits with the variant-id of the tree/collection? (Again only relevant if the action is executed from a Tree or Collection) [NL] const selection: Array = []; const context = await this.getContext(UMB_APP_LANGUAGE_CONTEXT); + if (!context) throw new Error('App language context not found'); const appCulture = context.getAppCulture(); // If the app language is one of the options, select it by default: if (appCulture && options.some((o) => o.unique === appCulture)) { selection.push(new UmbVariantId(appCulture, null).toString()); } - const result = await modalManagerContext - .open(this, UMB_DOCUMENT_UNPUBLISH_MODAL, { - data: { - options, - }, - value: { selection }, - }) - .onSubmit() - .catch(() => undefined); + const result = await umbOpenModal(this, UMB_DOCUMENT_UNPUBLISH_MODAL, { + data: { + options, + }, + value: { selection }, + }).catch(() => undefined); if (!result?.selection.length) return; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/modal/document-unpublish-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/modal/document-unpublish-modal.element.ts index 359eac8ab445..72e7de20b869 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/modal/document-unpublish-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/modal/document-unpublish-modal.element.ts @@ -120,6 +120,9 @@ export class UmbDocumentUnpublishModalElement extends UmbModalBaseElement< // If there are references, we also want to check if we are allowed to unpublish the document: if (this._hasReferences) { const documentConfigurationContext = await this.getContext(UMB_DOCUMENT_CONFIGURATION_CONTEXT); + if (!documentConfigurationContext) { + throw new Error('Document configuration context not found'); + } this._hasUnpublishPermission = (await documentConfigurationContext.getDocumentConfiguration())?.disableUnpublishWhenReferenced === false; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/workspace-action/unpublish.action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/workspace-action/unpublish.action.ts index 319d2fa2b612..3c94159db97f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/workspace-action/unpublish.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/workspace-action/unpublish.action.ts @@ -4,6 +4,9 @@ import { UmbWorkspaceActionBase } from '@umbraco-cms/backoffice/workspace'; export class UmbDocumentUnpublishWorkspaceAction extends UmbWorkspaceActionBase { override async execute() { const workspaceContext = await this.getContext(UMB_DOCUMENT_PUBLISHING_WORKSPACE_CONTEXT); + if (!workspaceContext) { + throw new Error('Publishing workspace context not found'); + } return workspaceContext.unpublish(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/workspace-context/document-publishing.workspace-context.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/workspace-context/document-publishing.workspace-context.ts index 2d2c9940bfb7..427426dcd510 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/workspace-context/document-publishing.workspace-context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/workspace-context/document-publishing.workspace-context.ts @@ -13,7 +13,7 @@ import { UmbUnpublishDocumentEntityAction } from '../unpublish/index.js'; import { UMB_DOCUMENT_PUBLISHING_WORKSPACE_CONTEXT } from './document-publishing.workspace-context.token.js'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UmbRequestReloadChildrenOfEntityEvent, UmbRequestReloadStructureForEntityEvent, @@ -92,24 +92,20 @@ export class UmbDocumentPublishingWorkspaceContext extends UmbContextBase ({ - unique: option.unique, - schedule: { - publishTime: option.variant?.scheduledPublishDate, - unpublishTime: option.variant?.scheduledUnpublishDate, - }, - })), - }, - }) - .onSubmit() - .catch(() => undefined); + const result = await umbOpenModal(this, UMB_DOCUMENT_SCHEDULE_MODAL, { + data: { + options, + activeVariants: selected, + pickableFilter: this.#publishableVariantsFilter, + prevalues: options.map((option) => ({ + unique: option.unique, + schedule: { + publishTime: option.variant?.scheduledPublishDate, + unpublishTime: option.variant?.scheduledUnpublishDate, + }, + })), + }, + }).catch(() => undefined); if (!result?.selection.length) return; @@ -159,6 +155,9 @@ export class UmbDocumentPublishingWorkspaceContext extends UmbContextBase { const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); + if (!notificationContext) { + throw new Error('Notification context is missing'); + } notificationContext.peek('danger', { data: { message: this.#localize.term('speechBubbles_editContentScheduledNotSavedText') }, }); @@ -206,17 +205,13 @@ export class UmbDocumentPublishingWorkspaceContext extends UmbContextBase undefined); + const result = await umbOpenModal(this, UMB_DOCUMENT_PUBLISH_WITH_DESCENDANTS_MODAL, { + data: { + options, + pickableFilter: this.#publishableVariantsFilter, + }, + value: { selection: selected }, + }).catch(() => undefined); if (!result?.selection.length) return; @@ -285,17 +280,13 @@ export class UmbDocumentPublishingWorkspaceContext extends UmbContextBase undefined); + const result = await umbOpenModal(this, UMB_DOCUMENT_PUBLISH_MODAL, { + data: { + options, + pickableFilter: this.#publishableVariantsFilter, + }, + value: { selection: selected }, + }).catch(() => undefined); if (!result?.selection.length || !unique) return; @@ -316,6 +307,9 @@ export class UmbDocumentPublishingWorkspaceContext extends UmbContextBase #localize = new UmbLocalizationController(this); override async execute() { - const modalManagerContext = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManagerContext.open(this, UMB_ROLLBACK_MODAL, {}); - - await modalContext.onSubmit(); + await umbOpenModal(this, UMB_ROLLBACK_MODAL, {}); const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); + if (!notificationContext) { + throw new Error('Notification context not found'); + } notificationContext.peek('positive', { data: { message: this.#localize.term('rollback_documentRolledBack') }, }); diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/rollback/modal/rollback-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/rollback/modal/rollback-modal.element.ts index e41ad2d0539d..a62a00a57111 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/rollback/modal/rollback-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/rollback/modal/rollback-modal.element.ts @@ -216,6 +216,9 @@ export class UmbRollbackModalElement extends UmbModalBaseElement @@ -297,9 +296,7 @@ export class UmbDocumentWorkspaceViewInfoElement extends UmbLitElement { value: { selection: [this._templateUnique], }, - }); - - const result = await modal?.onSubmit().catch(() => undefined); + }).catch(() => undefined); if (!result?.selection.length) return; diff --git a/src/Umbraco.Web.UI.Client/src/packages/extension-insights/entity-actions/unregister/unregister-extension.action.ts b/src/Umbraco.Web.UI.Client/src/packages/extension-insights/entity-actions/unregister/unregister-extension.action.ts index c904dc092d45..a239cfb47f58 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/extension-insights/entity-actions/unregister/unregister-extension.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/extension-insights/entity-actions/unregister/unregister-extension.action.ts @@ -21,6 +21,9 @@ export class UmbUnregisterExtensionEntityAction extends UmbEntityActionBase { - if (savedSearch) { - this.#saveSearch(savedSearch); - this._isQuerySaved = true; - } - }); + }) + .then((savedSearch) => { + if (savedSearch) { + this.#saveSearch(savedSearch); + this._isQuerySaved = true; + } + }) + .catch(() => {}); } override render() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/markdown-editor/components/input-markdown-editor/input-markdown.element.ts b/src/Umbraco.Web.UI.Client/src/packages/markdown-editor/components/input-markdown-editor/input-markdown.element.ts index f0a0f64d7ec5..4f4e3b67cfe0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/markdown-editor/components/input-markdown-editor/input-markdown.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/markdown-editor/components/input-markdown-editor/input-markdown.element.ts @@ -16,7 +16,7 @@ import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registr import { UmbChangeEvent, type UmbInputEvent } from '@umbraco-cms/backoffice/event'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UMB_MEDIA_PICKER_MODAL, UmbMediaUrlRepository } from '@umbraco-cms/backoffice/media'; import { UmbCodeEditorLoadedEvent } from '@umbraco-cms/backoffice/code-editor'; import type { UmbCodeEditorController, UmbCodeEditorElement } from '@umbraco-cms/backoffice/code-editor'; @@ -219,34 +219,28 @@ export class UmbInputMarkdownElement extends UmbFormControlMixin { - if (!value) return; - - const uniques = value.selection.filter((unique) => unique !== null) as Array; - const { data: mediaUrls } = await this.#mediaUrlRepository.requestItems(uniques); - const mediaUrl = mediaUrls?.length ? (mediaUrls[0].url ?? 'URL') : 'URL'; - - this.#editor?.monacoEditor?.executeEdits('', [ - { - range: selection, - text: `![${alt}](${mediaUrl})`, - }, - ]); - - this.#editor?.select({ - startColumn: selection.startColumn + 2, - endColumn: selection.startColumn + alt.length + 2, // +2 because of ![ - endLineNumber: selection.startLineNumber, - startLineNumber: selection.startLineNumber, - }); - }) + const value = await umbOpenModal(this, UMB_MEDIA_PICKER_MODAL) .catch(() => undefined) .finally(() => this._focusEditor()); + if (!value) return; + + const uniques = value.selection.filter((unique) => unique !== null) as Array; + const { data: mediaUrls } = await this.#mediaUrlRepository.requestItems(uniques); + const mediaUrl = mediaUrls?.length ? (mediaUrls[0].url ?? 'URL') : 'URL'; + + this.#editor?.monacoEditor?.executeEdits('', [ + { + range: selection, + text: `![${alt}](${mediaUrl})`, + }, + ]); + + this.#editor?.select({ + startColumn: selection.startColumn + 2, + endColumn: selection.startColumn + alt.length + 2, // +2 because of ![ + endLineNumber: selection.startLineNumber, + startLineNumber: selection.startLineNumber, + }); } private _insertLine() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/duplicate/repository/media-type-duplicate.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/duplicate/repository/media-type-duplicate.repository.ts index 7407bb11a36d..159a8cacb0e0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/duplicate/repository/media-type-duplicate.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/duplicate/repository/media-type-duplicate.repository.ts @@ -11,6 +11,9 @@ export class UmbDuplicateMediaTypeRepository extends UmbRepositoryBase implement if (!error) { const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); + if (!notificationContext) { + throw new Error('Notification context not found'); + } const notification = { data: { message: `Duplicated` } }; notificationContext.peek('positive', notification); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/export/repository/media-type-export.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/export/repository/media-type-export.repository.ts index 8f8c65dbdfdc..70a115671e6f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/export/repository/media-type-export.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/export/repository/media-type-export.repository.ts @@ -10,6 +10,9 @@ export class UmbExportMediaTypeRepository extends UmbRepositoryBase { if (!error) { const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); + if (!notificationContext) { + throw new Error('Notification context not found'); + } const notification = { data: { message: `Exported` } }; notificationContext.peek('positive', notification); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/import/media-type-import.action.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/import/media-type-import.action.ts index ee1eaa956c5d..5ee608c91e16 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/import/media-type-import.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/import/media-type-import.action.ts @@ -1,17 +1,18 @@ import { UMB_MEDIA_TYPE_IMPORT_MODAL } from './modal/media-type-import-modal.token.js'; import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; import { UmbEntityActionBase, UmbRequestReloadChildrenOfEntityEvent } from '@umbraco-cms/backoffice/entity-action'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { UMB_MODAL_MANAGER_CONTEXT, umbOpenModal } from '@umbraco-cms/backoffice/modal'; export class UmbImportMediaTypeEntityAction extends UmbEntityActionBase { override async execute() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_MEDIA_TYPE_IMPORT_MODAL, { + await umbOpenModal(this, UMB_MEDIA_TYPE_IMPORT_MODAL, { data: { unique: this.args.unique }, - }); - await modalContext.onSubmit().catch(() => {}); + }).catch(() => {}); const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!actionEventContext) { + throw new Error('Action event context not found.'); + } const event = new UmbRequestReloadChildrenOfEntityEvent({ unique: this.args.unique, entityType: this.args.entityType, diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/import/repository/media-type-import.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/import/repository/media-type-import.repository.ts index 1f13bbe4f5e7..b944e3478e60 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/import/repository/media-type-import.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/import/repository/media-type-import.repository.ts @@ -10,6 +10,9 @@ export class UmbMediaTypeImportRepository extends UmbRepositoryBase { if (!error) { const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); + if (!notificationContext) { + throw new Error('Notification context not found'); + } const notification = { data: { message: `Imported` } }; notificationContext.peek('positive', notification); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/move-to/repository/media-type-move.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/move-to/repository/media-type-move.repository.ts index 1f1f40363b92..2a3afaa32e31 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/move-to/repository/media-type-move.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/move-to/repository/media-type-move.repository.ts @@ -11,6 +11,9 @@ export class UmbMoveMediaTypeRepository extends UmbRepositoryBase implements Umb if (!error) { const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); + if (!notificationContext) { + throw new Error(`Failed to load notification context`); + } const notification = { data: { message: `Moved` } }; notificationContext.peek('positive', notification); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/media-collection.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/media-collection.element.ts index e5deb42fa9c0..6357b381ef71 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/media-collection.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/media-collection.element.ts @@ -64,6 +64,9 @@ export class UmbMediaCollectionElement extends UmbCollectionDefaultElement { this.#collectionContext?.requestCollection(); const eventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!eventContext) { + throw new Error('Could not get event context'); + } const reloadEvent = new UmbRequestReloadChildrenOfEntityEvent({ entityType: this._unique ? UMB_MEDIA_ENTITY_TYPE : UMB_MEDIA_ROOT_ENTITY_TYPE, unique: this._unique, diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/dropzone-manager.class.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/dropzone-manager.class.ts index b58069b537bc..0df2a09ad7b6 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/dropzone-manager.class.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/dropzone-manager.class.ts @@ -16,7 +16,7 @@ import { UmbArrayState, UmbObjectState } from '@umbraco-cms/backoffice/observabl import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import { UmbId } from '@umbraco-cms/backoffice/id'; import { UmbMediaTypeStructureRepository } from '@umbraco-cms/backoffice/media-type'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import type { UmbAllowedMediaTypeModel } from '@umbraco-cms/backoffice/media-type'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UMB_NOTIFICATION_CONTEXT } from '@umbraco-cms/backoffice/notification'; @@ -132,9 +132,9 @@ export class UmbDropzoneManager extends UmbControllerBase { } async #showDialogMediaTypePicker(options: Array) { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this.#host, UMB_DROPZONE_MEDIA_TYPE_PICKER_MODAL, { data: { options } }); - const value = await modalContext.onSubmit().catch(() => undefined); + const value = await umbOpenModal(this.#host, UMB_DROPZONE_MEDIA_TYPE_PICKER_MODAL, { data: { options } }).catch( + () => undefined, + ); return value?.mediaTypeUnique; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/entity-actions/create/create.action.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/entity-actions/create/create.action.ts index 42e2f9515411..3629d1424ba8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/entity-actions/create/create.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/entity-actions/create/create.action.ts @@ -3,7 +3,7 @@ import { UMB_MEDIA_CREATE_OPTIONS_MODAL } from './media-create-options-modal.tok import type { UmbEntityActionArgs } from '@umbraco-cms/backoffice/entity-action'; import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; export class UmbCreateMediaEntityAction extends UmbEntityActionBase { constructor(host: UmbControllerHost, args: UmbEntityActionArgs) { @@ -22,15 +22,12 @@ export class UmbCreateMediaEntityAction extends UmbEntityActionBase { mediaItem = data[0]; } - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_MEDIA_CREATE_OPTIONS_MODAL, { + await umbOpenModal(this, UMB_MEDIA_CREATE_OPTIONS_MODAL, { data: { parent: { unique: this.args.unique, entityType: this.args.entityType }, mediaType: mediaItem ? { unique: mediaItem.mediaType.unique } : null, }, }); - - await modalContext.onSubmit(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/entity-actions/move-to/repository/media-move.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/entity-actions/move-to/repository/media-move.repository.ts index bb7464b9400b..9c85792b90e1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/entity-actions/move-to/repository/media-move.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/entity-actions/move-to/repository/media-move.repository.ts @@ -11,6 +11,9 @@ export class UmbMoveMediaRepository extends UmbRepositoryBase implements UmbMove if (!error) { const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); + if (!notificationContext) { + throw new Error('Notification context not found.'); + } const notification = { data: { message: `Moved` } }; notificationContext.peek('positive', notification); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member-type/entity-actions/duplicate/repository/member-type-duplicate.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member-type/entity-actions/duplicate/repository/member-type-duplicate.repository.ts index 8ac4b8e77639..441d2704dc65 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member-type/entity-actions/duplicate/repository/member-type-duplicate.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member-type/entity-actions/duplicate/repository/member-type-duplicate.repository.ts @@ -11,6 +11,9 @@ export class UmbDuplicateMemberTypeRepository extends UmbRepositoryBase implemen if (!error) { const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); + if (!notificationContext) { + throw new Error('Notification context not found'); + } const notification = { data: { message: `Duplicated` } }; notificationContext.peek('positive', notification); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/entity-actions/create/create.action.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/entity-actions/create/create.action.ts index 20994dad83e3..3c36113153fa 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/entity-actions/create/create.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/entity-actions/create/create.action.ts @@ -2,7 +2,7 @@ import { UMB_MEMBER_CREATE_OPTIONS_MODAL } from './member-create-options-modal.t import type { UmbEntityActionArgs } from '@umbraco-cms/backoffice/entity-action'; import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; export class UmbCreateMemberEntityAction extends UmbEntityActionBase { constructor(host: UmbControllerHost, args: UmbEntityActionArgs) { @@ -10,9 +10,7 @@ export class UmbCreateMemberEntityAction extends UmbEntityActionBase { } override async execute() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_MEMBER_CREATE_OPTIONS_MODAL); - await modalContext.onSubmit(); + await umbOpenModal(this, UMB_MEMBER_CREATE_OPTIONS_MODAL); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/multi-url-picker/tiny-mce-plugin/tiny-mce-multi-url-picker.plugin.ts b/src/Umbraco.Web.UI.Client/src/packages/multi-url-picker/tiny-mce-plugin/tiny-mce-multi-url-picker.plugin.ts index 436df2067c5b..308c76fee3bb 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/multi-url-picker/tiny-mce-plugin/tiny-mce-multi-url-picker.plugin.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/multi-url-picker/tiny-mce-plugin/tiny-mce-multi-url-picker.plugin.ts @@ -3,7 +3,7 @@ import type { UmbLinkPickerLink, UmbLinkPickerLinkType } from '../link-picker-mo import type { UmbLinkPickerModalValue } from '../link-picker-modal/link-picker-modal.token.js'; import { UmbLocalizationController } from '@umbraco-cms/backoffice/localization-api'; import { UmbTinyMcePluginBase } from '@umbraco-cms/backoffice/tiny-mce'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import type { TinyMcePluginArguments } from '@umbraco-cms/backoffice/tiny-mce'; type AnchorElementAttributes = { @@ -76,8 +76,7 @@ export default class UmbTinyMceMultiUrlPickerPlugin extends UmbTinyMcePluginBase } async #openLinkPicker(currentTarget?: UmbLinkPickerLink) { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalHandler = modalManager.open(this, UMB_LINK_PICKER_MODAL, { + const linkPickerData = await umbOpenModal(this, UMB_LINK_PICKER_MODAL, { data: { config: {}, index: null, @@ -86,11 +85,8 @@ export default class UmbTinyMceMultiUrlPickerPlugin extends UmbTinyMcePluginBase value: { link: currentTarget ?? {}, }, - }); - - if (!modalHandler) return; + }).catch(() => undefined); - const linkPickerData = await modalHandler.onSubmit().catch(() => undefined); if (!linkPickerData) return; // TODO: This is a workaround for the issue where the link picker modal is returning a frozen object, and we need to extract the link into smaller parts to avoid the frozen object issue. diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/collection/config/layout/layout-configuration.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/collection/config/layout/layout-configuration.element.ts index 7408f7cf268b..050dba949199 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/collection/config/layout/layout-configuration.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/collection/config/layout/layout-configuration.element.ts @@ -14,7 +14,6 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor'; import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; import type { UmbInputManifestElement } from '@umbraco-cms/backoffice/components'; import type { UmbPropertyEditorConfigCollection, @@ -113,9 +112,9 @@ export class UmbPropertyEditorUICollectionLayoutConfigurationElement } async #onIconChange(icon: typeof UMB_ICON_PICKER_MODAL.VALUE, index: number) { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modal = modalManager.open(this, UMB_ICON_PICKER_MODAL, { value: icon }); - const picked = await modal?.onSubmit(); + const picked = await (await import('@umbraco-cms/backoffice/modal')) + .umbOpenModal(this, UMB_ICON_PICKER_MODAL, { value: icon }) + .catch(() => undefined); if (!picked) return; const values = [...(this.value ?? [])]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/icon-picker/property-editor-ui-icon-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/icon-picker/property-editor-ui-icon-picker.element.ts index 0f36ea0fcc9b..d4a2ee417d58 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/icon-picker/property-editor-ui-icon-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/icon-picker/property-editor-ui-icon-picker.element.ts @@ -1,6 +1,6 @@ import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/property-editor'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UMB_ICON_PICKER_MODAL } from '@umbraco-cms/backoffice/icon'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { extractUmbColorVariable } from '@umbraco-cms/backoffice/resources'; @@ -36,10 +36,7 @@ export class UmbPropertyEditorUIIconPickerElement extends UmbLitElement implemen private _color = ''; private async _openModal() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_ICON_PICKER_MODAL); - - const data = await modalContext?.onSubmit(); + const data = await umbOpenModal(this, UMB_ICON_PICKER_MODAL).catch(() => undefined); if (!data) return; if (data.color) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entity-actions/bulk-delete/bulk-delete-with-relation.action.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entity-actions/bulk-delete/bulk-delete-with-relation.action.ts index 71b26bf65337..4b5e9975a708 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entity-actions/bulk-delete/bulk-delete-with-relation.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entity-actions/bulk-delete/bulk-delete-with-relation.action.ts @@ -1,21 +1,17 @@ import type { MetaEntityBulkActionDeleteWithRelationKind } from './types.js'; import { UMB_BULK_DELETE_WITH_RELATION_CONFIRM_MODAL } from './modal/bulk-delete-with-relation-modal.token.js'; import { UmbDeleteEntityBulkAction } from '@umbraco-cms/backoffice/entity-bulk-action'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { UMB_MODAL_MANAGER_CONTEXT, umbOpenModal } from '@umbraco-cms/backoffice/modal'; export class UmbBulkDeleteWithRelationEntityAction extends UmbDeleteEntityBulkAction { override async _confirmDelete() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - - const modal = modalManager.open(this, UMB_BULK_DELETE_WITH_RELATION_CONFIRM_MODAL, { + await umbOpenModal(this, UMB_BULK_DELETE_WITH_RELATION_CONFIRM_MODAL, { data: { uniques: this.selection, itemRepositoryAlias: this.args.meta.itemRepositoryAlias, referenceRepositoryAlias: this.args.meta.referenceRepositoryAlias, }, }); - - await modal.onSubmit(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entity-actions/bulk-trash/bulk-trash-with-relation.action.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entity-actions/bulk-trash/bulk-trash-with-relation.action.ts index 40383894fd3f..6e7b1a170595 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entity-actions/bulk-trash/bulk-trash-with-relation.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entity-actions/bulk-trash/bulk-trash-with-relation.action.ts @@ -1,21 +1,17 @@ import type { MetaEntityBulkActionTrashWithRelationKind } from './types.js'; import { UMB_BULK_TRASH_WITH_RELATION_CONFIRM_MODAL } from './modal/constants.js'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UmbTrashEntityBulkAction } from '@umbraco-cms/backoffice/recycle-bin'; export class UmbBulkTrashWithRelationEntityAction extends UmbTrashEntityBulkAction { override async _confirmTrash() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - - const modal = modalManager.open(this, UMB_BULK_TRASH_WITH_RELATION_CONFIRM_MODAL, { + await umbOpenModal(this, UMB_BULK_TRASH_WITH_RELATION_CONFIRM_MODAL, { data: { uniques: this.selection, itemRepositoryAlias: this.args.meta.itemRepositoryAlias, referenceRepositoryAlias: this.args.meta.referenceRepositoryAlias, }, }); - - await modal.onSubmit(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entity-actions/delete/delete-with-relation.action.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entity-actions/delete/delete-with-relation.action.ts index 89e5c23c7e1d..5a89f91b4606 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entity-actions/delete/delete-with-relation.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entity-actions/delete/delete-with-relation.action.ts @@ -1,6 +1,6 @@ import type { MetaEntityActionDeleteWithRelationKind } from './types.js'; import { UMB_DELETE_WITH_RELATION_CONFIRM_MODAL } from './modal/constants.js'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UmbDeleteEntityAction } from '@umbraco-cms/backoffice/entity-action'; /** @@ -12,9 +12,7 @@ export class UmbDeleteWithRelationEntityAction extends UmbDeleteEntityAction { override async _confirmTrash(item: any) { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - - const modal = modalManager.open(this, UMB_TRASH_WITH_RELATION_CONFIRM_MODAL, { + await umbOpenModal(this, UMB_TRASH_WITH_RELATION_CONFIRM_MODAL, { data: { unique: item.unique, entityType: item.entityType, @@ -20,8 +18,6 @@ export class UmbTrashWithRelationEntityAction extends UmbTrashEntityAction undefined); - - const value = modalContext.getValue(); + }).catch(() => undefined); this._exposedFields = value?.fields; } async #onFieldViewClick(rowData: SearchResultResponseModel) { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - - const modalContext = modalManager.open(this, UMB_EXAMINE_FIELDS_VIEWER_MODAL, { + await umbOpenModal(this, UMB_EXAMINE_FIELDS_VIEWER_MODAL, { modal: { type: 'sidebar', size: 'medium', }, data: { searchResult: rowData, name: this.getSearchResultNodeName(rowData) }, - }); - await modalContext.onSubmit().catch(() => undefined); + }).catch(() => undefined); } override render() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/search/umb-search-header-app.element.ts b/src/Umbraco.Web.UI.Client/src/packages/search/umb-search-header-app.element.ts index 64b08b35f13e..eda517e289f3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/search/umb-search-header-app.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/search/umb-search-header-app.element.ts @@ -1,13 +1,12 @@ import { UMB_SEARCH_MODAL } from './search-modal/search-modal.token.js'; import { html, customElement } from '@umbraco-cms/backoffice/external/lit'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UmbHeaderAppButtonElement } from '@umbraco-cms/backoffice/components'; @customElement('umb-search-header-app') export class UmbSearchHeaderAppElement extends UmbHeaderAppButtonElement { async #onSearchClick() { - const context = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - context.open(this, UMB_SEARCH_MODAL); + await umbOpenModal(this, UMB_SEARCH_MODAL).catch(() => undefined); } override render() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/sysinfo/repository/sysinfo.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/sysinfo/repository/sysinfo.repository.ts index 1e964b826e5c..5f5970d6a037 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/sysinfo/repository/sysinfo.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/sysinfo/repository/sysinfo.repository.ts @@ -30,6 +30,10 @@ export class UmbSysinfoRepository extends UmbRepositoryBase { async serverUpgradeCheck(currentVersion: string): Promise { // Check if we are allowed to check again const appContext = await this.getContext(UMB_APP_CONTEXT); + if (!appContext) { + throw new Error('Could not get the app context.'); + } + // TODO: Provide a get method, so we do not need to observe in this case: const versionCheckPeriod = await this.observe(appContext.getServerConnection().versionCheckPeriod).asPromise(); if (versionCheckPeriod <= 0) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/entity-actions/create/create.action.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/entity-actions/create/create.action.ts index 24245f373483..8ae47452504e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/entity-actions/create/create.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/entity-actions/create/create.action.ts @@ -1,17 +1,10 @@ import { UMB_PARTIAL_VIEW_CREATE_OPTIONS_MODAL } from './options-modal/index.js'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import type { UmbEntityActionArgs } from '@umbraco-cms/backoffice/entity-action'; import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; export class UmbPartialViewCreateOptionsEntityAction extends UmbEntityActionBase { - constructor(host: UmbControllerHost, args: UmbEntityActionArgs) { - super(host, args); - } - override async execute() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_PARTIAL_VIEW_CREATE_OPTIONS_MODAL, { + await umbOpenModal(this, UMB_PARTIAL_VIEW_CREATE_OPTIONS_MODAL, { data: { parent: { unique: this.args.unique, @@ -19,8 +12,6 @@ export class UmbPartialViewCreateOptionsEntityAction extends UmbEntityActionBase }, }, }); - - await modalContext.onSubmit(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/entity-actions/create/options-modal/partial-view-create-options-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/entity-actions/create/options-modal/partial-view-create-options-modal.element.ts index 4c6356ea7531..ab97ff75e7fe 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/entity-actions/create/options-modal/partial-view-create-options-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/entity-actions/create/options-modal/partial-view-create-options-modal.element.ts @@ -2,7 +2,7 @@ import { UMB_PARTIAL_VIEW_FROM_SNIPPET_MODAL } from '../snippet-modal/index.js'; import { UMB_PARTIAL_VIEW_FOLDER_REPOSITORY_ALIAS } from '../../../constants.js'; import type { UmbPartialViewCreateOptionsModalData } from './index.js'; import { html, customElement } from '@umbraco-cms/backoffice/external/lit'; -import { UMB_MODAL_MANAGER_CONTEXT, UmbModalBaseElement } from '@umbraco-cms/backoffice/modal'; +import { UmbModalBaseElement, umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UmbCreateFolderEntityAction } from '@umbraco-cms/backoffice/tree'; @customElement('umb-partial-view-create-options-modal') @@ -42,14 +42,13 @@ export class UmbPartialViewCreateOptionsModalElement extends UmbModalBaseElement event.stopPropagation(); if (!this.data?.parent) throw new Error('A parent is required to create a folder'); - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_PARTIAL_VIEW_FROM_SNIPPET_MODAL, { + umbOpenModal(this, UMB_PARTIAL_VIEW_FROM_SNIPPET_MODAL, { data: { parent: this.data.parent, }, - }); - - modalContext?.onSubmit().then(() => this._submitModal()); + }) + .then(() => this._submitModal()) + .catch(() => undefined); } // close the modal when navigating to data type @@ -69,15 +68,15 @@ export class UmbPartialViewCreateOptionsModalElement extends UmbModalBaseElement - } + - } + - } + diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/scripts/entity-actions/create/create.action.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/scripts/entity-actions/create/create.action.ts index 254265505c3a..e6dfa3361e45 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/scripts/entity-actions/create/create.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/scripts/entity-actions/create/create.action.ts @@ -1,17 +1,10 @@ import { UMB_SCRIPT_CREATE_OPTIONS_MODAL } from './options-modal/index.js'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import type { UmbEntityActionArgs } from '@umbraco-cms/backoffice/entity-action'; import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; export class UmbScriptCreateOptionsEntityAction extends UmbEntityActionBase { - constructor(host: UmbControllerHost, args: UmbEntityActionArgs) { - super(host, args); - } - override async execute() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_SCRIPT_CREATE_OPTIONS_MODAL, { + await umbOpenModal(this, UMB_SCRIPT_CREATE_OPTIONS_MODAL, { data: { parent: { entityType: this.args.entityType, @@ -19,8 +12,6 @@ export class UmbScriptCreateOptionsEntityAction extends UmbEntityActionBase { override async execute() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_STYLESHEET_CREATE_OPTIONS_MODAL, { + await umbOpenModal(this, UMB_STYLESHEET_CREATE_OPTIONS_MODAL, { data: { parent: { unique: this.args.unique, @@ -13,8 +12,6 @@ export class UmbStylesheetCreateOptionsEntityAction extends UmbEntityActionBase< }, }, }); - - await modalContext.onSubmit(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/change-password/entity-action/change-user-password.action.ts b/src/Umbraco.Web.UI.Client/src/packages/user/change-password/entity-action/change-user-password.action.ts index 21cd10b963fc..9ebf53b74e11 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/change-password/entity-action/change-user-password.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/change-password/entity-action/change-user-password.action.ts @@ -21,6 +21,7 @@ export class UmbChangeUserPasswordEntityAction extends UmbEntityActionBase undefined); + if (!data) return; const currentUserContext = await this.getContext(UMB_CURRENT_USER_CONTEXT); if (!currentUserContext) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/external-login/modals/external-login-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/external-login/modals/external-login-modal.element.ts index 0048bb58e432..2167dfe016dc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/external-login/modals/external-login-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/external-login/modals/external-login-modal.element.ts @@ -198,6 +198,9 @@ export class UmbCurrentUserExternalLoginModalElement extends UmbLitElement { color: 'danger', }); const authContext = await this.getContext(UMB_AUTH_CONTEXT); + if (!authContext) { + throw new Error('Auth context is missing'); + } await authContext.unlinkLogin(item.providerSchemeName, item.providerKey); } catch (error) { let message = this.localize.term('errors_receivedErrorFromServer'); From 1c071fe0bdef4dd5d64171cd0ce44a089d09733a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Sun, 9 Mar 2025 21:13:11 +0100 Subject: [PATCH 18/26] correction batch 4 --- .../preview/apps/preview-culture.element.ts | 2 +- .../apps/preview/apps/preview-exit.element.ts | 2 +- .../apps/preview-open-website.element.ts | 2 +- .../block-grid-area-type-workspace.context.ts | 27 ++++++----- .../context/block-grid-entries.context.ts | 10 +++- .../context/block-grid-manager.context.ts | 6 +-- .../block-list-entry.element.ts | 3 ++ .../context/block-list-entries.context.ts | 10 +++- .../block-type-card.element.ts | 6 +-- .../input-block-type.element.ts | 3 ++ .../workspace/block-type-workspace.context.ts | 48 +++++++++++++------ .../block/context/block-manager.context.ts | 6 +++ .../clipboard-local-storage.manager.ts | 3 ++ .../context/clipboard.property-context.ts | 12 ++++- .../default/collection-default.context.ts | 1 + .../content-type-workspace-context-base.ts | 6 +++ .../content-type-design-editor.element.ts | 12 ++--- .../content-detail-workspace-base.ts | 29 ++++++----- .../common/duplicate/duplicate.action.ts | 3 ++ .../peek-error/peek-error.controller.ts | 3 ++ .../clear/property-action-clear.controller.ts | 3 ++ .../empty-recycle-bin.action.ts | 1 + .../entity-action/trash/trash.action.ts | 1 + .../core/resources/resource.controller.ts | 3 ++ .../rename-server-file-repository-base.ts | 2 + .../temporary-file-manager.class.ts | 2 + .../duplicate-to/duplicate-to.action.ts | 1 + .../entity-actions/move/move-to.action.ts | 1 + .../reload-tree-item-children.action.ts | 2 +- .../sort-children-of.action.ts | 10 ++-- .../delete-folder/delete-folder.action.ts | 1 + .../data-type-duplicate.repository.ts | 3 ++ .../repository/data-type-move.repository.ts | 3 ++ .../data-type-picker-flow-modal.element.ts | 3 ++ ...ata-type-details-workspace-view.element.ts | 16 +++---- .../entity-action/export/export.action.ts | 9 ++-- .../entity-action/import/import.action.ts | 6 +-- .../repository/dictionary-move.repository.ts | 3 ++ .../entity-actions/create/create.action.ts | 16 ++----- .../document-blueprint-move.repository.ts | 3 ++ .../entity-actions/create/create.action.ts | 7 +-- .../document-type-duplicate.repository.ts | 3 ++ .../document-type-export.repository.ts | 3 ++ .../import/document-type-import.action.ts | 9 ++-- .../document-type-import.repository.ts | 3 ++ .../document-type-move.repository.ts | 3 ++ .../create-blueprint.action.ts | 8 ++-- .../entity-actions/create/create.action.ts | 7 +-- .../culture-and-hostnames.action.ts | 12 +---- .../duplicate/duplicate-document.action.ts | 37 +++++++------- .../document-duplicate.repository.ts | 3 ++ .../repository/document-move.repository.ts | 3 ++ .../document-notifications.action.ts | 6 +-- .../public-access/public-access.action.ts | 15 ++---- .../item/document-item-data-resolver.ts | 13 +++-- .../publish-with-descendants.action.ts | 3 ++ .../publish/entity-action/publish.action.ts | 30 ++++++------ .../partial-view-workspace-editor.element.ts | 16 +++---- 58 files changed, 273 insertions(+), 191 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/apps/preview/apps/preview-culture.element.ts b/src/Umbraco.Web.UI.Client/src/apps/preview/apps/preview-culture.element.ts index 81d425e2a088..3fd66910edd9 100644 --- a/src/Umbraco.Web.UI.Client/src/apps/preview/apps/preview-culture.element.ts +++ b/src/Umbraco.Web.UI.Client/src/apps/preview/apps/preview-culture.element.ts @@ -36,7 +36,7 @@ export class UmbPreviewCultureElement extends UmbLitElement { this._culture = culture; const previewContext = await this.getContext(UMB_PREVIEW_CONTEXT); - previewContext.updateIFrame({ culture: culture.unique }); + previewContext?.updateIFrame({ culture: culture.unique }); } override render() { diff --git a/src/Umbraco.Web.UI.Client/src/apps/preview/apps/preview-exit.element.ts b/src/Umbraco.Web.UI.Client/src/apps/preview/apps/preview-exit.element.ts index e751e42ad3d8..95e907a38a87 100644 --- a/src/Umbraco.Web.UI.Client/src/apps/preview/apps/preview-exit.element.ts +++ b/src/Umbraco.Web.UI.Client/src/apps/preview/apps/preview-exit.element.ts @@ -6,7 +6,7 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; export class UmbPreviewExitElement extends UmbLitElement { async #onClick() { const previewContext = await this.getContext(UMB_PREVIEW_CONTEXT); - previewContext.exitPreview(0); + previewContext?.exitPreview(0); } override render() { diff --git a/src/Umbraco.Web.UI.Client/src/apps/preview/apps/preview-open-website.element.ts b/src/Umbraco.Web.UI.Client/src/apps/preview/apps/preview-open-website.element.ts index 95dd68f91736..aba28768e5c1 100644 --- a/src/Umbraco.Web.UI.Client/src/apps/preview/apps/preview-open-website.element.ts +++ b/src/Umbraco.Web.UI.Client/src/apps/preview/apps/preview-open-website.element.ts @@ -6,7 +6,7 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; export class UmbPreviewOpenWebsiteElement extends UmbLitElement { async #onClick() { const previewContext = await this.getContext(UMB_PREVIEW_CONTEXT); - previewContext.openWebsite(); + previewContext?.openWebsite(); } override render() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/components/block-grid-area-config-entry/workspace/block-grid-area-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/components/block-grid-area-config-entry/workspace/block-grid-area-type-workspace.context.ts index 192ba4d8460e..8bbc090c01db 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/components/block-grid-area-config-entry/workspace/block-grid-area-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/components/block-grid-area-config-entry/workspace/block-grid-area-type-workspace.context.ts @@ -80,17 +80,22 @@ export class UmbBlockGridAreaTypeWorkspaceContext async load(unique: string) { this.resetState(); - const context = await this.getContext(UMB_PROPERTY_CONTEXT); - this.observe(context.value, (value) => { - if (value) { - const blockTypeData = value.find((x: UmbBlockGridTypeAreaType) => x.key === unique); - if (blockTypeData) { - this.#data.setValue(blockTypeData); - return; - } - } - // Fallback to undefined: - this.#data.setValue(undefined); + this.consumeContext(UMB_PROPERTY_CONTEXT, (context) => { + this.observe( + context.value, + (value) => { + if (value) { + const blockTypeData = value.find((x: UmbBlockGridTypeAreaType) => x.key === unique); + if (blockTypeData) { + this.#data.setValue(blockTypeData); + return; + } + } + // Fallback to undefined: + this.#data.setValue(undefined); + }, + 'observePropertyValue', + ); }); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-entries.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-entries.context.ts index e410f894d07e..d7eb3d41a2df 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-entries.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-entries.context.ts @@ -165,12 +165,18 @@ export class UmbBlockGridEntriesContext // Idea: Maybe on setup should be async, so it can retrieve the values when needed? [NL] const index = routingInfo.index ? parseInt(routingInfo.index) : -1; const clipboardContext = await this.getContext(UMB_CLIPBOARD_PROPERTY_CONTEXT); + if (!clipboardContext) { + throw new Error('Clipboard context not available'); + } const pasteTranslatorManifests = clipboardContext.getPasteTranslatorManifests( UMB_BLOCK_GRID_PROPERTY_EDITOR_UI_ALIAS, ); // TODO: consider moving some of this logic to the clipboard property context const propertyContext = await this.getContext(UMB_PROPERTY_CONTEXT); + if (!propertyContext) { + throw new Error('Property context not available'); + } const config = propertyContext.getConfig() as UmbBlockGridPropertyEditorConfig; const valueResolver = new UmbClipboardPastePropertyValueTranslatorValueResolver(this); @@ -234,7 +240,9 @@ export class UmbBlockGridEntriesContext } } else if (value?.clipboard && value.clipboard.selection?.length && data) { const clipboardContext = await this.getContext(UMB_CLIPBOARD_PROPERTY_CONTEXT); - + if (!clipboardContext) { + throw new Error('Clipboard context not available'); + } const propertyValues = await clipboardContext.readMultiple( value.clipboard.selection, UMB_BLOCK_GRID_PROPERTY_EDITOR_UI_ALIAS, diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-manager.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-manager.context.ts index 7fb16cd57374..dec041408caf 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-manager.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-manager.context.ts @@ -33,7 +33,7 @@ export class UmbBlockGridManagerContext< return this.#inlineEditingMode.getValue(); } - #initAppUrl: Promise; + #initAppUrl: Promise; #serverUrl?: string; @@ -87,9 +87,9 @@ export class UmbBlockGridManagerContext< constructor(host: UmbControllerHost) { super(host); - this.#initAppUrl = this.getContext(UMB_APP_CONTEXT).then((appContext) => { + this.#initAppUrl = this.consumeContext(UMB_APP_CONTEXT, (appContext) => { this.#serverUrl = appContext.getServerUrl(); - }); + }).asPromise(); } /** * @deprecated Use createWithPresets instead. Will be removed in v.17. diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-entry/block-list-entry.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-entry/block-list-entry.element.ts index af584330efde..15e959230824 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-entry/block-list-entry.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-entry/block-list-entry.element.ts @@ -292,6 +292,9 @@ export class UmbBlockListEntryElement extends UmbLitElement implements UmbProper const propertyDatasetContext = await this.getContext(UMB_PROPERTY_DATASET_CONTEXT); const propertyContext = await this.getContext(UMB_PROPERTY_CONTEXT); const clipboardContext = await this.getContext(UMB_CLIPBOARD_PROPERTY_CONTEXT); + if (!propertyDatasetContext || !propertyContext || !clipboardContext) { + throw new Error('Could not get required contexts to copy.'); + } const workspaceName = propertyDatasetContext?.getName(); const propertyLabel = propertyContext?.getLabel(); diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/context/block-list-entries.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/context/block-list-entries.context.ts index e625f4d29899..c7fb204505d3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/context/block-list-entries.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/context/block-list-entries.context.ts @@ -39,6 +39,9 @@ export class UmbBlockListEntriesContext extends UmbBlockEntriesContext< if (!this._manager) return false; const index = routingInfo.index ? parseInt(routingInfo.index) : -1; const clipboardContext = await this.getContext(UMB_CLIPBOARD_PROPERTY_CONTEXT); + if (!clipboardContext) { + throw new Error('Clipboard context not found'); + } const pasteTranslatorManifests = clipboardContext.getPasteTranslatorManifests( UMB_BLOCK_LIST_PROPERTY_EDITOR_UI_ALIAS, @@ -46,6 +49,9 @@ export class UmbBlockListEntriesContext extends UmbBlockEntriesContext< // TODO: consider moving some of this logic to the clipboard property context const propertyContext = await this.getContext(UMB_PROPERTY_CONTEXT); + if (!propertyContext) { + throw new Error('Property context not found'); + } const config = propertyContext.getConfig(); const valueResolver = new UmbClipboardPastePropertyValueTranslatorValueResolver(this); @@ -103,7 +109,9 @@ export class UmbBlockListEntriesContext extends UmbBlockEntriesContext< } } else if (value?.clipboard && value.clipboard.selection?.length && data) { const clipboardContext = await this.getContext(UMB_CLIPBOARD_PROPERTY_CONTEXT); - + if (!clipboardContext) { + throw new Error('Clipboard context not found'); + } const propertyValues = await clipboardContext.readMultiple( value.clipboard.selection, UMB_BLOCK_LIST_PROPERTY_EDITOR_UI_ALIAS, diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/block-type-card/block-type-card.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/block-type-card/block-type-card.element.ts index 9e9160deaac1..5065ba776645 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/block-type-card/block-type-card.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/block-type-card/block-type-card.element.ts @@ -12,7 +12,7 @@ import { UUICardEvent } from '@umbraco-cms/backoffice/external/uui'; @customElement('umb-block-type-card') export class UmbBlockTypeCardElement extends UmbLitElement { // - #init: Promise; + #init: Promise; #serverUrl: string = ''; readonly #itemManager = new UmbRepositoryItemsManager( @@ -76,9 +76,9 @@ export class UmbBlockTypeCardElement extends UmbLitElement { constructor() { super(); - this.#init = this.getContext(UMB_APP_CONTEXT).then((appContext) => { + this.#init = this.consumeContext(UMB_APP_CONTEXT, (appContext) => { this.#serverUrl = appContext.getServerUrl(); - }); + }).asPromise(); this.observe(this.#itemManager.statuses, async (statuses) => { const status = statuses[0]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/input-block-type/input-block-type.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/input-block-type/input-block-type.element.ts index 5664722449fd..b3aeda0d3f59 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/input-block-type/input-block-type.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/input-block-type/input-block-type.element.ts @@ -140,6 +140,9 @@ export class UmbInputBlockTypeElement< async #onRequestDelete(item: BlockType) { const store = await this.getContext(UMB_DOCUMENT_TYPE_ITEM_STORE_CONTEXT); + if (!store) { + return; + } const contentType = store.getItems([item.contentElementTypeKey]); await umbConfirmModal(this, { color: 'danger', diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-type/workspace/block-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-type/workspace/block-type-workspace.context.ts index e9e6d295af05..27506dca475d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-type/workspace/block-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-type/workspace/block-type-workspace.context.ts @@ -25,6 +25,9 @@ export class UmbBlockTypeWorkspaceContext; + #propertyContext?: typeof UMB_PROPERTY_CONTEXT.TYPE; + #entityType: string; #data = new UmbObjectState(undefined); readonly data = this.#data.asObservable(); @@ -44,6 +47,10 @@ export class UmbBlockTypeWorkspaceContext { + this.#propertyContext = context; + }).asPromise(); + this.routes.setRoutes([ { // Would it make more sense to have groupKey before elementTypeKey? @@ -84,18 +91,23 @@ export class UmbBlockTypeWorkspaceContext { - if (value) { - const blockTypeData = value.find((x: UmbBlockTypeBaseModel) => x.contentElementTypeKey === unique); - if (blockTypeData) { - this.#data.setValue(blockTypeData); - return; + await this.#gotPropertyContext; + + this.observe( + this.#propertyContext?.value, + (value) => { + if (value) { + const blockTypeData = value.find((x: UmbBlockTypeBaseModel) => x.contentElementTypeKey === unique); + if (blockTypeData) { + this.#data.setValue(blockTypeData); + return; + } } - } - // Fallback to undefined: - this.#data.setValue(undefined); - }); + // Fallback to undefined: + this.#data.setValue(undefined); + }, + 'observePropertyValue', + ); } async create(contentElementTypeId: string, groupKey?: string | null) { @@ -174,10 +186,16 @@ export class UmbBlockTypeWorkspaceContext x?.contentElementTypeKey), + await this.#gotPropertyContext; + if (!this.#propertyContext) { + throw new Error('Property context is not available.'); + } + this.#propertyContext.setValue( + appendToFrozenArray( + this.#propertyContext.getValue() ?? [], + this.#data.getValue(), + (x) => x?.contentElementTypeKey, + ), ); this.setIsNew(false); diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-manager.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-manager.context.ts index f851d49ee5a6..da1524798020 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-manager.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-manager.context.ts @@ -363,6 +363,9 @@ export abstract class UmbBlockManagerContext< protected async _createBlockElementData(key: string, contentTypeKey: string) { // const appLanguage = await this.getContext(UMB_APP_LANGUAGE_CONTEXT); + if (!appLanguage) { + throw new Error('Could not retrieve app language context.'); + } const contentStructure = this.getStructure(contentTypeKey); if (!contentStructure) { @@ -501,6 +504,9 @@ export abstract class UmbBlockManagerContext< if (varyByCulture) { // get all mandatory cultures: const appLanguageContext = await this.getContext(UMB_APP_LANGUAGE_CONTEXT); + if (!appLanguageContext) { + throw new Error('Could not retrieve app language context.'); + } const mandatoryLanguages = await appLanguageContext.getMandatoryLanguages(); mandatoryLanguages.forEach((x) => { // No need to insert the same expose twice: diff --git a/src/Umbraco.Web.UI.Client/src/packages/clipboard/clipboard-local-storage.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/clipboard/clipboard-local-storage.manager.ts index 434d3bbb0a29..1e5e49f1b9bb 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/clipboard/clipboard-local-storage.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/clipboard/clipboard-local-storage.manager.ts @@ -94,6 +94,9 @@ export class UmbClipboardLocalStorageManager extends UmbControllerBase { } const context = await this.getContext(UMB_CURRENT_USER_CONTEXT); + if (!context) { + throw new Error('Could not get current user context'); + } this.#currentUserUnique = context.getUnique(); return this.#currentUserUnique; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/clipboard/property/context/clipboard.property-context.ts b/src/Umbraco.Web.UI.Client/src/packages/clipboard/property/context/clipboard.property-context.ts index 60c4ece70f3a..fb4134124612 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/clipboard/property/context/clipboard.property-context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/clipboard/property/context/clipboard.property-context.ts @@ -99,6 +99,9 @@ export class UmbClipboardPropertyContext extends UmbContextBase { const clipboardContext = await this.getContext(UMB_CLIPBOARD_CONTEXT); + if (!clipboardContext) { + throw new Error('Clipboard context is required'); + } const copyValueResolver = new UmbClipboardCopyPropertyValueTranslatorValueResolver(this); const values = await copyValueResolver.resolve(args.propertyValue, args.propertyEditorUiAlias); @@ -129,7 +132,11 @@ export class UmbClipboardPropertyContext extends UmbContextBase { // check if the collection is in the same context as the entity from the event const entityContext = await this.getContext(UMB_ENTITY_CONTEXT); + if (!entityContext) return; const unique = entityContext.getUnique(); const entityType = entityContext.getEntityType(); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/content-type-workspace-context-base.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/content-type-workspace-context-base.ts index 42fd9945506f..030b2cefc2a6 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/content-type-workspace-context-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/content-type-workspace-context-base.ts @@ -153,6 +153,9 @@ export abstract class UmbContentTypeWorkspaceContextBase< this._data.setPersisted(this.structure.getOwnerContentType()); const eventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!eventContext) { + throw new Error('Could not get the action event context'); + } const event = new UmbRequestReloadChildrenOfEntityEvent({ entityType: parent.entityType, unique: parent.unique, @@ -176,6 +179,9 @@ export abstract class UmbContentTypeWorkspaceContextBase< this._data.setPersisted(this.structure.getOwnerContentType()); const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!actionEventContext) { + throw new Error('Could not get the action event context'); + } const event = new UmbRequestReloadStructureForEntityEvent({ unique: this.getUnique()!, entityType: this.getEntityType(), diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/views/design/content-type-design-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/views/design/content-type-design-editor.element.ts index 7ca1e9a1cba7..0a4b127311bf 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/views/design/content-type-design-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/views/design/content-type-design-editor.element.ts @@ -18,7 +18,7 @@ import type { UmbWorkspaceViewElement, } from '@umbraco-cms/backoffice/workspace'; import type { UmbConfirmModalData } from '@umbraco-cms/backoffice/modal'; -import { UMB_MODAL_MANAGER_CONTEXT, umbConfirmModal } from '@umbraco-cms/backoffice/modal'; +import { UMB_MODAL_MANAGER_CONTEXT, umbConfirmModal, umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; @@ -367,15 +367,13 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements isNew: this.#workspaceContext.getIsNew()!, }; - const modalManagerContext = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManagerContext.open(this, UMB_COMPOSITION_PICKER_MODAL, { + const value = await umbOpenModal(this, UMB_COMPOSITION_PICKER_MODAL, { data: compositionConfiguration, - }); - await modalContext?.onSubmit(); + }).catch(() => undefined); - if (!modalContext?.value) return; + if (!value) return; - const compositionIds = modalContext.getValue().selection; + const compositionIds = value.selection; this.#workspaceContext?.setCompositions( compositionIds.map((unique) => ({ contentType: { unique }, compositionType: CompositionTypeModel.COMPOSITION })), diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content/workspace/content-detail-workspace-base.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content/workspace/content-detail-workspace-base.ts index 363a73bdf3d8..91b9d2f5bcb9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content/workspace/content-detail-workspace-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content/workspace/content-detail-workspace-base.ts @@ -39,7 +39,7 @@ import { UmbVariantValuesValidationPathTranslator, } from '@umbraco-cms/backoffice/validation'; import type { UmbModalToken } from '@umbraco-cms/backoffice/modal'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; import { UmbEntityUpdatedEvent, @@ -578,6 +578,9 @@ export abstract class UmbContentDetailWorkspaceContextBase< const variantsWithoutAName = saveData.variants.filter((x) => !x.name); if (variantsWithoutAName.length > 0) { const validationContext = await this.getContext(UMB_VALIDATION_CONTEXT); + if (!validationContext) { + throw new Error('Validation context is missing'); + } variantsWithoutAName.forEach((variant) => { validationContext.messages.addMessage( 'client', @@ -657,17 +660,13 @@ export abstract class UmbContentDetailWorkspaceContextBase< variantIds.push(UmbVariantId.Create(options[0])); } else if (this.#saveModalToken) { // If there are multiple variants, we will open the modal to let the user pick which variants to save. - const modalManagerContext = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const result = await modalManagerContext - .open(this, this.#saveModalToken, { - data: { - options, - pickableFilter: this._saveableVariantsFilter, - }, - value: { selection: selected }, - }) - .onSubmit() - .catch(() => undefined); + const result = await umbOpenModal(this, this.#saveModalToken, { + data: { + options, + pickableFilter: this._saveableVariantsFilter, + }, + value: { selection: selected }, + }).catch(() => undefined); if (!result?.selection.length) return; @@ -753,6 +752,9 @@ export abstract class UmbContentDetailWorkspaceContextBase< this._data.setCurrent(newCurrentData); const eventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!eventContext) { + throw new Error('Event context is missing'); + } const event = new UmbRequestReloadChildrenOfEntityEvent({ entityType: parent.entityType, unique: parent.unique, @@ -797,6 +799,9 @@ export abstract class UmbContentDetailWorkspaceContextBase< const entityType = this.getEntityType(); const eventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!eventContext) { + throw new Error('Event context is missing'); + } const structureEvent = new UmbRequestReloadStructureForEntityEvent({ unique, entityType }); eventContext.dispatchEvent(structureEvent); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/common/duplicate/duplicate.action.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/common/duplicate/duplicate.action.ts index cc0d2710e61b..392930b313d7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/common/duplicate/duplicate.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/common/duplicate/duplicate.action.ts @@ -30,6 +30,9 @@ export class UmbDuplicateEntityAction extends UmbEntityActionBase { async #reloadMenu() { const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!actionEventContext) { + throw new Error('Action event context is not available'); + } const event = new UmbRequestReloadStructureForEntityEvent({ unique: this.args.unique, entityType: this.args.entityType, diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error.controller.ts index 80dc9638a1e1..342f48291f7e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error.controller.ts @@ -8,6 +8,9 @@ import './peek-error-notification.element.js'; export class UmbPeekErrorController extends UmbControllerBase { async open(args: UmbPeekErrorArgs): Promise { const context = await this.getContext(UMB_NOTIFICATION_CONTEXT); + if (!context) { + throw new Error('Could not get notification context'); + } context.peek('danger', { elementName: 'umb-peek-error-notification', diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-action/common/clear/property-action-clear.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-action/common/clear/property-action-clear.controller.ts index b4ce1068eb8f..9cc85c43ef6e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-action/common/clear/property-action-clear.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-action/common/clear/property-action-clear.controller.ts @@ -4,6 +4,9 @@ import { UMB_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/property'; export class UmbClearPropertyAction extends UmbPropertyActionBase { override async execute() { const propertyContext = await this.getContext(UMB_PROPERTY_CONTEXT); + if (!propertyContext) { + return; + } propertyContext.clearValue(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/recycle-bin/entity-action/empty-recycle-bin/empty-recycle-bin.action.ts b/src/Umbraco.Web.UI.Client/src/packages/core/recycle-bin/entity-action/empty-recycle-bin/empty-recycle-bin.action.ts index cedb3a5eda09..96706c76fb21 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/recycle-bin/entity-action/empty-recycle-bin/empty-recycle-bin.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/recycle-bin/entity-action/empty-recycle-bin/empty-recycle-bin.action.ts @@ -30,6 +30,7 @@ export class UmbEmptyRecycleBinEntityAction extends UmbEntityActionBase maxFileSize) { const notification = await this.getContext(UMB_NOTIFICATION_CONTEXT); + if (!notification) throw new Error('Notification context is missing'); notification.peek('warning', { data: { headline: 'Upload', @@ -112,6 +113,7 @@ export class UmbTemporaryFileManager< (disallowedExtensions?.length && disallowedExtensions.includes(fileExtension)) ) { const notification = await this.getContext(UMB_NOTIFICATION_CONTEXT); + if (!notification) throw new Error('Notification context is missing'); notification.peek('warning', { data: { message: `${this.#localization.term('media_disallowedFileType')}: ${fileExtension}`, diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/entity-actions/duplicate-to/duplicate-to.action.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/entity-actions/duplicate-to/duplicate-to.action.ts index a844ff58b203..c43a309b6e0c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/entity-actions/duplicate-to/duplicate-to.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/entity-actions/duplicate-to/duplicate-to.action.ts @@ -40,6 +40,7 @@ export class UmbDuplicateToEntityAction extends UmbEntityActionBase { override async execute() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modal = modalManager.open(this._host, UMB_SORT_CHILDREN_OF_MODAL, { + await umbOpenModal(this, UMB_SORT_CHILDREN_OF_MODAL, { data: { unique: this.args.unique, entityType: this.args.entityType, sortChildrenOfRepositoryAlias: this.args.meta.sortChildrenOfRepositoryAlias, treeRepositoryAlias: this.args.meta.treeRepositoryAlias, }, - }); - - await modal.onSubmit().catch(() => undefined); + }).catch(() => undefined); const eventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!eventContext) throw new Error('Event context is not available'); eventContext.dispatchEvent( new UmbRequestReloadChildrenOfEntityEvent({ diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/folder/entity-action/delete-folder/delete-folder.action.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/folder/entity-action/delete-folder/delete-folder.action.ts index 4947ccee23d0..aa84ab9b0f81 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/folder/entity-action/delete-folder/delete-folder.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/folder/entity-action/delete-folder/delete-folder.action.ts @@ -49,6 +49,7 @@ export class UmbDeleteFolderEntityAction extends UmbEntityActionBase ui.alias === params.uiAlias)?.name; const dataTypeName = `${contentContext?.getName() ?? ''} - ${propContext.getName() ?? ''} - ${propertyEditorName}`; diff --git a/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/views/details/data-type-details-workspace-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/views/details/data-type-details-workspace-view.element.ts index 63e561091427..073774fe8d19 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/views/details/data-type-details-workspace-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/views/details/data-type-details-workspace-view.element.ts @@ -2,7 +2,7 @@ import { UMB_DATA_TYPE_WORKSPACE_CONTEXT } from '../../data-type-workspace.conte import { css, customElement, html, nothing, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UMB_PROPERTY_EDITOR_UI_PICKER_MODAL } from '@umbraco-cms/backoffice/property-editor'; import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/workspace'; import { umbBindToValidation } from '@umbraco-cms/backoffice/validation'; @@ -55,15 +55,11 @@ export class UmbDataTypeDetailsWorkspaceViewEditElement extends UmbLitElement im } async #openPropertyEditorUIPicker() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const value = await modalManager - .open(this, UMB_PROPERTY_EDITOR_UI_PICKER_MODAL, { - value: { - selection: this._propertyEditorUiAlias ? [this._propertyEditorUiAlias] : [], - }, - }) - .onSubmit() - .catch(() => undefined); + const value = await umbOpenModal(this, UMB_PROPERTY_EDITOR_UI_PICKER_MODAL, { + value: { + selection: this._propertyEditorUiAlias ? [this._propertyEditorUiAlias] : [], + }, + }).catch(() => undefined); if (value) { this.#workspaceContext?.setPropertyEditorUiAlias(value.selection[0]); diff --git a/src/Umbraco.Web.UI.Client/src/packages/dictionary/entity-action/export/export.action.ts b/src/Umbraco.Web.UI.Client/src/packages/dictionary/entity-action/export/export.action.ts index aacaf27588f8..17eafe51bd9b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/dictionary/entity-action/export/export.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/dictionary/entity-action/export/export.action.ts @@ -2,20 +2,17 @@ import { UmbDictionaryExportRepository } from '../../repository/index.js'; import { UMB_EXPORT_DICTIONARY_MODAL } from './export-dictionary-modal.token.js'; import { blobDownload } from '@umbraco-cms/backoffice/utils'; import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; export class UmbExportDictionaryEntityAction extends UmbEntityActionBase { override async execute() { if (!this.args.unique) throw new Error('Unique is not available'); - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_EXPORT_DICTIONARY_MODAL, { data: { unique: this.args.unique } }); - - const { includeChildren } = await modalContext.onSubmit(); + const value = await umbOpenModal(this, UMB_EXPORT_DICTIONARY_MODAL, { data: { unique: this.args.unique } }); // Export the file const repository = new UmbDictionaryExportRepository(this); - const { data } = await repository.requestExport(this.args.unique, includeChildren); + const { data } = await repository.requestExport(this.args.unique, value.includeChildren); if (!data) return; diff --git a/src/Umbraco.Web.UI.Client/src/packages/dictionary/entity-action/import/import.action.ts b/src/Umbraco.Web.UI.Client/src/packages/dictionary/entity-action/import/import.action.ts index 12d876790239..309523b6f56a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/dictionary/entity-action/import/import.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/dictionary/entity-action/import/import.action.ts @@ -1,12 +1,10 @@ import { UMB_IMPORT_DICTIONARY_MODAL } from './import-dictionary-modal.token.js'; import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; export class UmbImportDictionaryEntityAction extends UmbEntityActionBase { override async execute() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_IMPORT_DICTIONARY_MODAL, { data: { unique: this.args.unique } }); - await modalContext.onSubmit(); + await umbOpenModal(this, UMB_IMPORT_DICTIONARY_MODAL, { data: { unique: this.args.unique } }); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/dictionary/entity-action/move-to/repository/dictionary-move.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/dictionary/entity-action/move-to/repository/dictionary-move.repository.ts index 29e58c640e49..eb09af93fab0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/dictionary/entity-action/move-to/repository/dictionary-move.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/dictionary/entity-action/move-to/repository/dictionary-move.repository.ts @@ -11,6 +11,9 @@ export class UmbMoveDictionaryRepository extends UmbRepositoryBase implements Um if (!error) { const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); + if (!notificationContext) { + throw new Error('Notification context not found'); + } const notification = { data: { message: `Moved` } }; notificationContext.peek('positive', notification); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/entity-actions/create/create.action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/entity-actions/create/create.action.ts index 128856c9fb93..e3c8c9bf2a3d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/entity-actions/create/create.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/entity-actions/create/create.action.ts @@ -1,18 +1,11 @@ import { UMB_DOCUMENT_BLUEPRINT_ENTITY_TYPE } from '../../entity.js'; import { UMB_DOCUMENT_BLUEPRINT_OPTIONS_CREATE_MODAL } from './constants.js'; -import type { UmbEntityActionArgs } from '@umbraco-cms/backoffice/entity-action'; import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; export class UmbCreateDocumentBlueprintEntityAction extends UmbEntityActionBase { - constructor(host: UmbControllerHost, args: UmbEntityActionArgs) { - super(host, args); - } - override async execute() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_DOCUMENT_BLUEPRINT_OPTIONS_CREATE_MODAL, { + const value = await umbOpenModal(this, UMB_DOCUMENT_BLUEPRINT_OPTIONS_CREATE_MODAL, { data: { parent: { unique: this.args.unique, @@ -21,11 +14,10 @@ export class UmbCreateDocumentBlueprintEntityAction extends UmbEntityActionBase< }, }); - await modalContext.onSubmit().catch(() => undefined); - - const documentTypeUnique = modalContext.getValue().documentTypeUnique; + const documentTypeUnique = value.documentTypeUnique; if (!documentTypeUnique) return; + // TODO: Lets avoid having such hardcoded URLs. [NL] const url = `section/settings/workspace/${UMB_DOCUMENT_BLUEPRINT_ENTITY_TYPE}/create/parent/${this.args.entityType}/${this.args.unique ?? 'null'}/${documentTypeUnique}`; history.pushState(null, '', url); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/entity-actions/move-to/repository/document-blueprint-move.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/entity-actions/move-to/repository/document-blueprint-move.repository.ts index 3c295b9f7070..21825ca819ac 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/entity-actions/move-to/repository/document-blueprint-move.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/entity-actions/move-to/repository/document-blueprint-move.repository.ts @@ -11,6 +11,9 @@ export class UmbMoveDocumentBlueprintRepository extends UmbRepositoryBase implem if (!error) { const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); + if (!notificationContext) { + throw new Error('Notification context not found'); + } const notification = { data: { message: `Moved` } }; notificationContext.peek('positive', notification); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/create/create.action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/create/create.action.ts index 2e6f54367706..6ca1dbe338bc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/create/create.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/create/create.action.ts @@ -1,11 +1,10 @@ import { UMB_DOCUMENT_TYPE_CREATE_OPTIONS_MODAL } from './modal/constants.js'; import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; export class UmbCreateDocumentTypeEntityAction extends UmbEntityActionBase { override async execute() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_DOCUMENT_TYPE_CREATE_OPTIONS_MODAL, { + await umbOpenModal(this, UMB_DOCUMENT_TYPE_CREATE_OPTIONS_MODAL, { data: { parent: { unique: this.args.unique, @@ -13,8 +12,6 @@ export class UmbCreateDocumentTypeEntityAction extends UmbEntityActionBase { override async execute() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_DOCUMENT_TYPE_IMPORT_MODAL, { + await umbOpenModal(this, UMB_DOCUMENT_TYPE_IMPORT_MODAL, { data: { unique: this.args.unique }, }); - await modalContext.onSubmit().catch(() => {}); const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!actionEventContext) { + throw new Error('Action event context is not available'); + } const event = new UmbRequestReloadChildrenOfEntityEvent({ unique: this.args.unique, entityType: this.args.entityType, diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/import/repository/document-type-import.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/import/repository/document-type-import.repository.ts index ea520402b11d..fbd041798d8b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/import/repository/document-type-import.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/import/repository/document-type-import.repository.ts @@ -10,6 +10,9 @@ export class UmbDocumentTypeImportRepository extends UmbRepositoryBase { if (!error) { const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); + if (!notificationContext) { + throw new Error('Notification context not found'); + } const notification = { data: { message: `Imported` } }; notificationContext.peek('positive', notification); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/move-to/repository/document-type-move.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/move-to/repository/document-type-move.repository.ts index d1f26681147d..a4c5e1a1362c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/move-to/repository/document-type-move.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/move-to/repository/document-type-move.repository.ts @@ -11,6 +11,9 @@ export class UmbMoveDocumentTypeRepository extends UmbRepositoryBase implements if (!error) { const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); + if (!notificationContext) { + throw new Error('Notification context not found'); + } const notification = { data: { message: `Moved` } }; notificationContext.peek('positive', notification); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/create-blueprint/create-blueprint.action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/create-blueprint/create-blueprint.action.ts index 6d5079dc3773..50ce4d2a9bfc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/create-blueprint/create-blueprint.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/create-blueprint/create-blueprint.action.ts @@ -1,7 +1,7 @@ import { UmbDocumentCreateBlueprintRepository } from './repository/document-create-blueprint.repository.js'; import { UMB_CREATE_BLUEPRINT_MODAL } from './constants.js'; import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { UmbEntityActionArgs } from '@umbraco-cms/backoffice/entity-action'; @@ -15,13 +15,11 @@ export class UmbCreateDocumentBlueprintEntityAction extends UmbEntityActionBase< override async execute() { if (!this.args.unique) throw new Error('Unique is required'); - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_CREATE_BLUEPRINT_MODAL, { + const value = await umbOpenModal(this, UMB_CREATE_BLUEPRINT_MODAL, { data: { unique: this.args.unique }, }); - await modalContext.onSubmit().catch(() => undefined); - const { name, parent } = modalContext.getValue(); + const { name, parent } = value; if (!name) return; await this.#repository.create({ name, parent, document: { id: this.args.unique } }); diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/create/create.action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/create/create.action.ts index af2adec3bef7..9383940f682b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/create/create.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/create/create.action.ts @@ -3,7 +3,7 @@ import { UMB_DOCUMENT_CREATE_OPTIONS_MODAL } from './document-create-options-mod import type { UmbEntityActionArgs } from '@umbraco-cms/backoffice/entity-action'; import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; export class UmbCreateDocumentEntityAction extends UmbEntityActionBase { constructor(host: UmbControllerHost, args: UmbEntityActionArgs) { @@ -22,15 +22,12 @@ export class UmbCreateDocumentEntityAction extends UmbEntityActionBase { documentItem = data[0]; } - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_DOCUMENT_CREATE_OPTIONS_MODAL, { + await umbOpenModal(this, UMB_DOCUMENT_CREATE_OPTIONS_MODAL, { data: { parent: { unique: this.args.unique, entityType: this.args.entityType }, documentType: documentItem ? { unique: documentItem.documentType.unique } : null, }, }); - - await modalContext.onSubmit(); } } export default UmbCreateDocumentEntityAction; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/culture-and-hostnames/culture-and-hostnames.action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/culture-and-hostnames/culture-and-hostnames.action.ts index 6fa0469af3f2..08862ff46ad5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/culture-and-hostnames/culture-and-hostnames.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/culture-and-hostnames/culture-and-hostnames.action.ts @@ -1,20 +1,12 @@ -import type { UmbEntityActionArgs } from '@umbraco-cms/backoffice/entity-action'; import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UMB_CULTURE_AND_HOSTNAMES_MODAL } from '@umbraco-cms/backoffice/document'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; export class UmbDocumentCultureAndHostnamesEntityAction extends UmbEntityActionBase { - constructor(host: UmbControllerHost, args: UmbEntityActionArgs) { - super(host, args); - } - override async execute() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modalContext = modalManager.open(this, UMB_CULTURE_AND_HOSTNAMES_MODAL, { + await umbOpenModal(this, UMB_CULTURE_AND_HOSTNAMES_MODAL, { data: { unique: this.args.unique }, }); - await modalContext.onSubmit(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/duplicate/duplicate-document.action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/duplicate/duplicate-document.action.ts index 6b2872c074ab..4a3d9311a128 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/duplicate/duplicate-document.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/duplicate/duplicate-document.action.ts @@ -1,7 +1,7 @@ import { UMB_DOCUMENT_ENTITY_TYPE, UMB_DOCUMENT_ROOT_ENTITY_TYPE } from '../../entity.js'; import { UMB_DUPLICATE_DOCUMENT_MODAL } from './modal/index.js'; import { UmbDuplicateDocumentRepository } from './repository/index.js'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; import { UmbEntityActionBase, UmbRequestReloadChildrenOfEntityEvent } from '@umbraco-cms/backoffice/entity-action'; @@ -10,38 +10,35 @@ export class UmbDuplicateDocumentEntityAction extends UmbEntityActionBase if (!this.args.unique) throw new Error('Unique is not available'); if (!this.args.entityType) throw new Error('Entity Type is not available'); - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modal = modalManager.open(this, UMB_DUPLICATE_DOCUMENT_MODAL, { + const value = await umbOpenModal(this, UMB_DUPLICATE_DOCUMENT_MODAL, { data: { unique: this.args.unique, entityType: this.args.entityType, }, }); - try { - const value = await modal.onSubmit(); - const destinationUnique = value.destination.unique; - if (destinationUnique === undefined) throw new Error('Destination Unique is not available'); + const destinationUnique = value.destination.unique; + if (destinationUnique === undefined) throw new Error('Destination Unique is not available'); - const duplicateRepository = new UmbDuplicateDocumentRepository(this); + const duplicateRepository = new UmbDuplicateDocumentRepository(this); - const { error } = await duplicateRepository.requestDuplicate({ - unique: this.args.unique, - destination: { unique: destinationUnique }, - relateToOriginal: value.relateToOriginal, - includeDescendants: value.includeDescendants, - }); - - if (!error) { - this.#reloadMenu(destinationUnique); - } - } catch (error) { - console.log(error); + const { error } = await duplicateRepository.requestDuplicate({ + unique: this.args.unique, + destination: { unique: destinationUnique }, + relateToOriginal: value.relateToOriginal, + includeDescendants: value.includeDescendants, + }); + + if (!error) { + this.#reloadMenu(destinationUnique); } } async #reloadMenu(destinationUnique: string | null) { const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!actionEventContext) { + throw new Error('Action event context is not available'); + } // When duplicating, the destination entity type may or may not be the same as that of // the item selected for duplication (that is available in this.args). diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/duplicate/repository/document-duplicate.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/duplicate/repository/document-duplicate.repository.ts index 584a2f1a125d..4b75d0f9d17d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/duplicate/repository/document-duplicate.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/duplicate/repository/document-duplicate.repository.ts @@ -11,6 +11,9 @@ export class UmbDuplicateDocumentRepository extends UmbRepositoryBase { if (!error) { const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); + if (!notificationContext) { + throw new Error('Notification context not found'); + } const notification = { data: { message: `Duplicated` } }; notificationContext.peek('positive', notification); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/move-to/repository/document-move.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/move-to/repository/document-move.repository.ts index 7f4c96acc0d4..deb04abc6e42 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/move-to/repository/document-move.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/move-to/repository/document-move.repository.ts @@ -11,6 +11,9 @@ export class UmbMoveDocumentRepository extends UmbRepositoryBase implements UmbM if (!error) { const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); + if (!notificationContext) { + throw new Error('Notification context not found'); + } const notification = { data: { message: `Moved` } }; notificationContext.peek('positive', notification); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/notifications/document-notifications.action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/notifications/document-notifications.action.ts index a4844b73e0c2..36e62d4b05a5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/notifications/document-notifications.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/notifications/document-notifications.action.ts @@ -2,7 +2,7 @@ import { UMB_DOCUMENT_NOTIFICATIONS_MODAL } from './modal/document-notifications import type { UmbEntityActionArgs } from '@umbraco-cms/backoffice/entity-action'; import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; export class UmbDocumentNotificationsEntityAction extends UmbEntityActionBase { constructor(host: UmbControllerHost, args: UmbEntityActionArgs) { @@ -10,11 +10,9 @@ export class UmbDocumentNotificationsEntityAction extends UmbEntityActionBase undefined); } } export default UmbDocumentNotificationsEntityAction; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/public-access/public-access.action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/public-access/public-access.action.ts index 3fed99003276..54244c453412 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/public-access/public-access.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/public-access/public-access.action.ts @@ -1,29 +1,24 @@ import { UMB_PUBLIC_ACCESS_MODAL } from './modal/public-access-modal.token.js'; -import type { UmbEntityActionArgs } from '@umbraco-cms/backoffice/entity-action'; import { UmbEntityActionBase, UmbRequestReloadChildrenOfEntityEvent, UmbRequestReloadStructureForEntityEvent, } from '@umbraco-cms/backoffice/entity-action'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; -import type { UmbDocumentDetailRepository } from '@umbraco-cms/backoffice/document'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; export class UmbDocumentPublicAccessEntityAction extends UmbEntityActionBase { - constructor(host: UmbDocumentDetailRepository, args: UmbEntityActionArgs) { - super(host, args); - } - override async execute() { if (!this.args.unique) throw new Error('Unique is not available'); - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const modal = modalManager.open(this, UMB_PUBLIC_ACCESS_MODAL, { data: { unique: this.args.unique } }); - await modal.onSubmit(); + await umbOpenModal(this, UMB_PUBLIC_ACCESS_MODAL, { data: { unique: this.args.unique } }); this.#requestReloadEntity(); } async #requestReloadEntity() { const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!actionEventContext) { + throw new Error('Action event context is not available'); + } const entityStructureEvent = new UmbRequestReloadStructureForEntityEvent({ unique: this.args.unique, diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/item/document-item-data-resolver.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/item/document-item-data-resolver.ts index 0fc145e928ab..c660e4e53612 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/item/document-item-data-resolver.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/item/document-item-data-resolver.ts @@ -3,7 +3,6 @@ import type { UmbDocumentItemModel } from './types.js'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { DocumentVariantStateModel } from '@umbraco-cms/backoffice/external/backend-api'; -import type { UmbAppLanguageContext } from '@umbraco-cms/backoffice/language'; import { UMB_APP_LANGUAGE_CONTEXT } from '@umbraco-cms/backoffice/language'; import { UmbBooleanState, UmbStringState } from '@umbraco-cms/backoffice/observable-api'; import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property'; @@ -23,7 +22,7 @@ export class UmbDocumentItemDataResolver; + #init: Promise; #unique = new UmbStringState(undefined); public readonly unique = this.#unique.asObservable(); @@ -47,12 +46,12 @@ export class UmbDocumentItemDataResolver { - this.#propertyDataSetCulture = context.getVariantId(); - this.#setVariantAwareValues(); - }); - this.#init = Promise.all([ + this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, (context) => { + this.#propertyDataSetCulture = context.getVariantId(); + this.#setVariantAwareValues(); + }).asPromise(), + this.consumeContext(UMB_APP_LANGUAGE_CONTEXT, (context) => { this.observe(context.appLanguageCulture, (culture) => { this.#appCulture = culture; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish-with-descendants/workspace-action/publish-with-descendants.action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish-with-descendants/workspace-action/publish-with-descendants.action.ts index 9e802ab80faa..79268ffde995 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish-with-descendants/workspace-action/publish-with-descendants.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish-with-descendants/workspace-action/publish-with-descendants.action.ts @@ -4,6 +4,9 @@ import { UmbWorkspaceActionBase } from '@umbraco-cms/backoffice/workspace'; export class UmbDocumentPublishWithDescendantsWorkspaceAction extends UmbWorkspaceActionBase { override async execute() { const workspaceContext = await this.getContext(UMB_DOCUMENT_PUBLISHING_WORKSPACE_CONTEXT); + if (!workspaceContext) { + throw new Error('The workspace context is missing'); + } return workspaceContext.publishWithDescendants(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish/entity-action/publish.action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish/entity-action/publish.action.ts index 098993fc23e2..b8a01e567c03 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish/entity-action/publish.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish/entity-action/publish.action.ts @@ -7,7 +7,7 @@ import type { UmbEntityActionArgs } from '@umbraco-cms/backoffice/entity-action' import { UmbEntityActionBase, UmbRequestReloadStructureForEntityEvent } from '@umbraco-cms/backoffice/entity-action'; import { UmbVariantId } from '@umbraco-cms/backoffice/variant'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; import { UMB_CURRENT_USER_CONTEXT } from '@umbraco-cms/backoffice/current-user'; import { UMB_NOTIFICATION_CONTEXT } from '@umbraco-cms/backoffice/notification'; @@ -22,6 +22,7 @@ export class UmbPublishDocumentEntityAction extends UmbEntityActionBase { if (!this.args.unique) throw new Error('The document unique identifier is missing'); const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); + if (!notificationContext) throw new Error('The notification context is missing'); const localize = new UmbLocalizationController(this); const languageRepository = new UmbLanguageCollectionRepository(this._host); @@ -33,9 +34,11 @@ export class UmbPublishDocumentEntityAction extends UmbEntityActionBase { if (!documentData) throw new Error('The document was not found'); const appLanguageContext = await this.getContext(UMB_APP_LANGUAGE_CONTEXT); + if (!appLanguageContext) throw new Error('The app language context is missing'); const appCulture = appLanguageContext.getAppCulture(); const currentUserContext = await this.getContext(UMB_CURRENT_USER_CONTEXT); + if (!currentUserContext) throw new Error('The current user context is missing'); const currentUserAllowedLanguages = currentUserContext.getLanguages(); const currentUserHasAccessToAllLanguages = currentUserContext.getHasAccessToAllLanguages(); @@ -61,6 +64,7 @@ export class UmbPublishDocumentEntityAction extends UmbEntityActionBase { ); const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!actionEventContext) throw new Error('The action event context is missing'); const event = new UmbRequestReloadStructureForEntityEvent({ unique: this.args.unique, entityType: this.args.entityType, @@ -94,21 +98,17 @@ export class UmbPublishDocumentEntityAction extends UmbEntityActionBase { selection.push(options[0].unique); } - const modalManagerContext = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const result = await modalManagerContext - .open(this, UMB_DOCUMENT_PUBLISH_MODAL, { - data: { - options, - pickableFilter: (option) => { - if (!option.culture) return false; - if (currentUserHasAccessToAllLanguages) return true; - return currentUserAllowedLanguages.includes(option.culture); - }, + const result = await umbOpenModal(this, UMB_DOCUMENT_PUBLISH_MODAL, { + data: { + options, + pickableFilter: (option) => { + if (!option.culture) return false; + if (currentUserHasAccessToAllLanguages) return true; + return currentUserAllowedLanguages.includes(option.culture); }, - value: { selection }, - }) - .onSubmit() - .catch(() => undefined); + }, + value: { selection }, + }).catch(() => undefined); if (!result?.selection.length) return; diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/workspace/partial-view-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/workspace/partial-view-workspace-editor.element.ts index 2f48701c948b..4bf7289934e0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/workspace/partial-view-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/workspace/partial-view-workspace-editor.element.ts @@ -3,7 +3,7 @@ import type { UmbTemplatingInsertMenuElement } from '../../local-components/inse import { UMB_PARTIAL_VIEW_WORKSPACE_CONTEXT } from './partial-view-workspace.context-token.js'; import { css, customElement, html, nothing, query, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; -import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UMB_TEMPLATE_QUERY_BUILDER_MODAL } from '@umbraco-cms/backoffice/template'; import type { UmbCodeEditorElement } from '@umbraco-cms/backoffice/code-editor'; @@ -52,15 +52,11 @@ export class UmbPartialViewWorkspaceEditorElement extends UmbLitElement { } async #openQueryBuilder() { - const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const queryBuilderModal = modalManager.open(this, UMB_TEMPLATE_QUERY_BUILDER_MODAL); - - queryBuilderModal - ?.onSubmit() - .then((queryBuilderModalValue) => { - if (queryBuilderModalValue.value) this._codeEditor?.insert(getQuerySnippet(queryBuilderModalValue.value)); - }) - .catch(() => undefined); + const queryBuilderModalValue = await umbOpenModal(this, UMB_TEMPLATE_QUERY_BUILDER_MODAL).catch(() => undefined); + + if (queryBuilderModalValue?.value) { + this._codeEditor?.insert(getQuerySnippet(queryBuilderModalValue.value)); + } } override render() { From c054ac92223d90fe6647f30aad82961f5a65b10d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Sun, 9 Mar 2025 21:14:33 +0100 Subject: [PATCH 19/26] correction batch 5 --- .../workspace/block-grid-area-type-workspace.context.ts | 3 +++ .../block/block-grid/context/block-grid-entry.context.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/components/block-grid-area-config-entry/workspace/block-grid-area-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/components/block-grid-area-config-entry/workspace/block-grid-area-type-workspace.context.ts index 8bbc090c01db..9cb21959c37e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/components/block-grid-area-config-entry/workspace/block-grid-area-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/components/block-grid-area-config-entry/workspace/block-grid-area-type-workspace.context.ts @@ -176,6 +176,9 @@ export class UmbBlockGridAreaTypeWorkspaceContext } const context = await this.getContext(UMB_PROPERTY_CONTEXT); + if (!context) { + throw new Error('Property context not found.'); + } // TODO: We should most likely consume already, in this way I avoid having the reset this consumption. context.setValue(appendToFrozenArray(context.getValue() ?? [], this.#data.getValue(), (x) => x?.key)); diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-entry.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-entry.context.ts index de3b11d474a5..94ccd89e6969 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-entry.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-entry.context.ts @@ -293,6 +293,9 @@ export class UmbBlockGridEntryContext const propertyDatasetContext = await this.getContext(UMB_PROPERTY_DATASET_CONTEXT); const propertyContext = await this.getContext(UMB_PROPERTY_CONTEXT); const clipboardContext = await this.getContext(UMB_CLIPBOARD_PROPERTY_CONTEXT); + if (!clipboardContext) { + throw new Error('No clipboard context found'); + } const workspaceName = propertyDatasetContext?.getName(); const propertyLabel = propertyContext?.getLabel(); From 9e4ded5cf52b6a5b9b2a4487188badb79386b40a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Sun, 9 Mar 2025 21:25:27 +0100 Subject: [PATCH 20/26] correction batch 6 --- .../block-type-custom-view-guide.element.ts | 2 +- .../create/collection-create-action.element.ts | 6 +----- .../entity-actions-bundle.element.ts | 6 +----- .../design/content-type-design-editor.element.ts | 2 +- ...ntity-create-option-action-list-modal.element.ts | 13 ++++++------- .../entity-action/default/entity-action.element.ts | 7 +------ .../entity-bulk-action.element.ts | 6 +----- .../common/confirm/confirm-modal.controller.ts | 2 -- .../core/modal/controller/open-modal.controller.ts | 2 +- .../kinds/default/property-action.element.ts | 6 +----- .../default/workspace-action-menu-item.element.ts | 6 +----- .../modal/data-type-create-options-modal.element.ts | 10 ++++------ ...cument-blueprint-options-create-modal.element.ts | 12 ++++++------ .../entity-bulk-action/unpublish.bulk-action.ts | 4 +--- .../media-type-create-options-modal.element.ts | 10 ++++------ .../import/media-type-import.action.ts | 2 +- .../bulk-delete/bulk-delete-with-relation.action.ts | 2 +- .../views/section-view-examine-searchers.ts | 2 +- .../partial-view-create-options-modal.element.ts | 10 ++++------ .../script-create-options-modal.element.ts | 12 ++++++------ .../stylesheet-create-options-modal.element.ts | 12 ++++++------ .../query-builder/query-builder-modal.element.ts | 2 +- .../create/modal/create-user-modal.element.ts | 2 +- .../invite-user.collection-action.ts | 2 +- 24 files changed, 52 insertions(+), 88 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/block-type-custom-view-guide/block-type-custom-view-guide.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/block-type-custom-view-guide/block-type-custom-view-guide.element.ts index 1bc04243f49b..5d54f25b417c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/block-type-custom-view-guide/block-type-custom-view-guide.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/block-type-custom-view-guide/block-type-custom-view-guide.element.ts @@ -6,7 +6,7 @@ import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registr import { stringOrStringArrayContains } from '@umbraco-cms/backoffice/utils'; import { UmbExtensionsManifestInitializer } from '@umbraco-cms/backoffice/extension-api'; import { UmbDocumentTypeDetailRepository } from '@umbraco-cms/backoffice/document-type'; -import { UMB_MODAL_MANAGER_CONTEXT, umbOpenModal } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import type { ManifestBlockEditorCustomView } from '@umbraco-cms/backoffice/block-custom-view'; @customElement('umb-block-type-custom-view-guide') diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/collection/action/create/collection-create-action.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/collection/action/create/collection-create-action.element.ts index 0b721ec903df..2d2f98c6d70c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/collection/action/create/collection-create-action.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/collection/action/create/collection-create-action.element.ts @@ -42,11 +42,7 @@ export class UmbCollectionCreateActionButtonElement extends UmbLitElement { } if (!controller.api) throw new Error('No API found'); - try { - await controller.api.execute(); - } catch (error) { - return; - } + await controller.api.execute().catch(() => {}); } constructor() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/entity-actions-bundle/entity-actions-bundle.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/entity-actions-bundle/entity-actions-bundle.element.ts index db1fe6c6c8f3..50f0b0cfeea7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/entity-actions-bundle/entity-actions-bundle.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/entity-actions-bundle/entity-actions-bundle.element.ts @@ -104,11 +104,7 @@ export class UmbEntityActionsBundleElement extends UmbLitElement { } event.stopPropagation(); - try { - await this._firstActionApi?.execute(); - } catch (error) { - return; - } + await this._firstActionApi?.execute().catch(() => {}); } #onActionExecuted() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/views/design/content-type-design-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/views/design/content-type-design-editor.element.ts index 0a4b127311bf..2da080658614 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/views/design/content-type-design-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/views/design/content-type-design-editor.element.ts @@ -18,7 +18,7 @@ import type { UmbWorkspaceViewElement, } from '@umbraco-cms/backoffice/workspace'; import type { UmbConfirmModalData } from '@umbraco-cms/backoffice/modal'; -import { UMB_MODAL_MANAGER_CONTEXT, umbConfirmModal, umbOpenModal } from '@umbraco-cms/backoffice/modal'; +import { umbConfirmModal, umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/common/create/modal/entity-create-option-action-list-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/common/create/modal/entity-create-option-action-list-modal.element.ts index 8f4ad27ce7b8..3df6311c7797 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/common/create/modal/entity-create-option-action-list-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/common/create/modal/entity-create-option-action-list-modal.element.ts @@ -68,13 +68,12 @@ export class UmbEntityCreateOptionActionListModalElement extends UmbModalBaseEle throw new Error('No API found'); } - try { - await controller.api.execute(); - } catch (error) { - return; - } - - this._submitModal(); + controller.api + .execute() + .then(() => { + this._submitModal(); + }) + .catch(() => {}); } async #onNavigate(event: Event, href: string | undefined) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/default/entity-action.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/default/entity-action.element.ts index 96407a4bac22..789b50c601f5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/default/entity-action.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/default/entity-action.element.ts @@ -49,13 +49,8 @@ export class UmbEntityActionDefaultElement< async #onClickLabel(event: UUIMenuItemEvent) { if (!this._href) { event.stopPropagation(); - try { - await this.#api?.execute(); - } catch (error) { - return; - } + await this.#api?.execute().catch(() => {}); } - console.log('success'); this.dispatchEvent(new UmbActionExecutedEvent()); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-bulk-action/entity-bulk-action.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-bulk-action/entity-bulk-action.element.ts index 7bbe79772b74..66513f528ed1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-bulk-action/entity-bulk-action.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-bulk-action/entity-bulk-action.element.ts @@ -26,11 +26,7 @@ export class UmbEntityBulkActionDefaultElement< async #onClick(event: PointerEvent) { if (!this.api) return; event.stopPropagation(); - try { - await this.api.execute(); - } catch (error) { - return; - } + await this.api.execute().catch(() => {}); this.dispatchEvent(new UmbActionExecutedEvent()); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/confirm/confirm-modal.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/confirm/confirm-modal.controller.ts index e896fbfa5dfc..7e2b9d6bbf9b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/confirm/confirm-modal.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/confirm/confirm-modal.controller.ts @@ -1,7 +1,5 @@ -import { UMB_MODAL_MANAGER_CONTEXT } from '../../context/index.js'; import { UmbOpenModalController } from '../../index.js'; import { UMB_CONFIRM_MODAL, type UmbConfirmModalData } from './confirm-modal.token.js'; -import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; /** @deprecated use `UmbConfirmModalData`, will be removed in v.17 */ diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/controller/open-modal.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/controller/open-modal.controller.ts index 7cffdb71b984..55ada1c8dc46 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/controller/open-modal.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/controller/open-modal.controller.ts @@ -1,4 +1,4 @@ -import { UMB_MODAL_MANAGER_CONTEXT, type UmbModalContextClassArgs, type UmbModalRejectReason } from '../index.js'; +import { UMB_MODAL_MANAGER_CONTEXT, type UmbModalContextClassArgs } from '../index.js'; import type { UmbModalToken } from '../token/modal-token.js'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-action/kinds/default/property-action.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-action/kinds/default/property-action.element.ts index dabebb5d8d82..d57abc563da8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-action/kinds/default/property-action.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-action/kinds/default/property-action.element.ts @@ -34,11 +34,7 @@ export class UmbPropertyActionElement< async #onClickLabel(event: UUIMenuItemEvent) { if (!this._href) { event.stopPropagation(); - try { - await this.#api?.execute(); - } catch (error) { - return; - } + await this.#api?.execute().catch(() => {}); } this.dispatchEvent(new UmbActionExecutedEvent()); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-action-menu-item/default/workspace-action-menu-item.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-action-menu-item/default/workspace-action-menu-item.element.ts index c85f9498bc52..279f4bc4e17d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-action-menu-item/default/workspace-action-menu-item.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-action-menu-item/default/workspace-action-menu-item.element.ts @@ -34,11 +34,7 @@ export class UmbWorkspaceActionMenuItemElement< async #onClickLabel(event: UUIMenuItemEvent) { if (!this._href) { event.stopPropagation(); - try { - await this.#api?.execute(); - } catch (error) { - return; - } + await this.#api?.execute().catch(() => {}); } this.dispatchEvent(new UmbActionExecutedEvent()); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/data-type/entity-actions/create/modal/data-type-create-options-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/data-type/entity-actions/create/modal/data-type-create-options-modal.element.ts index 67019a67b1f2..d82257a9ade4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/data-type/entity-actions/create/modal/data-type-create-options-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/data-type/entity-actions/create/modal/data-type-create-options-modal.element.ts @@ -51,12 +51,10 @@ export class UmbDataTypeCreateOptionsModalElement extends UmbModalBaseElement this._submitModal()) + .catch(() => undefined); } override render() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/entity-actions/create/modal/document-blueprint-options-create-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/entity-actions/create/modal/document-blueprint-options-create-modal.element.ts index 3565747afd05..41bb58dc45ae 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/entity-actions/create/modal/document-blueprint-options-create-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/entity-actions/create/modal/document-blueprint-options-create-modal.element.ts @@ -50,12 +50,12 @@ export class UmbDocumentBlueprintOptionsCreateModalElement extends UmbModalBaseE async #onCreateFolderClick(event: PointerEvent) { event.stopPropagation(); - try { - await this.#createFolderAction?.execute(); - this._submitModal(); - } catch (error) { - return; - } + this.#createFolderAction + ?.execute() + .then(() => { + this._submitModal(); + }) + .catch(() => {}); } #onSelected(event: UmbSelectedEvent) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/entity-bulk-action/unpublish.bulk-action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/entity-bulk-action/unpublish.bulk-action.ts index ee369add5aad..12176627abcf 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/entity-bulk-action/unpublish.bulk-action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/unpublish/entity-bulk-action/unpublish.bulk-action.ts @@ -2,7 +2,7 @@ import { UmbUnpublishDocumentEntityAction } from '../entity-action/index.js'; import type { UmbDocumentVariantOptionModel } from '../../../types.js'; import { UMB_DOCUMENT_ENTITY_TYPE, UMB_DOCUMENT_UNPUBLISH_MODAL } from '../../../constants.js'; import { UmbDocumentPublishingRepository } from '../../repository/index.js'; -import { UMB_MODAL_MANAGER_CONTEXT, umbConfirmModal, umbOpenModal } from '@umbraco-cms/backoffice/modal'; +import { umbConfirmModal, umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UmbEntityBulkActionBase } from '@umbraco-cms/backoffice/entity-bulk-action'; import { UMB_APP_LANGUAGE_CONTEXT, UmbLanguageCollectionRepository } from '@umbraco-cms/backoffice/language'; import { UmbVariantId } from '@umbraco-cms/backoffice/variant'; @@ -55,8 +55,6 @@ export class UmbDocumentUnpublishEntityBulkAction extends UmbEntityBulkActionBas segment: null, })); - const modalManagerContext = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - const eventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); if (!eventContext) { throw new Error('Event context not found'); diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/create/modal/media-type-create-options-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/create/modal/media-type-create-options-modal.element.ts index fb0f8555e761..58ef88ce38b8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/create/modal/media-type-create-options-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/create/modal/media-type-create-options-modal.element.ts @@ -41,12 +41,10 @@ export class UmbMediaTypeCreateOptionsModalElement extends UmbModalBaseElement this.modalContext?.submit()) + .catch(() => undefined); } // close the modal when navigating to data type diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/import/media-type-import.action.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/import/media-type-import.action.ts index 5ee608c91e16..981413133198 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/import/media-type-import.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/import/media-type-import.action.ts @@ -1,7 +1,7 @@ import { UMB_MEDIA_TYPE_IMPORT_MODAL } from './modal/media-type-import-modal.token.js'; import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; import { UmbEntityActionBase, UmbRequestReloadChildrenOfEntityEvent } from '@umbraco-cms/backoffice/entity-action'; -import { UMB_MODAL_MANAGER_CONTEXT, umbOpenModal } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; export class UmbImportMediaTypeEntityAction extends UmbEntityActionBase { override async execute() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entity-actions/bulk-delete/bulk-delete-with-relation.action.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entity-actions/bulk-delete/bulk-delete-with-relation.action.ts index 4b5e9975a708..c93f35e1e211 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entity-actions/bulk-delete/bulk-delete-with-relation.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entity-actions/bulk-delete/bulk-delete-with-relation.action.ts @@ -1,7 +1,7 @@ import type { MetaEntityBulkActionDeleteWithRelationKind } from './types.js'; import { UMB_BULK_DELETE_WITH_RELATION_CONFIRM_MODAL } from './modal/bulk-delete-with-relation-modal.token.js'; import { UmbDeleteEntityBulkAction } from '@umbraco-cms/backoffice/entity-bulk-action'; -import { UMB_MODAL_MANAGER_CONTEXT, umbOpenModal } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; export class UmbBulkDeleteWithRelationEntityAction extends UmbDeleteEntityBulkAction { override async _confirmDelete() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/search/examine-management-dashboard/views/section-view-examine-searchers.ts b/src/Umbraco.Web.UI.Client/src/packages/search/examine-management-dashboard/views/section-view-examine-searchers.ts index 7c0b0b7e04e8..cb3837558be7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/search/examine-management-dashboard/views/section-view-examine-searchers.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/search/examine-management-dashboard/views/section-view-examine-searchers.ts @@ -1,7 +1,7 @@ import { UMB_EXAMINE_FIELDS_SETTINGS_MODAL, UMB_EXAMINE_FIELDS_VIEWER_MODAL } from '../modal/constants.js'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { css, html, nothing, customElement, state, query, property } from '@umbraco-cms/backoffice/external/lit'; -import { UMB_MODAL_MANAGER_CONTEXT, umbOpenModal } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/workspace'; import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router'; import type { SearchResultResponseModel, FieldPresentationModel } from '@umbraco-cms/backoffice/external/backend-api'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/entity-actions/create/options-modal/partial-view-create-options-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/entity-actions/create/options-modal/partial-view-create-options-modal.element.ts index ab97ff75e7fe..4911002b2e21 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/entity-actions/create/options-modal/partial-view-create-options-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/entity-actions/create/options-modal/partial-view-create-options-modal.element.ts @@ -30,12 +30,10 @@ export class UmbPartialViewCreateOptionsModalElement extends UmbModalBaseElement async #onCreateFolderClick(event: PointerEvent) { event.stopPropagation(); - try { - await this.#createFolderAction?.execute(); - this._submitModal(); - } catch (error) { - return; - } + await this.#createFolderAction + ?.execute() + .then(() => this._submitModal()) + .catch(() => undefined); } async #onCreateFromSnippetClick(event: PointerEvent) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/scripts/entity-actions/create/options-modal/script-create-options-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/scripts/entity-actions/create/options-modal/script-create-options-modal.element.ts index 194170312bc4..1c2af4380398 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/scripts/entity-actions/create/options-modal/script-create-options-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/scripts/entity-actions/create/options-modal/script-create-options-modal.element.ts @@ -26,12 +26,12 @@ export class UmbScriptCreateOptionsModalElement extends UmbModalBaseElement { + this._submitModal(); + }) + .catch(() => {}); } // close the modal when navigating to data type diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/entity-actions/create/options-modal/stylesheet-create-options-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/entity-actions/create/options-modal/stylesheet-create-options-modal.element.ts index bf65d131e22f..ac9328a382bd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/entity-actions/create/options-modal/stylesheet-create-options-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/entity-actions/create/options-modal/stylesheet-create-options-modal.element.ts @@ -29,12 +29,12 @@ export class UmbStylesheetCreateOptionsModalElement extends UmbModalBaseElement< async #onCreateFolderClick(event: PointerEvent) { event.stopPropagation(); - try { - await this.#createFolderAction?.execute(); - this._submitModal(); - } catch (error) { - return; - } + this.#createFolderAction + ?.execute() + .then(() => { + this._submitModal(); + }) + .catch(() => {}); } // close the modal when navigating to data type diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/modals/query-builder/query-builder-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/modals/query-builder/query-builder-modal.element.ts index e9144f14b08d..9be803914770 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/modals/query-builder/query-builder-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/modals/query-builder/query-builder-modal.element.ts @@ -8,7 +8,7 @@ import type { } from './query-builder-modal.token.js'; import type { UUIComboboxListElement } from '@umbraco-cms/backoffice/external/uui'; import { css, html, customElement, state, query, queryAll, ifDefined } from '@umbraco-cms/backoffice/external/lit'; -import { UmbModalBaseElement, UMB_MODAL_MANAGER_CONTEXT, umbOpenModal } from '@umbraco-cms/backoffice/modal'; +import { UmbModalBaseElement, umbOpenModal } from '@umbraco-cms/backoffice/modal'; import type { TemplateQueryResultResponseModel, TemplateQuerySettingsResponseModel, diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/create-user-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/create-user-modal.element.ts index 25154c920959..a2b2eb60d0d9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/create-user-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/create-user-modal.element.ts @@ -6,7 +6,7 @@ import type { UmbUserGroupInputElement } from '@umbraco-cms/backoffice/user-grou import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; import { css, html, customElement, query } from '@umbraco-cms/backoffice/external/lit'; -import { UmbModalBaseElement, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal'; import type { UmbReferenceByUnique } from '@umbraco-cms/backoffice/models'; @customElement('umb-create-user-modal') diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/collection-action/invite-user.collection-action.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/collection-action/invite-user.collection-action.ts index b25264a83f9c..f8aec04bdc79 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/collection-action/invite-user.collection-action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/collection-action/invite-user.collection-action.ts @@ -1,6 +1,6 @@ import { UMB_INVITE_USER_MODAL } from '../modal/index.js'; import { UmbCollectionActionBase } from '@umbraco-cms/backoffice/collection'; -import { UMB_MODAL_MANAGER_CONTEXT, umbOpenModal } from '@umbraco-cms/backoffice/modal'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; export class UmbInviteUserCollectionAction extends UmbCollectionActionBase { async execute() { From 6256537ce826a1284d2db32341a8db933bb0a452 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 12 Mar 2025 21:17:41 +0100 Subject: [PATCH 21/26] add null checks --- .../tiptap/extensions/toolbar/anchor.tiptap-toolbar-api.ts | 1 + .../extensions/toolbar/character-map.tiptap-toolbar-api.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/anchor.tiptap-toolbar-api.ts b/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/anchor.tiptap-toolbar-api.ts index 42a8d5f96a31..234df7ae8ab9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/anchor.tiptap-toolbar-api.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/anchor.tiptap-toolbar-api.ts @@ -10,6 +10,7 @@ export default class UmbTiptapToolbarAnchorExtensionApi extends UmbTiptapToolbar if (!attrs) return; const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); + if (!modalManager) throw new Error('Modal manager not found'); const modal = modalManager.open(this, UMB_TIPTAP_ANCHOR_MODAL, { data: { id: attrs?.id } }); if (!modal) return; diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/character-map.tiptap-toolbar-api.ts b/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/character-map.tiptap-toolbar-api.ts index ef239b3727ea..784a45e242de 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/character-map.tiptap-toolbar-api.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/character-map.tiptap-toolbar-api.ts @@ -8,6 +8,7 @@ export default class UmbTiptapToolbarCharacterMapExtensionApi extends UmbTiptapT if (!editor) return; const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); + if (!modalManager) throw new Error('Modal manager not found'); const modal = modalManager.open(this, UMB_TIPTAP_CHARACTER_MAP_MODAL); if (!modal) return; From b21f81c2f7263387dadf8423594479406929d7b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 13 Mar 2025 11:03:04 +0100 Subject: [PATCH 22/26] no need for promise.all --- .../property/context/clipboard.property-context.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/clipboard/property/context/clipboard.property-context.ts b/src/Umbraco.Web.UI.Client/src/packages/clipboard/property/context/clipboard.property-context.ts index fb4134124612..58068ae10a15 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/clipboard/property/context/clipboard.property-context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/clipboard/property/context/clipboard.property-context.ts @@ -32,11 +32,9 @@ export class UmbClipboardPropertyContext extends UmbContextBase { - this.#modalManagerContext = context; - }).asPromise(), - ]); + this.#init = this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (context) => { + this.#modalManagerContext = context; + }).asPromise(); } /** From af56ecb5bd85872e9c3d3d9137dad61ba3200e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 13 Mar 2025 15:56:20 +0100 Subject: [PATCH 23/26] remove todo --- .../extension-element-and-api-slot-element-base.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/extension-element-and-api-slot-element-base.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/extension-element-and-api-slot-element-base.ts index 7ef30b8a229b..8837c0ea38c8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/extension-element-and-api-slot-element-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/extension-element-and-api-slot-element-base.ts @@ -4,8 +4,6 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import type { ManifestElementAndApi } from '@umbraco-cms/backoffice/extension-api'; import { UmbExtensionElementAndApiInitializer } from '@umbraco-cms/backoffice/extension-api'; -// TODO: Eslint: allow abstract element class to end with "ElementBase" instead of "Element" - export abstract class UmbExtensionElementAndApiSlotElementBase< ManifestType extends ManifestElementAndApi, > extends UmbLitElement { From 89c064b434d2e86349fca32f21ecf20eab2320ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 13 Mar 2025 15:56:56 +0100 Subject: [PATCH 24/26] promise clean up --- .../core/tree/data/tree-repository-base.ts | 2 +- .../core/tree/default/default-tree.element.ts | 44 +++++++++---------- .../delete-folder/delete-folder.action.ts | 37 ++++------------ .../repository/current-user.repository.ts | 4 +- 4 files changed, 32 insertions(+), 55 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/data/tree-repository-base.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/data/tree-repository-base.ts index 358438def7e7..18baee61cec4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/data/tree-repository-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/data/tree-repository-base.ts @@ -62,7 +62,7 @@ export abstract class UmbTreeRepositoryBase< this._init = this.consumeContext(treeStoreContextAlias, (instance) => { this._treeStore = instance; - }).asPromise(); + }).asPromise({ preventTimeout: true }); } /** diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/default/default-tree.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/default/default-tree.element.ts index 329e9dfb3d0c..74cbc3514164 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/default/default-tree.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/default/default-tree.element.ts @@ -52,61 +52,59 @@ export class UmbDefaultTreeElement extends UmbLitElement { @state() private _totalPages = 1; - #treeContext?: UmbDefaultTreeContext; - #init: Promise; + @state() + _treeContext?: UmbDefaultTreeContext; constructor() { super(); - this.#init = Promise.all([ - // TODO: Notice this can be retrieve via a api property. [NL] - this.consumeContext(UMB_TREE_CONTEXT, (instance) => { - this.#treeContext = instance; - this.observe(this.#treeContext.treeRoot, (treeRoot) => (this._treeRoot = treeRoot)); - this.observe(this.#treeContext.rootItems, (rootItems) => (this._rootItems = rootItems)); - this.observe(this.#treeContext.pagination.currentPage, (value) => (this._currentPage = value)); - this.observe(this.#treeContext.pagination.totalPages, (value) => (this._totalPages = value)); - }).asPromise(), - ]); + // TODO: Notice this can be retrieve via a api property. [NL] + this.consumeContext(UMB_TREE_CONTEXT, (instance) => { + this._treeContext = instance; + this.observe(this._treeContext.treeRoot, (treeRoot) => (this._treeRoot = treeRoot)); + this.observe(this._treeContext.rootItems, (rootItems) => (this._rootItems = rootItems)); + this.observe(this._treeContext.pagination.currentPage, (value) => (this._currentPage = value)); + this.observe(this._treeContext.pagination.totalPages, (value) => (this._totalPages = value)); + }); } protected override async updated( _changedProperties: PropertyValueMap | Map, ): Promise { super.updated(_changedProperties); - await this.#init; + if (this._treeContext === undefined) return; if (_changedProperties.has('selectionConfiguration')) { this._selectionConfiguration = this.selectionConfiguration; - this.#treeContext!.selection.setMultiple(this._selectionConfiguration.multiple ?? false); - this.#treeContext!.selection.setSelectable(this._selectionConfiguration.selectable ?? true); - this.#treeContext!.selection.setSelection(this._selectionConfiguration.selection ?? []); + this._treeContext!.selection.setMultiple(this._selectionConfiguration.multiple ?? false); + this._treeContext!.selection.setSelectable(this._selectionConfiguration.selectable ?? true); + this._treeContext!.selection.setSelection(this._selectionConfiguration.selection ?? []); } if (_changedProperties.has('startNode')) { - this.#treeContext!.setStartNode(this.startNode); + this._treeContext!.setStartNode(this.startNode); } if (_changedProperties.has('hideTreeRoot')) { - this.#treeContext!.setHideTreeRoot(this.hideTreeRoot); + this._treeContext!.setHideTreeRoot(this.hideTreeRoot); } if (_changedProperties.has('foldersOnly')) { - this.#treeContext!.setFoldersOnly(this.foldersOnly ?? false); + this._treeContext!.setFoldersOnly(this.foldersOnly ?? false); } if (_changedProperties.has('selectableFilter')) { - this.#treeContext!.selectableFilter = this.selectableFilter; + this._treeContext!.selectableFilter = this.selectableFilter; } if (_changedProperties.has('filter')) { - this.#treeContext!.filter = this.filter; + this._treeContext!.filter = this.filter; } } getSelection() { - return this.#treeContext?.selection.getSelection(); + return this._treeContext?.selection.getSelection(); } override render() { @@ -144,7 +142,7 @@ export class UmbDefaultTreeElement extends UmbLitElement { #onLoadMoreClick = (event: any) => { event.stopPropagation(); const next = (this._currentPage = this._currentPage + 1); - this.#treeContext?.pagination.setCurrentPageNumber(next); + this._treeContext?.pagination.setCurrentPageNumber(next); }; #renderPaging() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/folder/entity-action/delete-folder/delete-folder.action.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/folder/entity-action/delete-folder/delete-folder.action.ts index aa84ab9b0f81..508e8d450444 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/folder/entity-action/delete-folder/delete-folder.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/folder/entity-action/delete-folder/delete-folder.action.ts @@ -1,41 +1,20 @@ import type { MetaEntityActionFolderKind, UmbFolderModel } from '../../types.js'; import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import type { UmbEntityActionArgs } from '@umbraco-cms/backoffice/entity-action'; import { UmbEntityActionBase, UmbRequestReloadStructureForEntityEvent } from '@umbraco-cms/backoffice/entity-action'; -import { UmbExtensionApiInitializer } from '@umbraco-cms/backoffice/extension-api'; -import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; +import { createExtensionApiByAlias } from '@umbraco-cms/backoffice/extension-registry'; import { umbConfirmModal } from '@umbraco-cms/backoffice/modal'; import type { UmbDetailRepository } from '@umbraco-cms/backoffice/repository'; export class UmbDeleteFolderEntityAction extends UmbEntityActionBase { - // TODO: make base type for item and detail models - #folderRepository?: UmbDetailRepository; - #init: Promise; - - constructor(host: UmbControllerHost, args: UmbEntityActionArgs) { - super(host, args); - - // TODO: We should properly look into how we can simplify the one time usage of a extension api, as its a bit of overkill to take conditions/overwrites and observation of extensions into play here: [NL] - // But since this happens when we execute an action, it does most likely not hurt any users, but it is a bit of a overkill to do this for every action: [NL] - this.#init = Promise.all([ - new UmbExtensionApiInitializer( - this._host, - umbExtensionsRegistry, - this.args.meta.folderRepositoryAlias, - [this._host], - (permitted, ctrl) => { - this.#folderRepository = permitted ? (ctrl.api as UmbDetailRepository) : undefined; - }, - ).asPromise(), - ]); - } - override async execute() { if (!this.args.unique) throw new Error('Unique is not available'); - await this.#init; + const folderRepository = await createExtensionApiByAlias>( + this._host, + this.args.meta.folderRepositoryAlias, + [this._host], + ); - const { data: folder } = await this.#folderRepository!.requestByUnique(this.args.unique); + const { data: folder } = await folderRepository.requestByUnique(this.args.unique); if (folder) { // TODO: maybe we can show something about how many items are part of the folder? @@ -46,7 +25,7 @@ export class UmbDeleteFolderEntityAction extends UmbEntityActionBase { this.#currentUserStore = instance; - }).asPromise(), + }).asPromise({ preventTimeout: true }), this.consumeContext(UMB_NOTIFICATION_CONTEXT, (instance) => { this.notificationContext = instance; - }).asPromise(), + }).asPromise({ preventTimeout: true }), ]); } From e76ceeeaa4b8368e311b7fb385246487c0ef34b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 14 Mar 2025 09:55:31 +0100 Subject: [PATCH 25/26] rejection reason --- .../src/libs/context-api/consume/context-consumer.ts | 6 ++++-- .../core/repository/detail/detail-repository-base.ts | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts index 35d0870ca0d2..d1cf88634a70 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts @@ -23,7 +23,7 @@ export class UmbContextConsumer; #promise?: Promise; #promiseResolver?: (instance: ResultType) => void; - #promiseRejecter?: (instance?: ResultType) => void; + #promiseRejecter?: (reason: string) => void; #instance?: ResultType; get instance() { @@ -160,7 +160,9 @@ export class UmbContextConsumer { // If we still have the rejecter, it means that the context was not found immediately, so lets reject the promise. [NL] - this.#promiseRejecter?.(); + this.#promiseRejecter?.( + `Context could not be found. (Context Alias: ${this.#contextAlias} with API Alias: ${this.#apiAlias})`, + ); }); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/detail-repository-base.ts b/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/detail-repository-base.ts index 831cdab778a8..178b9062cd07 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/detail-repository-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/detail-repository-base.ts @@ -38,14 +38,15 @@ export abstract class UmbDetailRepositoryBase< this.detailDataSource = new detailSource(host) as UmbDetailDataSourceType; + // TODO: ideally no preventTimeouts here.. [NL] this.#init = Promise.all([ this.consumeContext(detailStoreContextAlias, (instance) => { this.#detailStore = instance; - }).asPromise(), + }).asPromise({ preventTimeout: true }), this.consumeContext(UMB_NOTIFICATION_CONTEXT, (instance) => { this.#notificationContext = instance; - }).asPromise(), + }).asPromise({ preventTimeout: true }), ]); } From 4dce0db2632157268bfc02648f1420511729de85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 14 Mar 2025 14:35:21 +0100 Subject: [PATCH 26/26] implement preventTimeouts where it makes sense --- .../src/apps/app/app-auth.controller.ts | 2 +- .../libs/context-api/consume/context-consumer.ts | 10 ++++++++-- .../context/block-grid-manager.context.ts | 2 +- .../block-type-card/block-type-card.element.ts | 2 +- .../workspace/block-type-workspace.context.ts | 2 +- .../block/block/context/block-entries.context.ts | 2 +- .../block/workspace/block-workspace.context.ts | 4 ++-- .../paste/paste-from-clipboard.property-action.ts | 2 +- .../property/context/clipboard.property-context.ts | 11 ++--------- .../workspace/property-type-workspace.context.ts | 2 +- .../core/repository/item/item-repository-base.ts | 2 +- .../packages/core/resources/resource.controller.ts | 2 +- .../modal-route-registration.controller.ts | 7 ++----- .../context/server-model-validator.context.ts | 2 +- .../repository/data-type-collection.repository.ts | 8 +++----- .../data-type-picker-flow-modal.element.ts | 4 ++-- .../detail/data-type-detail.repository.ts | 8 +++----- .../documents/item/document-item-data-resolver.ts | 2 +- .../repository/document-publishing.repository.ts | 14 ++++---------- .../document-publishing.workspace-context.ts | 4 ++-- .../member/repository/member-repository-base.ts | 6 +++--- .../detail/relation-type-detail.repository.ts | 8 +++----- .../src/packages/tags/repository/tag.repository.ts | 2 +- .../current-user/utils/is-current-user.function.ts | 2 +- .../repository/user-group-collection.repository.ts | 2 +- .../user/user/repository/user-repository-base.ts | 6 +++--- .../repository/webhook-event.repository.ts | 8 +++----- 27 files changed, 54 insertions(+), 72 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/apps/app/app-auth.controller.ts b/src/Umbraco.Web.UI.Client/src/apps/app/app-auth.controller.ts index 6b1ee082df77..93f1f6de1d2e 100644 --- a/src/Umbraco.Web.UI.Client/src/apps/app/app-auth.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/apps/app/app-auth.controller.ts @@ -25,7 +25,7 @@ export class UmbAppAuthController extends UmbControllerBase { }, '_authState', ); - }).asPromise(); + }).asPromise({ preventTimeout: true }); } /** diff --git a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts index d1cf88634a70..6fd55915e1ff 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts @@ -18,6 +18,7 @@ export type UmbContextConsumerAsPromiseOptionsType = { export class UmbContextConsumer { protected _retrieveHost: HostElementMethod; + #raf?: number; #skipHost?: boolean; #stopAtContextMatch = true; #callback?: UmbContextCallback; @@ -158,10 +159,11 @@ export class UmbContextConsumer requestAnimationFrame(resolve)); } */ - requestAnimationFrame(() => { + this.#raf = requestAnimationFrame(() => { + const hostElement = this._retrieveHost(); // If we still have the rejecter, it means that the context was not found immediately, so lets reject the promise. [NL] this.#promiseRejecter?.( - `Context could not be found. (Context Alias: ${this.#contextAlias} with API Alias: ${this.#apiAlias})`, + `Context could not be found. (Context Alias: ${this.#contextAlias} with API Alias: ${this.#apiAlias}). Controller is hosted on ${hostElement?.parentNode?.nodeName ?? 'Not attached node'} > ${hostElement?.nodeName}`, ); }); } @@ -174,6 +176,10 @@ export class UmbContextConsumer { this.#serverUrl = appContext.getServerUrl(); - }).asPromise(); + }).asPromise({ preventTimeout: true }); } /** * @deprecated Use createWithPresets instead. Will be removed in v.17. diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/block-type-card/block-type-card.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/block-type-card/block-type-card.element.ts index 5065ba776645..d6c8a1f16d3d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/block-type-card/block-type-card.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/block-type-card/block-type-card.element.ts @@ -78,7 +78,7 @@ export class UmbBlockTypeCardElement extends UmbLitElement { this.#init = this.consumeContext(UMB_APP_CONTEXT, (appContext) => { this.#serverUrl = appContext.getServerUrl(); - }).asPromise(); + }).asPromise({ preventTimeout: true }); this.observe(this.#itemManager.statuses, async (statuses) => { const status = statuses[0]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-type/workspace/block-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-type/workspace/block-type-workspace.context.ts index 27506dca475d..22bc74416ddf 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-type/workspace/block-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-type/workspace/block-type-workspace.context.ts @@ -49,7 +49,7 @@ export class UmbBlockTypeWorkspaceContext { this.#propertyContext = context; - }).asPromise(); + }).asPromise({ preventTimeout: true }); this.routes.setRoutes([ { diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-entries.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-entries.context.ts index 99e7a726df00..5d959e088a1c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-entries.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-entries.context.ts @@ -53,7 +53,7 @@ export abstract class UmbBlockEntriesContext< this._retrieveManager = this.consumeContext(blockManagerContextToken, (blockGridManager) => { this._manager = blockGridManager; this._gotBlockManager(); - }).asPromise(); + }).asPromise({ preventTimeout: true }); } async getManager() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts index b565d4de487b..8fc6a90af82a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts @@ -88,7 +88,7 @@ export class UmbBlockWorkspaceContext { this.#blockManager = manager; @@ -97,7 +97,7 @@ export class UmbBlockWorkspaceContext { this.#blockEntries = context; - }).asPromise(); + }).asPromise({ preventTimeout: true }); this.consumeContext(UMB_BLOCK_ENTRY_CONTEXT, (context) => { this.#name.setValue(context.getName()); diff --git a/src/Umbraco.Web.UI.Client/src/packages/clipboard/property/actions/paste/paste-from-clipboard.property-action.ts b/src/Umbraco.Web.UI.Client/src/packages/clipboard/property/actions/paste/paste-from-clipboard.property-action.ts index e4c54117e8df..6af9a0d14ab1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/clipboard/property/actions/paste/paste-from-clipboard.property-action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/clipboard/property/actions/paste/paste-from-clipboard.property-action.ts @@ -73,7 +73,7 @@ export class UmbPasteFromClipboardPropertyAction extends UmbPropertyActionBase { #init?: Promise; - #modalManagerContext?: typeof UMB_MODAL_MANAGER_CONTEXT.TYPE; - constructor(host: UmbControllerHost) { super(host, UMB_CLIPBOARD_PROPERTY_CONTEXT); - - this.#init = this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (context) => { - this.#modalManagerContext = context; - }).asPromise(); } /** @@ -138,7 +132,7 @@ export class UmbClipboardPropertyContext extends UmbContextBase { const hasSupportedPasteTranslator = this.hasSupportedPasteTranslator( @@ -169,7 +163,6 @@ export class UmbClipboardPropertyContext extends UmbContextBase this._init = this.consumeContext(itemStoreContextAlias, (instance) => { this._itemStore = instance as UmbItemStore; - }).asPromise(); + }).asPromise({ preventTimeout: true }); } /** diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts index c08f554212de..d3e77124ddd8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts @@ -107,7 +107,7 @@ export class UmbResourceController extends UmbControllerBase { switch (error.status ?? 0) { case 401: { // See if we can get the UmbAuthContext and let it know the user is timed out - const authContext = await this.getContext(UMB_AUTH_CONTEXT); + const authContext = await this.getContext(UMB_AUTH_CONTEXT, { preventTimeout: true }); if (!authContext) { throw new Error('Could not get the auth context'); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/router/modal-registration/modal-route-registration.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/core/router/modal-registration/modal-route-registration.controller.ts index 81477fb309e1..23a710001355 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/router/modal-registration/modal-route-registration.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/router/modal-registration/modal-route-registration.controller.ts @@ -48,7 +48,6 @@ export class UmbModalRouteRegistrationController< { // #init; - #contextConsumer; #addendum?: string; #additionalPath?: string; @@ -101,11 +100,10 @@ export class UmbModalRouteRegistrationController< ); }); - this.#contextConsumer = this.consumeContext(UMB_ROUTE_CONTEXT, (_routeContext) => { + this.#init = this.consumeContext(UMB_ROUTE_CONTEXT, (_routeContext) => { this.#routeContext = _routeContext; this.#registerModal(); - }); - this.#init = this.#contextConsumer.asPromise(); + }).asPromise({ preventTimeout: true }); } /** @@ -349,7 +347,6 @@ export class UmbModalRouteRegistrationController< public override destroy(): void { super.destroy(); - this.#contextConsumer.destroy(); this.#modalRegistrationContext = undefined; this.#uniquePaths = undefined as any; this.#routeContext = undefined; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/validation/context/server-model-validator.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/validation/context/server-model-validator.context.ts index f856d42a557a..dc8cdbea9d75 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/validation/context/server-model-validator.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/validation/context/server-model-validator.context.ts @@ -44,7 +44,7 @@ export class UmbServerModelValidatorContext context.addValidator(this); // Run translators? - }).asPromise(); + }).asPromise({ preventTimeout: true }); } async askServerForValidation(data: unknown, requestPromise: Promise>): Promise { diff --git a/src/Umbraco.Web.UI.Client/src/packages/data-type/collection/repository/data-type-collection.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/data-type/collection/repository/data-type-collection.repository.ts index 0eea3000ab48..48be1b03c1b8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/data-type/collection/repository/data-type-collection.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/data-type/collection/repository/data-type-collection.repository.ts @@ -15,11 +15,9 @@ export class UmbDataTypeCollectionRepository extends UmbRepositoryBase implement constructor(host: UmbControllerHost) { super(host); - this.#init = Promise.all([ - this.consumeContext(UMB_DATA_TYPE_ITEM_STORE_CONTEXT, (instance) => { - this.#itemStore = instance; - }).asPromise(), - ]); + this.#init = this.consumeContext(UMB_DATA_TYPE_ITEM_STORE_CONTEXT, (instance) => { + this.#itemStore = instance; + }).asPromise({ preventTimeout: true }); this.#collectionSource = new UmbDataTypeCollectionServerDataSource(host); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/data-type/modals/data-type-picker-flow/data-type-picker-flow-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/data-type/modals/data-type-picker-flow/data-type-picker-flow-modal.element.ts index f668fff33ca7..ade2465cedc4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/data-type/modals/data-type-picker-flow/data-type-picker-flow-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/data-type/modals/data-type-picker-flow/data-type-picker-flow-modal.element.ts @@ -129,8 +129,8 @@ export class UmbDataTypePickerFlowModalElement extends UmbModalBaseElement< this.removeUmbController(propContextConsumer); }).passContextAliasMatches(); const [contentContext, propContext] = await Promise.all([ - contentContextConsumer.asPromise(), - propContextConsumer.asPromise(), + contentContextConsumer.asPromise({ preventTimeout: true }), + propContextConsumer.asPromise({ preventTimeout: true }), this.#initPromise, ]); if (!contentContext || !propContext) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/data-type/repository/detail/data-type-detail.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/data-type/repository/detail/data-type-detail.repository.ts index 33f5c5a65a84..37b65915bce0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/data-type/repository/detail/data-type-detail.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/data-type/repository/detail/data-type-detail.repository.ts @@ -11,11 +11,9 @@ export class UmbDataTypeDetailRepository extends UmbDetailRepositoryBase { - this.#detailStore = instance; - }).asPromise(), - ]); + this.#init = this.consumeContext(UMB_DATA_TYPE_DETAIL_STORE_CONTEXT, (instance) => { + this.#detailStore = instance; + }).asPromise({ preventTimeout: true }); } async byPropertyEditorUiAlias(propertyEditorUiAlias: string) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/item/document-item-data-resolver.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/item/document-item-data-resolver.ts index c660e4e53612..58699b7d598b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/item/document-item-data-resolver.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/item/document-item-data-resolver.ts @@ -50,7 +50,7 @@ export class UmbDocumentItemDataResolver { this.#propertyDataSetCulture = context.getVariantId(); this.#setVariantAwareValues(); - }).asPromise(), + }).asPromise({ preventTimeout: true }), this.consumeContext(UMB_APP_LANGUAGE_CONTEXT, (context) => { this.observe(context.appLanguageCulture, (culture) => { diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/repository/document-publishing.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/repository/document-publishing.repository.ts index 7599d8a763f2..3e19ff85a6bf 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/repository/document-publishing.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/repository/document-publishing.repository.ts @@ -19,11 +19,9 @@ export class UmbDocumentPublishingRepository extends UmbRepositoryBase { this.#publishingDataSource = new UmbDocumentPublishingServerDataSource(this); - this.#init = Promise.all([ - this.consumeContext(UMB_NOTIFICATION_CONTEXT, (instance) => { - this.#notificationContext = instance; - }).asPromise(), - ]); + this.#init = this.consumeContext(UMB_NOTIFICATION_CONTEXT, (instance) => { + this.#notificationContext = instance; + }).asPromise({ preventTimeout: true }); } /** @@ -73,11 +71,7 @@ export class UmbDocumentPublishingRepository extends UmbRepositoryBase { * @param includeUnpublishedDescendants * @memberof UmbDocumentPublishingRepository */ - async publishWithDescendants( - id: string, - variantIds: Array, - includeUnpublishedDescendants: boolean, - ) { + async publishWithDescendants(id: string, variantIds: Array, includeUnpublishedDescendants: boolean) { if (!id) throw new Error('id is missing'); if (!variantIds) throw new Error('variant IDs are missing'); await this.#init; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/workspace-context/document-publishing.workspace-context.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/workspace-context/document-publishing.workspace-context.ts index 7ffbce1387e3..57e05838899a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/workspace-context/document-publishing.workspace-context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/workspace-context/document-publishing.workspace-context.ts @@ -50,11 +50,11 @@ export class UmbDocumentPublishingWorkspaceContext extends UmbContextBase { this.#documentWorkspaceContext = context; this.#initPendingChanges(); - }).asPromise(), + }).asPromise({ preventTimeout: true }), this.consumeContext(UMB_ACTION_EVENT_CONTEXT, async (context) => { this.#eventContext = context; - }).asPromise(), + }).asPromise({ preventTimeout: true }), ]); this.consumeContext(UMB_NOTIFICATION_CONTEXT, (context) => { diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/repository/member-repository-base.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/repository/member-repository-base.ts index 74257955e161..911fe09130d2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/repository/member-repository-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/repository/member-repository-base.ts @@ -19,15 +19,15 @@ export abstract class UmbMemberRepositoryBase extends UmbRepositoryBase { this.init = Promise.all([ this.consumeContext(UMB_MEMBER_DETAIL_STORE_CONTEXT, (instance) => { this.detailStore = instance; - }).asPromise(), + }).asPromise({ preventTimeout: true }), this.consumeContext(UMB_MEMBER_ITEM_STORE_CONTEXT, (instance) => { this.itemStore = instance; - }).asPromise(), + }).asPromise({ preventTimeout: true }), this.consumeContext(UMB_NOTIFICATION_CONTEXT, (instance) => { this.notificationContext = instance; - }).asPromise(), + }).asPromise({ preventTimeout: true }), ]); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/detail/relation-type-detail.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/detail/relation-type-detail.repository.ts index 013234458fd4..4f79653af30e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/detail/relation-type-detail.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/detail/relation-type-detail.repository.ts @@ -18,11 +18,9 @@ export class UmbRelationTypeDetailRepository constructor(host: UmbControllerHost) { super(host); - this.#init = Promise.all([ - this.consumeContext(UMB_RELATION_TYPE_DETAIL_STORE_CONTEXT, (instance) => { - this.#detailStore = instance; - }).asPromise(), - ]); + this.#init = this.consumeContext(UMB_RELATION_TYPE_DETAIL_STORE_CONTEXT, (instance) => { + this.#detailStore = instance; + }).asPromise({ preventTimeout: true }); } /** diff --git a/src/Umbraco.Web.UI.Client/src/packages/tags/repository/tag.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/tags/repository/tag.repository.ts index 9a164029636f..1d73ff8018bf 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tags/repository/tag.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tags/repository/tag.repository.ts @@ -18,7 +18,7 @@ export class UmbTagRepository extends UmbControllerBase implements UmbApi { this.#init = this.consumeContext(UMB_TAG_STORE_CONTEXT, (instance) => { this.#tagStore = instance; - }).asPromise(); + }).asPromise({ preventTimeout: true }); } async requestTags( diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/utils/is-current-user.function.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/utils/is-current-user.function.ts index fcb077363d72..2fb8e2e6fdf9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/utils/is-current-user.function.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/utils/is-current-user.function.ts @@ -9,7 +9,7 @@ import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; */ export const isCurrentUser = async (host: UmbControllerHost, userUnique: string) => { const ctrl = new UmbContextConsumerController(host, UMB_CURRENT_USER_CONTEXT); - const currentUserContext = await ctrl.asPromise(); + const currentUserContext = await ctrl.asPromise().catch(() => undefined); ctrl.destroy(); return await currentUserContext!.isUserCurrentUser(userUnique); diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/collection/repository/user-group-collection.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/collection/repository/user-group-collection.repository.ts index c2479659abfe..a5f32f9b69d3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/collection/repository/user-group-collection.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/collection/repository/user-group-collection.repository.ts @@ -19,7 +19,7 @@ export class UmbUserGroupCollectionRepository extends UmbControllerBase implemen this.#init = this.consumeContext(UMB_USER_GROUP_DETAIL_STORE_CONTEXT, (instance) => { this.#detailStore = instance; - }).asPromise(); + }).asPromise({ preventTimeout: true }); } async requestCollection(filter: UmbUserGroupCollectionFilterModel = { skip: 0, take: 100 }) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/repository/user-repository-base.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/repository/user-repository-base.ts index 3a0e90fd414c..bd81e5eec66e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/repository/user-repository-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/repository/user-repository-base.ts @@ -19,15 +19,15 @@ export abstract class UmbUserRepositoryBase extends UmbRepositoryBase { this.init = Promise.all([ this.consumeContext(UMB_USER_DETAIL_STORE_CONTEXT, (instance) => { this.detailStore = instance; - }).asPromise(), + }).asPromise({ preventTimeout: true }), this.consumeContext(UMB_USER_ITEM_STORE_CONTEXT, (instance) => { this.itemStore = instance; - }).asPromise(), + }).asPromise({ preventTimeout: true }), this.consumeContext(UMB_NOTIFICATION_CONTEXT, (instance) => { this.notificationContext = instance; - }).asPromise(), + }).asPromise({ preventTimeout: true }), ]); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/webhook/webhook-event/repository/webhook-event.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/webhook/webhook-event/repository/webhook-event.repository.ts index aa57d568ec80..669f3f53c2cd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/webhook/webhook-event/repository/webhook-event.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/webhook/webhook-event/repository/webhook-event.repository.ts @@ -16,11 +16,9 @@ export class UmbWebhookEventRepository extends UmbRepositoryBase implements UmbA this.#source = new UmbWebhookEventServerDataSource(host); - this.#init = Promise.all([ - this.consumeContext(UMB_WEBHOOK_EVENT_STORE_CONTEXT, (instance) => { - this.#store = instance; - }).asPromise(), - ]); + this.#init = this.consumeContext(UMB_WEBHOOK_EVENT_STORE_CONTEXT, (instance) => { + this.#store = instance; + }).asPromise({ preventTimeout: true }); } async requestEvents() {