From 8d360b68a6541be1f1dacdfb0b0df0e1fbdaf524 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 22 Aug 2024 16:50:16 +0000 Subject: [PATCH 01/55] Adds new method to extensionRegistry for appendCondition --- .../registry/extension.registry.test.ts | 83 ++++++++++++++++++- .../registry/extension.registry.ts | 29 ++++++- 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts index 83ee09d37b..0ad82590b7 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts @@ -1,4 +1,5 @@ -import type { ManifestElementWithElementName, ManifestKind, ManifestBase } from '../types/index.js'; +import { WorkspaceAliasConditionConfig } from '@umbraco-cms/backoffice/workspace'; +import type { ManifestElementWithElementName, ManifestKind, ManifestBase, ManifestWithDynamicConditions, UmbConditionConfigBase } from '../types/index.js'; import { UmbExtensionRegistry } from './extension.registry.js'; import { expect } from '@open-wc/testing'; @@ -453,3 +454,83 @@ describe('UmbExtensionRegistry with exclusions', () => { expect(extensionRegistry.isRegistered('Umb.Test.Section.Late')).to.be.false; }); }); + +describe('Append Conditions', () => { + let extensionRegistry: UmbExtensionRegistry; + let manifests: Array< + ManifestWithDynamicConditions + >; + + beforeEach(() => { + extensionRegistry = new UmbExtensionRegistry(); + manifests = [ + { + type: 'section', + name: 'test-section-1', + alias: 'Umb.Test.Section.1', + weight: 1, + conditions: [ + { + alias: "Umb.Test.Condition.Valid" + } + ] + }, + { + type: 'section', + name: 'test-section-2', + alias: 'Umb.Test.Section.2', + weight: 200 + }, + ]; + + manifests.forEach((manifest) => extensionRegistry.register(manifest)); + + extensionRegistry.register({ + type: 'condition', + name: 'test-condition-invalid', + alias: 'Umb.Test.Condition.Invalid' + }); + }); + + + it('allows an extension condition to be updated', () => { + expect(extensionRegistry.isRegistered('Umb.Test.Section.1')).to.be.true; + expect(extensionRegistry.isRegistered('Umb.Test.Section.2')).to.be.true; + expect(extensionRegistry.isRegistered('Umb.Test.Condition.Invalid')).to.be.true; + expect(extensionRegistry.isRegistered('Umb.Test.Condition.Valid')).to.be.false; + + const ext = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; + expect(ext.conditions?.length).to.equal(1); + + // Register new condition as if I was in my own entrypoint + extensionRegistry.register({ + type: 'condition', + name: 'test-condition-valid', + alias: 'Umb.Test.Condition.Valid' + }); + + // Add the new condition to the extension + const conditionToAdd:UmbConditionConfigBase = { + alias: 'Umb.Test.Condition.Valid' + }; + extensionRegistry.appendCondition('Umb.Test.Section.1', conditionToAdd); + + // Check new condition is registered + expect(extensionRegistry.isRegistered('Umb.Test.Condition.Valid')).to.be.true; + + // Verify the extension now has two conditions + const updatedExt = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; + expect(updatedExt.conditions?.length).to.equal(2); + + // Add a condition with a specific config to Section2 + const workspaceCondition:WorkspaceAliasConditionConfig = { + alias: 'Umb.Condition.WorkspaceAlias', + match: 'Umb.Workspace.Document' + + }; + extensionRegistry.appendCondition('Umb.Test.Section.2', workspaceCondition); + + const updatedWorkspaceExt = extensionRegistry.getByAlias('Umb.Test.Section.2') as ManifestWithDynamicConditions; + expect(updatedWorkspaceExt.conditions?.length).to.equal(1); + }); +}); diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts index 2680d599e9..a716615b16 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts @@ -1,4 +1,4 @@ -import type { ManifestBase, ManifestKind } from '../types/index.js'; +import type { ManifestBase, ManifestKind, ManifestWithDynamicConditions, UmbConditionConfigBase } from '../types/index.js'; import type { SpecificManifestTypeOrManifestBase } from '../types/map.types.js'; import { UmbBasicState } from '@umbraco-cms/backoffice/observable-api'; import type { Observable } from '@umbraco-cms/backoffice/external/rxjs'; @@ -430,4 +430,31 @@ export class UmbExtensionRegistry< distinctUntilChanged(extensionAndKindMatchArrayMemoization), ) as Observable>; } + + /** + * Appends a new condition to an existing extension + * Useful to add a condition for example the Save And Publish workspace action shipped by core + * As overwriting the whole extension to simply add an extra condition is not ideal as it causes a lot of duplicated code + * and could easily get out of sync from the CMS core implementation if a 3rd party dev was to try and overwrite it + * @param alias {string} - The alias of the extension to get. + * @param newCondition {UmbConditionConfigBase} - The condition to append to the extension. + */ + appendCondition(alias: string, newCondition: UmbConditionConfigBase) { + const allExtensions = this._extensions.getValue(); + const extensionToUpdate = allExtensions.find((ext) => ext.alias === alias) as ManifestWithDynamicConditions; + + if(extensionToUpdate === undefined) { + console.error(`Extension with alias ${alias} not found`); + } + + // Append the condition to the extensions conditions array + if (extensionToUpdate.conditions){ + extensionToUpdate.conditions.push(newCondition); + } else { + extensionToUpdate.conditions = [newCondition]; + } + + // Update the extensions observable + this._extensions.setValue(allExtensions); + } } From b4da6520d51c761bb25dd8fc7de7de8766db704a Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Fri, 23 Aug 2024 09:57:11 +0000 Subject: [PATCH 02/55] Adds appendConditions to allow adding multiple in one go --- .../registry/extension.registry.test.ts | 20 +++++++++++++++++++ .../registry/extension.registry.ts | 11 +++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts index 0ad82590b7..f6add8c5c2 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts @@ -533,4 +533,24 @@ describe('Append Conditions', () => { const updatedWorkspaceExt = extensionRegistry.getByAlias('Umb.Test.Section.2') as ManifestWithDynamicConditions; expect(updatedWorkspaceExt.conditions?.length).to.equal(1); }); + + it('allows an extension to update with multiple conditions', () => { + const ext = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; + expect(ext.conditions?.length).to.equal(1); + + const conditions:Array = [ + { + alias: 'Umb.Test.Condition.Valid' + }, + { + alias: 'Umb.Condition.WorkspaceAlias', + match: 'Umb.Workspace.Document' + } as WorkspaceAliasConditionConfig + ] + + extensionRegistry.appendConditions('Umb.Test.Section.1', conditions); + + const extUpdated = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; + expect(ext.conditions?.length).to.equal(3); + }); }); diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts index a716615b16..4311109022 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts @@ -436,7 +436,7 @@ export class UmbExtensionRegistry< * Useful to add a condition for example the Save And Publish workspace action shipped by core * As overwriting the whole extension to simply add an extra condition is not ideal as it causes a lot of duplicated code * and could easily get out of sync from the CMS core implementation if a 3rd party dev was to try and overwrite it - * @param alias {string} - The alias of the extension to get. + * @param alias {string} - The alias of the extension to append the condition to * @param newCondition {UmbConditionConfigBase} - The condition to append to the extension. */ appendCondition(alias: string, newCondition: UmbConditionConfigBase) { @@ -457,4 +457,13 @@ export class UmbExtensionRegistry< // Update the extensions observable this._extensions.setValue(allExtensions); } + + /** + * Appends a collection of conditions to an exsiting extension + * @param alias {string} - The alias of the extension to append the condition to + * @param newConditions {Array} - A collection of conditions to append to an extension. + */ + appendConditions(alias: string, newConditions: Array){ + newConditions.forEach((condition) => this.appendCondition(alias, condition)); + } } From 73db2a4c189685e21b15334321a0b11e13e387b9 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 29 Aug 2024 11:10:48 +0000 Subject: [PATCH 03/55] Adds prependCondition and prependConditions so you can make sure your condition loads first, as order of conditions are important --- .../registry/extension.registry.test.ts | 89 +++++++++++++++++++ .../registry/extension.registry.ts | 48 ++++++++-- 2 files changed, 132 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts index f6add8c5c2..9add871f65 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts @@ -554,3 +554,92 @@ describe('Append Conditions', () => { expect(ext.conditions?.length).to.equal(3); }); }); + +describe('Prepend Conditions', () => { + let extensionRegistry: UmbExtensionRegistry; + let manifests: Array; + + beforeEach(() => { + extensionRegistry = new UmbExtensionRegistry(); + manifests = [ + { + type: 'section', + name: 'test-section-1', + alias: 'Umb.Test.Section.1', + weight: 1, + conditions: [ + { + alias: "Umb.Test.Condition.Valid" + } + ] + }, + { + type: 'section', + name: 'test-section-2', + alias: 'Umb.Test.Section.2', + weight: 200 + }, + ]; + + manifests.forEach((manifest) => extensionRegistry.register(manifest)); + + extensionRegistry.register({ + type: 'condition', + name: 'test-condition-invalid', + alias: 'Umb.Test.Condition.Invalid' + }); + }); + + it('allows an extension condition to be prepended', () => { + expect(extensionRegistry.isRegistered('Umb.Test.Section.1')).to.be.true; + expect(extensionRegistry.isRegistered('Umb.Test.Section.2')).to.be.true; + expect(extensionRegistry.isRegistered('Umb.Test.Condition.Invalid')).to.be.true; + expect(extensionRegistry.isRegistered('Umb.Test.Condition.Valid')).to.be.false; + + const ext = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; + expect(ext.conditions?.length).to.equal(1); + + // Register new condition as if I was in my own entrypoint + extensionRegistry.register({ + type: 'condition', + name: 'test-condition-valid', + alias: 'Umb.Test.Condition.Valid' + }); + + // Prepend the new condition to the extension + const conditionToPrepend: UmbConditionConfigBase = { + alias: 'Umb.Test.Condition.Valid' + }; + extensionRegistry.prependCondition('Umb.Test.Section.1', conditionToPrepend); + + // Check new condition is registered + expect(extensionRegistry.isRegistered('Umb.Test.Condition.Valid')).to.be.true; + + // Verify the extension now has two conditions and the new condition is prepended + const updatedExt = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; + expect(updatedExt.conditions?.length).to.equal(2); + expect(updatedExt.conditions?.[0]?.alias).to.equal('Umb.Test.Condition.Valid'); + }); + + it('allows an extension to update with multiple prepended conditions', () => { + const ext = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; + expect(ext.conditions?.length).to.equal(1); + + const conditions: Array = [ + { + alias: 'Umb.Test.Condition.Valid' + }, + { + alias: 'Umb.Condition.WorkspaceAlias', + match: 'Umb.Workspace.Document' + } as WorkspaceAliasConditionConfig + ]; + + extensionRegistry.prependConditions('Umb.Test.Section.1', conditions); + + const extUpdated = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; + expect(extUpdated.conditions?.length).to.equal(3); + expect(extUpdated.conditions?.[0]?.alias).to.equal('Umb.Condition.WorkspaceAlias'); + expect(extUpdated.conditions?.[1]?.alias).to.equal('Umb.Test.Condition.Valid'); + }); +}); diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts index 4311109022..f6e9f9d934 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts @@ -1,4 +1,9 @@ -import type { ManifestBase, ManifestKind, ManifestWithDynamicConditions, UmbConditionConfigBase } from '../types/index.js'; +import type { + ManifestBase, + ManifestKind, + ManifestWithDynamicConditions, + UmbConditionConfigBase, +} from '../types/index.js'; import type { SpecificManifestTypeOrManifestBase } from '../types/map.types.js'; import { UmbBasicState } from '@umbraco-cms/backoffice/observable-api'; import type { Observable } from '@umbraco-cms/backoffice/external/rxjs'; @@ -430,7 +435,7 @@ export class UmbExtensionRegistry< distinctUntilChanged(extensionAndKindMatchArrayMemoization), ) as Observable>; } - + /** * Appends a new condition to an existing extension * Useful to add a condition for example the Save And Publish workspace action shipped by core @@ -443,12 +448,12 @@ export class UmbExtensionRegistry< const allExtensions = this._extensions.getValue(); const extensionToUpdate = allExtensions.find((ext) => ext.alias === alias) as ManifestWithDynamicConditions; - if(extensionToUpdate === undefined) { + if (extensionToUpdate === undefined) { console.error(`Extension with alias ${alias} not found`); } // Append the condition to the extensions conditions array - if (extensionToUpdate.conditions){ + if (extensionToUpdate.conditions) { extensionToUpdate.conditions.push(newCondition); } else { extensionToUpdate.conditions = [newCondition]; @@ -463,7 +468,40 @@ export class UmbExtensionRegistry< * @param alias {string} - The alias of the extension to append the condition to * @param newConditions {Array} - A collection of conditions to append to an extension. */ - appendConditions(alias: string, newConditions: Array){ + appendConditions(alias: string, newConditions: Array) { newConditions.forEach((condition) => this.appendCondition(alias, condition)); } + + /** + * Prepends a new condition to an existing extension + * @param alias {string} - The alias of the extension to prepend the condition to + * @param newCondition {UmbConditionConfigBase} - The condition to prepend to the extension. + */ + prependCondition(alias: string, newCondition: UmbConditionConfigBase) { + const allExtensions = this._extensions.getValue(); + const extensionToUpdate = allExtensions.find((ext) => ext.alias === alias) as ManifestWithDynamicConditions; + + if (extensionToUpdate === undefined) { + console.error(`Extension with alias ${alias} not found`); + } + + // Prepend the condition to the extensions conditions array + if (extensionToUpdate.conditions) { + extensionToUpdate.conditions.unshift(newCondition); + } else { + extensionToUpdate.conditions = [newCondition]; + } + + // Update the extensions observable + this._extensions.setValue(allExtensions); + } + + /** + * Prepends a collection of conditions to an existing extension + * @param alias {string} - The alias of the extension to prepend the conditions to + * @param newConditions {Array} - A collection of conditions to prepend to an extension. + */ + prependConditions(alias: string, newConditions: Array) { + newConditions.forEach((condition) => this.prependCondition(alias, condition)); + } } From e25641534a8f106205108d12a49ba6191ee4edd9 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 29 Aug 2024 16:14:06 +0000 Subject: [PATCH 04/55] Adds _whenExtensionAliasIsRegistered as a promise so that we basically wait until the manifest is registered so late extensions will work as well Seems to work with my hack in an entrypoint and the console logs the extension with the updated condition but its the tests I am struggling to get to work. As this code is heavily worked from me trying to Google, read RXJS docs and talking with Copilot I am not fully in confident in this approach --- .../registry/extension.registry.test.ts | 19 +-- .../registry/extension.registry.ts | 118 +++++++++++++----- .../packages/property-editors/entry-point.ts | 31 +++++ 3 files changed, 125 insertions(+), 43 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts index 9add871f65..94c5fccbf5 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts @@ -493,7 +493,7 @@ describe('Append Conditions', () => { }); - it('allows an extension condition to be updated', () => { + it('allows an extension condition to be updated', async () => { expect(extensionRegistry.isRegistered('Umb.Test.Section.1')).to.be.true; expect(extensionRegistry.isRegistered('Umb.Test.Section.2')).to.be.true; expect(extensionRegistry.isRegistered('Umb.Test.Condition.Invalid')).to.be.true; @@ -513,7 +513,7 @@ describe('Append Conditions', () => { const conditionToAdd:UmbConditionConfigBase = { alias: 'Umb.Test.Condition.Valid' }; - extensionRegistry.appendCondition('Umb.Test.Section.1', conditionToAdd); + await extensionRegistry.appendCondition('Umb.Test.Section.1', conditionToAdd); // Check new condition is registered expect(extensionRegistry.isRegistered('Umb.Test.Condition.Valid')).to.be.true; @@ -528,13 +528,13 @@ describe('Append Conditions', () => { match: 'Umb.Workspace.Document' }; - extensionRegistry.appendCondition('Umb.Test.Section.2', workspaceCondition); + await extensionRegistry.appendCondition('Umb.Test.Section.2', workspaceCondition); const updatedWorkspaceExt = extensionRegistry.getByAlias('Umb.Test.Section.2') as ManifestWithDynamicConditions; expect(updatedWorkspaceExt.conditions?.length).to.equal(1); }); - it('allows an extension to update with multiple conditions', () => { + it('allows an extension to update with multiple conditions', async () => { const ext = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; expect(ext.conditions?.length).to.equal(1); @@ -548,7 +548,7 @@ describe('Append Conditions', () => { } as WorkspaceAliasConditionConfig ] - extensionRegistry.appendConditions('Umb.Test.Section.1', conditions); + await extensionRegistry.appendConditions('Umb.Test.Section.1', conditions); const extUpdated = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; expect(ext.conditions?.length).to.equal(3); @@ -590,7 +590,7 @@ describe('Prepend Conditions', () => { }); }); - it('allows an extension condition to be prepended', () => { + it('allows an extension condition to be prepended', async () => { expect(extensionRegistry.isRegistered('Umb.Test.Section.1')).to.be.true; expect(extensionRegistry.isRegistered('Umb.Test.Section.2')).to.be.true; expect(extensionRegistry.isRegistered('Umb.Test.Condition.Invalid')).to.be.true; @@ -610,7 +610,8 @@ describe('Prepend Conditions', () => { const conditionToPrepend: UmbConditionConfigBase = { alias: 'Umb.Test.Condition.Valid' }; - extensionRegistry.prependCondition('Umb.Test.Section.1', conditionToPrepend); + + await extensionRegistry.prependCondition('Umb.Test.Section.1', conditionToPrepend); // Check new condition is registered expect(extensionRegistry.isRegistered('Umb.Test.Condition.Valid')).to.be.true; @@ -621,7 +622,7 @@ describe('Prepend Conditions', () => { expect(updatedExt.conditions?.[0]?.alias).to.equal('Umb.Test.Condition.Valid'); }); - it('allows an extension to update with multiple prepended conditions', () => { + it('allows an extension to update with multiple prepended conditions', async () => { const ext = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; expect(ext.conditions?.length).to.equal(1); @@ -635,7 +636,7 @@ describe('Prepend Conditions', () => { } as WorkspaceAliasConditionConfig ]; - extensionRegistry.prependConditions('Umb.Test.Section.1', conditions); + await extensionRegistry.prependConditions('Umb.Test.Section.1', conditions); const extUpdated = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; expect(extUpdated.conditions?.length).to.equal(3); diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts index f6e9f9d934..7d2837de3e 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts @@ -6,8 +6,8 @@ import type { } from '../types/index.js'; import type { SpecificManifestTypeOrManifestBase } from '../types/map.types.js'; import { UmbBasicState } from '@umbraco-cms/backoffice/observable-api'; -import type { Observable } from '@umbraco-cms/backoffice/external/rxjs'; -import { map, distinctUntilChanged, combineLatest, of, switchMap } from '@umbraco-cms/backoffice/external/rxjs'; +import type { Observable, Subscription } from '@umbraco-cms/backoffice/external/rxjs'; +import { map, distinctUntilChanged, combineLatest, of, switchMap, filter } from '@umbraco-cms/backoffice/external/rxjs'; /** * @@ -436,6 +436,37 @@ export class UmbExtensionRegistry< ) as Observable>; } + + /** + * Returns a promise that resolves when the extension with the specified alias is found. + * @param alias {string} - The alias of the extension to wait for. + * @returns {Promise} - A promise that resolves with the extension. + */ + private _whenExtensionAliasIsRegistered(alias: string): Promise { + return new Promise((resolve, reject) => { + const subscription: Subscription = this.extensions + .pipe(filter((allExtensions) => allExtensions.some((ext) => ext.alias === alias))) + .subscribe({ + next: (allExtensions) => { + console.log('I AM IN NEXT', allExtensions); + const extension = allExtensions.find((ext) => ext.alias === alias); + if (extension) { + subscription.unsubscribe(); + resolve(extension as ManifestBase); + } + }, + error: (error) => { + console.error('I AM IN ERROR', error); + reject(error); + }, + complete: () => { + console.log('I AM IN COMPLETE'); + reject(new Error(`Extension with alias ${alias} not found`)); + }, + }); + }); + } + /** * Appends a new condition to an existing extension * Useful to add a condition for example the Save And Publish workspace action shipped by core @@ -444,23 +475,39 @@ export class UmbExtensionRegistry< * @param alias {string} - The alias of the extension to append the condition to * @param newCondition {UmbConditionConfigBase} - The condition to append to the extension. */ - appendCondition(alias: string, newCondition: UmbConditionConfigBase) { - const allExtensions = this._extensions.getValue(); - const extensionToUpdate = allExtensions.find((ext) => ext.alias === alias) as ManifestWithDynamicConditions; + async appendCondition(alias: string, newCondition: UmbConditionConfigBase): Promise { + try { - if (extensionToUpdate === undefined) { - console.error(`Extension with alias ${alias} not found`); + // Wait for the extension to be registered (as it could be registered late) + const extensionToWaitFor = (await this._whenExtensionAliasIsRegistered(alias)) as ManifestWithDynamicConditions; + + // Got it... now carry on & mutate it + console.log('got the extension to update/mutate', extensionToWaitFor); + + // Append the condition to the extensions conditions array + if (extensionToWaitFor.conditions) { + extensionToWaitFor.conditions.push(newCondition); + } else { + extensionToWaitFor.conditions = [newCondition]; + } + + const allExtensions = this._extensions.getValue(); + const extensionToUpdateIndex = allExtensions.findIndex((ext) => ext.alias === alias); + if (extensionToUpdateIndex !== -1) { + // Replace the existing extension with the updated one + allExtensions[extensionToUpdateIndex] = extensionToWaitFor as ManifestTypes; + + // Update the main extensions collection/observable + this._extensions.setValue(allExtensions); + + // Log the updated extensions for debugging + console.log('UPDATED extensions:', this._extensions.getValue()); + console.table(this._extensions.getValue()); + } + } catch (error) { + // TODO: [WB] Will this ever catch an error? + console.error(`Extension with alias ${alias} was never found and threw ${error}`); } - - // Append the condition to the extensions conditions array - if (extensionToUpdate.conditions) { - extensionToUpdate.conditions.push(newCondition); - } else { - extensionToUpdate.conditions = [newCondition]; - } - - // Update the extensions observable - this._extensions.setValue(allExtensions); } /** @@ -468,7 +515,7 @@ export class UmbExtensionRegistry< * @param alias {string} - The alias of the extension to append the condition to * @param newConditions {Array} - A collection of conditions to append to an extension. */ - appendConditions(alias: string, newConditions: Array) { + async appendConditions(alias: string, newConditions: Array): Promise { newConditions.forEach((condition) => this.appendCondition(alias, condition)); } @@ -477,23 +524,26 @@ export class UmbExtensionRegistry< * @param alias {string} - The alias of the extension to prepend the condition to * @param newCondition {UmbConditionConfigBase} - The condition to prepend to the extension. */ - prependCondition(alias: string, newCondition: UmbConditionConfigBase) { - const allExtensions = this._extensions.getValue(); - const extensionToUpdate = allExtensions.find((ext) => ext.alias === alias) as ManifestWithDynamicConditions; + async prependCondition(alias: string, newCondition: UmbConditionConfigBase): Promise { + try { - if (extensionToUpdate === undefined) { - console.error(`Extension with alias ${alias} not found`); + // Wait for the extension to be registered (as it could be registered late) + const extensionToUpdate = (await this._whenExtensionAliasIsRegistered(alias)) as ManifestWithDynamicConditions; + + // Got it... now carry on & mutate it + console.log('got the extension to update/mutate', extensionToUpdate); + + // Append the condition to the extensions conditions array + if (extensionToUpdate.conditions) { + extensionToUpdate.conditions.unshift(newCondition); + } else { + extensionToUpdate.conditions = [newCondition]; + } + + } catch (error) { + // TODO: [WB] Will this ever catch an error? + console.error(`Extension with alias ${alias} was never found and threw ${error}`); } - - // Prepend the condition to the extensions conditions array - if (extensionToUpdate.conditions) { - extensionToUpdate.conditions.unshift(newCondition); - } else { - extensionToUpdate.conditions = [newCondition]; - } - - // Update the extensions observable - this._extensions.setValue(allExtensions); } /** @@ -501,7 +551,7 @@ export class UmbExtensionRegistry< * @param alias {string} - The alias of the extension to prepend the conditions to * @param newConditions {Array} - A collection of conditions to prepend to an extension. */ - prependConditions(alias: string, newConditions: Array) { + async prependConditions(alias: string, newConditions: Array): Promise { newConditions.forEach((condition) => this.prependCondition(alias, condition)); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/entry-point.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/entry-point.ts index 9745b0d139..baafe2af43 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/entry-point.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/entry-point.ts @@ -1,2 +1,33 @@ +import type { ManifestWithDynamicConditions, UmbConditionConfigBase, UmbEntryPointOnInit } from '@umbraco-cms/backoffice/extension-api'; +import type { WorkspaceAliasConditionConfig } from '@umbraco-cms/backoffice/workspace'; + import './checkbox-list/components/index.js'; import './content-picker/components/index.js'; + +export const onInit: UmbEntryPointOnInit = (_host, _extensionRegistry) => { + + console.log('HELLO AGAIN'); + + const condition: UmbConditionConfigBase = { + alias: 'Umb.Condition.WorkspaceAlias', + match: 'Umb.Workspace.WARRENYO', + } as WorkspaceAliasConditionConfig; + + _extensionRegistry.appendCondition('Umb.Dashboard.UmbracoNewsLATE', condition); + + const ext:ManifestWithDynamicConditions = { + alias: 'Umb.Dashboard.UmbracoNewsLATE', + type: 'dashboard', + name: 'WARREN Package', + weight: 100, + conditions: [ + { + alias: 'Umb.Condition.WorkspaceAlias', + match: 'Umb.Workspace.LATE-COMER-EXISTING', + } as WorkspaceAliasConditionConfig, + ], + }; + + _extensionRegistry.register(ext); + +}; From 81f2a8a13c7b3b7166bc3008792475c57c76d9a4 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 30 Aug 2024 10:19:27 +0200 Subject: [PATCH 05/55] simplify _whenExtensionAliasIsRegistered --- .../registry/extension.registry.ts | 43 ++++++------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts index 7d2837de3e..e21077c4ab 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts @@ -6,8 +6,16 @@ import type { } from '../types/index.js'; import type { SpecificManifestTypeOrManifestBase } from '../types/map.types.js'; import { UmbBasicState } from '@umbraco-cms/backoffice/observable-api'; -import type { Observable, Subscription } from '@umbraco-cms/backoffice/external/rxjs'; -import { map, distinctUntilChanged, combineLatest, of, switchMap, filter } from '@umbraco-cms/backoffice/external/rxjs'; +import type { Observable } from '@umbraco-cms/backoffice/external/rxjs'; +import { + map, + distinctUntilChanged, + combineLatest, + of, + switchMap, + filter, + firstValueFrom, +} from '@umbraco-cms/backoffice/external/rxjs'; /** * @@ -436,35 +444,15 @@ export class UmbExtensionRegistry< ) as Observable>; } - /** * Returns a promise that resolves when the extension with the specified alias is found. * @param alias {string} - The alias of the extension to wait for. * @returns {Promise} - A promise that resolves with the extension. */ - private _whenExtensionAliasIsRegistered(alias: string): Promise { - return new Promise((resolve, reject) => { - const subscription: Subscription = this.extensions - .pipe(filter((allExtensions) => allExtensions.some((ext) => ext.alias === alias))) - .subscribe({ - next: (allExtensions) => { - console.log('I AM IN NEXT', allExtensions); - const extension = allExtensions.find((ext) => ext.alias === alias); - if (extension) { - subscription.unsubscribe(); - resolve(extension as ManifestBase); - } - }, - error: (error) => { - console.error('I AM IN ERROR', error); - reject(error); - }, - complete: () => { - console.log('I AM IN COMPLETE'); - reject(new Error(`Extension with alias ${alias} not found`)); - }, - }); - }); + private async _whenExtensionAliasIsRegistered(alias: string): Promise { + const source = this.extensions.pipe(filter((allExtensions) => allExtensions.some((ext) => ext.alias === alias))); + const value = await firstValueFrom(source); + return value[0]; } /** @@ -477,7 +465,6 @@ export class UmbExtensionRegistry< */ async appendCondition(alias: string, newCondition: UmbConditionConfigBase): Promise { try { - // Wait for the extension to be registered (as it could be registered late) const extensionToWaitFor = (await this._whenExtensionAliasIsRegistered(alias)) as ManifestWithDynamicConditions; @@ -526,7 +513,6 @@ export class UmbExtensionRegistry< */ async prependCondition(alias: string, newCondition: UmbConditionConfigBase): Promise { try { - // Wait for the extension to be registered (as it could be registered late) const extensionToUpdate = (await this._whenExtensionAliasIsRegistered(alias)) as ManifestWithDynamicConditions; @@ -539,7 +525,6 @@ export class UmbExtensionRegistry< } else { extensionToUpdate.conditions = [newCondition]; } - } catch (error) { // TODO: [WB] Will this ever catch an error? console.error(`Extension with alias ${alias} was never found and threw ${error}`); From 7c4680cf22b74b0a10a4e47199726c23c7bf6a49 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 30 Aug 2024 10:22:24 +0200 Subject: [PATCH 06/55] split some tests --- .../registry/extension.registry.test.ts | 178 +++++++++--------- 1 file changed, 92 insertions(+), 86 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts index 94c5fccbf5..dd1e8612f9 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts @@ -1,5 +1,11 @@ import { WorkspaceAliasConditionConfig } from '@umbraco-cms/backoffice/workspace'; -import type { ManifestElementWithElementName, ManifestKind, ManifestBase, ManifestWithDynamicConditions, UmbConditionConfigBase } from '../types/index.js'; +import type { + ManifestElementWithElementName, + ManifestKind, + ManifestBase, + ManifestWithDynamicConditions, + UmbConditionConfigBase, +} from '../types/index.js'; import { UmbExtensionRegistry } from './extension.registry.js'; import { expect } from '@open-wc/testing'; @@ -457,9 +463,7 @@ describe('UmbExtensionRegistry with exclusions', () => { describe('Append Conditions', () => { let extensionRegistry: UmbExtensionRegistry; - let manifests: Array< - ManifestWithDynamicConditions - >; + let manifests: Array; beforeEach(() => { extensionRegistry = new UmbExtensionRegistry(); @@ -471,15 +475,15 @@ describe('Append Conditions', () => { weight: 1, conditions: [ { - alias: "Umb.Test.Condition.Valid" - } - ] + alias: 'Umb.Test.Condition.Valid', + }, + ], }, { type: 'section', name: 'test-section-2', alias: 'Umb.Test.Section.2', - weight: 200 + weight: 200, }, ]; @@ -488,17 +492,18 @@ describe('Append Conditions', () => { extensionRegistry.register({ type: 'condition', name: 'test-condition-invalid', - alias: 'Umb.Test.Condition.Invalid' + alias: 'Umb.Test.Condition.Invalid', }); }); - - it('allows an extension condition to be updated', async () => { + it('should have the extensions registered', () => { expect(extensionRegistry.isRegistered('Umb.Test.Section.1')).to.be.true; expect(extensionRegistry.isRegistered('Umb.Test.Section.2')).to.be.true; expect(extensionRegistry.isRegistered('Umb.Test.Condition.Invalid')).to.be.true; expect(extensionRegistry.isRegistered('Umb.Test.Condition.Valid')).to.be.false; + }); + it('allows an extension condition to be updated', async () => { const ext = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; expect(ext.conditions?.length).to.equal(1); @@ -506,12 +511,12 @@ describe('Append Conditions', () => { extensionRegistry.register({ type: 'condition', name: 'test-condition-valid', - alias: 'Umb.Test.Condition.Valid' + alias: 'Umb.Test.Condition.Valid', }); // Add the new condition to the extension - const conditionToAdd:UmbConditionConfigBase = { - alias: 'Umb.Test.Condition.Valid' + const conditionToAdd: UmbConditionConfigBase = { + alias: 'Umb.Test.Condition.Valid', }; await extensionRegistry.appendCondition('Umb.Test.Section.1', conditionToAdd); @@ -523,10 +528,9 @@ describe('Append Conditions', () => { expect(updatedExt.conditions?.length).to.equal(2); // Add a condition with a specific config to Section2 - const workspaceCondition:WorkspaceAliasConditionConfig = { + const workspaceCondition: WorkspaceAliasConditionConfig = { alias: 'Umb.Condition.WorkspaceAlias', - match: 'Umb.Workspace.Document' - + match: 'Umb.Workspace.Document', }; await extensionRegistry.appendCondition('Umb.Test.Section.2', workspaceCondition); @@ -538,15 +542,15 @@ describe('Append Conditions', () => { const ext = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; expect(ext.conditions?.length).to.equal(1); - const conditions:Array = [ + const conditions: Array = [ { - alias: 'Umb.Test.Condition.Valid' + alias: 'Umb.Test.Condition.Valid', }, { alias: 'Umb.Condition.WorkspaceAlias', - match: 'Umb.Workspace.Document' - } as WorkspaceAliasConditionConfig - ] + match: 'Umb.Workspace.Document', + } as WorkspaceAliasConditionConfig, + ]; await extensionRegistry.appendConditions('Umb.Test.Section.1', conditions); @@ -560,87 +564,89 @@ describe('Prepend Conditions', () => { let manifests: Array; beforeEach(() => { - extensionRegistry = new UmbExtensionRegistry(); - manifests = [ + extensionRegistry = new UmbExtensionRegistry(); + manifests = [ + { + type: 'section', + name: 'test-section-1', + alias: 'Umb.Test.Section.1', + weight: 1, + conditions: [ { - type: 'section', - name: 'test-section-1', - alias: 'Umb.Test.Section.1', - weight: 1, - conditions: [ - { - alias: "Umb.Test.Condition.Valid" - } - ] + alias: 'Umb.Test.Condition.Valid', }, - { - type: 'section', - name: 'test-section-2', - alias: 'Umb.Test.Section.2', - weight: 200 - }, - ]; + ], + }, + { + type: 'section', + name: 'test-section-2', + alias: 'Umb.Test.Section.2', + weight: 200, + }, + ]; - manifests.forEach((manifest) => extensionRegistry.register(manifest)); + manifests.forEach((manifest) => extensionRegistry.register(manifest)); - extensionRegistry.register({ - type: 'condition', - name: 'test-condition-invalid', - alias: 'Umb.Test.Condition.Invalid' - }); + extensionRegistry.register({ + type: 'condition', + name: 'test-condition-invalid', + alias: 'Umb.Test.Condition.Invalid', + }); + }); + + it('should have the extensions registered', () => { + expect(extensionRegistry.isRegistered('Umb.Test.Section.1')).to.be.true; + expect(extensionRegistry.isRegistered('Umb.Test.Section.2')).to.be.true; + expect(extensionRegistry.isRegistered('Umb.Test.Condition.Invalid')).to.be.true; + expect(extensionRegistry.isRegistered('Umb.Test.Condition.Valid')).to.be.false; }); it('allows an extension condition to be prepended', async () => { - expect(extensionRegistry.isRegistered('Umb.Test.Section.1')).to.be.true; - expect(extensionRegistry.isRegistered('Umb.Test.Section.2')).to.be.true; - expect(extensionRegistry.isRegistered('Umb.Test.Condition.Invalid')).to.be.true; - expect(extensionRegistry.isRegistered('Umb.Test.Condition.Valid')).to.be.false; + const ext = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; + expect(ext.conditions?.length).to.equal(1); - const ext = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; - expect(ext.conditions?.length).to.equal(1); + // Register new condition as if I was in my own entrypoint + extensionRegistry.register({ + type: 'condition', + name: 'test-condition-valid', + alias: 'Umb.Test.Condition.Valid', + }); - // Register new condition as if I was in my own entrypoint - extensionRegistry.register({ - type: 'condition', - name: 'test-condition-valid', - alias: 'Umb.Test.Condition.Valid' - }); + // Prepend the new condition to the extension + const conditionToPrepend: UmbConditionConfigBase = { + alias: 'Umb.Test.Condition.Valid', + }; - // Prepend the new condition to the extension - const conditionToPrepend: UmbConditionConfigBase = { - alias: 'Umb.Test.Condition.Valid' - }; + await extensionRegistry.prependCondition('Umb.Test.Section.1', conditionToPrepend); - await extensionRegistry.prependCondition('Umb.Test.Section.1', conditionToPrepend); + // Check new condition is registered + expect(extensionRegistry.isRegistered('Umb.Test.Condition.Valid')).to.be.true; - // Check new condition is registered - expect(extensionRegistry.isRegistered('Umb.Test.Condition.Valid')).to.be.true; - - // Verify the extension now has two conditions and the new condition is prepended - const updatedExt = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; - expect(updatedExt.conditions?.length).to.equal(2); - expect(updatedExt.conditions?.[0]?.alias).to.equal('Umb.Test.Condition.Valid'); + // Verify the extension now has two conditions and the new condition is prepended + const updatedExt = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; + expect(updatedExt.conditions?.length).to.equal(2); + expect(updatedExt.conditions?.[0]?.alias).to.equal('Umb.Test.Condition.Valid'); }); it('allows an extension to update with multiple prepended conditions', async () => { - const ext = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; - expect(ext.conditions?.length).to.equal(1); + const ext = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; + expect(ext.conditions?.length).to.equal(1); - const conditions: Array = [ - { - alias: 'Umb.Test.Condition.Valid' - }, - { - alias: 'Umb.Condition.WorkspaceAlias', - match: 'Umb.Workspace.Document' - } as WorkspaceAliasConditionConfig - ]; + const conditions: Array = [ + { + alias: 'Umb.Test.Condition.Valid', + }, + { + alias: 'Umb.Condition.WorkspaceAlias', + match: 'Umb.Workspace.Document', + } as WorkspaceAliasConditionConfig, + ]; - await extensionRegistry.prependConditions('Umb.Test.Section.1', conditions); + await extensionRegistry.prependConditions('Umb.Test.Section.1', conditions); - const extUpdated = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; - expect(extUpdated.conditions?.length).to.equal(3); - expect(extUpdated.conditions?.[0]?.alias).to.equal('Umb.Condition.WorkspaceAlias'); - expect(extUpdated.conditions?.[1]?.alias).to.equal('Umb.Test.Condition.Valid'); + const extUpdated = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; + expect(extUpdated.conditions?.length).to.equal(3); + expect(extUpdated.conditions?.[0]?.alias).to.equal('Umb.Condition.WorkspaceAlias'); + expect(extUpdated.conditions?.[1]?.alias).to.equal('Umb.Test.Condition.Valid'); }); }); From 062177ad66ceffa74542e3c8ef0a76a2267c7a2e Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Fri, 30 Aug 2024 11:43:31 +0100 Subject: [PATCH 07/55] Rework of tests to pass and minor fix to _whenExtensionAliasIsRegistered to get the ext alias that matches --- .../registry/extension.registry.test.ts | 56 +++++++++++-------- .../registry/extension.registry.ts | 21 +++---- 2 files changed, 42 insertions(+), 35 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts index dd1e8612f9..e089f1bd17 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts @@ -475,7 +475,7 @@ describe('Append Conditions', () => { weight: 1, conditions: [ { - alias: 'Umb.Test.Condition.Valid', + alias: 'Umb.Test.Condition.Invalid', }, ], }, @@ -483,7 +483,7 @@ describe('Append Conditions', () => { type: 'section', name: 'test-section-2', alias: 'Umb.Test.Section.2', - weight: 200, + weight: 200 }, ]; @@ -523,19 +523,23 @@ describe('Append Conditions', () => { // Check new condition is registered expect(extensionRegistry.isRegistered('Umb.Test.Condition.Valid')).to.be.true; - // Verify the extension now has two conditions + // Verify the extension now has two conditions and in correct order with aliases const updatedExt = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; expect(updatedExt.conditions?.length).to.equal(2); + expect(updatedExt.conditions?.[0]?.alias).to.equal('Umb.Test.Condition.Invalid'); + expect(updatedExt.conditions?.[1]?.alias).to.equal('Umb.Test.Condition.Valid'); // Add a condition with a specific config to Section2 const workspaceCondition: WorkspaceAliasConditionConfig = { alias: 'Umb.Condition.WorkspaceAlias', match: 'Umb.Workspace.Document', }; + await extensionRegistry.appendCondition('Umb.Test.Section.2', workspaceCondition); const updatedWorkspaceExt = extensionRegistry.getByAlias('Umb.Test.Section.2') as ManifestWithDynamicConditions; expect(updatedWorkspaceExt.conditions?.length).to.equal(1); + expect(updatedWorkspaceExt.conditions?.[0]?.alias).to.equal('Umb.Condition.WorkspaceAlias'); }); it('allows an extension to update with multiple conditions', async () => { @@ -555,7 +559,10 @@ describe('Append Conditions', () => { await extensionRegistry.appendConditions('Umb.Test.Section.1', conditions); const extUpdated = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; - expect(ext.conditions?.length).to.equal(3); + expect(extUpdated.conditions?.length).to.equal(3); + expect(extUpdated.conditions?.[0]?.alias).to.equal('Umb.Test.Condition.Invalid'); + expect(extUpdated.conditions?.[1]?.alias).to.equal('Umb.Test.Condition.Valid'); + expect(extUpdated.conditions?.[2]?.alias).to.equal('Umb.Condition.WorkspaceAlias'); }); }); @@ -582,59 +589,60 @@ describe('Prepend Conditions', () => { name: 'test-section-2', alias: 'Umb.Test.Section.2', weight: 200, + conditions: [ + { + alias: 'Umb.Test.Condition.Valid', + }, + ], }, ]; manifests.forEach((manifest) => extensionRegistry.register(manifest)); - - extensionRegistry.register({ - type: 'condition', - name: 'test-condition-invalid', - alias: 'Umb.Test.Condition.Invalid', - }); }); it('should have the extensions registered', () => { expect(extensionRegistry.isRegistered('Umb.Test.Section.1')).to.be.true; expect(extensionRegistry.isRegistered('Umb.Test.Section.2')).to.be.true; - expect(extensionRegistry.isRegistered('Umb.Test.Condition.Invalid')).to.be.true; + expect(extensionRegistry.isRegistered('Umb.Test.Condition.Invalid')).to.be.false; expect(extensionRegistry.isRegistered('Umb.Test.Condition.Valid')).to.be.false; }); it('allows an extension condition to be prepended', async () => { const ext = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; expect(ext.conditions?.length).to.equal(1); + expect(ext.conditions?.[0]?.alias).to.equal('Umb.Test.Condition.Valid'); - // Register new condition as if I was in my own entrypoint extensionRegistry.register({ type: 'condition', - name: 'test-condition-valid', - alias: 'Umb.Test.Condition.Valid', + name: 'test-condition-invalid', + alias: 'Umb.Test.Condition.Invalid', }); // Prepend the new condition to the extension const conditionToPrepend: UmbConditionConfigBase = { - alias: 'Umb.Test.Condition.Valid', + alias: 'Umb.Test.Condition.Invalid', }; await extensionRegistry.prependCondition('Umb.Test.Section.1', conditionToPrepend); // Check new condition is registered - expect(extensionRegistry.isRegistered('Umb.Test.Condition.Valid')).to.be.true; + expect(extensionRegistry.isRegistered('Umb.Test.Condition.Invalid')).to.be.true; // Verify the extension now has two conditions and the new condition is prepended const updatedExt = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; expect(updatedExt.conditions?.length).to.equal(2); - expect(updatedExt.conditions?.[0]?.alias).to.equal('Umb.Test.Condition.Valid'); + expect(updatedExt.conditions?.[0]?.alias).to.equal('Umb.Test.Condition.Invalid'); // Our new one prepended + expect(updatedExt.conditions?.[1]?.alias).to.equal('Umb.Test.Condition.Valid'); }); it('allows an extension to update with multiple prepended conditions', async () => { - const ext = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; + const ext = extensionRegistry.getByAlias('Umb.Test.Section.2') as ManifestWithDynamicConditions; expect(ext.conditions?.length).to.equal(1); + expect(ext.conditions?.[0]?.alias).to.equal('Umb.Test.Condition.Valid'); const conditions: Array = [ { - alias: 'Umb.Test.Condition.Valid', + alias: 'Umb.Test.Condition.Invalid', }, { alias: 'Umb.Condition.WorkspaceAlias', @@ -642,11 +650,15 @@ describe('Prepend Conditions', () => { } as WorkspaceAliasConditionConfig, ]; - await extensionRegistry.prependConditions('Umb.Test.Section.1', conditions); + await extensionRegistry.prependConditions('Umb.Test.Section.2', conditions); - const extUpdated = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; + const extUpdated = extensionRegistry.getByAlias('Umb.Test.Section.2') as ManifestWithDynamicConditions; expect(extUpdated.conditions?.length).to.equal(3); + + // The thing to note here our two new conditions is that are prepended in reverse order they are passed in + // as each one is prepended to the front of the array expect(extUpdated.conditions?.[0]?.alias).to.equal('Umb.Condition.WorkspaceAlias'); - expect(extUpdated.conditions?.[1]?.alias).to.equal('Umb.Test.Condition.Valid'); + expect(extUpdated.conditions?.[1]?.alias).to.equal('Umb.Test.Condition.Invalid'); + expect(extUpdated.conditions?.[2]?.alias).to.equal('Umb.Test.Condition.Valid'); }); }); diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts index e21077c4ab..5cd0dbcbe8 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts @@ -452,7 +452,8 @@ export class UmbExtensionRegistry< private async _whenExtensionAliasIsRegistered(alias: string): Promise { const source = this.extensions.pipe(filter((allExtensions) => allExtensions.some((ext) => ext.alias === alias))); const value = await firstValueFrom(source); - return value[0]; + const ext = value.find((ext) => ext.alias === alias) as ManifestBase; + return ext; } /** @@ -468,9 +469,6 @@ export class UmbExtensionRegistry< // Wait for the extension to be registered (as it could be registered late) const extensionToWaitFor = (await this._whenExtensionAliasIsRegistered(alias)) as ManifestWithDynamicConditions; - // Got it... now carry on & mutate it - console.log('got the extension to update/mutate', extensionToWaitFor); - // Append the condition to the extensions conditions array if (extensionToWaitFor.conditions) { extensionToWaitFor.conditions.push(newCondition); @@ -486,10 +484,6 @@ export class UmbExtensionRegistry< // Update the main extensions collection/observable this._extensions.setValue(allExtensions); - - // Log the updated extensions for debugging - console.log('UPDATED extensions:', this._extensions.getValue()); - console.table(this._extensions.getValue()); } } catch (error) { // TODO: [WB] Will this ever catch an error? @@ -503,7 +497,9 @@ export class UmbExtensionRegistry< * @param newConditions {Array} - A collection of conditions to append to an extension. */ async appendConditions(alias: string, newConditions: Array): Promise { - newConditions.forEach((condition) => this.appendCondition(alias, condition)); + for (const condition of newConditions) { + await this.appendCondition(alias, condition); + } } /** @@ -516,9 +512,6 @@ export class UmbExtensionRegistry< // Wait for the extension to be registered (as it could be registered late) const extensionToUpdate = (await this._whenExtensionAliasIsRegistered(alias)) as ManifestWithDynamicConditions; - // Got it... now carry on & mutate it - console.log('got the extension to update/mutate', extensionToUpdate); - // Append the condition to the extensions conditions array if (extensionToUpdate.conditions) { extensionToUpdate.conditions.unshift(newCondition); @@ -537,6 +530,8 @@ export class UmbExtensionRegistry< * @param newConditions {Array} - A collection of conditions to prepend to an extension. */ async prependConditions(alias: string, newConditions: Array): Promise { - newConditions.forEach((condition) => this.prependCondition(alias, condition)); + for (const condition of newConditions) { + await this.prependCondition(alias, condition); + } } } From 648ea30fa957b75c8307d436d4e3a2d238caff38 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Fri, 30 Aug 2024 13:27:48 +0100 Subject: [PATCH 08/55] Trying to add a test to show that a late registered extension works - but test says otherwise compared to using it in entrypoint --- .../registry/extension.registry.test.ts | 46 ++++++++++++++++++- .../packages/property-editors/entry-point.ts | 20 +++++++- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts index e089f1bd17..b38fdac8b2 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts @@ -483,7 +483,7 @@ describe('Append Conditions', () => { type: 'section', name: 'test-section-2', alias: 'Umb.Test.Section.2', - weight: 200 + weight: 200, }, ]; @@ -661,4 +661,48 @@ describe('Prepend Conditions', () => { expect(extUpdated.conditions?.[1]?.alias).to.equal('Umb.Test.Condition.Invalid'); expect(extUpdated.conditions?.[2]?.alias).to.equal('Umb.Test.Condition.Valid'); }); + + it('allows conditions to be prepended when an extension is loaded later on', async () => { + const conditions: Array = [ + { + alias: 'Umb.Test.Condition.Invalid', + }, + { + alias: 'Umb.Condition.WorkspaceAlias', + match: 'Umb.Workspace.Document', + } as WorkspaceAliasConditionConfig, + ]; + + console.log('About to go KABOOM..'); + + // Prepend the conditions + // [WB] HELP: Why is this fine when using in in an entrypoint + // /src/packages/property-editors/entry-point.ts + // But this TEST implodes if it can't find the extension that is not yet registered + await extensionRegistry.prependConditions('Late.Extension.To.Be.Loaded', conditions); + + // Make sure the extension is not registered YET + expect(extensionRegistry.isRegistered('Late.Extension.To.Be.Loaded')).to.be.false; + + // Register the extension LATE/after the conditions have been added + extensionRegistry.register({ + type: 'section', + name: 'Late Section Extension with one condition', + alias: 'Late.Extension.To.Be.Loaded', + weight: 200, + conditions: [ + { + alias: 'Umb.Test.Condition.Valid', + }, + ], + }); + + expect(extensionRegistry.isRegistered('Late.Extension.To.Be.Loaded')).to.be.true; + + const extUpdated = extensionRegistry.getByAlias('Late.Extension.To.Be.Loaded') as ManifestWithDynamicConditions; + expect(extUpdated.conditions?.length).to.equal(3); + expect(extUpdated.conditions?.[0]?.alias).to.equal('Umb.Condition.WorkspaceAlias'); + expect(extUpdated.conditions?.[1]?.alias).to.equal('Umb.Test.Condition.Invalid'); + expect(extUpdated.conditions?.[2]?.alias).to.equal('Umb.Test.Condition.Valid'); + }); }); diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/entry-point.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/entry-point.ts index baafe2af43..64d64bc9c4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/entry-point.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/entry-point.ts @@ -1,4 +1,8 @@ -import type { ManifestWithDynamicConditions, UmbConditionConfigBase, UmbEntryPointOnInit } from '@umbraco-cms/backoffice/extension-api'; +import type { + ManifestWithDynamicConditions, + UmbConditionConfigBase, + UmbEntryPointOnInit, +} from '@umbraco-cms/backoffice/extension-api'; import type { WorkspaceAliasConditionConfig } from '@umbraco-cms/backoffice/workspace'; import './checkbox-list/components/index.js'; @@ -13,9 +17,16 @@ export const onInit: UmbEntryPointOnInit = (_host, _extensionRegistry) => { match: 'Umb.Workspace.WARRENYO', } as WorkspaceAliasConditionConfig; + console.log( + 'Should not be false and not registered', + _extensionRegistry.isRegistered('Umb.Dashboard.UmbracoNewsLATE'), + ); + _extensionRegistry.appendCondition('Umb.Dashboard.UmbracoNewsLATE', condition); - const ext:ManifestWithDynamicConditions = { + console.log('I HAZ APPENED CONDITIONS'); + + const ext: ManifestWithDynamicConditions = { alias: 'Umb.Dashboard.UmbracoNewsLATE', type: 'dashboard', name: 'WARREN Package', @@ -30,4 +41,9 @@ export const onInit: UmbEntryPointOnInit = (_host, _extensionRegistry) => { _extensionRegistry.register(ext); + const amIRegistered = _extensionRegistry.isRegistered('Umb.Dashboard.UmbracoNewsLATE'); + console.log('Should be true and registered', amIRegistered); + + const getTheThing = _extensionRegistry.getByAlias('Umb.Dashboard.UmbracoNewsLATE'); + console.log('Should be the extension', getTheThing); }; From bd863ddf4aa80ff81a1624f98c05f46ef58efc3f Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 2 Sep 2024 17:18:21 +0100 Subject: [PATCH 09/55] Remove the prepend conditions and rename append to addCondition and addCondtions As the order of conditions is not important, as all conditions set on an extensions must be true/valid --- .../registry/extension.registry.ts | 43 +++---------------- 1 file changed, 5 insertions(+), 38 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts index 5cd0dbcbe8..26b483b032 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts @@ -457,14 +457,14 @@ export class UmbExtensionRegistry< } /** - * Appends a new condition to an existing extension + * Add a new condition to an existing extension * Useful to add a condition for example the Save And Publish workspace action shipped by core * As overwriting the whole extension to simply add an extra condition is not ideal as it causes a lot of duplicated code * and could easily get out of sync from the CMS core implementation if a 3rd party dev was to try and overwrite it * @param alias {string} - The alias of the extension to append the condition to * @param newCondition {UmbConditionConfigBase} - The condition to append to the extension. */ - async appendCondition(alias: string, newCondition: UmbConditionConfigBase): Promise { + async addCondition(alias: string, newCondition: UmbConditionConfigBase): Promise { try { // Wait for the extension to be registered (as it could be registered late) const extensionToWaitFor = (await this._whenExtensionAliasIsRegistered(alias)) as ManifestWithDynamicConditions; @@ -492,46 +492,13 @@ export class UmbExtensionRegistry< } /** - * Appends a collection of conditions to an exsiting extension + * Adds a collection of conditions to an exsiting extension * @param alias {string} - The alias of the extension to append the condition to * @param newConditions {Array} - A collection of conditions to append to an extension. */ - async appendConditions(alias: string, newConditions: Array): Promise { + async addConditions(alias: string, newConditions: Array): Promise { for (const condition of newConditions) { - await this.appendCondition(alias, condition); - } - } - - /** - * Prepends a new condition to an existing extension - * @param alias {string} - The alias of the extension to prepend the condition to - * @param newCondition {UmbConditionConfigBase} - The condition to prepend to the extension. - */ - async prependCondition(alias: string, newCondition: UmbConditionConfigBase): Promise { - try { - // Wait for the extension to be registered (as it could be registered late) - const extensionToUpdate = (await this._whenExtensionAliasIsRegistered(alias)) as ManifestWithDynamicConditions; - - // Append the condition to the extensions conditions array - if (extensionToUpdate.conditions) { - extensionToUpdate.conditions.unshift(newCondition); - } else { - extensionToUpdate.conditions = [newCondition]; - } - } catch (error) { - // TODO: [WB] Will this ever catch an error? - console.error(`Extension with alias ${alias} was never found and threw ${error}`); - } - } - - /** - * Prepends a collection of conditions to an existing extension - * @param alias {string} - The alias of the extension to prepend the conditions to - * @param newConditions {Array} - A collection of conditions to prepend to an extension. - */ - async prependConditions(alias: string, newConditions: Array): Promise { - for (const condition of newConditions) { - await this.prependCondition(alias, condition); + await this.addCondition(alias, condition); } } } From bdfa2818cc6ae02da45300d3f63c8cd4ddfa5cfc Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 2 Sep 2024 20:03:34 +0100 Subject: [PATCH 10/55] Update tests Still need to uncomment & reinvestigate the late loading test --- .../registry/extension.registry.test.ts | 193 +++++------------- 1 file changed, 48 insertions(+), 145 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts index b38fdac8b2..feb27191c8 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts @@ -461,7 +461,7 @@ describe('UmbExtensionRegistry with exclusions', () => { }); }); -describe('Append Conditions', () => { +describe('Add Conditions', () => { let extensionRegistry: UmbExtensionRegistry; let manifests: Array; @@ -518,7 +518,7 @@ describe('Append Conditions', () => { const conditionToAdd: UmbConditionConfigBase = { alias: 'Umb.Test.Condition.Valid', }; - await extensionRegistry.appendCondition('Umb.Test.Section.1', conditionToAdd); + await extensionRegistry.addCondition('Umb.Test.Section.1', conditionToAdd); // Check new condition is registered expect(extensionRegistry.isRegistered('Umb.Test.Condition.Valid')).to.be.true; @@ -535,7 +535,7 @@ describe('Append Conditions', () => { match: 'Umb.Workspace.Document', }; - await extensionRegistry.appendCondition('Umb.Test.Section.2', workspaceCondition); + await extensionRegistry.addCondition('Umb.Test.Section.2', workspaceCondition); const updatedWorkspaceExt = extensionRegistry.getByAlias('Umb.Test.Section.2') as ManifestWithDynamicConditions; expect(updatedWorkspaceExt.conditions?.length).to.equal(1); @@ -556,7 +556,7 @@ describe('Append Conditions', () => { } as WorkspaceAliasConditionConfig, ]; - await extensionRegistry.appendConditions('Umb.Test.Section.1', conditions); + await extensionRegistry.addConditions('Umb.Test.Section.1', conditions); const extUpdated = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; expect(extUpdated.conditions?.length).to.equal(3); @@ -564,145 +564,48 @@ describe('Append Conditions', () => { expect(extUpdated.conditions?.[1]?.alias).to.equal('Umb.Test.Condition.Valid'); expect(extUpdated.conditions?.[2]?.alias).to.equal('Umb.Condition.WorkspaceAlias'); }); -}); - -describe('Prepend Conditions', () => { - let extensionRegistry: UmbExtensionRegistry; - let manifests: Array; - - beforeEach(() => { - extensionRegistry = new UmbExtensionRegistry(); - manifests = [ - { - type: 'section', - name: 'test-section-1', - alias: 'Umb.Test.Section.1', - weight: 1, - conditions: [ - { - alias: 'Umb.Test.Condition.Valid', - }, - ], - }, - { - type: 'section', - name: 'test-section-2', - alias: 'Umb.Test.Section.2', - weight: 200, - conditions: [ - { - alias: 'Umb.Test.Condition.Valid', - }, - ], - }, - ]; - - manifests.forEach((manifest) => extensionRegistry.register(manifest)); - }); - - it('should have the extensions registered', () => { - expect(extensionRegistry.isRegistered('Umb.Test.Section.1')).to.be.true; - expect(extensionRegistry.isRegistered('Umb.Test.Section.2')).to.be.true; - expect(extensionRegistry.isRegistered('Umb.Test.Condition.Invalid')).to.be.false; - expect(extensionRegistry.isRegistered('Umb.Test.Condition.Valid')).to.be.false; - }); - - it('allows an extension condition to be prepended', async () => { - const ext = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; - expect(ext.conditions?.length).to.equal(1); - expect(ext.conditions?.[0]?.alias).to.equal('Umb.Test.Condition.Valid'); - - extensionRegistry.register({ - type: 'condition', - name: 'test-condition-invalid', - alias: 'Umb.Test.Condition.Invalid', - }); - - // Prepend the new condition to the extension - const conditionToPrepend: UmbConditionConfigBase = { - alias: 'Umb.Test.Condition.Invalid', - }; - - await extensionRegistry.prependCondition('Umb.Test.Section.1', conditionToPrepend); - - // Check new condition is registered - expect(extensionRegistry.isRegistered('Umb.Test.Condition.Invalid')).to.be.true; - - // Verify the extension now has two conditions and the new condition is prepended - const updatedExt = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; - expect(updatedExt.conditions?.length).to.equal(2); - expect(updatedExt.conditions?.[0]?.alias).to.equal('Umb.Test.Condition.Invalid'); // Our new one prepended - expect(updatedExt.conditions?.[1]?.alias).to.equal('Umb.Test.Condition.Valid'); - }); - - it('allows an extension to update with multiple prepended conditions', async () => { - const ext = extensionRegistry.getByAlias('Umb.Test.Section.2') as ManifestWithDynamicConditions; - expect(ext.conditions?.length).to.equal(1); - expect(ext.conditions?.[0]?.alias).to.equal('Umb.Test.Condition.Valid'); - - const conditions: Array = [ - { - alias: 'Umb.Test.Condition.Invalid', - }, - { - alias: 'Umb.Condition.WorkspaceAlias', - match: 'Umb.Workspace.Document', - } as WorkspaceAliasConditionConfig, - ]; - - await extensionRegistry.prependConditions('Umb.Test.Section.2', conditions); - - const extUpdated = extensionRegistry.getByAlias('Umb.Test.Section.2') as ManifestWithDynamicConditions; - expect(extUpdated.conditions?.length).to.equal(3); - - // The thing to note here our two new conditions is that are prepended in reverse order they are passed in - // as each one is prepended to the front of the array - expect(extUpdated.conditions?.[0]?.alias).to.equal('Umb.Condition.WorkspaceAlias'); - expect(extUpdated.conditions?.[1]?.alias).to.equal('Umb.Test.Condition.Invalid'); - expect(extUpdated.conditions?.[2]?.alias).to.equal('Umb.Test.Condition.Valid'); - }); - - it('allows conditions to be prepended when an extension is loaded later on', async () => { - const conditions: Array = [ - { - alias: 'Umb.Test.Condition.Invalid', - }, - { - alias: 'Umb.Condition.WorkspaceAlias', - match: 'Umb.Workspace.Document', - } as WorkspaceAliasConditionConfig, - ]; - - console.log('About to go KABOOM..'); - - // Prepend the conditions - // [WB] HELP: Why is this fine when using in in an entrypoint - // /src/packages/property-editors/entry-point.ts - // But this TEST implodes if it can't find the extension that is not yet registered - await extensionRegistry.prependConditions('Late.Extension.To.Be.Loaded', conditions); - - // Make sure the extension is not registered YET - expect(extensionRegistry.isRegistered('Late.Extension.To.Be.Loaded')).to.be.false; - - // Register the extension LATE/after the conditions have been added - extensionRegistry.register({ - type: 'section', - name: 'Late Section Extension with one condition', - alias: 'Late.Extension.To.Be.Loaded', - weight: 200, - conditions: [ - { - alias: 'Umb.Test.Condition.Valid', - }, - ], - }); - - expect(extensionRegistry.isRegistered('Late.Extension.To.Be.Loaded')).to.be.true; - - const extUpdated = extensionRegistry.getByAlias('Late.Extension.To.Be.Loaded') as ManifestWithDynamicConditions; - expect(extUpdated.conditions?.length).to.equal(3); - expect(extUpdated.conditions?.[0]?.alias).to.equal('Umb.Condition.WorkspaceAlias'); - expect(extUpdated.conditions?.[1]?.alias).to.equal('Umb.Test.Condition.Invalid'); - expect(extUpdated.conditions?.[2]?.alias).to.equal('Umb.Test.Condition.Valid'); - }); + + // it('allows conditions to be prepended when an extension is loaded later on', async () => { + // const conditions: Array = [ + // { + // alias: 'Umb.Test.Condition.Invalid', + // }, + // { + // alias: 'Umb.Condition.WorkspaceAlias', + // match: 'Umb.Workspace.Document', + // } as WorkspaceAliasConditionConfig, + // ]; + + // console.log('About to go KABOOM..'); + + // // Prepend the conditions + // // [WB] HELP: Why is this fine when using in in an entrypoint + // // /src/packages/property-editors/entry-point.ts + // // But this TEST implodes if it can't find the extension that is not yet registered + // await extensionRegistry.addConditions('Late.Extension.To.Be.Loaded', conditions); + + // // Make sure the extension is not registered YET + // expect(extensionRegistry.isRegistered('Late.Extension.To.Be.Loaded')).to.be.false; + + // // Register the extension LATE/after the conditions have been added + // extensionRegistry.register({ + // type: 'section', + // name: 'Late Section Extension with one condition', + // alias: 'Late.Extension.To.Be.Loaded', + // weight: 200, + // conditions: [ + // { + // alias: 'Umb.Test.Condition.Valid', + // }, + // ], + // }); + + // expect(extensionRegistry.isRegistered('Late.Extension.To.Be.Loaded')).to.be.true; + + // const extUpdated = extensionRegistry.getByAlias('Late.Extension.To.Be.Loaded') as ManifestWithDynamicConditions; + // expect(extUpdated.conditions?.length).to.equal(3); + // expect(extUpdated.conditions?.[0]?.alias).to.equal('Umb.Condition.WorkspaceAlias'); + // expect(extUpdated.conditions?.[1]?.alias).to.equal('Umb.Test.Condition.Invalid'); + // expect(extUpdated.conditions?.[2]?.alias).to.equal('Umb.Test.Condition.Valid'); + // }); }); From a4b7584f306b21f1ca920d7f7b254e6fcffd920c Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 3 Sep 2024 19:38:45 +0100 Subject: [PATCH 11/55] Fix up code so test passes & my rough entrypoint demo of usage works --- .../src/packages/property-editors/entry-point.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/entry-point.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/entry-point.ts index 64d64bc9c4..f83895ac9b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/entry-point.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/entry-point.ts @@ -22,9 +22,9 @@ export const onInit: UmbEntryPointOnInit = (_host, _extensionRegistry) => { _extensionRegistry.isRegistered('Umb.Dashboard.UmbracoNewsLATE'), ); - _extensionRegistry.appendCondition('Umb.Dashboard.UmbracoNewsLATE', condition); + _extensionRegistry.addCondition('Umb.Dashboard.UmbracoNewsLATE', condition); - console.log('I HAZ APPENED CONDITIONS'); + console.log('I HAZ ADDED CONDITION'); const ext: ManifestWithDynamicConditions = { alias: 'Umb.Dashboard.UmbracoNewsLATE', From 87dc1c974d89e61c81cc1b89989c8dc6b76a449e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 9 Sep 2024 17:59:20 +0200 Subject: [PATCH 12/55] scaffold help package + header app --- .../src/apps/backoffice/backoffice.element.ts | 1 + .../packages/help/help-header-app.element.ts | 21 +++++++++++++++++++ .../src/packages/help/manifests.ts | 16 ++++++++++++++ .../src/packages/help/umbraco-package.ts | 9 ++++++++ .../src/packages/help/vite.config.ts | 12 +++++++++++ 5 files changed, 59 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/help/help-header-app.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/help/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/help/umbraco-package.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/help/vite.config.ts diff --git a/src/Umbraco.Web.UI.Client/src/apps/backoffice/backoffice.element.ts b/src/Umbraco.Web.UI.Client/src/apps/backoffice/backoffice.element.ts index d59e98126c..cdaffce824 100644 --- a/src/Umbraco.Web.UI.Client/src/apps/backoffice/backoffice.element.ts +++ b/src/Umbraco.Web.UI.Client/src/apps/backoffice/backoffice.element.ts @@ -18,6 +18,7 @@ const CORE_PACKAGES = [ import('../../packages/dictionary/umbraco-package.js'), import('../../packages/documents/umbraco-package.js'), import('../../packages/health-check/umbraco-package.js'), + import('../../packages/help/umbraco-package.js'), import('../../packages/language/umbraco-package.js'), import('../../packages/log-viewer/umbraco-package.js'), import('../../packages/markdown-editor/umbraco-package.js'), diff --git a/src/Umbraco.Web.UI.Client/src/packages/help/help-header-app.element.ts b/src/Umbraco.Web.UI.Client/src/packages/help/help-header-app.element.ts new file mode 100644 index 0000000000..e34b0d906b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/help/help-header-app.element.ts @@ -0,0 +1,21 @@ +import type { CSSResultGroup } from '@umbraco-cms/backoffice/external/lit'; +import { css, html, customElement } from '@umbraco-cms/backoffice/external/lit'; +import { UmbHeaderAppButtonElement } from '@umbraco-cms/backoffice/components'; + +const elementName = 'umb-help-header-app'; +@customElement(elementName) +export class UmbHelpHeaderAppElement extends UmbHeaderAppButtonElement { + override render() { + return html`
My Header App
`; + } + + static override styles: CSSResultGroup = [UmbHeaderAppButtonElement.styles, css``]; +} + +export { UmbHelpHeaderAppElement as element }; + +declare global { + interface HTMLElementTagNameMap { + [elementName]: UmbHelpHeaderAppElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/help/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/help/manifests.ts new file mode 100644 index 0000000000..9504557d0d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/help/manifests.ts @@ -0,0 +1,16 @@ +import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; + +export const manifests: Array = [ + { + type: 'headerApp', + alias: 'Umb.HeaderApp.Help', + name: 'Help Header App', + element: () => import('./help-header-app.element.js'), + weight: 0, + meta: { + label: 'TODO: how should we enable this to not be set.', + icon: 'TODO: how should we enable this to not be set.', + pathname: 'help', + }, + }, +]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/help/umbraco-package.ts b/src/Umbraco.Web.UI.Client/src/packages/help/umbraco-package.ts new file mode 100644 index 0000000000..bbf3a996b9 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/help/umbraco-package.ts @@ -0,0 +1,9 @@ +export const name = 'Umbraco.Core.Help'; +export const extensions = [ + { + name: 'Help Bundle', + alias: 'Umb.Bundle.Help', + type: 'bundle', + js: () => import('./manifests.js'), + }, +]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/help/vite.config.ts b/src/Umbraco.Web.UI.Client/src/packages/help/vite.config.ts new file mode 100644 index 0000000000..a320e9a053 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/help/vite.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite'; +import { rmSync } from 'fs'; +import { getDefaultConfig } from '../../vite-config-base'; + +const dist = '../../../dist-cms/packages/help'; + +// delete the unbundled dist folder +rmSync(dist, { recursive: true, force: true }); + +export default defineConfig({ + ...getDefaultConfig({ dist, entry: ['manifests.ts', 'umbraco-package.ts'] }), +}); From 0b40be1e58bf54ee09741f1fd4accf2ed926f799 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 9 Sep 2024 18:04:44 +0200 Subject: [PATCH 13/55] render button with icon --- .../src/packages/help/help-header-app.element.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/help/help-header-app.element.ts b/src/Umbraco.Web.UI.Client/src/packages/help/help-header-app.element.ts index e34b0d906b..bafddc24b0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/help/help-header-app.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/help/help-header-app.element.ts @@ -6,7 +6,11 @@ const elementName = 'umb-help-header-app'; @customElement(elementName) export class UmbHelpHeaderAppElement extends UmbHeaderAppButtonElement { override render() { - return html`
My Header App
`; + return html` + + + + `; } static override styles: CSSResultGroup = [UmbHeaderAppButtonElement.styles, css``]; From 25c1cfee7568234a30138ea27c9b7cf19e30306f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 9 Sep 2024 19:07:43 +0200 Subject: [PATCH 14/55] split into header app and menu + register two menu items --- .../header-app/help-header-app.element.ts | 48 +++++++++++++++++++ .../src/packages/help/header-app/manifests.ts | 11 +++++ .../packages/help/help-header-app.element.ts | 25 ---------- .../src/packages/help/manifests.ts | 17 ++----- .../src/packages/help/menu/constants.ts | 1 + .../src/packages/help/menu/index.ts | 1 + .../src/packages/help/menu/manifests.ts | 32 +++++++++++++ 7 files changed, 96 insertions(+), 39 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/help/header-app/help-header-app.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/help/header-app/manifests.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/packages/help/help-header-app.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/help/menu/constants.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/help/menu/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/help/menu/manifests.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/help/header-app/help-header-app.element.ts b/src/Umbraco.Web.UI.Client/src/packages/help/header-app/help-header-app.element.ts new file mode 100644 index 0000000000..7b0b767d13 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/help/header-app/help-header-app.element.ts @@ -0,0 +1,48 @@ +import { UMB_HELP_MENU_ALIAS } from '../menu/index.js'; +import type { CSSResultGroup } from '@umbraco-cms/backoffice/external/lit'; +import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; +import { UmbHeaderAppButtonElement } from '@umbraco-cms/backoffice/components'; +import type { ManifestMenu } from '@umbraco-cms/backoffice/extension-registry'; + +const elementName = 'umb-help-header-app'; +@customElement(elementName) +export class UmbHelpHeaderAppElement extends UmbHeaderAppButtonElement { + @state() + private _popoverOpen = false; + + #onPopoverToggle(event: ToggleEvent) { + // TODO: This ignorer is just neede for JSON SCHEMA TO WORK, As its not updated with latest TS jet. + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + this._popoverOpen = event.newState === 'open'; + } + + override render() { + return html` + + + + + + + + + + + + `; + } + + static override styles: CSSResultGroup = [UmbHeaderAppButtonElement.styles, css``]; +} + +export { UmbHelpHeaderAppElement as element }; + +declare global { + interface HTMLElementTagNameMap { + [elementName]: UmbHelpHeaderAppElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/help/header-app/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/help/header-app/manifests.ts new file mode 100644 index 0000000000..46bb441c2c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/help/header-app/manifests.ts @@ -0,0 +1,11 @@ +import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; + +export const manifests: Array = [ + { + type: 'headerApp', + alias: 'Umb.HeaderApp.Help', + name: 'Help Header App', + element: () => import('./help-header-app.element.js'), + weight: 500, + }, +]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/help/help-header-app.element.ts b/src/Umbraco.Web.UI.Client/src/packages/help/help-header-app.element.ts deleted file mode 100644 index bafddc24b0..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/help/help-header-app.element.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { CSSResultGroup } from '@umbraco-cms/backoffice/external/lit'; -import { css, html, customElement } from '@umbraco-cms/backoffice/external/lit'; -import { UmbHeaderAppButtonElement } from '@umbraco-cms/backoffice/components'; - -const elementName = 'umb-help-header-app'; -@customElement(elementName) -export class UmbHelpHeaderAppElement extends UmbHeaderAppButtonElement { - override render() { - return html` - - - - `; - } - - static override styles: CSSResultGroup = [UmbHeaderAppButtonElement.styles, css``]; -} - -export { UmbHelpHeaderAppElement as element }; - -declare global { - interface HTMLElementTagNameMap { - [elementName]: UmbHelpHeaderAppElement; - } -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/help/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/help/manifests.ts index 9504557d0d..223544e6db 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/help/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/help/manifests.ts @@ -1,16 +1,5 @@ +import { manifests as headerAppManifests } from './header-app/manifests.js'; +import { manifests as menuManifests } from './menu/manifests.js'; import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; -export const manifests: Array = [ - { - type: 'headerApp', - alias: 'Umb.HeaderApp.Help', - name: 'Help Header App', - element: () => import('./help-header-app.element.js'), - weight: 0, - meta: { - label: 'TODO: how should we enable this to not be set.', - icon: 'TODO: how should we enable this to not be set.', - pathname: 'help', - }, - }, -]; +export const manifests: Array = [...menuManifests, ...headerAppManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/help/menu/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/help/menu/constants.ts new file mode 100644 index 0000000000..cae4c017c3 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/help/menu/constants.ts @@ -0,0 +1 @@ +export const UMB_HELP_MENU_ALIAS = 'Umb.Menu.Help'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/help/menu/index.ts b/src/Umbraco.Web.UI.Client/src/packages/help/menu/index.ts new file mode 100644 index 0000000000..4f07201dcf --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/help/menu/index.ts @@ -0,0 +1 @@ +export * from './constants.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/help/menu/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/help/menu/manifests.ts new file mode 100644 index 0000000000..06cab3d506 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/help/menu/manifests.ts @@ -0,0 +1,32 @@ +import { UMB_HELP_MENU_ALIAS } from './constants.js'; +import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; + +export const manifests: Array = [ + { + type: 'menu', + alias: UMB_HELP_MENU_ALIAS, + name: 'Help Menu', + }, + { + type: 'menuItem', + alias: 'Umb.MenuItem.Help.LearningBase', + name: 'Learning Base Help Menu Item', + weight: 200, + meta: { + label: 'Umbraco Learning Base', + icon: 'icon-movie-alt', + menus: [UMB_HELP_MENU_ALIAS], + }, + }, + { + type: 'menuItem', + alias: 'Umb.MenuItem.Help.CommunityWebsite', + name: 'Community Website Help Menu Item', + weight: 100, + meta: { + label: 'Community Website', + icon: 'icon-hearts', + menus: [UMB_HELP_MENU_ALIAS], + }, + }, +]; From 74ae427b8fe86fea2907231a2f6fac170e33e113 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 9 Sep 2024 21:43:54 +0200 Subject: [PATCH 15/55] register user sidebar menu --- .../packages/settings/advanced/manifests.ts | 6 ++-- .../src/packages/user/manifests.ts | 2 +- .../{user-section => section}/constants.ts | 0 .../user/{user-section => section}/index.ts | 0 .../src/packages/user/section/manifests.ts | 31 +++++++++++++++++++ .../packages/user/section/menu/constants.ts | 1 + .../src/packages/user/section/menu/index.ts | 1 + .../packages/user/section/menu/manifests.ts | 9 ++++++ .../user/section/sidebar-app/index.ts | 1 + .../user/section/sidebar-app/manifests.ts | 23 ++++++++++++++ .../user/user-group/section-view/manifests.ts | 2 +- .../packages/user/user-section/manifests.ts | 21 ------------- .../user/user/section-view/manifests.ts | 2 +- 13 files changed, 72 insertions(+), 27 deletions(-) rename src/Umbraco.Web.UI.Client/src/packages/user/{user-section => section}/constants.ts (100%) rename src/Umbraco.Web.UI.Client/src/packages/user/{user-section => section}/index.ts (100%) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/section/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/section/menu/constants.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/section/menu/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/section/menu/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/section/sidebar-app/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/section/sidebar-app/manifests.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user-section/manifests.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/settings/advanced/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/settings/advanced/manifests.ts index 5a452d9e3d..3931a9edb9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/settings/advanced/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/settings/advanced/manifests.ts @@ -10,11 +10,11 @@ export const manifests = [ { type: 'sectionSidebarApp', kind: 'menu', - alias: 'Umb.SectionSidebarMenu.AdvancedSettings', - name: 'Advanced Settings Sidebar Menu', + alias: 'Umb.SectionSidebarApp.Menu.Users', + name: 'Users Section Sidebar Menu', weight: 100, meta: { - label: '#treeHeaders_advancedGroup', + label: 'Users', menu: UMB_ADVANCED_SETTINGS_MENU_ALIAS, }, conditions: [ diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/manifests.ts index 96353d28f7..d649d8f06f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/manifests.ts @@ -1,6 +1,6 @@ import { manifests as userGroupManifests } from './user-group/manifests.js'; import { manifests as userManifests } from './user/manifests.js'; -import { manifests as userSectionManifests } from './user-section/manifests.js'; +import { manifests as userSectionManifests } from './section/manifests.js'; import { manifests as currentUserManifests } from './current-user/manifests.js'; import { manifests as userPermissionManifests } from './user-permission/manifests.js'; import { manifests as changePasswordManifests } from './change-password/manifests.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-section/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/user/section/constants.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/user/user-section/constants.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/section/constants.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-section/index.ts b/src/Umbraco.Web.UI.Client/src/packages/user/section/index.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/user/user-section/index.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/section/index.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/section/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/section/manifests.ts new file mode 100644 index 0000000000..bb49da5322 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/section/manifests.ts @@ -0,0 +1,31 @@ +import { UMB_USER_MANAGEMENT_SECTION_ALIAS } from './constants.js'; +import { manifests as sectionSidebarAppManifests } from './sidebar-app/manifests.js'; +import { manifests as menuManifests } from './menu/manifests.js'; +import type { + ManifestSection, + ManifestTypes, + UmbBackofficeManifestKind, +} from '@umbraco-cms/backoffice/extension-registry'; + +const section: ManifestSection = { + type: 'section', + alias: UMB_USER_MANAGEMENT_SECTION_ALIAS, + name: 'User Management Section', + weight: 600, + meta: { + label: '#sections_users', + pathname: 'user-management', + }, + conditions: [ + { + alias: 'Umb.Condition.SectionUserPermission', + match: UMB_USER_MANAGEMENT_SECTION_ALIAS, + }, + ], +}; + +export const manifests: Array = [ + section, + ...sectionSidebarAppManifests, + ...menuManifests, +]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/section/menu/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/user/section/menu/constants.ts new file mode 100644 index 0000000000..7bf050d53c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/section/menu/constants.ts @@ -0,0 +1 @@ +export const UMB_USER_MANAGEMENT_MENU_ALIAS = 'Umb.Menu.UserManagement'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/section/menu/index.ts b/src/Umbraco.Web.UI.Client/src/packages/user/section/menu/index.ts new file mode 100644 index 0000000000..4f07201dcf --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/section/menu/index.ts @@ -0,0 +1 @@ +export * from './constants.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/section/menu/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/section/menu/manifests.ts new file mode 100644 index 0000000000..f5852aa534 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/section/menu/manifests.ts @@ -0,0 +1,9 @@ +import { UMB_USER_MANAGEMENT_MENU_ALIAS } from './constants.js'; + +export const manifests = [ + { + type: 'menu', + alias: UMB_USER_MANAGEMENT_MENU_ALIAS, + name: 'User Management Menu', + }, +]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/section/sidebar-app/index.ts b/src/Umbraco.Web.UI.Client/src/packages/user/section/sidebar-app/index.ts new file mode 100644 index 0000000000..4f07201dcf --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/section/sidebar-app/index.ts @@ -0,0 +1 @@ +export * from './constants.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/section/sidebar-app/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/section/sidebar-app/manifests.ts new file mode 100644 index 0000000000..f21d698bc2 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/section/sidebar-app/manifests.ts @@ -0,0 +1,23 @@ +import { UMB_USER_MANAGEMENT_SECTION_ALIAS } from '../constants.js'; +import { UMB_USER_MANAGEMENT_MENU_ALIAS } from '../menu/index.js'; +import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; + +export const manifests: Array = [ + { + type: 'sectionSidebarApp', + kind: 'menu', + alias: 'Umb.SectionSidebarApp.Menu.UserManagement', + name: 'User Management Menu Sidebar App', + weight: 100, + meta: { + label: '#treeHeaders_users', + menu: UMB_USER_MANAGEMENT_MENU_ALIAS, + }, + conditions: [ + { + alias: 'Umb.Condition.SectionAlias', + match: UMB_USER_MANAGEMENT_SECTION_ALIAS, + }, + ], + }, +]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/manifests.ts index 3780224244..f4549d458f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/manifests.ts @@ -1,4 +1,4 @@ -import { UMB_USER_MANAGEMENT_SECTION_ALIAS } from '../../user-section/index.js'; +import { UMB_USER_MANAGEMENT_SECTION_ALIAS } from '../../section/index.js'; import type { ManifestSectionView, ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; const sectionsViews: Array = [ diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-section/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-section/manifests.ts deleted file mode 100644 index 74bb597e28..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-section/manifests.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { UMB_USER_MANAGEMENT_SECTION_ALIAS } from './constants.js'; -import type { ManifestSection, ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; - -const section: ManifestSection = { - type: 'section', - alias: UMB_USER_MANAGEMENT_SECTION_ALIAS, - name: 'User Management Section', - weight: 600, - meta: { - label: '#sections_users', - pathname: 'user-management', - }, - conditions: [ - { - alias: 'Umb.Condition.SectionUserPermission', - match: UMB_USER_MANAGEMENT_SECTION_ALIAS, - }, - ], -}; - -export const manifests: Array = [section]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/manifests.ts index a9dbcd430b..8af99c6b24 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/manifests.ts @@ -1,4 +1,4 @@ -import { UMB_USER_MANAGEMENT_SECTION_ALIAS } from '../../user-section/index.js'; +import { UMB_USER_MANAGEMENT_SECTION_ALIAS } from '../../section/index.js'; import type { ManifestSectionView, ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; const sectionsViews: Array = [ From 084da134cae885f656bd90b3837c01f5fff7751e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 9 Sep 2024 21:56:10 +0200 Subject: [PATCH 16/55] register root workspace --- .../src/packages/user/user/manifests.ts | 7 +- .../packages/user/user/menu-item/manifests.ts | 18 +++++ .../user/user/section-view/manifests.ts | 27 +++----- .../user-root-workspace-view.element.ts | 21 ++++++ .../users-section-view.element.ts | 67 ------------------- 5 files changed, 52 insertions(+), 88 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user/menu-item/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/user-root-workspace-view.element.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/users-section-view.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/manifests.ts index a5eb9bfeea..88fe76cfcd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/manifests.ts @@ -8,9 +8,11 @@ import { manifests as repositoryManifests } from './repository/manifests.js'; import { manifests as sectionViewManifests } from './section-view/manifests.js'; import { manifests as propertyEditorManifests } from './property-editor/manifests.js'; import { manifests as workspaceManifests } from './workspace/manifests.js'; -import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; +import { manifests as menuItemManifests } from './menu-item/manifests.js'; -export const manifests: Array = [ +import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; + +export const manifests: Array = [ ...collectionManifests, ...conditionsManifests, ...entityActionsManifests, @@ -21,4 +23,5 @@ export const manifests: Array = [ ...sectionViewManifests, ...propertyEditorManifests, ...workspaceManifests, + ...menuItemManifests, ]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/menu-item/manifests.ts new file mode 100644 index 0000000000..2239c2fe0f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/menu-item/manifests.ts @@ -0,0 +1,18 @@ +import { UMB_USER_MANAGEMENT_MENU_ALIAS } from '../../section/menu/constants.js'; +import { UMB_USER_ROOT_ENTITY_TYPE } from '../entity.js'; +import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; + +export const manifests: Array = [ + { + type: 'menuItem', + alias: 'Umb.MenuItem.Users', + name: 'Users Menu Item', + weight: 100, + meta: { + label: '#treeHeaders_users', + icon: 'icon-user', + entityType: UMB_USER_ROOT_ENTITY_TYPE, + menus: [UMB_USER_MANAGEMENT_MENU_ALIAS], + }, + }, +]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/manifests.ts index 8af99c6b24..aef4c6370e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/manifests.ts @@ -1,25 +1,14 @@ -import { UMB_USER_MANAGEMENT_SECTION_ALIAS } from '../../section/index.js'; -import type { ManifestSectionView, ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; +import { UMB_USER_ROOT_ENTITY_TYPE } from '../entity.js'; +import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; -const sectionsViews: Array = [ +export const manifests: Array = [ { - type: 'sectionView', - alias: 'Umb.SectionView.Users', - name: 'Users Section View', - js: () => import('./users-section-view.element.js'), - weight: 200, + type: 'workspace', + alias: 'Umb.Workspace.UserRoot', + name: 'User Root Workspace View', + element: () => import('./user-root-workspace-view.element.js'), meta: { - label: '#general_users', - pathname: 'users', - icon: 'icon-user', + entityType: UMB_USER_ROOT_ENTITY_TYPE, }, - conditions: [ - { - alias: 'Umb.Condition.SectionAlias', - match: UMB_USER_MANAGEMENT_SECTION_ALIAS, - }, - ], }, ]; - -export const manifests: Array = [...sectionsViews]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/user-root-workspace-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/user-root-workspace-view.element.ts new file mode 100644 index 0000000000..6e286dada3 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/user-root-workspace-view.element.ts @@ -0,0 +1,21 @@ +import { UMB_USER_COLLECTION_ALIAS } from '../collection/index.js'; +import { html, customElement } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; + +const elementName = 'umb-user-root-workspace'; +@customElement(elementName) +export class UmbUserRootWorkspaceElement extends UmbLitElement { + override render() { + return html` + ; + `; + } +} + +export { UmbUserRootWorkspaceElement as element }; + +declare global { + interface HTMLElementTagNameMap { + [elementName]: UmbUserRootWorkspaceElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/users-section-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/users-section-view.element.ts deleted file mode 100644 index 22f9d5069d..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/users-section-view.element.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { UMB_USER_COLLECTION_ALIAS } from '../collection/index.js'; -import { UMB_USER_ENTITY_TYPE, UMB_USER_ROOT_ENTITY_TYPE } from '../entity.js'; -import { css, html, customElement } from '@umbraco-cms/backoffice/external/lit'; -import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import type { UmbRoute } from '@umbraco-cms/backoffice/router'; -import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; -import { UmbCollectionElement } from '@umbraco-cms/backoffice/collection'; -import { UmbWorkspaceElement } from '@umbraco-cms/backoffice/workspace'; -import { UmbEntityContext } from '@umbraco-cms/backoffice/entity'; - -@customElement('umb-section-view-users') -export class UmbSectionViewUsersElement extends UmbLitElement { - #routes: UmbRoute[] = [ - { - path: 'collection', - component: () => { - const element = new UmbCollectionElement(); - const entityContext = new UmbEntityContext(element); - entityContext.setEntityType(UMB_USER_ROOT_ENTITY_TYPE); - entityContext.setUnique(null); - element.setAttribute('alias', UMB_USER_COLLECTION_ALIAS); - return element; - }, - }, - { - path: 'user', - component: () => { - const element = new UmbWorkspaceElement(); - element.setAttribute('entity-type', UMB_USER_ENTITY_TYPE); - return element; - }, - }, - { - path: '', - redirectTo: 'collection', - }, - { - path: `**`, - component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement, - }, - ]; - - override render() { - return html` `; - } - - static override styles = [ - UmbTextStyles, - css` - :host { - height: 100%; - } - - #router-slot { - height: calc(100% - var(--umb-header-layout-height)); - } - `, - ]; -} - -export default UmbSectionViewUsersElement; - -declare global { - interface HTMLElementTagNameMap { - 'umb-section-view-users': UmbSectionViewUsersElement; - } -} From cb19f4fe65337ebb69b0ada6e5b10733b5292b40 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 10 Sep 2024 08:53:01 +0200 Subject: [PATCH 17/55] register user group menu item --- .../src/packages/user/user-group/entity.ts | 2 + .../src/packages/user/user-group/manifests.ts | 19 +++--- .../user/user-group/menu-item/manifests.ts | 18 ++++++ .../user/user-group/section-view/manifests.ts | 27 +++----- .../user-group-root-workspace.element.ts | 21 +++++++ .../user-group-section-view.element.ts | 63 ------------------- .../packages/user/user/menu-item/manifests.ts | 2 +- .../user/user/section-view/manifests.ts | 2 +- ...ment.ts => user-root-workspace.element.ts} | 0 9 files changed, 62 insertions(+), 92 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user-group/menu-item/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/user-group-root-workspace.element.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/user-group-section-view.element.ts rename src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/{user-root-workspace-view.element.ts => user-root-workspace.element.ts} (100%) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/entity.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/entity.ts index 40fc592fed..3978bfa6a5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/entity.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/entity.ts @@ -1,3 +1,5 @@ export const UMB_USER_GROUP_ENTITY_TYPE = 'user-group'; +export const UMB_USER_GROUP_ROOT_ENTITY_TYPE = 'user-group-root'; export type UmbUserGroupEntityType = typeof UMB_USER_GROUP_ENTITY_TYPE; +export type UmbUserGroupRootEntityType = typeof UMB_USER_GROUP_ROOT_ENTITY_TYPE; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/manifests.ts index 4a03fbb339..1ac88d4e75 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/manifests.ts @@ -1,18 +1,21 @@ import { manifests as collectionManifests } from './collection/manifests.js'; -import { manifests as repositoryManifests } from './repository/manifests.js'; -import { manifests as workspaceManifests } from './workspace/manifests.js'; -import { manifests as modalManifests } from './modals/manifests.js'; -import { manifests as sectionViewManifests } from './section-view/manifests.js'; import { manifests as entityActionManifests } from './entity-actions/manifests.js'; import { manifests as entityBulkActionManifests } from './entity-bulk-actions/manifests.js'; +import { manifests as menuItemManifests } from './menu-item/manifests.js'; +import { manifests as modalManifests } from './modals/manifests.js'; +import { manifests as repositoryManifests } from './repository/manifests.js'; +import { manifests as sectionViewManifests } from './section-view/manifests.js'; +import { manifests as workspaceManifests } from './workspace/manifests.js'; + import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; export const manifests: Array = [ ...collectionManifests, - ...repositoryManifests, - ...workspaceManifests, - ...modalManifests, - ...sectionViewManifests, ...entityActionManifests, ...entityBulkActionManifests, + ...menuItemManifests, + ...modalManifests, + ...repositoryManifests, + ...sectionViewManifests, + ...workspaceManifests, ]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/menu-item/manifests.ts new file mode 100644 index 0000000000..1c770acdae --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/menu-item/manifests.ts @@ -0,0 +1,18 @@ +import { UMB_USER_MANAGEMENT_MENU_ALIAS } from '../../section/menu/constants.js'; +import { UMB_USER_GROUP_ROOT_ENTITY_TYPE } from '../entity.js'; +import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; + +export const manifests: Array = [ + { + type: 'menuItem', + alias: 'Umb.MenuItem.UserGroups', + name: 'User Groups Menu Item', + weight: 100, + meta: { + label: '#user_usergroups', + icon: 'icon-users', + entityType: UMB_USER_GROUP_ROOT_ENTITY_TYPE, + menus: [UMB_USER_MANAGEMENT_MENU_ALIAS], + }, + }, +]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/manifests.ts index f4549d458f..ade0536011 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/manifests.ts @@ -1,25 +1,14 @@ -import { UMB_USER_MANAGEMENT_SECTION_ALIAS } from '../../section/index.js'; -import type { ManifestSectionView, ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; +import { UMB_USER_GROUP_ROOT_ENTITY_TYPE } from '../entity.js'; +import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; -const sectionsViews: Array = [ +export const manifests: Array = [ { - type: 'sectionView', - alias: 'Umb.SectionView.UserGroup', - name: 'User Group Section View', - js: () => import('./user-group-section-view.element.js'), - weight: 100, + type: 'workspace', + alias: 'Umb.Workspace.UserGroupRoot', + name: 'User Group Root Workspace View', + element: () => import('./user-group-root-workspace.element.js'), meta: { - label: '#user_usergroups', - pathname: 'user-groups', - icon: 'icon-users', + entityType: UMB_USER_GROUP_ROOT_ENTITY_TYPE, }, - conditions: [ - { - alias: 'Umb.Condition.SectionAlias', - match: UMB_USER_MANAGEMENT_SECTION_ALIAS, - }, - ], }, ]; - -export const manifests: Array = [...sectionsViews]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/user-group-root-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/user-group-root-workspace.element.ts new file mode 100644 index 0000000000..f02687d62d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/user-group-root-workspace.element.ts @@ -0,0 +1,21 @@ +import { UMB_USER_GROUP_COLLECTION_ALIAS } from '../collection/index.js'; +import { html, customElement } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; + +const elementName = 'umb-user-group-root-workspace'; +@customElement(elementName) +export class UmbUserGroupRootWorkspaceElement extends UmbLitElement { + override render() { + return html` + ; + `; + } +} + +export { UmbUserGroupRootWorkspaceElement as element }; + +declare global { + interface HTMLElementTagNameMap { + [elementName]: UmbUserGroupRootWorkspaceElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/user-group-section-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/user-group-section-view.element.ts deleted file mode 100644 index 4611f0962d..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/user-group-section-view.element.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { UMB_USER_GROUP_COLLECTION_ALIAS } from '../collection/index.js'; -import { UMB_USER_GROUP_ENTITY_TYPE } from '../entity.js'; -import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import { css, html, customElement } from '@umbraco-cms/backoffice/external/lit'; -import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; -import type { UmbRoute } from '@umbraco-cms/backoffice/router'; -import { UmbCollectionElement } from '@umbraco-cms/backoffice/collection'; -import { UmbWorkspaceElement } from '@umbraco-cms/backoffice/workspace'; - -@customElement('umb-user-group-section-view') -export class UmbUserGroupSectionViewElement extends UmbLitElement { - #routes: UmbRoute[] = [ - { - path: 'collection', - component: () => { - const element = new UmbCollectionElement(); - element.setAttribute('alias', UMB_USER_GROUP_COLLECTION_ALIAS); - return element; - }, - }, - { - path: 'user-group', - component: () => { - const element = new UmbWorkspaceElement(); - element.setAttribute('entity-type', UMB_USER_GROUP_ENTITY_TYPE); - return element; - }, - }, - { - path: '', - redirectTo: 'collection', - }, - { - path: `**`, - component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement, - }, - ]; - - override render() { - return html``; - } - - static override styles = [ - UmbTextStyles, - css` - :host { - height: 100%; - } - - #router-slot { - height: calc(100% - var(--umb-header-layout-height)); - } - `, - ]; -} - -export default UmbUserGroupSectionViewElement; - -declare global { - interface HTMLElementTagNameMap { - 'umb-user-group-section-view': UmbUserGroupSectionViewElement; - } -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/menu-item/manifests.ts index 2239c2fe0f..c1980c58ef 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/menu-item/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/menu-item/manifests.ts @@ -7,7 +7,7 @@ export const manifests: Array = [ type: 'menuItem', alias: 'Umb.MenuItem.Users', name: 'Users Menu Item', - weight: 100, + weight: 200, meta: { label: '#treeHeaders_users', icon: 'icon-user', diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/manifests.ts index aef4c6370e..96eea28eda 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/manifests.ts @@ -6,7 +6,7 @@ export const manifests: Array = [ type: 'workspace', alias: 'Umb.Workspace.UserRoot', name: 'User Root Workspace View', - element: () => import('./user-root-workspace-view.element.js'), + element: () => import('./user-root-workspace.element.js'), meta: { entityType: UMB_USER_ROOT_ENTITY_TYPE, }, diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/user-root-workspace-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/user-root-workspace.element.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/user-root-workspace-view.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/user-root-workspace.element.ts From 89e14c290cddc4ea46fec312082857864b8ec84c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 10 Sep 2024 08:53:36 +0200 Subject: [PATCH 18/55] add link menu item kind --- .../core/extension-registry/models/index.ts | 3 +- .../models/menu-item.model.ts | 10 +++++++ .../src/packages/core/manifests.ts | 2 ++ .../menu-item-layout.element.ts | 11 +++++++- .../menu-item/link/link-menu-item.element.ts | 28 +++++++++++++++++++ .../components/menu-item/link/manifests.ts | 14 ++++++++++ .../menu/components/menu-item/manifests.ts | 4 +++ .../src/packages/core/menu/manifests.ts | 4 +++ .../src/packages/help/menu/manifests.ts | 8 ++++-- 9 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item/link/link-menu-item.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item/link/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/menu/manifests.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/index.ts index adc53de04c..278207f19a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/index.ts @@ -30,7 +30,7 @@ import type { ManifestHealthCheck } from './health-check.model.js'; import type { ManifestIcons } from './icons.model.js'; import type { ManifestLocalization } from './localization.model.js'; import type { ManifestMenu } from './menu.model.js'; -import type { ManifestMenuItem, ManifestMenuItemTreeKind } from './menu-item.model.js'; +import type { ManifestMenuItem, ManifestMenuItemLinkKind, ManifestMenuItemTreeKind } from './menu-item.model.js'; import type { ManifestModal } from './modal.model.js'; import type { ManifestPackageView } from './package-view.model.js'; import type { ManifestPreviewAppProvider } from './preview-app.model.js'; @@ -186,6 +186,7 @@ export type ManifestTypes = | ManifestMenu | ManifestMenuItem | ManifestMenuItemTreeKind + | ManifestMenuItemLinkKind | ManifestMfaLoginProvider | ManifestModal | ManifestMonacoMarkdownEditorAction diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/menu-item.model.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/menu-item.model.ts index 05eeb81b78..68f7d2f354 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/menu-item.model.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/menu-item.model.ts @@ -26,3 +26,13 @@ export interface MetaMenuItemTreeKind extends MetaMenuItem { treeAlias: string; hideTreeRoot?: boolean; } + +export interface ManifestMenuItemLinkKind extends ManifestMenuItem { + type: 'menuItem'; + kind: 'link'; + meta: MetaMenuItemLinkKind; +} + +export interface MetaMenuItemLinkKind extends MetaMenuItem { + href: string; +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/core/manifests.ts index 893b161f1f..5fc8f5c5a8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/manifests.ts @@ -9,6 +9,7 @@ import { manifests as entityBulkActionManifests } from './entity-bulk-action/man import { manifests as extensionManifests } from './extension-registry/manifests.js'; import { manifests as iconRegistryManifests } from './icon-registry/manifests.js'; import { manifests as localizationManifests } from './localization/manifests.js'; +import { manifests as menuManifests } from './menu/manifests.js'; import { manifests as modalManifests } from './modal/common/manifests.js'; import { manifests as pickerManifests } from './picker/manifests.js'; import { manifests as propertyActionManifests } from './property-action/manifests.js'; @@ -35,6 +36,7 @@ export const manifests: Array = [ ...extensionManifests, ...iconRegistryManifests, ...localizationManifests, + ...menuManifests, ...modalManifests, ...pickerManifests, ...propertyActionManifests, diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item-layout/menu-item-layout.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item-layout/menu-item-layout.element.ts index e9d7291e34..af64f06949 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item-layout/menu-item-layout.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item-layout/menu-item-layout.element.ts @@ -47,6 +47,14 @@ export class UmbMenuItemLayoutElement extends UmbLitElement { #debouncedCheckIsActive = debounce(() => this.#checkIsActive(), 100); + #getTarget() { + if (this.href && this.href.startsWith('http')) { + return '_blank'; + } + + return '_self'; + } + #checkIsActive() { if (!this.href) { this._isActive = false; @@ -63,7 +71,8 @@ export class UmbMenuItemLayoutElement extends UmbLitElement { label=${this.label} .caretLabel=${this.localize.term('visuallyHiddenTexts_expandChildItems') + ' ' + this.label} ?active=${this._isActive} - ?has-children=${this.hasChildren}> + ?has-children=${this.hasChildren} + target=${this.#getTarget()}> ${this.entityType ? html` + + `; + } +} + +export { UmbLinkMenuItemElement as element }; + +declare global { + interface HTMLElementTagNameMap { + [elementName]: UmbLinkMenuItemElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item/link/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item/link/manifests.ts new file mode 100644 index 0000000000..1645bd2edc --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item/link/manifests.ts @@ -0,0 +1,14 @@ +import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; + +export const manifests: Array = [ + { + type: 'kind', + alias: 'Umb.Kind.MenuItem.Link', + matchKind: 'link', + matchType: 'menuItem', + manifest: { + type: 'menuItem', + element: () => import('./link-menu-item.element.js'), + }, + }, +]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item/manifests.ts new file mode 100644 index 0000000000..08daa5be16 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item/manifests.ts @@ -0,0 +1,4 @@ +import { manifests as linkManifests } from './link/manifests.js'; +import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; + +export const manifests: Array = [...linkManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/menu/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/core/menu/manifests.ts new file mode 100644 index 0000000000..88cfb7bd3d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/menu/manifests.ts @@ -0,0 +1,4 @@ +import { manifests as menuItemManifests } from './components/menu-item/manifests.js'; +import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; + +export const manifests: Array = [...menuItemManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/help/menu/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/help/menu/manifests.ts index 06cab3d506..4d9985a5b5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/help/menu/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/help/menu/manifests.ts @@ -9,24 +9,28 @@ export const manifests: Array = [ }, { type: 'menuItem', + kind: 'link', alias: 'Umb.MenuItem.Help.LearningBase', name: 'Learning Base Help Menu Item', weight: 200, meta: { + menus: [UMB_HELP_MENU_ALIAS], label: 'Umbraco Learning Base', icon: 'icon-movie-alt', - menus: [UMB_HELP_MENU_ALIAS], + href: 'https://learn.umbraco.com', }, }, { type: 'menuItem', + kind: 'link', alias: 'Umb.MenuItem.Help.CommunityWebsite', name: 'Community Website Help Menu Item', weight: 100, meta: { + menus: [UMB_HELP_MENU_ALIAS], label: 'Community Website', icon: 'icon-hearts', - menus: [UMB_HELP_MENU_ALIAS], + href: 'https://our.umbraco.com', }, }, ]; From 0212eb119498549d27825b1bb6ec241c3b824826 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 10 Sep 2024 12:55:06 +0200 Subject: [PATCH 19/55] update import path --- src/Umbraco.Web.UI.Client/src/packages/user/user-group/paths.ts | 2 +- src/Umbraco.Web.UI.Client/src/packages/user/user/paths.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/paths.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/paths.ts index 6fc1f8cc7e..bcd681d6dc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/paths.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/paths.ts @@ -1,4 +1,4 @@ -import { UMB_USER_SECTION_PATHNAME } from '../user-section/paths.js'; +import { UMB_USER_SECTION_PATHNAME } from '../section/paths.js'; import { UMB_USER_GROUP_ENTITY_TYPE } from './entity.js'; import { UMB_WORKSPACE_PATH_PATTERN } from '@umbraco-cms/backoffice/workspace'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/paths.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/paths.ts index e9040e7270..eb80086f08 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/paths.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/paths.ts @@ -1,4 +1,4 @@ -import { UMB_USER_SECTION_PATHNAME } from '../user-section/paths.js'; +import { UMB_USER_SECTION_PATHNAME } from '../section/paths.js'; import { UMB_USER_ENTITY_TYPE } from './entity.js'; import { UMB_WORKSPACE_PATH_PATTERN } from '@umbraco-cms/backoffice/workspace'; From 15fcf11d9bdb4acad25d88f3e7d1fddbb1fdd081 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 10 Sep 2024 14:36:00 +0200 Subject: [PATCH 20/55] move target logic to link element --- .../menu-item-layout.element.ts | 19 ++++++++++--------- .../menu-item/link/link-menu-item.element.ts | 11 +++++++++++ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item-layout/menu-item-layout.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item-layout/menu-item-layout.element.ts index af64f06949..b6471e064d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item-layout/menu-item-layout.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item-layout/menu-item-layout.element.ts @@ -37,6 +37,15 @@ export class UmbMenuItemLayoutElement extends UmbLitElement { @property({ type: String }) public href?: string; + /** + * Set an anchor tag target, only used when using href. + * @type {string} + * @attr + * @default undefined + */ + @property({ type: String }) + public target?: '_blank' | '_parent' | '_self' | '_top'; + @state() private _isActive = false; @@ -47,14 +56,6 @@ export class UmbMenuItemLayoutElement extends UmbLitElement { #debouncedCheckIsActive = debounce(() => this.#checkIsActive(), 100); - #getTarget() { - if (this.href && this.href.startsWith('http')) { - return '_blank'; - } - - return '_self'; - } - #checkIsActive() { if (!this.href) { this._isActive = false; @@ -72,7 +73,7 @@ export class UmbMenuItemLayoutElement extends UmbLitElement { .caretLabel=${this.localize.term('visuallyHiddenTexts_expandChildItems') + ' ' + this.label} ?active=${this._isActive} ?has-children=${this.hasChildren} - target=${this.#getTarget()}> + target=${ifDefined(this.href && this.target ? this.target : undefined)}> ${this.entityType ? html` From a3acc6add8bc5b176715403b266e58b02b72e16c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 10 Sep 2024 14:59:31 +0200 Subject: [PATCH 21/55] add condition to check if the current user is admin --- .../conditions/is-admin/constants.ts | 1 + .../current-user/conditions/is-admin/index.ts | 1 + .../is-admin/is-admin.condition.manifest.ts | 9 +++++++++ .../conditions/is-admin/is-admin.condition.ts | 20 +++++++++++++++++++ .../user/current-user/conditions/manifests.ts | 3 +++ .../packages/user/current-user/manifests.ts | 16 +++++++-------- 6 files changed, 41 insertions(+), 9 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/is-admin/constants.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/is-admin/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/is-admin/is-admin.condition.manifest.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/is-admin/is-admin.condition.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/manifests.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/is-admin/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/is-admin/constants.ts new file mode 100644 index 0000000000..2d3a8d78da --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/is-admin/constants.ts @@ -0,0 +1 @@ +export const UMB_CURRENT_USER_IS_ADMIN_CONDITION_ALIAS = 'Umb.Condition.CurrentUser.IsAdmin'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/is-admin/index.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/is-admin/index.ts new file mode 100644 index 0000000000..4f07201dcf --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/is-admin/index.ts @@ -0,0 +1 @@ +export * from './constants.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/is-admin/is-admin.condition.manifest.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/is-admin/is-admin.condition.manifest.ts new file mode 100644 index 0000000000..b9c81293e0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/is-admin/is-admin.condition.manifest.ts @@ -0,0 +1,9 @@ +import { UMB_CURRENT_USER_IS_ADMIN_CONDITION_ALIAS } from './constants.js'; +import type { ManifestCondition } from '@umbraco-cms/backoffice/extension-api'; + +export const manifest: ManifestCondition = { + type: 'condition', + name: 'Current user is admin Condition', + alias: UMB_CURRENT_USER_IS_ADMIN_CONDITION_ALIAS, + api: () => import('./is-admin.condition.js'), +}; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/is-admin/is-admin.condition.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/is-admin/is-admin.condition.ts new file mode 100644 index 0000000000..438258d6f4 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/is-admin/is-admin.condition.ts @@ -0,0 +1,20 @@ +import { isCurrentUserAnAdmin } from '../../utils/is-current-user.function.js'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import type { + UmbConditionConfigBase, + UmbConditionControllerArguments, + UmbExtensionCondition, +} from '@umbraco-cms/backoffice/extension-api'; +import { UmbConditionBase } from '@umbraco-cms/backoffice/extension-registry'; + +export class UmbContentHasPropertiesWorkspaceCondition + extends UmbConditionBase + implements UmbExtensionCondition +{ + constructor(host: UmbControllerHost, args: UmbConditionControllerArguments) { + super(host, args); + isCurrentUserAnAdmin(host).then((isAdmin) => (this.permitted = isAdmin)); + } +} + +export { UmbContentHasPropertiesWorkspaceCondition as api }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/manifests.ts new file mode 100644 index 0000000000..63918c839e --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/manifests.ts @@ -0,0 +1,3 @@ +import { manifest as isAdminManifests } from './is-admin/is-admin.condition.manifest.js'; + +export const manifests = [isAdminManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/manifests.ts index dce911901e..32ebb91d36 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/manifests.ts @@ -1,11 +1,13 @@ import { manifest as actionDefaultKindManifest } from './action/default.kind.js'; -import { manifests as modalManifests } from './modals/manifests.js'; -import { manifests as historyManifests } from './history/manifests.js'; +import { manifests as conditionManifests } from './conditions/manifests.js'; import { manifests as externalLoginProviderManifests } from './external-login/manifests.js'; +import { manifests as historyManifests } from './history/manifests.js'; import { manifests as mfaLoginProviderManifests } from './mfa-login/manifests.js'; +import { manifests as modalManifests } from './modals/manifests.js'; import { manifests as profileManifests } from './profile/manifests.js'; -import { manifests as themeManifests } from './theme/manifests.js'; import { manifests as repositoryManifests } from './repository/manifests.js'; +import { manifests as themeManifests } from './theme/manifests.js'; + import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; export const headerApps: Array = [ @@ -21,19 +23,15 @@ export const headerApps: Array = [ name: 'Current User', element: () => import('./current-user-header-app.element.js'), weight: 0, - meta: { - label: 'TODO: how should we enable this to not be set.', - icon: 'TODO: how should we enable this to not be set.', - pathname: 'user', - }, }, ]; export const manifests = [ actionDefaultKindManifest, + ...conditionManifests, + ...externalLoginProviderManifests, ...headerApps, ...historyManifests, - ...externalLoginProviderManifests, ...mfaLoginProviderManifests, ...modalManifests, ...profileManifests, From 2327a537e5b1a55d80c3f634314a8ade29bac8bb Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 10 Sep 2024 15:01:55 +0200 Subject: [PATCH 22/55] export condition alias --- .../src/packages/user/current-user/conditions/index.ts | 1 + .../src/packages/user/current-user/index.ts | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/index.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/index.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/index.ts new file mode 100644 index 0000000000..8e80a3f329 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/conditions/index.ts @@ -0,0 +1 @@ +export * from './is-admin/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/index.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/index.ts index 343c0ed765..606a128e69 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/index.ts @@ -1,9 +1,10 @@ export * from './action/index.js'; export * from './components/index.js'; -export * from './history/current-user-history.store.js'; -export * from './utils/index.js'; -export * from './repository/index.js'; +export * from './conditions/index.js'; export * from './current-user.context.js'; export * from './current-user.context.token.js'; +export * from './history/current-user-history.store.js'; +export * from './repository/index.js'; +export * from './utils/index.js'; export type * from './types.js'; From 60b4b8875e78d4b09b6d8cdd97c3746654faf167 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 10 Sep 2024 15:02:09 +0200 Subject: [PATCH 23/55] add conditions to links --- .../src/packages/help/menu/manifests.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/help/menu/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/help/menu/manifests.ts index 4d9985a5b5..aa4b9d68c9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/help/menu/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/help/menu/manifests.ts @@ -1,4 +1,5 @@ import { UMB_HELP_MENU_ALIAS } from './constants.js'; +import { UMB_CURRENT_USER_IS_ADMIN_CONDITION_ALIAS } from '@umbraco-cms/backoffice/current-user'; import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; export const manifests: Array = [ @@ -19,6 +20,11 @@ export const manifests: Array = [ icon: 'icon-movie-alt', href: 'https://learn.umbraco.com', }, + conditions: [ + { + alias: UMB_CURRENT_USER_IS_ADMIN_CONDITION_ALIAS, + }, + ], }, { type: 'menuItem', @@ -32,5 +38,10 @@ export const manifests: Array = [ icon: 'icon-hearts', href: 'https://our.umbraco.com', }, + conditions: [ + { + alias: UMB_CURRENT_USER_IS_ADMIN_CONDITION_ALIAS, + }, + ], }, ]; From b66f14e26f850dd2afc9052bb5eb368afd93947d Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 10 Sep 2024 15:54:25 +0200 Subject: [PATCH 24/55] update links --- src/Umbraco.Web.UI.Client/src/packages/help/menu/manifests.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/help/menu/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/help/menu/manifests.ts index aa4b9d68c9..ee466c9a80 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/help/menu/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/help/menu/manifests.ts @@ -18,7 +18,7 @@ export const manifests: Array = [ menus: [UMB_HELP_MENU_ALIAS], label: 'Umbraco Learning Base', icon: 'icon-movie-alt', - href: 'https://learn.umbraco.com', + href: 'https://umbra.co/ulb', }, conditions: [ { @@ -36,7 +36,7 @@ export const manifests: Array = [ menus: [UMB_HELP_MENU_ALIAS], label: 'Community Website', icon: 'icon-hearts', - href: 'https://our.umbraco.com', + href: 'https://our.umbraco.com?utm_source=core&utm_medium=help&utm_content=link&utm_campaign=our', }, conditions: [ { From 4cee6bf1a175a4d0de775da90dac7a9b80063678 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 10 Sep 2024 18:53:49 +0200 Subject: [PATCH 25/55] pass entity type from manifest --- .../menu/components/menu-item/menu-item-default.element.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item/menu-item-default.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item/menu-item-default.element.ts index 75fbc48075..916598bc99 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item/menu-item-default.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/menu/components/menu-item/menu-item-default.element.ts @@ -45,7 +45,8 @@ export class UmbMenuItemDefaultElement extends UmbLitElement implements UmbMenuI + .label=${this.localize.string(this.manifest.meta.label ?? this.manifest.name)} + .entityType=${this.manifest.meta.entityType}> `; } From 242937103b6d66ccc30e2577ba78c47591b17219 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 10 Sep 2024 21:13:01 +0200 Subject: [PATCH 26/55] add path helper to root --- src/Umbraco.Web.UI.Client/src/packages/user/user/paths.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/paths.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/paths.ts index eb80086f08..210af851fd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/paths.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/paths.ts @@ -1,8 +1,13 @@ import { UMB_USER_SECTION_PATHNAME } from '../section/paths.js'; -import { UMB_USER_ENTITY_TYPE } from './entity.js'; +import { UMB_USER_ENTITY_TYPE, UMB_USER_ROOT_ENTITY_TYPE } from './entity.js'; import { UMB_WORKSPACE_PATH_PATTERN } from '@umbraco-cms/backoffice/workspace'; export const UMB_USER_WORKSPACE_PATH = UMB_WORKSPACE_PATH_PATTERN.generateAbsolute({ sectionName: UMB_USER_SECTION_PATHNAME, entityType: UMB_USER_ENTITY_TYPE, }); + +export const UMB_USER_ROOT_WORKSPACE_PATH = UMB_WORKSPACE_PATH_PATTERN.generateAbsolute({ + sectionName: UMB_USER_SECTION_PATHNAME, + entityType: UMB_USER_ROOT_ENTITY_TYPE, +}); From ad4118b9ac10ed4c0e9552c5a21a41a395821851 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 10 Sep 2024 21:13:12 +0200 Subject: [PATCH 27/55] back button to root --- .../user/user/workspace/user-workspace-editor.element.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace-editor.element.ts index c4e11d2175..3a1d79c7ef 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace-editor.element.ts @@ -13,6 +13,8 @@ import './components/user-workspace-access/user-workspace-access.element.js'; import './components/user-workspace-info/user-workspace-info.element.js'; import './components/user-workspace-avatar/user-workspace-avatar.element.js'; import './components/user-workspace-client-credentials/user-workspace-client-credentials.element.js'; +import { UMB_USER_WORKSPACE_ALIAS } from './constants.js'; +import { UMB_USER_ROOT_WORKSPACE_PATH } from '../paths.js'; @customElement('umb-user-workspace-editor') export class UmbUserWorkspaceEditorElement extends UmbLitElement { @@ -50,7 +52,10 @@ export class UmbUserWorkspaceEditorElement extends UmbLitElement { if (!this._user) return html`User not found`; return html` - + ${this.#renderHeader()}
${this.#renderLeftColumn()}
From 533d37f4a07d415794a3efed7697fed366ceb56f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 10 Sep 2024 21:39:06 +0200 Subject: [PATCH 28/55] wip create + invite entity actions --- .../create/create-user-entity-action.ts | 21 ++++ .../user/entity-actions/create/manifests.ts | 22 ++++ .../user/entity-actions/create/modal/index.ts | 8 ++ .../entity-actions/create/modal/manifests.ts | 10 ++ .../user-create-options-modal.element.ts | 108 ++++++++++++++++++ .../invite/invite-user-entity-action.ts | 11 ++ .../user/entity-actions/invite/manifests.ts | 19 +++ .../user/user/entity-actions/manifests.ts | 12 +- 8 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/create-user-entity-action.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/user-create-options-modal.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/invite/invite-user-entity-action.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/invite/manifests.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/create-user-entity-action.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/create-user-entity-action.ts new file mode 100644 index 0000000000..a6da26da4f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/create-user-entity-action.ts @@ -0,0 +1,21 @@ +import { UMB_USER_CREATE_OPTIONS_MODAL } from './modal/index.js'; +import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; +import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; + +export class UmbCreateUserEntityAction extends UmbEntityActionBase { + override async execute() { + const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); + const modalContext = modalManager.open(this, UMB_USER_CREATE_OPTIONS_MODAL, { + data: { + parent: { + unique: this.args.unique, + entityType: this.args.entityType, + }, + }, + }); + + await modalContext.onSubmit(); + } +} + +export { UmbCreateUserEntityAction as api }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/manifests.ts new file mode 100644 index 0000000000..7915152337 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/manifests.ts @@ -0,0 +1,22 @@ +import { UMB_USER_ROOT_ENTITY_TYPE } from '../../entity.js'; + +import { manifests as modalManifests } from './modal/manifests.js'; + +import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; + +export const manifests: Array = [ + { + type: 'entityAction', + kind: 'default', + alias: 'Umb.EntityAction.User.Create', + name: 'Create User Entity Action', + weight: 1200, + api: () => import('./create-user-entity-action.js'), + forEntityTypes: [UMB_USER_ROOT_ENTITY_TYPE], + meta: { + icon: 'icon-add', + label: '#actions_create', + }, + }, + ...modalManifests, +]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/index.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/index.ts new file mode 100644 index 0000000000..778a1fe38d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/index.ts @@ -0,0 +1,8 @@ +import { UmbModalToken } from '@umbraco-cms/backoffice/modal'; + +export const UMB_USER_CREATE_OPTIONS_MODAL = new UmbModalToken('Umb.Modal.User.CreateOptions', { + modal: { + type: 'sidebar', + size: 'small', + }, +}); diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/manifests.ts new file mode 100644 index 0000000000..2c736c75fd --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/manifests.ts @@ -0,0 +1,10 @@ +import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; + +export const manifests: Array = [ + { + type: 'modal', + alias: 'Umb.Modal.User.CreateOptions', + name: 'User Create Options Modal', + element: () => import('./user-create-options-modal.element.js'), + }, +]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/user-create-options-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/user-create-options-modal.element.ts new file mode 100644 index 0000000000..29932ea273 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/user-create-options-modal.element.ts @@ -0,0 +1,108 @@ +import { UMB_CREATE_USER_MODAL } from '../../../modals/create/create-user-modal.token.js'; +import { UmbUserKind, type UmbUserKindType } from '../../../utils/index.js'; +import { html, customElement, map } from '@umbraco-cms/backoffice/external/lit'; +import { UMB_MODAL_MANAGER_CONTEXT, UmbModalBaseElement } from '@umbraco-cms/backoffice/modal'; +import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; +import { UMB_ENTITY_CONTEXT } from '@umbraco-cms/backoffice/entity'; +import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; +import { UmbRequestReloadChildrenOfEntityEvent } from '@umbraco-cms/backoffice/entity-action'; + +interface UmbUserCreateOptionModel { + label: string; + description: string; + icon: string; + kind: UmbUserKindType; +} + +const elementName = 'umb-user-create-options-modal'; +@customElement(elementName) +export class UmbUserCreateOptionsModalElement extends UmbModalBaseElement { + #options: Array = [ + { + label: this.localize.term('user_userKindDefault'), + description: 'Donec augue nunc, ullamcorper non turpis ut, maximus facilisis lorem. Nunc id sagittis magna.', + icon: 'icon-user', + kind: UmbUserKind.DEFAULT, + }, + { + label: this.localize.term('user_userKindApi'), + description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + icon: 'icon-unplug', + kind: UmbUserKind.API, + }, + ]; + + async #onClick(event: Event, kind: UmbUserKindType) { + event.stopPropagation(); + const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); + const entityContext = await this.getContext(UMB_ENTITY_CONTEXT); + + const unique = entityContext.getUnique(); + const entityType = entityContext.getEntityType(); + + if (unique === undefined) throw new Error('Missing unique'); + if (!entityType) throw new Error('Missing entityType'); + + const modalContext = modalManager.open(this, UMB_CREATE_USER_MODAL, { + data: { + user: { + kind, + }, + }, + }); + + modalContext + ?.onSubmit() + .then(() => { + this.#requestReloadChildrenOfEntity({ entityType, unique }); + }) + .catch(async () => { + // modal is closed after creation instead of navigating to the new user. + // We therefore need to reload the children of the entity + this.#requestReloadChildrenOfEntity({ entityType, unique }); + }); + } + + async #requestReloadChildrenOfEntity({ entityType, unique }: UmbEntityModel) { + const eventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + const event = new UmbRequestReloadChildrenOfEntityEvent({ + entityType, + unique, + }); + + eventContext.dispatchEvent(event); + } + + override render() { + return html` + + + + ${map( + this.#options, + (item) => html` + this.#onClick(event, item.kind)}> + `, + )} + + + + + `; + } +} + +export { UmbUserCreateOptionsModalElement as element }; + +declare global { + interface HTMLElementTagNameMap { + [elementName]: UmbUserCreateOptionsModalElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/invite/invite-user-entity-action.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/invite/invite-user-entity-action.ts new file mode 100644 index 0000000000..4ac61a28d5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/invite/invite-user-entity-action.ts @@ -0,0 +1,11 @@ +import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; +import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; + +export class UmbCreateUserEntityAction extends UmbEntityActionBase { + override async execute() { + const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); + debugger; + } +} + +export { UmbCreateUserEntityAction as api }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/invite/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/invite/manifests.ts new file mode 100644 index 0000000000..0fc1e67e74 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/invite/manifests.ts @@ -0,0 +1,19 @@ +import { UMB_USER_ROOT_ENTITY_TYPE } from '../../entity.js'; + +import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; + +export const manifests: Array = [ + { + type: 'entityAction', + kind: 'default', + alias: 'Umb.EntityAction.User.Invite', + name: 'Invite User Entity Action', + weight: 1000, + api: () => import('./invite-user-entity-action.js'), + forEntityTypes: [UMB_USER_ROOT_ENTITY_TYPE], + meta: { + icon: 'icon-paper-plane', + label: '#user_invite', + }, + }, +]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/manifests.ts index b67955449e..493f108ff1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/manifests.ts @@ -1,6 +1,10 @@ import { UMB_USER_DETAIL_REPOSITORY_ALIAS, UMB_USER_ITEM_REPOSITORY_ALIAS } from '../repository/index.js'; import { UMB_USER_ENTITY_TYPE } from '../entity.js'; -import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; + +import { manifests as createManifests } from './create/manifests.js'; +import { manifests as inviteManifests } from './invite/manifests.js'; + +import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; const entityActions: Array = [ { @@ -93,4 +97,8 @@ const entityActions: Array = [ }, ]; -export const manifests: Array = [...entityActions]; +export const manifests: Array = [ + ...entityActions, + ...createManifests, + ...inviteManifests, +]; From 8e1f15cbad7049d2fa661b7d467b1b88c4e9eec7 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 10 Sep 2024 22:01:12 +0200 Subject: [PATCH 29/55] update back path --- .../src/packages/user/user-group/paths.ts | 7 ++++++- .../src/packages/user/user-group/workspace/constants.ts | 1 + .../workspace/user-group-workspace-editor.element.ts | 6 ++++-- 3 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/constants.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/paths.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/paths.ts index bcd681d6dc..51aa649211 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/paths.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/paths.ts @@ -1,8 +1,13 @@ import { UMB_USER_SECTION_PATHNAME } from '../section/paths.js'; -import { UMB_USER_GROUP_ENTITY_TYPE } from './entity.js'; +import { UMB_USER_GROUP_ENTITY_TYPE, UMB_USER_GROUP_ROOT_ENTITY_TYPE } from './entity.js'; import { UMB_WORKSPACE_PATH_PATTERN } from '@umbraco-cms/backoffice/workspace'; export const UMB_USER_GROUP_WORKSPACE_PATH = UMB_WORKSPACE_PATH_PATTERN.generateAbsolute({ sectionName: UMB_USER_SECTION_PATHNAME, entityType: UMB_USER_GROUP_ENTITY_TYPE, }); + +export const UMB_USER_GROUP_ROOT_WORKSPACE_PATH = UMB_WORKSPACE_PATH_PATTERN.generateAbsolute({ + sectionName: UMB_USER_SECTION_PATHNAME, + entityType: UMB_USER_GROUP_ROOT_ENTITY_TYPE, +}); diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/constants.ts new file mode 100644 index 0000000000..6972100cb8 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/constants.ts @@ -0,0 +1 @@ +export const UMB_USER_GROUP_WORKSPACE_ALIAS = 'Umb.Workspace.UserGroup'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-workspace-editor.element.ts index 9374872d2a..a4d129dd04 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-workspace-editor.element.ts @@ -1,5 +1,7 @@ import type { UmbUserGroupDetailModel } from '../index.js'; +import { UMB_USER_GROUP_ROOT_WORKSPACE_PATH } from '../paths.js'; import { UMB_USER_GROUP_WORKSPACE_CONTEXT } from './user-group-workspace.context-token.js'; +import { UMB_USER_GROUP_WORKSPACE_ALIAS } from './constants.js'; import type { UUIBooleanInputEvent } from '@umbraco-cms/backoffice/external/uui'; import { css, html, nothing, customElement, state, ifDefined } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement, umbFocus } from '@umbraco-cms/backoffice/lit-element'; @@ -170,9 +172,9 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { return html` + back-path=${UMB_USER_GROUP_ROOT_WORKSPACE_PATH}> ${this.#renderHeader()} ${this.#renderMain()} `; From 888a3653939d0b5b85a1677d0405a3b9f4682bf4 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 11 Sep 2024 10:34:20 +0200 Subject: [PATCH 30/55] add help module --- src/Umbraco.Web.UI.Client/package-lock.json | 4 ++-- src/Umbraco.Web.UI.Client/package.json | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index 826baef473..434bbdb8ca 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -1,12 +1,12 @@ { "name": "@umbraco-cms/backoffice", - "version": "14.3.0", + "version": "15.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@umbraco-cms/backoffice", - "version": "14.3.0", + "version": "15.0.0", "license": "MIT", "workspaces": [ "./src/packages/block", diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 075d0e1d0a..9e7ba1eee0 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -41,6 +41,7 @@ "./entity": "./dist-cms/packages/core/entity/index.js", "./event": "./dist-cms/packages/core/event/index.js", "./extension-registry": "./dist-cms/packages/core/extension-registry/index.js", + "./help": "./dist-cms/packages/core/help/index.js", "./icon": "./dist-cms/packages/core/icon-registry/index.js", "./id": "./dist-cms/packages/core/id/index.js", "./imaging": "./dist-cms/packages/media/imaging/index.js", From d3e030423deaa66cc28a454f5938b76581438dd3 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 11 Sep 2024 10:34:29 +0200 Subject: [PATCH 31/55] export alias --- src/Umbraco.Web.UI.Client/src/packages/help/index.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/help/index.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/help/index.ts b/src/Umbraco.Web.UI.Client/src/packages/help/index.ts new file mode 100644 index 0000000000..f15384a062 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/help/index.ts @@ -0,0 +1 @@ +export * from './menu/index.js'; From c74a90c5c06c41584d2f1e2b25787f928921a323 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 11 Sep 2024 10:34:45 +0200 Subject: [PATCH 32/55] Update tsconfig.json --- src/Umbraco.Web.UI.Client/tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/tsconfig.json b/src/Umbraco.Web.UI.Client/tsconfig.json index 1d69cbe783..89fcb27d48 100644 --- a/src/Umbraco.Web.UI.Client/tsconfig.json +++ b/src/Umbraco.Web.UI.Client/tsconfig.json @@ -67,6 +67,7 @@ DON'T EDIT THIS FILE DIRECTLY. It is generated by /devops/tsconfig/index.js "@umbraco-cms/backoffice/entity": ["./src/packages/core/entity/index.ts"], "@umbraco-cms/backoffice/event": ["./src/packages/core/event/index.ts"], "@umbraco-cms/backoffice/extension-registry": ["./src/packages/core/extension-registry/index.ts"], + "@umbraco-cms/backoffice/help": ["./src/packages/core/help/index.ts"], "@umbraco-cms/backoffice/icon": ["./src/packages/core/icon-registry/index.ts"], "@umbraco-cms/backoffice/id": ["./src/packages/core/id/index.ts"], "@umbraco-cms/backoffice/imaging": ["./src/packages/media/imaging/index.ts"], From 9e01730ffb1e2a30b4bbe05beb7f06a9121dd738 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 11 Sep 2024 12:11:12 +0200 Subject: [PATCH 33/55] only render header app if menu has items --- .../header-app/help-header-app.element.ts | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/help/header-app/help-header-app.element.ts b/src/Umbraco.Web.UI.Client/src/packages/help/header-app/help-header-app.element.ts index 7b0b767d13..0c8ff69b84 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/help/header-app/help-header-app.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/help/header-app/help-header-app.element.ts @@ -1,8 +1,9 @@ import { UMB_HELP_MENU_ALIAS } from '../menu/index.js'; import type { CSSResultGroup } from '@umbraco-cms/backoffice/external/lit'; -import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; +import { css, html, customElement, state, nothing } from '@umbraco-cms/backoffice/external/lit'; import { UmbHeaderAppButtonElement } from '@umbraco-cms/backoffice/components'; -import type { ManifestMenu } from '@umbraco-cms/backoffice/extension-registry'; +import { umbExtensionsRegistry, type ManifestMenu } from '@umbraco-cms/backoffice/extension-registry'; +import { UmbExtensionsManifestInitializer } from '@umbraco-cms/backoffice/extension-api'; const elementName = 'umb-help-header-app'; @customElement(elementName) @@ -10,6 +11,24 @@ export class UmbHelpHeaderAppElement extends UmbHeaderAppButtonElement { @state() private _popoverOpen = false; + @state() + private _helpMenuHasMenuItems = false; + + constructor() { + super(); + + new UmbExtensionsManifestInitializer( + this, + umbExtensionsRegistry, + 'menuItem', + (manifest) => manifest.meta.menus.includes(UMB_HELP_MENU_ALIAS), + (menuItems) => { + const manifests = menuItems.map((menuItem) => menuItem.manifest); + this._helpMenuHasMenuItems = manifests.length > 0; + }, + ); + } + #onPopoverToggle(event: ToggleEvent) { // TODO: This ignorer is just neede for JSON SCHEMA TO WORK, As its not updated with latest TS jet. // eslint-disable-next-line @typescript-eslint/ban-ts-comment @@ -18,11 +37,21 @@ export class UmbHelpHeaderAppElement extends UmbHeaderAppButtonElement { } override render() { + return html` ${this.#renderButton()} ${this.#renderPopover()} `; + } + + #renderButton() { + if (!this._helpMenuHasMenuItems) return nothing; + return html` + `; + } + #renderPopover() { + return html` From 1ba46b496bb7b339ef526a784887f9ddce444b74 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 11 Sep 2024 12:19:56 +0200 Subject: [PATCH 34/55] update package build --- src/Umbraco.Web.UI.Client/package.json | 2 +- src/Umbraco.Web.UI.Client/src/packages/help/package.json | 8 ++++++++ .../src/packages/help/vite.config.ts | 2 +- src/Umbraco.Web.UI.Client/tsconfig.json | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/help/package.json diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index cefbbb4419..a522d9d100 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -41,7 +41,7 @@ "./entity": "./dist-cms/packages/core/entity/index.js", "./event": "./dist-cms/packages/core/event/index.js", "./extension-registry": "./dist-cms/packages/core/extension-registry/index.js", - "./help": "./dist-cms/packages/core/help/index.js", + "./help": "./dist-cms/packages/help/index.js", "./icon": "./dist-cms/packages/core/icon-registry/index.js", "./id": "./dist-cms/packages/core/id/index.js", "./imaging": "./dist-cms/packages/media/imaging/index.js", diff --git a/src/Umbraco.Web.UI.Client/src/packages/help/package.json b/src/Umbraco.Web.UI.Client/src/packages/help/package.json new file mode 100644 index 0000000000..3cae8e94ec --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/help/package.json @@ -0,0 +1,8 @@ +{ + "name": "@umbraco-backoffice/help", + "private": true, + "type": "module", + "scripts": { + "build": "vite build" + } +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/packages/help/vite.config.ts b/src/Umbraco.Web.UI.Client/src/packages/help/vite.config.ts index a320e9a053..965d250b98 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/help/vite.config.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/help/vite.config.ts @@ -8,5 +8,5 @@ const dist = '../../../dist-cms/packages/help'; rmSync(dist, { recursive: true, force: true }); export default defineConfig({ - ...getDefaultConfig({ dist, entry: ['manifests.ts', 'umbraco-package.ts'] }), + ...getDefaultConfig({ dist }), }); diff --git a/src/Umbraco.Web.UI.Client/tsconfig.json b/src/Umbraco.Web.UI.Client/tsconfig.json index 89fcb27d48..7807084b15 100644 --- a/src/Umbraco.Web.UI.Client/tsconfig.json +++ b/src/Umbraco.Web.UI.Client/tsconfig.json @@ -67,7 +67,7 @@ DON'T EDIT THIS FILE DIRECTLY. It is generated by /devops/tsconfig/index.js "@umbraco-cms/backoffice/entity": ["./src/packages/core/entity/index.ts"], "@umbraco-cms/backoffice/event": ["./src/packages/core/event/index.ts"], "@umbraco-cms/backoffice/extension-registry": ["./src/packages/core/extension-registry/index.ts"], - "@umbraco-cms/backoffice/help": ["./src/packages/core/help/index.ts"], + "@umbraco-cms/backoffice/help": ["./src/packages/help/index.ts"], "@umbraco-cms/backoffice/icon": ["./src/packages/core/icon-registry/index.ts"], "@umbraco-cms/backoffice/id": ["./src/packages/core/id/index.ts"], "@umbraco-cms/backoffice/imaging": ["./src/packages/media/imaging/index.ts"], From 4f2990adc921db866d0b64b9a52552cae03ace11 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 11 Sep 2024 12:38:12 +0200 Subject: [PATCH 35/55] Update package-lock.json --- src/Umbraco.Web.UI.Client/package-lock.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index 5005f8e5d4..14b88b3569 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -7811,6 +7811,10 @@ "resolved": "src/packages/health-check", "link": true }, + "node_modules/@umbraco-backoffice/help": { + "resolved": "src/packages/help", + "link": true + }, "node_modules/@umbraco-backoffice/language": { "resolved": "src/packages/language", "link": true @@ -23078,6 +23082,7 @@ "src/packages/health-check": { "name": "@umbraco-backoffice/health-check" }, + "src/packages/help": {}, "src/packages/language": { "name": "@umbraco-backoffice/language" }, @@ -23120,7 +23125,9 @@ "src/packages/static-file": { "name": "@umbraco-backoffice/static-file" }, - "src/packages/sysinfo": {}, + "src/packages/sysinfo": { + "name": "@umbraco-backoffice/sysinfo" + }, "src/packages/tags": { "name": "@umbraco-backoffice/tag" }, From 646106482788089f7b33fdf835d53d285be88f30 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 11 Sep 2024 14:57:08 +0200 Subject: [PATCH 36/55] add pattern validation --- ...ate-user-client-credential-modal.element.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/client-credential/create/modal/create-user-client-credential-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/client-credential/create/modal/create-user-client-credential-modal.element.ts index dc48873e55..c18ac77d4b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/client-credential/create/modal/create-user-client-credential-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/client-credential/create/modal/create-user-client-credential-modal.element.ts @@ -7,6 +7,7 @@ import type { import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { css, html, customElement, query } from '@umbraco-cms/backoffice/external/lit'; import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal'; +import type { UUIInputElement } from '@umbraco-cms/backoffice/external/uui'; const elementName = 'umb-create-user-client-credential-modal'; @customElement(elementName) @@ -17,10 +18,27 @@ export class UmbCreateUserModalElement extends UmbModalBaseElement< @query('#CreateUserClientCredentialForm') _form?: HTMLFormElement; + @query('#unique') + _inputUniqueElement?: UUIInputElement; + #userClientCredentialRepository = new UmbUserClientCredentialRepository(this); #uniquePrefix = 'umbraco-back-office-'; + protected override firstUpdated(): void { + // For some reason the pattern attribute is not working with this specific regex. It complains about the regex is invalid. + // TODO: investigate why this is happening. + this._inputUniqueElement?.addValidator( + 'patternMismatch', + () => 'Only alphanumeric characters and hyphens are allowed', + () => { + const value = (this._inputUniqueElement?.value as string) || ''; + // eslint-disable-next-line no-useless-escape + return !new RegExp(/^[a-zA-Z0-9\-]+$/).test(value); + }, + ); + } + async #onSubmit(e: SubmitEvent) { e.preventDefault(); From 4906e9f626156d1dd2167456bdfb495f41540ebf Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 11 Sep 2024 15:37:27 +0200 Subject: [PATCH 37/55] add to folder --- .../user/section/sidebar-app/index.ts | 2 +- .../src/packages/user/user-group/manifests.ts | 4 +- ...orkspace-action-user-group-save.element.ts | 2 +- .../user-allow-action-base.condition.ts | 2 +- .../packages/user/user/workspace/manifests.ts | 44 ++----------------- .../user-workspace-action-save.element.ts | 0 .../user-workspace-access.element.ts | 2 +- .../user-workspace-assign-access.element.ts | 2 +- .../user-workspace-avatar.element.ts | 2 +- ...er-workspace-client-credentials.element.ts | 8 ++-- .../user-workspace-info.element.ts | 8 ++-- ...user-workspace-profile-settings.element.ts | 4 +- .../user/workspace/{ => user}/constants.ts | 0 .../user/user/workspace/user/manifests.ts | 42 ++++++++++++++++++ .../user-workspace-editor.element.ts | 6 +-- .../user-workspace.context-token.ts | 2 +- .../{ => user}/user-workspace.context.ts | 10 ++--- .../{ => user}/user-workspace.test.ts | 0 18 files changed, 72 insertions(+), 68 deletions(-) rename src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/{ => user}/actions/user-workspace-action-save.element.ts (100%) rename src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/{ => user}/components/user-workspace-access/user-workspace-access.element.ts (97%) rename src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/{ => user}/components/user-workspace-assign-access/user-workspace-assign-access.element.ts (99%) rename src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/{ => user}/components/user-workspace-avatar/user-workspace-avatar.element.ts (97%) rename src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/{ => user}/components/user-workspace-client-credentials/user-workspace-client-credentials.element.ts (93%) rename src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/{ => user}/components/user-workspace-info/user-workspace-info.element.ts (95%) rename src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/{ => user}/components/user-workspace-profile-settings/user-workspace-profile-settings.element.ts (97%) rename src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/{ => user}/constants.ts (100%) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/manifests.ts rename src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/{ => user}/user-workspace-editor.element.ts (97%) rename src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/{ => user}/user-workspace.context-token.ts (89%) rename src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/{ => user}/user-workspace.context.ts (94%) rename src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/{ => user}/user-workspace.test.ts (100%) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/section/sidebar-app/index.ts b/src/Umbraco.Web.UI.Client/src/packages/user/section/sidebar-app/index.ts index 4f07201dcf..42f853e5be 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/section/sidebar-app/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/section/sidebar-app/index.ts @@ -1 +1 @@ -export * from './constants.js'; +export * from '../constants.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/manifests.ts index 1ac88d4e75..a68693f9c3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/manifests.ts @@ -7,9 +7,9 @@ import { manifests as repositoryManifests } from './repository/manifests.js'; import { manifests as sectionViewManifests } from './section-view/manifests.js'; import { manifests as workspaceManifests } from './workspace/manifests.js'; -import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; +import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; -export const manifests: Array = [ +export const manifests: Array = [ ...collectionManifests, ...entityActionManifests, ...entityBulkActionManifests, diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/actions/workspace-action-user-group-save.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/actions/workspace-action-user-group-save.element.ts index 1c86ca5b08..530c72b616 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/actions/workspace-action-user-group-save.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/actions/workspace-action-user-group-save.element.ts @@ -1,4 +1,4 @@ -import { UMB_USER_WORKSPACE_CONTEXT } from '../../../user/workspace/user-workspace.context-token.js'; +import { UMB_USER_WORKSPACE_CONTEXT } from '../../../user/workspace/user/user-workspace.context-token.js'; import { html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; import type { UUIButtonState } from '@umbraco-cms/backoffice/external/uui'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-action-base.condition.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-action-base.condition.ts index bdae21f4af..7dffc20550 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-action-base.condition.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-action-base.condition.ts @@ -1,5 +1,5 @@ import type { UmbUserStateEnum } from '../types.js'; -import { UMB_USER_WORKSPACE_CONTEXT } from '../workspace/user-workspace.context-token.js'; +import { UMB_USER_WORKSPACE_CONTEXT } from '../workspace/user/user-workspace.context-token.js'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { isCurrentUser } from '@umbraco-cms/backoffice/current-user'; import type { diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/manifests.ts index d2c5c90ec4..a8bafd21d8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/manifests.ts @@ -1,42 +1,4 @@ -import { UMB_USER_ENTITY_TYPE } from '../entity.js'; -import { UMB_USER_WORKSPACE_ALIAS } from './constants.js'; -import { UmbSubmitWorkspaceAction } from '@umbraco-cms/backoffice/workspace'; -import type { - ManifestWorkspaces, - ManifestWorkspaceActions, - ManifestTypes, -} from '@umbraco-cms/backoffice/extension-registry'; +import { manifests as userManifests } from './user/manifests.js'; +import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; -const workspace: ManifestWorkspaces = { - type: 'workspace', - kind: 'routable', - alias: UMB_USER_WORKSPACE_ALIAS, - name: 'User Workspace', - api: () => import('./user-workspace.context.js'), - meta: { - entityType: UMB_USER_ENTITY_TYPE, - }, -}; - -const workspaceActions: Array = [ - { - type: 'workspaceAction', - kind: 'default', - alias: 'Umb.WorkspaceAction.User.Save', - name: 'Save User Workspace Action', - api: UmbSubmitWorkspaceAction, - meta: { - label: '#buttons_save', - look: 'primary', - color: 'positive', - }, - conditions: [ - { - alias: 'Umb.Condition.WorkspaceAlias', - match: workspace.alias, - }, - ], - }, -]; - -export const manifests: Array = [workspace, ...workspaceActions]; +export const manifests: Array = [...userManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/actions/user-workspace-action-save.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/actions/user-workspace-action-save.element.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/actions/user-workspace-action-save.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/actions/user-workspace-action-save.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-access/user-workspace-access.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/components/user-workspace-access/user-workspace-access.element.ts similarity index 97% rename from src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-access/user-workspace-access.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/components/user-workspace-access/user-workspace-access.element.ts index 7177e91909..86197319e5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-access/user-workspace-access.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/components/user-workspace-access/user-workspace-access.element.ts @@ -1,5 +1,5 @@ import { UMB_USER_WORKSPACE_CONTEXT } from '../../user-workspace.context-token.js'; -import type { UmbUserStartNodesModel } from '../../../types.js'; +import type { UmbUserStartNodesModel } from '../../../../types.js'; import { html, customElement, state, css } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-assign-access/user-workspace-assign-access.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/components/user-workspace-assign-access/user-workspace-assign-access.element.ts similarity index 99% rename from src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-assign-access/user-workspace-assign-access.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/components/user-workspace-assign-access/user-workspace-assign-access.element.ts index 6a7a881039..d32bb6e0fd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-assign-access/user-workspace-assign-access.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/components/user-workspace-assign-access/user-workspace-assign-access.element.ts @@ -1,5 +1,5 @@ import { UMB_USER_WORKSPACE_CONTEXT } from '../../user-workspace.context-token.js'; -import type { UmbUserDetailModel } from '../../../types.js'; +import type { UmbUserDetailModel } from '../../../../types.js'; import { html, customElement, state, nothing, css } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-avatar/user-workspace-avatar.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/components/user-workspace-avatar/user-workspace-avatar.element.ts similarity index 97% rename from src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-avatar/user-workspace-avatar.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/components/user-workspace-avatar/user-workspace-avatar.element.ts index b3c7317d12..9400230d7a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-avatar/user-workspace-avatar.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/components/user-workspace-avatar/user-workspace-avatar.element.ts @@ -1,4 +1,4 @@ -import type { UmbUserDetailModel } from '../../../types.js'; +import type { UmbUserDetailModel } from '../../../../types.js'; import { UMB_USER_WORKSPACE_CONTEXT } from '../../user-workspace.context-token.js'; import { css, html, customElement, query, nothing, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-client-credentials/user-workspace-client-credentials.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/components/user-workspace-client-credentials/user-workspace-client-credentials.element.ts similarity index 93% rename from src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-client-credentials/user-workspace-client-credentials.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/components/user-workspace-client-credentials/user-workspace-client-credentials.element.ts index 512d97f2d6..7d77417056 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-client-credentials/user-workspace-client-credentials.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/components/user-workspace-client-credentials/user-workspace-client-credentials.element.ts @@ -2,10 +2,10 @@ import { UMB_USER_WORKSPACE_CONTEXT } from '../../user-workspace.context-token.j import type { UmbDeleteUserClientCredentialRequestArgs, UmbUserClientCredentialModel, -} from '../../../client-credential/index.js'; -import { UmbUserClientCredentialRepository } from '../../../client-credential/index.js'; -import { UMB_CREATE_USER_CLIENT_CREDENTIAL_MODAL } from '../../../client-credential/create/modal/create-user-client-credential-modal.token.js'; -import { UmbUserKind } from '../../../utils/index.js'; +} from '../../../../client-credential/index.js'; +import { UmbUserClientCredentialRepository } from '../../../../client-credential/index.js'; +import { UMB_CREATE_USER_CLIENT_CREDENTIAL_MODAL } from '../../../../client-credential/create/modal/create-user-client-credential-modal.token.js'; +import { UmbUserKind } from '../../../../utils/index.js'; import { html, customElement, state, css, nothing } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-info/user-workspace-info.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/components/user-workspace-info/user-workspace-info.element.ts similarity index 95% rename from src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-info/user-workspace-info.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/components/user-workspace-info/user-workspace-info.element.ts index 898bea5823..8f5d2437b0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-info/user-workspace-info.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/components/user-workspace-info/user-workspace-info.element.ts @@ -1,8 +1,8 @@ -import type { UmbUserDisplayStatus } from '../../../utils.js'; -import { TimeFormatOptions, getDisplayStateFromUserStatus } from '../../../utils.js'; +import type { UmbUserDisplayStatus } from '../../../../utils.js'; +import { TimeFormatOptions, getDisplayStateFromUserStatus } from '../../../../utils.js'; import { UMB_USER_WORKSPACE_CONTEXT } from '../../user-workspace.context-token.js'; -import type { UmbUserDetailModel } from '../../../types.js'; -import { UmbUserKind } from '../../../utils/index.js'; +import type { UmbUserDetailModel } from '../../../../types.js'; +import { UmbUserKind } from '../../../../utils/index.js'; import { html, customElement, state, css, repeat, ifDefined, nothing } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-profile-settings/user-workspace-profile-settings.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/components/user-workspace-profile-settings/user-workspace-profile-settings.element.ts similarity index 97% rename from src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-profile-settings/user-workspace-profile-settings.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/components/user-workspace-profile-settings/user-workspace-profile-settings.element.ts index fd4e67c615..0d313eb130 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-profile-settings/user-workspace-profile-settings.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/components/user-workspace-profile-settings/user-workspace-profile-settings.element.ts @@ -1,11 +1,11 @@ import { UMB_USER_WORKSPACE_CONTEXT } from '../../user-workspace.context-token.js'; -import type { UmbUserDetailModel } from '../../../types.js'; +import type { UmbUserDetailModel } from '../../../../types.js'; +import { UmbUserKind } from '../../../../utils/index.js'; import { html, customElement, state, ifDefined, css, nothing } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import type { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import type { UmbUiCultureInputElement } from '@umbraco-cms/backoffice/localization'; -import { UmbUserKind } from '../../../utils/index.js'; @customElement('umb-user-workspace-profile-settings') export class UmbUserWorkspaceProfileSettingsElement extends UmbLitElement { diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/constants.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/constants.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/constants.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/manifests.ts new file mode 100644 index 0000000000..3f4203dd88 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/manifests.ts @@ -0,0 +1,42 @@ +import { UMB_USER_ENTITY_TYPE } from '../../entity.js'; +import { UMB_USER_WORKSPACE_ALIAS } from './constants.js'; +import { UmbSubmitWorkspaceAction } from '@umbraco-cms/backoffice/workspace'; +import type { + ManifestWorkspaces, + ManifestWorkspaceActions, + ManifestTypes, +} from '@umbraco-cms/backoffice/extension-registry'; + +const workspace: ManifestWorkspaces = { + type: 'workspace', + kind: 'routable', + alias: UMB_USER_WORKSPACE_ALIAS, + name: 'User Workspace', + api: () => import('./user-workspace.context.js'), + meta: { + entityType: UMB_USER_ENTITY_TYPE, + }, +}; + +const workspaceActions: Array = [ + { + type: 'workspaceAction', + kind: 'default', + alias: 'Umb.WorkspaceAction.User.Save', + name: 'Save User Workspace Action', + api: UmbSubmitWorkspaceAction, + meta: { + label: '#buttons_save', + look: 'primary', + color: 'positive', + }, + conditions: [ + { + alias: 'Umb.Condition.WorkspaceAlias', + match: workspace.alias, + }, + ], + }, +]; + +export const manifests: Array = [workspace, ...workspaceActions]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/user-workspace-editor.element.ts similarity index 97% rename from src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace-editor.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/user-workspace-editor.element.ts index 3a1d79c7ef..b65ebebf63 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/user-workspace-editor.element.ts @@ -1,6 +1,8 @@ -import type { UmbUserDetailModel } from '../index.js'; +import type { UmbUserDetailModel } from '../../index.js'; +import { UMB_USER_ROOT_WORKSPACE_PATH } from '../../paths.js'; import type { UmbUserWorkspaceContext } from './user-workspace.context.js'; import { UMB_USER_WORKSPACE_CONTEXT } from './user-workspace.context-token.js'; +import { UMB_USER_WORKSPACE_ALIAS } from './constants.js'; import type { UUIInputElement } from '@umbraco-cms/backoffice/external/uui'; import { UUIInputEvent } from '@umbraco-cms/backoffice/external/uui'; import { css, html, nothing, customElement, state } from '@umbraco-cms/backoffice/external/lit'; @@ -13,8 +15,6 @@ import './components/user-workspace-access/user-workspace-access.element.js'; import './components/user-workspace-info/user-workspace-info.element.js'; import './components/user-workspace-avatar/user-workspace-avatar.element.js'; import './components/user-workspace-client-credentials/user-workspace-client-credentials.element.js'; -import { UMB_USER_WORKSPACE_ALIAS } from './constants.js'; -import { UMB_USER_ROOT_WORKSPACE_PATH } from '../paths.js'; @customElement('umb-user-workspace-editor') export class UmbUserWorkspaceEditorElement extends UmbLitElement { diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace.context-token.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/user-workspace.context-token.ts similarity index 89% rename from src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace.context-token.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/user-workspace.context-token.ts index ac99021cc5..bac31a226c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace.context-token.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/user-workspace.context-token.ts @@ -1,4 +1,4 @@ -import { UMB_USER_ENTITY_TYPE } from '../entity.js'; +import { UMB_USER_ENTITY_TYPE } from '../../entity.js'; import type { UmbUserWorkspaceContext } from './user-workspace.context.js'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import type { UmbSubmittableWorkspaceContext } from '@umbraco-cms/backoffice/workspace'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/user-workspace.context.ts similarity index 94% rename from src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace.context.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/user-workspace.context.ts index 69587e191d..18963318ec 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/user-workspace.context.ts @@ -1,8 +1,8 @@ -import type { UmbUserDetailModel, UmbUserStartNodesModel, UmbUserStateEnum } from '../types.js'; -import { UMB_USER_ENTITY_TYPE } from '../entity.js'; -import { UmbUserDetailRepository } from '../repository/index.js'; -import { UmbUserAvatarRepository } from '../repository/avatar/index.js'; -import { UmbUserConfigRepository } from '../repository/config/index.js'; +import type { UmbUserDetailModel, UmbUserStartNodesModel, UmbUserStateEnum } from '../../types.js'; +import { UMB_USER_ENTITY_TYPE } from '../../entity.js'; +import { UmbUserDetailRepository } from '../../repository/index.js'; +import { UmbUserAvatarRepository } from '../../repository/avatar/index.js'; +import { UmbUserConfigRepository } from '../../repository/config/index.js'; import { UMB_USER_WORKSPACE_ALIAS } from './constants.js'; import { UmbUserWorkspaceEditorElement } from './user-workspace-editor.element.js'; import type { UmbSubmittableWorkspaceContext } from '@umbraco-cms/backoffice/workspace'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace.test.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/user-workspace.test.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace.test.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/user-workspace.test.ts From ae5708c32ccfb41b9bfce404c13083e46c9ae87f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 11 Sep 2024 15:38:05 +0200 Subject: [PATCH 38/55] rename folder --- .../packages/user/user/{section-view => user-root}/manifests.ts | 0 .../{section-view => user-root}/user-root-workspace.element.ts | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/Umbraco.Web.UI.Client/src/packages/user/user/{section-view => user-root}/manifests.ts (100%) rename src/Umbraco.Web.UI.Client/src/packages/user/user/{section-view => user-root}/user-root-workspace.element.ts (100%) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/user-root/manifests.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/manifests.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user/user-root/manifests.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/user-root-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/user-root/user-root-workspace.element.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/user-root-workspace.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user/user-root/user-root-workspace.element.ts From 8783b5cf8beca43fc26cf7ac29d6023088dcc1ed Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 11 Sep 2024 15:38:59 +0200 Subject: [PATCH 39/55] move into workspace folder --- src/Umbraco.Web.UI.Client/src/packages/user/user/manifests.ts | 2 -- .../src/packages/user/user/workspace/manifests.ts | 3 ++- .../packages/user/user/{ => workspace}/user-root/manifests.ts | 2 +- .../{ => workspace}/user-root/user-root-workspace.element.ts | 0 4 files changed, 3 insertions(+), 4 deletions(-) rename src/Umbraco.Web.UI.Client/src/packages/user/user/{ => workspace}/user-root/manifests.ts (86%) rename src/Umbraco.Web.UI.Client/src/packages/user/user/{ => workspace}/user-root/user-root-workspace.element.ts (100%) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/manifests.ts index 383ff1ad80..b73a4378c2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/manifests.ts @@ -7,7 +7,6 @@ import { manifests as inviteManifests } from './invite/manifests.js'; import { manifests as modalManifests } from './modals/manifests.js'; import { manifests as propertyEditorManifests } from './property-editor/manifests.js'; import { manifests as repositoryManifests } from './repository/manifests.js'; -import { manifests as sectionViewManifests } from './section-view/manifests.js'; import { manifests as workspaceManifests } from './workspace/manifests.js'; import { manifests as menuItemManifests } from './menu-item/manifests.js'; @@ -23,7 +22,6 @@ export const manifests: Array = [ ...modalManifests, ...propertyEditorManifests, ...repositoryManifests, - ...sectionViewManifests, ...workspaceManifests, ...menuItemManifests, ]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/manifests.ts index a8bafd21d8..09e4d463e9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/manifests.ts @@ -1,4 +1,5 @@ import { manifests as userManifests } from './user/manifests.js'; +import { manifests as userRootManifests } from './user-root/manifests.js'; import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; -export const manifests: Array = [...userManifests]; +export const manifests: Array = [...userManifests, ...userRootManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/user-root/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-root/manifests.ts similarity index 86% rename from src/Umbraco.Web.UI.Client/src/packages/user/user/user-root/manifests.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-root/manifests.ts index 96eea28eda..9cb07892d3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/user-root/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-root/manifests.ts @@ -1,4 +1,4 @@ -import { UMB_USER_ROOT_ENTITY_TYPE } from '../entity.js'; +import { UMB_USER_ROOT_ENTITY_TYPE } from '../../entity.js'; import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; export const manifests: Array = [ diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/user-root/user-root-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-root/user-root-workspace.element.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/user/user/user-root/user-root-workspace.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-root/user-root-workspace.element.ts From 5f7d22778e542e84471e2aa60dcb48de03ff3f85 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 11 Sep 2024 15:40:31 +0200 Subject: [PATCH 40/55] add missing type --- .../src/packages/user/user/workspace/manifests.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/manifests.ts index 09e4d463e9..2208cee94d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/manifests.ts @@ -1,5 +1,5 @@ import { manifests as userManifests } from './user/manifests.js'; import { manifests as userRootManifests } from './user-root/manifests.js'; -import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; +import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; -export const manifests: Array = [...userManifests, ...userRootManifests]; +export const manifests: Array = [...userManifests, ...userRootManifests]; From 7e35937d0d0b41665175f20a28bbae8461c5f936 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 11 Sep 2024 15:40:37 +0200 Subject: [PATCH 41/55] fix path --- .../user/workspace/user-root/user-root-workspace.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-root/user-root-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-root/user-root-workspace.element.ts index 6e286dada3..65ec9cd88c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-root/user-root-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-root/user-root-workspace.element.ts @@ -1,4 +1,4 @@ -import { UMB_USER_COLLECTION_ALIAS } from '../collection/index.js'; +import { UMB_USER_COLLECTION_ALIAS } from '../../collection/index.js'; import { html, customElement } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; From 637b31c406d71b15c3589f9543d3077df50227d8 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 11 Sep 2024 15:43:55 +0200 Subject: [PATCH 42/55] delete unused code --- ...orkspace-action-user-group-save.element.ts | 52 ------------------- 1 file changed, 52 deletions(-) delete mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/actions/workspace-action-user-group-save.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/actions/workspace-action-user-group-save.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/actions/workspace-action-user-group-save.element.ts deleted file mode 100644 index 530c72b616..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/actions/workspace-action-user-group-save.element.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { UMB_USER_WORKSPACE_CONTEXT } from '../../../user/workspace/user/user-workspace.context-token.js'; -import { html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; -import type { UUIButtonState } from '@umbraco-cms/backoffice/external/uui'; -import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; -// TODO: Revisit this component, it can be made via a kind with api instead. [NL] -// TODO: This seems like legacy code [NL] -@customElement('umb-workspace-action-user-group-save') -export class UmbWorkspaceActionUserGroupSaveElement extends UmbLitElement { - @state() - private _saveButtonState?: UUIButtonState; - - private _workspaceContext?: typeof UMB_USER_WORKSPACE_CONTEXT.TYPE; - - constructor() { - super(); - - this.consumeContext(UMB_USER_WORKSPACE_CONTEXT, (instance) => { - this._workspaceContext = instance; - }); - } - - private async _handleSave() { - if (!this._workspaceContext) return; - - this._saveButtonState = 'waiting'; - await this._workspaceContext - .requestSubmit() - .then(() => { - this._saveButtonState = 'success'; - }) - .catch(() => { - this._saveButtonState = 'failed'; - }); - } - - override render() { - return html``; - } -} - -export default UmbWorkspaceActionUserGroupSaveElement; - -declare global { - interface HTMLElementTagNameMap { - 'umb-workspace-action-user-group-save': UmbWorkspaceActionUserGroupSaveElement; - } -} From 6c00bf251ed4e636adc3782feed0bc00bfc226aa Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 11 Sep 2024 16:04:02 +0200 Subject: [PATCH 43/55] set up entity context --- .../workspace/user-root/user-root-workspace.element.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-root/user-root-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-root/user-root-workspace.element.ts index 65ec9cd88c..2411336b55 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-root/user-root-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-root/user-root-workspace.element.ts @@ -1,10 +1,20 @@ import { UMB_USER_COLLECTION_ALIAS } from '../../collection/index.js'; +import { UMB_USER_ROOT_ENTITY_TYPE } from '../../entity.js'; +import { UmbEntityContext } from '@umbraco-cms/backoffice/entity'; import { html, customElement } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; const elementName = 'umb-user-root-workspace'; @customElement(elementName) export class UmbUserRootWorkspaceElement extends UmbLitElement { + constructor() { + super(); + // TODO: this.should happen automatically + const entityContext = new UmbEntityContext(this); + entityContext.setEntityType(UMB_USER_ROOT_ENTITY_TYPE); + entityContext.setUnique(null); + } + override render() { return html` ; From 7ce744f21fbf54818297e147e156c5028cbbb429 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 11 Sep 2024 16:09:03 +0200 Subject: [PATCH 44/55] add invite entity action + clean up --- .../user/user/entity-actions/manifests.ts | 7 +---- .../invite/invite-user-entity-action.ts | 4 ++- .../entity-action}/invite/manifests.ts | 2 +- .../user/invite/entity-action/manifests.ts | 28 ++++--------------- .../entity-action/resend-invite/manifests.ts | 19 +++++++++++++ .../packages/user/user/invite/manifests.ts | 4 +-- 6 files changed, 31 insertions(+), 33 deletions(-) rename src/Umbraco.Web.UI.Client/src/packages/user/user/{entity-actions => invite/entity-action}/invite/invite-user-entity-action.ts (70%) rename src/Umbraco.Web.UI.Client/src/packages/user/user/{entity-actions => invite/entity-action}/invite/manifests.ts (88%) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/manifests.ts index 493f108ff1..f59da30aeb 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/manifests.ts @@ -2,7 +2,6 @@ import { UMB_USER_DETAIL_REPOSITORY_ALIAS, UMB_USER_ITEM_REPOSITORY_ALIAS } from import { UMB_USER_ENTITY_TYPE } from '../entity.js'; import { manifests as createManifests } from './create/manifests.js'; -import { manifests as inviteManifests } from './invite/manifests.js'; import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; @@ -97,8 +96,4 @@ const entityActions: Array = [ }, ]; -export const manifests: Array = [ - ...entityActions, - ...createManifests, - ...inviteManifests, -]; +export const manifests: Array = [...entityActions, ...createManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/invite/invite-user-entity-action.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/invite/invite-user-entity-action.ts similarity index 70% rename from src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/invite/invite-user-entity-action.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/invite/invite-user-entity-action.ts index 4ac61a28d5..7d7f86ec79 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/invite/invite-user-entity-action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/invite/invite-user-entity-action.ts @@ -1,10 +1,12 @@ +import { UMB_INVITE_USER_MODAL } from '../../index.js'; import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; export class UmbCreateUserEntityAction extends UmbEntityActionBase { override async execute() { const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - debugger; + const modalContext = modalManager.open(this, UMB_INVITE_USER_MODAL); + await modalContext?.onSubmit(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/invite/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/invite/manifests.ts similarity index 88% rename from src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/invite/manifests.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/invite/manifests.ts index 0fc1e67e74..64ca8e8772 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/invite/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/invite/manifests.ts @@ -1,4 +1,4 @@ -import { UMB_USER_ROOT_ENTITY_TYPE } from '../../entity.js'; +import { UMB_USER_ROOT_ENTITY_TYPE } from '../../../entity.js'; import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/manifests.ts index af09b5ff79..0958868a9f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/manifests.ts @@ -1,27 +1,9 @@ -import { UMB_USER_ENTITY_TYPE } from '../../entity.js'; +import { manifests as inviteManifests } from './invite/manifests.js'; import { manifests as resendInviteManifests } from './resend-invite/manifests.js'; -import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; -const entityActions: Array = [ - { - type: 'entityAction', - kind: 'default', - alias: 'Umb.EntityAction.User.ResendInvite', - name: 'Resend Invite User Entity Action', - weight: 500, - api: () => import('./resend-invite/resend-invite.action.js'), - forEntityTypes: [UMB_USER_ENTITY_TYPE], - meta: { - icon: 'icon-message', - label: '#actions_resendInvite', - }, - conditions: [ - { - alias: 'Umb.Condition.User.AllowResendInviteAction', - }, - ], - }, +import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; + +export const manifests: Array = [ + ...inviteManifests, ...resendInviteManifests, ]; - -export const manifests: Array = [...entityActions]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/resend-invite/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/resend-invite/manifests.ts index 87dac3af79..1525273137 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/resend-invite/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/resend-invite/manifests.ts @@ -1,6 +1,25 @@ +import { UMB_USER_ENTITY_TYPE } from '../../../entity.js'; import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; export const manifests: Array = [ + { + type: 'entityAction', + kind: 'default', + alias: 'Umb.EntityAction.User.ResendInvite', + name: 'Resend Invite User Entity Action', + weight: 500, + api: () => import('./resend-invite.action.js'), + forEntityTypes: [UMB_USER_ENTITY_TYPE], + meta: { + icon: 'icon-message', + label: '#actions_resendInvite', + }, + conditions: [ + { + alias: 'Umb.Condition.User.AllowResendInviteAction', + }, + ], + }, { type: 'condition', name: 'User Allow Resend Invite Action Condition', diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/manifests.ts index 63b76f1ec9..3d56168a11 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/manifests.ts @@ -2,9 +2,9 @@ import { manifests as collectionActionManifests } from './collection-action/mani import { manifests as modalManifests } from './modal/manifests.js'; import { manifests as repositoryManifests } from './repository/manifests.js'; import { manifests as entityActionManifests } from './entity-action/manifests.js'; -import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; +import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; -export const manifests: Array = [ +export const manifests: Array = [ ...collectionActionManifests, ...modalManifests, ...repositoryManifests, From 4fc5044271f2c94fc6556cd37487d8b4a6433fa8 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 11 Sep 2024 16:23:51 +0200 Subject: [PATCH 45/55] update user group create path --- .../packages/user/user-group/collection/action/manifests.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/collection/action/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/collection/action/manifests.ts index 1168e303e3..3f67cc84e1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/collection/action/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/collection/action/manifests.ts @@ -1,3 +1,4 @@ +import { UMB_USER_GROUP_WORKSPACE_PATH } from '../../paths.js'; import { UMB_COLLECTION_ALIAS_CONDITION } from '@umbraco-cms/backoffice/collection'; import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; @@ -9,7 +10,7 @@ export const createManifest: ManifestTypes = { weight: 200, meta: { label: '#general_create', - href: 'section/user-management/view/user-groups/user-group/create', + href: `${UMB_USER_GROUP_WORKSPACE_PATH}/create`, }, conditions: [ { From 45943bd49deb944d4ba02c9d456803229bb7980c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 12 Sep 2024 20:38:05 +0200 Subject: [PATCH 46/55] import type --- .../src/libs/extension-api/registry/extension.registry.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts index feb27191c8..7f1d48752a 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts @@ -1,4 +1,4 @@ -import { WorkspaceAliasConditionConfig } from '@umbraco-cms/backoffice/workspace'; +import type { WorkspaceAliasConditionConfig } from '@umbraco-cms/backoffice/workspace'; import type { ManifestElementWithElementName, ManifestKind, From 12cc2674d7ee30855828774c6d67f07b4b25de3c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 12 Sep 2024 21:58:23 +0200 Subject: [PATCH 47/55] revert merge mistake --- .../src/packages/settings/advanced/manifests.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/settings/advanced/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/settings/advanced/manifests.ts index 3931a9edb9..5a452d9e3d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/settings/advanced/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/settings/advanced/manifests.ts @@ -10,11 +10,11 @@ export const manifests = [ { type: 'sectionSidebarApp', kind: 'menu', - alias: 'Umb.SectionSidebarApp.Menu.Users', - name: 'Users Section Sidebar Menu', + alias: 'Umb.SectionSidebarMenu.AdvancedSettings', + name: 'Advanced Settings Sidebar Menu', weight: 100, meta: { - label: 'Users', + label: '#treeHeaders_advancedGroup', menu: UMB_ADVANCED_SETTINGS_MENU_ALIAS, }, conditions: [ From 81946afe12411841bb5a79fa3143b3a1e40d6203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 12 Sep 2024 22:01:34 +0200 Subject: [PATCH 48/55] remove test code --- .../packages/property-editors/entry-point.ts | 47 ------------------- 1 file changed, 47 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/entry-point.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/entry-point.ts index f83895ac9b..9745b0d139 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/entry-point.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/entry-point.ts @@ -1,49 +1,2 @@ -import type { - ManifestWithDynamicConditions, - UmbConditionConfigBase, - UmbEntryPointOnInit, -} from '@umbraco-cms/backoffice/extension-api'; -import type { WorkspaceAliasConditionConfig } from '@umbraco-cms/backoffice/workspace'; - import './checkbox-list/components/index.js'; import './content-picker/components/index.js'; - -export const onInit: UmbEntryPointOnInit = (_host, _extensionRegistry) => { - - console.log('HELLO AGAIN'); - - const condition: UmbConditionConfigBase = { - alias: 'Umb.Condition.WorkspaceAlias', - match: 'Umb.Workspace.WARRENYO', - } as WorkspaceAliasConditionConfig; - - console.log( - 'Should not be false and not registered', - _extensionRegistry.isRegistered('Umb.Dashboard.UmbracoNewsLATE'), - ); - - _extensionRegistry.addCondition('Umb.Dashboard.UmbracoNewsLATE', condition); - - console.log('I HAZ ADDED CONDITION'); - - const ext: ManifestWithDynamicConditions = { - alias: 'Umb.Dashboard.UmbracoNewsLATE', - type: 'dashboard', - name: 'WARREN Package', - weight: 100, - conditions: [ - { - alias: 'Umb.Condition.WorkspaceAlias', - match: 'Umb.Workspace.LATE-COMER-EXISTING', - } as WorkspaceAliasConditionConfig, - ], - }; - - _extensionRegistry.register(ext); - - const amIRegistered = _extensionRegistry.isRegistered('Umb.Dashboard.UmbracoNewsLATE'); - console.log('Should be true and registered', amIRegistered); - - const getTheThing = _extensionRegistry.getByAlias('Umb.Dashboard.UmbracoNewsLATE'); - console.log('Should be the extension', getTheThing); -}; From 3ba18cdeacfb9a07ddd3389f3a1cbe4c94a62a3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 12 Sep 2024 22:01:45 +0200 Subject: [PATCH 49/55] refactor for a more direct appending implementation --- .../registry/extension.registry.test.ts | 152 +++++++++++++----- .../registry/extension.registry.ts | 120 +++++++------- 2 files changed, 172 insertions(+), 100 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts index 7f1d48752a..caed039f60 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.test.ts @@ -518,7 +518,7 @@ describe('Add Conditions', () => { const conditionToAdd: UmbConditionConfigBase = { alias: 'Umb.Test.Condition.Valid', }; - await extensionRegistry.addCondition('Umb.Test.Section.1', conditionToAdd); + await extensionRegistry.appendCondition('Umb.Test.Section.1', conditionToAdd); // Check new condition is registered expect(extensionRegistry.isRegistered('Umb.Test.Condition.Valid')).to.be.true; @@ -529,13 +529,17 @@ describe('Add Conditions', () => { expect(updatedExt.conditions?.[0]?.alias).to.equal('Umb.Test.Condition.Invalid'); expect(updatedExt.conditions?.[1]?.alias).to.equal('Umb.Test.Condition.Valid'); + // Verify the other extension was not updated: + const otherExt = extensionRegistry.getByAlias('Umb.Test.Section.2') as ManifestWithDynamicConditions; + expect(otherExt.conditions).to.be.undefined; + // Add a condition with a specific config to Section2 const workspaceCondition: WorkspaceAliasConditionConfig = { alias: 'Umb.Condition.WorkspaceAlias', match: 'Umb.Workspace.Document', }; - await extensionRegistry.addCondition('Umb.Test.Section.2', workspaceCondition); + await extensionRegistry.appendCondition('Umb.Test.Section.2', workspaceCondition); const updatedWorkspaceExt = extensionRegistry.getByAlias('Umb.Test.Section.2') as ManifestWithDynamicConditions; expect(updatedWorkspaceExt.conditions?.length).to.equal(1); @@ -556,7 +560,7 @@ describe('Add Conditions', () => { } as WorkspaceAliasConditionConfig, ]; - await extensionRegistry.addConditions('Umb.Test.Section.1', conditions); + await extensionRegistry.appendConditions('Umb.Test.Section.1', conditions); const extUpdated = extensionRegistry.getByAlias('Umb.Test.Section.1') as ManifestWithDynamicConditions; expect(extUpdated.conditions?.length).to.equal(3); @@ -565,47 +569,115 @@ describe('Add Conditions', () => { expect(extUpdated.conditions?.[2]?.alias).to.equal('Umb.Condition.WorkspaceAlias'); }); - // it('allows conditions to be prepended when an extension is loaded later on', async () => { - // const conditions: Array = [ - // { - // alias: 'Umb.Test.Condition.Invalid', - // }, - // { - // alias: 'Umb.Condition.WorkspaceAlias', - // match: 'Umb.Workspace.Document', - // } as WorkspaceAliasConditionConfig, - // ]; + it('allows conditions to be prepended when an extension is loaded later on', async () => { + const conditions: Array = [ + { + alias: 'Umb.Test.Condition.Invalid', + }, + { + alias: 'Umb.Condition.WorkspaceAlias', + match: 'Umb.Workspace.Document', + } as WorkspaceAliasConditionConfig, + ]; - // console.log('About to go KABOOM..'); + // Prepend the conditions, but do not await this. + extensionRegistry.appendConditions('Late.Extension.To.Be.Loaded', conditions); - // // Prepend the conditions - // // [WB] HELP: Why is this fine when using in in an entrypoint - // // /src/packages/property-editors/entry-point.ts - // // But this TEST implodes if it can't find the extension that is not yet registered - // await extensionRegistry.addConditions('Late.Extension.To.Be.Loaded', conditions); + // Make sure the extension is not registered YET + expect(extensionRegistry.isRegistered('Late.Extension.To.Be.Loaded')).to.be.false; - // // Make sure the extension is not registered YET - // expect(extensionRegistry.isRegistered('Late.Extension.To.Be.Loaded')).to.be.false; + // Register the extension LATE/after the conditions have been added + extensionRegistry.register({ + type: 'section', + name: 'Late Section Extension with one condition', + alias: 'Late.Extension.To.Be.Loaded', + weight: 200, + conditions: [ + { + alias: 'Umb.Test.Condition.Valid', + }, + ], + }); - // // Register the extension LATE/after the conditions have been added - // extensionRegistry.register({ - // type: 'section', - // name: 'Late Section Extension with one condition', - // alias: 'Late.Extension.To.Be.Loaded', - // weight: 200, - // conditions: [ - // { - // alias: 'Umb.Test.Condition.Valid', - // }, - // ], - // }); + expect(extensionRegistry.isRegistered('Late.Extension.To.Be.Loaded')).to.be.true; - // expect(extensionRegistry.isRegistered('Late.Extension.To.Be.Loaded')).to.be.true; + const extUpdated = extensionRegistry.getByAlias('Late.Extension.To.Be.Loaded') as ManifestWithDynamicConditions; - // const extUpdated = extensionRegistry.getByAlias('Late.Extension.To.Be.Loaded') as ManifestWithDynamicConditions; - // expect(extUpdated.conditions?.length).to.equal(3); - // expect(extUpdated.conditions?.[0]?.alias).to.equal('Umb.Condition.WorkspaceAlias'); - // expect(extUpdated.conditions?.[1]?.alias).to.equal('Umb.Test.Condition.Invalid'); - // expect(extUpdated.conditions?.[2]?.alias).to.equal('Umb.Test.Condition.Valid'); - // }); + expect(extUpdated.conditions?.length).to.equal(3); + expect(extUpdated.conditions?.[0]?.alias).to.equal('Umb.Test.Condition.Valid'); + expect(extUpdated.conditions?.[1]?.alias).to.equal('Umb.Test.Condition.Invalid'); + expect(extUpdated.conditions?.[2]?.alias).to.equal('Umb.Condition.WorkspaceAlias'); + }); + + /** + * As of current state, it is by design without further reasons to why, but it is made so additional conditions are only added to a current or next time registered manifest. + * Meaning if it happens to be unregistered and re-registered it does not happen again. + * Unless the exact same appending of conditions happens again. [NL] + * + * This makes sense if extensions gets offloaded and re-registered, but the extension that registered additional conditions didn't get loaded/registered second time. Therefor they need to be re-registered for such to work. [NL] + */ + it('only append conditions to the next time the extension is registered', async () => { + const conditions: Array = [ + { + alias: 'Umb.Test.Condition.Invalid', + }, + { + alias: 'Umb.Condition.WorkspaceAlias', + match: 'Umb.Workspace.Document', + } as WorkspaceAliasConditionConfig, + ]; + + // Prepend the conditions, but do not await this. + extensionRegistry.appendConditions('Late.Extension.To.Be.Loaded', conditions); + + // Make sure the extension is not registered YET + expect(extensionRegistry.isRegistered('Late.Extension.To.Be.Loaded')).to.be.false; + + // Register the extension LATE/after the conditions have been added + extensionRegistry.register({ + type: 'section', + name: 'Late Section Extension with one condition', + alias: 'Late.Extension.To.Be.Loaded', + weight: 200, + conditions: [ + { + alias: 'Umb.Test.Condition.Valid', + }, + ], + }); + + expect(extensionRegistry.isRegistered('Late.Extension.To.Be.Loaded')).to.be.true; + + const extUpdateFirstTime = extensionRegistry.getByAlias( + 'Late.Extension.To.Be.Loaded', + ) as ManifestWithDynamicConditions; + expect(extUpdateFirstTime.conditions?.length).to.equal(3); + + extensionRegistry.unregister('Late.Extension.To.Be.Loaded'); + + // Make sure the extension is not registered YET + expect(extensionRegistry.isRegistered('Late.Extension.To.Be.Loaded')).to.be.false; + + // Register the extension LATE/after the conditions have been added + extensionRegistry.register({ + type: 'section', + name: 'Late Section Extension with one condition', + alias: 'Late.Extension.To.Be.Loaded', + weight: 200, + conditions: [ + { + alias: 'Umb.Test.Condition.Valid', + }, + ], + }); + + expect(extensionRegistry.isRegistered('Late.Extension.To.Be.Loaded')).to.be.true; + + const extUpdateSecondTime = extensionRegistry.getByAlias( + 'Late.Extension.To.Be.Loaded', + ) as ManifestWithDynamicConditions; + + expect(extUpdateSecondTime.conditions?.length).to.equal(1); + expect(extUpdateSecondTime.conditions?.[0]?.alias).to.equal('Umb.Test.Condition.Valid'); + }); }); diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts index 26b483b032..e1535825a4 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts @@ -7,15 +7,7 @@ import type { import type { SpecificManifestTypeOrManifestBase } from '../types/map.types.js'; import { UmbBasicState } from '@umbraco-cms/backoffice/observable-api'; import type { Observable } from '@umbraco-cms/backoffice/external/rxjs'; -import { - map, - distinctUntilChanged, - combineLatest, - of, - switchMap, - filter, - firstValueFrom, -} from '@umbraco-cms/backoffice/external/rxjs'; +import { map, distinctUntilChanged, combineLatest, of, switchMap } from '@umbraco-cms/backoffice/external/rxjs'; /** * @@ -113,8 +105,26 @@ export class UmbExtensionRegistry< private _kinds = new UmbBasicState>>([]); public readonly kinds = this._kinds.asObservable(); + #exclusions: Array = []; + #additionalConditions: Map> = new Map(); + #appendAdditionalConditions(manifest: ManifestTypes) { + const newConditions = this.#additionalConditions.get(manifest.alias); + if (newConditions) { + // Append the condition to the extensions conditions array + if ((manifest as ManifestWithDynamicConditions).conditions) { + for (const condition of newConditions) { + (manifest as ManifestWithDynamicConditions).conditions!.push(condition); + } + } else { + (manifest as ManifestWithDynamicConditions).conditions = newConditions; + } + this.#additionalConditions.delete(manifest.alias); + } + return manifest; + } + defineKind(kind: ManifestKind): void { const extensionsValues = this._extensions.getValue(); const extension = extensionsValues.find( @@ -149,12 +159,25 @@ export class UmbExtensionRegistry< }; register(manifest: ManifestTypes | ManifestKind): void { - const isValid = this.#checkExtension(manifest); + const isValid = this.#validateExtension(manifest); if (!isValid) { return; } - this._extensions.setValue([...this._extensions.getValue(), manifest as ManifestTypes]); + if (manifest.type === 'kind') { + this.defineKind(manifest as ManifestKind); + return; + } + + const isApproved = this.#isExtensionApproved(manifest); + if (!isApproved) { + return; + } + + this._extensions.setValue([ + ...this._extensions.getValue(), + this.#appendAdditionalConditions(manifest as ManifestTypes), + ]); } getAllExtensions(): Array { @@ -190,7 +213,7 @@ export class UmbExtensionRegistry< return false; } - #checkExtension(manifest: ManifestTypes | ManifestKind): boolean { + #validateExtension(manifest: ManifestTypes | ManifestKind): boolean { if (!manifest.type) { console.error(`Extension is missing type`, manifest); return false; @@ -201,11 +224,9 @@ export class UmbExtensionRegistry< return false; } - if (manifest.type === 'kind') { - this.defineKind(manifest as ManifestKind); - return false; - } - + return true; + } + #isExtensionApproved(manifest: ManifestTypes | ManifestKind): boolean { if (!this.#acceptExtension(manifest as ManifestTypes)) { return false; } @@ -445,60 +466,39 @@ export class UmbExtensionRegistry< } /** - * Returns a promise that resolves when the extension with the specified alias is found. - * @param alias {string} - The alias of the extension to wait for. - * @returns {Promise} - A promise that resolves with the extension. + * Append a new condition to an existing extension + * Useful to add a condition for example the Save And Publish workspace action shipped by core. + * @param {string} alias - The alias of the extension to append the condition to. + * @param {UmbConditionConfigBase} newCondition - The condition to append to the extension. */ - private async _whenExtensionAliasIsRegistered(alias: string): Promise { - const source = this.extensions.pipe(filter((allExtensions) => allExtensions.some((ext) => ext.alias === alias))); - const value = await firstValueFrom(source); - const ext = value.find((ext) => ext.alias === alias) as ManifestBase; - return ext; + appendCondition(alias: string, newCondition: UmbConditionConfigBase) { + this.appendConditions(alias, [newCondition]); } /** - * Add a new condition to an existing extension - * Useful to add a condition for example the Save And Publish workspace action shipped by core - * As overwriting the whole extension to simply add an extra condition is not ideal as it causes a lot of duplicated code - * and could easily get out of sync from the CMS core implementation if a 3rd party dev was to try and overwrite it - * @param alias {string} - The alias of the extension to append the condition to - * @param newCondition {UmbConditionConfigBase} - The condition to append to the extension. + * Appends an array of conditions to an existing extension + * @param {string} alias - The alias of the extension to append the condition to + * @param {Array} newConditions - An array of conditions to be appended to an extension manifest. */ - async addCondition(alias: string, newCondition: UmbConditionConfigBase): Promise { - try { - // Wait for the extension to be registered (as it could be registered late) - const extensionToWaitFor = (await this._whenExtensionAliasIsRegistered(alias)) as ManifestWithDynamicConditions; + appendConditions(alias: string, newConditions: Array) { + const existingConditionsToBeAdded = this.#additionalConditions.get(alias); + this.#additionalConditions.set( + alias, + existingConditionsToBeAdded ? [...existingConditionsToBeAdded, ...newConditions] : newConditions, + ); - // Append the condition to the extensions conditions array - if (extensionToWaitFor.conditions) { - extensionToWaitFor.conditions.push(newCondition); - } else { - extensionToWaitFor.conditions = [newCondition]; - } - - const allExtensions = this._extensions.getValue(); - const extensionToUpdateIndex = allExtensions.findIndex((ext) => ext.alias === alias); - if (extensionToUpdateIndex !== -1) { + const allExtensions = this._extensions.getValue(); + for (const extension of allExtensions) { + if (extension.alias === alias) { // Replace the existing extension with the updated one - allExtensions[extensionToUpdateIndex] = extensionToWaitFor as ManifestTypes; + allExtensions[allExtensions.indexOf(extension)] = this.#appendAdditionalConditions(extension as ManifestTypes); // Update the main extensions collection/observable this._extensions.setValue(allExtensions); - } - } catch (error) { - // TODO: [WB] Will this ever catch an error? - console.error(`Extension with alias ${alias} was never found and threw ${error}`); - } - } - /** - * Adds a collection of conditions to an exsiting extension - * @param alias {string} - The alias of the extension to append the condition to - * @param newConditions {Array} - A collection of conditions to append to an extension. - */ - async addConditions(alias: string, newConditions: Array): Promise { - for (const condition of newConditions) { - await this.addCondition(alias, condition); + //Stop the search: + break; + } } } } From 79712b41352006dc3530e703b9c0c49ba3285d8a Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 12 Sep 2024 22:48:41 +0200 Subject: [PATCH 50/55] move into folder --- .../user/user-group/workspace/manifests.ts | 44 ++----------------- ...oup-entity-user-permission-list.element.ts | 0 ...-group-granular-permission-list.element.ts | 0 .../workspace/{ => user-group}/constants.ts | 0 .../workspace/user-group/manifests.ts | 42 ++++++++++++++++++ .../user-group-workspace-editor.element.ts | 4 +- .../user-group-workspace.context-token.ts | 2 +- .../user-group-workspace.context.ts | 4 +- 8 files changed, 50 insertions(+), 46 deletions(-) rename src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/{ => user-group}/components/user-group-entity-user-permission-list.element.ts (100%) rename src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/{ => user-group}/components/user-group-granular-permission-list.element.ts (100%) rename src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/{ => user-group}/constants.ts (100%) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/manifests.ts rename src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/{ => user-group}/user-group-workspace-editor.element.ts (98%) rename src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/{ => user-group}/user-group-workspace.context-token.ts (89%) rename src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/{ => user-group}/user-group-workspace.context.ts (97%) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/manifests.ts index 4a593776bc..806ce0f556 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/manifests.ts @@ -1,42 +1,4 @@ -import type { - ManifestWorkspaces, - ManifestWorkspaceActions, - ManifestWorkspaceView, - ManifestTypes, -} from '@umbraco-cms/backoffice/extension-registry'; -import { UmbSubmitWorkspaceAction } from '@umbraco-cms/backoffice/workspace'; +import { manifests as userGroupManifests } from './user-group/manifests.js'; +import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; -const workspace: ManifestWorkspaces = { - type: 'workspace', - kind: 'routable', - alias: 'Umb.Workspace.UserGroup', - name: 'User Group Workspace', - api: () => import('./user-group-workspace.context.js'), - meta: { - entityType: 'user-group', - }, -}; - -const workspaceViews: Array = []; -const workspaceActions: Array = [ - { - type: 'workspaceAction', - kind: 'default', - alias: 'Umb.WorkspaceAction.UserGroup.Save', - name: 'Save User Group Workspace Action', - api: UmbSubmitWorkspaceAction, - meta: { - label: '#buttons_save', - look: 'primary', - color: 'positive', - }, - conditions: [ - { - alias: 'Umb.Condition.WorkspaceAlias', - match: workspace.alias, - }, - ], - }, -]; - -export const manifests: Array = [workspace, ...workspaceViews, ...workspaceActions]; +export const manifests: Array = [...userGroupManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/components/user-group-entity-user-permission-list.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/components/user-group-entity-user-permission-list.element.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/components/user-group-entity-user-permission-list.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/components/user-group-entity-user-permission-list.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/components/user-group-granular-permission-list.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/components/user-group-granular-permission-list.element.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/components/user-group-granular-permission-list.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/components/user-group-granular-permission-list.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/constants.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/constants.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/constants.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/manifests.ts new file mode 100644 index 0000000000..4a593776bc --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/manifests.ts @@ -0,0 +1,42 @@ +import type { + ManifestWorkspaces, + ManifestWorkspaceActions, + ManifestWorkspaceView, + ManifestTypes, +} from '@umbraco-cms/backoffice/extension-registry'; +import { UmbSubmitWorkspaceAction } from '@umbraco-cms/backoffice/workspace'; + +const workspace: ManifestWorkspaces = { + type: 'workspace', + kind: 'routable', + alias: 'Umb.Workspace.UserGroup', + name: 'User Group Workspace', + api: () => import('./user-group-workspace.context.js'), + meta: { + entityType: 'user-group', + }, +}; + +const workspaceViews: Array = []; +const workspaceActions: Array = [ + { + type: 'workspaceAction', + kind: 'default', + alias: 'Umb.WorkspaceAction.UserGroup.Save', + name: 'Save User Group Workspace Action', + api: UmbSubmitWorkspaceAction, + meta: { + label: '#buttons_save', + look: 'primary', + color: 'positive', + }, + conditions: [ + { + alias: 'Umb.Condition.WorkspaceAlias', + match: workspace.alias, + }, + ], + }, +]; + +export const manifests: Array = [workspace, ...workspaceViews, ...workspaceActions]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/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 similarity index 98% rename from src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-workspace-editor.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/user-group-workspace-editor.element.ts index a4d129dd04..01835e7c2a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/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 @@ -1,5 +1,5 @@ -import type { UmbUserGroupDetailModel } from '../index.js'; -import { UMB_USER_GROUP_ROOT_WORKSPACE_PATH } from '../paths.js'; +import type { UmbUserGroupDetailModel } from '../../index.js'; +import { UMB_USER_GROUP_ROOT_WORKSPACE_PATH } from '../../paths.js'; import { UMB_USER_GROUP_WORKSPACE_CONTEXT } from './user-group-workspace.context-token.js'; import { UMB_USER_GROUP_WORKSPACE_ALIAS } from './constants.js'; import type { UUIBooleanInputEvent } from '@umbraco-cms/backoffice/external/uui'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-workspace.context-token.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/user-group-workspace.context-token.ts similarity index 89% rename from src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-workspace.context-token.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/user-group-workspace.context-token.ts index a09ae6a716..3a11176569 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-workspace.context-token.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/user-group-workspace.context-token.ts @@ -1,4 +1,4 @@ -import { UMB_USER_GROUP_ENTITY_TYPE } from '../index.js'; +import { UMB_USER_GROUP_ENTITY_TYPE } from '../../index.js'; import type { UmbUserGroupWorkspaceContext } from './user-group-workspace.context.js'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import type { UmbSubmittableWorkspaceContext } from '@umbraco-cms/backoffice/workspace'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/user-group-workspace.context.ts similarity index 97% rename from src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-workspace.context.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/user-group-workspace.context.ts index c360e2057f..6f81961747 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/user-group-workspace.context.ts @@ -1,5 +1,5 @@ -import { UmbUserGroupDetailRepository } from '../repository/detail/index.js'; -import type { UmbUserGroupDetailModel } from '../types.js'; +import { UmbUserGroupDetailRepository } from '../../repository/detail/index.js'; +import type { UmbUserGroupDetailModel } from '../../types.js'; import { UmbUserGroupWorkspaceEditorElement } from './user-group-workspace-editor.element.js'; import type { UmbUserPermissionModel } from '@umbraco-cms/backoffice/user-permission'; import type { UmbRoutableWorkspaceContext, UmbSubmittableWorkspaceContext } from '@umbraco-cms/backoffice/workspace'; From 7ec84306cbf587160f75b180837c2a5b45d27c68 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 12 Sep 2024 22:49:09 +0200 Subject: [PATCH 51/55] rename folder --- .../user-group/{section-view => user-group-root}/manifests.ts | 0 .../user-group-root-workspace.element.ts | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/Umbraco.Web.UI.Client/src/packages/user/user-group/{section-view => user-group-root}/manifests.ts (100%) rename src/Umbraco.Web.UI.Client/src/packages/user/user-group/{section-view => user-group-root}/user-group-root-workspace.element.ts (100%) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/user-group-root/manifests.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/manifests.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user-group/user-group-root/manifests.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/user-group-root-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/user-group-root/user-group-root-workspace.element.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/user-group-root-workspace.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user-group/user-group-root/user-group-root-workspace.element.ts From c442fc86017e31f4fc2dcf863c4ed6c16c300e8b Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 12 Sep 2024 22:49:35 +0200 Subject: [PATCH 52/55] move folder into workspace --- .../src/packages/user/user-group/manifests.ts | 2 +- .../user-group/{ => workspace}/user-group-root/manifests.ts | 2 +- .../user-group-root/user-group-root-workspace.element.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename src/Umbraco.Web.UI.Client/src/packages/user/user-group/{ => workspace}/user-group-root/manifests.ts (86%) rename src/Umbraco.Web.UI.Client/src/packages/user/user-group/{ => workspace}/user-group-root/user-group-root-workspace.element.ts (89%) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/manifests.ts index a68693f9c3..7db75cbebf 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/manifests.ts @@ -4,7 +4,7 @@ import { manifests as entityBulkActionManifests } from './entity-bulk-actions/ma import { manifests as menuItemManifests } from './menu-item/manifests.js'; import { manifests as modalManifests } from './modals/manifests.js'; import { manifests as repositoryManifests } from './repository/manifests.js'; -import { manifests as sectionViewManifests } from './section-view/manifests.js'; +import { manifests as sectionViewManifests } from './workspace/user-group-root/manifests.js'; import { manifests as workspaceManifests } from './workspace/manifests.js'; import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/user-group-root/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-root/manifests.ts similarity index 86% rename from src/Umbraco.Web.UI.Client/src/packages/user/user-group/user-group-root/manifests.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-root/manifests.ts index ade0536011..ac7b088e93 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/user-group-root/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-root/manifests.ts @@ -1,4 +1,4 @@ -import { UMB_USER_GROUP_ROOT_ENTITY_TYPE } from '../entity.js'; +import { UMB_USER_GROUP_ROOT_ENTITY_TYPE } from '../../entity.js'; import type { ManifestTypes, UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry'; export const manifests: Array = [ diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/user-group-root/user-group-root-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-root/user-group-root-workspace.element.ts similarity index 89% rename from src/Umbraco.Web.UI.Client/src/packages/user/user-group/user-group-root/user-group-root-workspace.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-root/user-group-root-workspace.element.ts index f02687d62d..0a77413d07 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/user-group-root/user-group-root-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-root/user-group-root-workspace.element.ts @@ -1,4 +1,4 @@ -import { UMB_USER_GROUP_COLLECTION_ALIAS } from '../collection/index.js'; +import { UMB_USER_GROUP_COLLECTION_ALIAS } from '../../collection/index.js'; import { html, customElement } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; From 8c459331b784284e2b1e6b3f12320f945da43f4b Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 12 Sep 2024 22:50:58 +0200 Subject: [PATCH 53/55] localize headline --- .../user-group-root/user-group-root-workspace.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-root/user-group-root-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-root/user-group-root-workspace.element.ts index 0a77413d07..0900cee472 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-root/user-group-root-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-root/user-group-root-workspace.element.ts @@ -6,7 +6,7 @@ const elementName = 'umb-user-group-root-workspace'; @customElement(elementName) export class UmbUserGroupRootWorkspaceElement extends UmbLitElement { override render() { - return html` + return html` ; `; } From 45554676a206c8454deef7f92eb1b65fdf1f3a25 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 12 Sep 2024 22:56:11 +0200 Subject: [PATCH 54/55] localize header --- .../user/workspace/user-root/user-root-workspace.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-root/user-root-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-root/user-root-workspace.element.ts index 2411336b55..335f7b9590 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-root/user-root-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-root/user-root-workspace.element.ts @@ -16,7 +16,7 @@ export class UmbUserRootWorkspaceElement extends UmbLitElement { } override render() { - return html` + return html` ; `; } From 2fdfdcb41d2e66b757e2012679c4972d71164fc9 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 12 Sep 2024 23:12:53 +0200 Subject: [PATCH 55/55] remove lorem ipsum --- .../create/modal/user-create-options-modal.element.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/user-create-options-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/user-create-options-modal.element.ts index 29932ea273..74e8646990 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/user-create-options-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/entity-actions/create/modal/user-create-options-modal.element.ts @@ -9,7 +9,7 @@ import { UmbRequestReloadChildrenOfEntityEvent } from '@umbraco-cms/backoffice/e interface UmbUserCreateOptionModel { label: string; - description: string; + description?: string; icon: string; kind: UmbUserKindType; } @@ -20,13 +20,11 @@ export class UmbUserCreateOptionsModalElement extends UmbModalBaseElement { #options: Array = [ { label: this.localize.term('user_userKindDefault'), - description: 'Donec augue nunc, ullamcorper non turpis ut, maximus facilisis lorem. Nunc id sagittis magna.', icon: 'icon-user', kind: UmbUserKind.DEFAULT, }, { label: this.localize.term('user_userKindApi'), - description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', icon: 'icon-unplug', kind: UmbUserKind.API, },