-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2509 from umbraco/v15/hotfix/create-options-exten…
…sion-point Hotfix: Entity Create Option Action Extension Point
- Loading branch information
Showing
50 changed files
with
2,378 additions
and
1,819 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
157 changes: 157 additions & 0 deletions
157
src/packages/core/collection/action/create/collection-create-action.element.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
import { html, customElement, state, ifDefined } from '@umbraco-cms/backoffice/external/lit'; | ||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; | ||
import type { UmbExtensionApiInitializer } from '@umbraco-cms/backoffice/extension-api'; | ||
import { UmbExtensionsApiInitializer } from '@umbraco-cms/backoffice/extension-api'; | ||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; | ||
import { UMB_ENTITY_CONTEXT } from '@umbraco-cms/backoffice/entity'; | ||
import type { ManifestEntityCreateOptionAction } from '@umbraco-cms/backoffice/entity-create-option-action'; | ||
|
||
type ManifestType = ManifestEntityCreateOptionAction; | ||
|
||
const elementName = 'umb-collection-create-action-button'; | ||
@customElement(elementName) | ||
export class UmbCollectionCreateActionButtonElement extends UmbLitElement { | ||
@state() | ||
private _popoverOpen = false; | ||
|
||
@state() | ||
private _multipleOptions = false; | ||
|
||
@state() | ||
private _apiControllers: Array<UmbExtensionApiInitializer<ManifestType>> = []; | ||
|
||
@state() | ||
_hrefList: Array<string | undefined> = []; | ||
|
||
#createLabel = this.localize.term('general_create'); | ||
#entityContext?: typeof UMB_ENTITY_CONTEXT.TYPE; | ||
|
||
#onPopoverToggle(event: PointerEvent) { | ||
// 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'; | ||
} | ||
|
||
async #onClick(event: Event, controller: UmbExtensionApiInitializer<ManifestType>, href?: string) { | ||
event.stopPropagation(); | ||
|
||
// skip if href is defined | ||
if (href) { | ||
return; | ||
} | ||
|
||
if (!controller.api) throw new Error('No API found'); | ||
await controller.api.execute(); | ||
} | ||
|
||
constructor() { | ||
super(); | ||
|
||
this.consumeContext(UMB_ENTITY_CONTEXT, (context) => { | ||
this.#entityContext = context; | ||
this.#initApi(); | ||
}); | ||
} | ||
|
||
#initApi() { | ||
if (!this.#entityContext) return; | ||
|
||
const entityType = this.#entityContext.getEntityType(); | ||
if (!entityType) throw new Error('No entityType found'); | ||
|
||
const unique = this.#entityContext.getUnique(); | ||
if (unique === undefined) throw new Error('No unique found'); | ||
|
||
new UmbExtensionsApiInitializer( | ||
this, | ||
umbExtensionsRegistry, | ||
'entityCreateOptionAction', | ||
(manifest: ManifestType) => { | ||
return [{ entityType, unique, meta: manifest.meta }]; | ||
}, | ||
(manifest: ManifestType) => manifest.forEntityTypes.includes(entityType), | ||
async (controllers) => { | ||
this._apiControllers = controllers as unknown as Array<UmbExtensionApiInitializer<ManifestType>>; | ||
this._multipleOptions = controllers.length > 1; | ||
const hrefPromises = this._apiControllers.map((controller) => controller.api?.getHref()); | ||
this._hrefList = await Promise.all(hrefPromises); | ||
}, | ||
); | ||
} | ||
|
||
#getTarget(href?: string) { | ||
if (href && href.startsWith('http')) { | ||
return '_blank'; | ||
} | ||
|
||
return '_self'; | ||
} | ||
|
||
override render() { | ||
return this._multipleOptions ? this.#renderMultiOptionAction() : this.#renderSingleOptionAction(); | ||
} | ||
|
||
#renderSingleOptionAction() { | ||
return html` <uui-button | ||
label=${this.#createLabel} | ||
color="default" | ||
look="outline" | ||
@click=${(event: Event) => this.#onClick(event, this._apiControllers[0])}></uui-button>`; | ||
} | ||
|
||
#renderMultiOptionAction() { | ||
return html` | ||
<uui-button | ||
popovertarget="collection-action-menu-popover" | ||
label=${this.#createLabel} | ||
color="default" | ||
look="outline"> | ||
${this.#createLabel} | ||
<uui-symbol-expand .open=${this._popoverOpen}></uui-symbol-expand> | ||
</uui-button> | ||
${this.#renderDropdown()} | ||
`; | ||
} | ||
|
||
#renderDropdown() { | ||
return html` | ||
<uui-popover-container | ||
id="collection-action-menu-popover" | ||
placement="bottom-start" | ||
@toggle=${this.#onPopoverToggle}> | ||
<umb-popover-layout> | ||
<uui-scroll-container> | ||
${this._apiControllers.map((controller, index) => this.#renderMenuItem(controller, index))} | ||
</uui-scroll-container> | ||
</umb-popover-layout> | ||
</uui-popover-container> | ||
`; | ||
} | ||
|
||
#renderMenuItem(controller: UmbExtensionApiInitializer<ManifestType>, index: number) { | ||
const manifest = controller.manifest; | ||
if (!manifest) throw new Error('No manifest found'); | ||
|
||
const label = manifest.meta.label ? this.localize.string(manifest.meta.label) : manifest.name; | ||
const href = this._hrefList[index]; | ||
|
||
return html` | ||
<uui-menu-item | ||
label=${label} | ||
@click=${(event: Event) => this.#onClick(event, controller, href)} | ||
href=${ifDefined(href)} | ||
target=${this.#getTarget(href)}> | ||
<umb-icon slot="icon" .name=${manifest.meta.icon}></umb-icon> | ||
</uui-menu-item> | ||
`; | ||
} | ||
} | ||
|
||
export { UmbCollectionCreateActionButtonElement as element }; | ||
|
||
declare global { | ||
interface HTMLElementTagNameMap { | ||
[elementName]: UmbCollectionCreateActionButtonElement; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import type { UmbExtensionManifestKind } from '@umbraco-cms/backoffice/extension-registry'; | ||
|
||
export const manifests: Array<UmbExtensionManifest | UmbExtensionManifestKind> = [ | ||
{ | ||
type: 'kind', | ||
alias: 'Umb.Kind.CollectionAction.Create', | ||
matchKind: 'create', | ||
matchType: 'collectionAction', | ||
manifest: { | ||
type: 'collectionAction', | ||
kind: 'create', | ||
element: () => import('./collection-create-action.element.js'), | ||
weight: 1200, | ||
meta: { | ||
label: '#actions_create', | ||
}, | ||
}, | ||
}, | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import type { ManifestCollectionAction } from '../../extensions/index.js'; | ||
|
||
export interface ManifestCollectionActionCreateKind extends ManifestCollectionAction { | ||
type: 'collectionAction'; | ||
kind: 'create'; | ||
} | ||
|
||
declare global { | ||
interface UmbExtensionManifestMap { | ||
umbCollectionActionCreateKind: ManifestCollectionActionCreateKind; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { manifests as createManifests } from './create/manifests.js'; | ||
import type { UmbExtensionManifestKind } from '@umbraco-cms/backoffice/extension-registry'; | ||
|
||
export const manifests: Array<UmbExtensionManifest | UmbExtensionManifestKind> = [...createManifests]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,10 @@ | ||
import type { UmbExtensionManifestKind } from '../extension-registry/registry.js'; | ||
import { manifests as actionManifests } from './action/manifests.js'; | ||
import { manifests as conditionManifests } from './conditions/manifests.js'; | ||
import { manifests as workspaceViewManifests } from './workspace-view/manifests.js'; | ||
|
||
export const manifests: Array<UmbExtensionManifest | UmbExtensionManifestKind> = [ | ||
...actionManifests, | ||
...workspaceViewManifests, | ||
...conditionManifests, | ||
]; |
22 changes: 22 additions & 0 deletions
22
src/packages/core/entity-action/common/create/create.action.kind.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { UMB_ENTITY_ACTION_DEFAULT_KIND_MANIFEST } from '../../default/default.action.kind.js'; | ||
import type { UmbExtensionManifestKind } from '@umbraco-cms/backoffice/extension-registry'; | ||
|
||
export const manifest: UmbExtensionManifestKind = { | ||
type: 'kind', | ||
alias: 'Umb.Kind.EntityAction.Create', | ||
matchKind: 'create', | ||
matchType: 'entityAction', | ||
manifest: { | ||
...UMB_ENTITY_ACTION_DEFAULT_KIND_MANIFEST.manifest, | ||
type: 'entityAction', | ||
kind: 'create', | ||
api: () => import('./create.action.js'), | ||
weight: 1200, | ||
forEntityTypes: [], | ||
meta: { | ||
icon: 'icon-add', | ||
label: '#actions_create', | ||
additionalOptions: true, | ||
}, | ||
}, | ||
}; |
59 changes: 59 additions & 0 deletions
59
src/packages/core/entity-action/common/create/create.action.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { UmbEntityActionBase } from '../../entity-action-base.js'; | ||
import type { UmbEntityActionArgs } from '../../types.js'; | ||
import type { MetaEntityActionCreateKind } from './types.js'; | ||
import { UMB_ENTITY_CREATE_OPTION_ACTION_LIST_MODAL } from './modal/index.js'; | ||
import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; | ||
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; | ||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; | ||
import { createExtensionApi, UmbExtensionsManifestInitializer } from '@umbraco-cms/backoffice/extension-api'; | ||
import type { ManifestEntityCreateOptionAction } from '@umbraco-cms/backoffice/entity-create-option-action'; | ||
|
||
export class UmbCreateEntityAction extends UmbEntityActionBase<MetaEntityActionCreateKind> { | ||
#hasSingleOption = true; | ||
#singleActionOptionManifest?: ManifestEntityCreateOptionAction; | ||
|
||
constructor(host: UmbControllerHost, args: UmbEntityActionArgs<MetaEntityActionCreateKind>) { | ||
super(host, args); | ||
|
||
new UmbExtensionsManifestInitializer( | ||
this, | ||
umbExtensionsRegistry, | ||
'entityCreateOptionAction', | ||
(ext) => ext.forEntityTypes.includes(this.args.entityType), | ||
async (actionOptions) => { | ||
this.#hasSingleOption = actionOptions.length === 1; | ||
this.#singleActionOptionManifest = this.#hasSingleOption | ||
? (actionOptions[0].manifest as unknown as ManifestEntityCreateOptionAction) | ||
: undefined; | ||
}, | ||
'umbEntityActionsObserver', | ||
); | ||
} | ||
|
||
override async execute() { | ||
if (this.#hasSingleOption) { | ||
if (!this.#singleActionOptionManifest) throw new Error('No first action manifest found'); | ||
|
||
const api = await createExtensionApi(this, this.#singleActionOptionManifest, [ | ||
{ unique: this.args.unique, entityType: this.args.entityType, meta: this.#singleActionOptionManifest.meta }, | ||
]); | ||
|
||
if (!api) throw new Error(`Could not create api for ${this.#singleActionOptionManifest.alias}`); | ||
|
||
await api.execute(); | ||
return; | ||
} | ||
|
||
const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); | ||
const modalContext = modalManager.open(this, UMB_ENTITY_CREATE_OPTION_ACTION_LIST_MODAL, { | ||
data: { | ||
unique: this.args.unique, | ||
entityType: this.args.entityType, | ||
}, | ||
}); | ||
|
||
await modalContext.onSubmit(); | ||
} | ||
} | ||
|
||
export { UmbCreateEntityAction as api }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { UmbCreateEntityAction } from './create.action.js'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { manifest as createKindManifest } from './create.action.kind.js'; | ||
import { manifests as modalManifests } from './modal/manifests.js'; | ||
|
||
export const manifests = [createKindManifest, ...modalManifests]; |
1 change: 1 addition & 0 deletions
1
src/packages/core/entity-action/common/create/modal/constants.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export const UMB_ENTITY_CREATE_OPTION_ACTION_LIST_MODAL_ALIAS = 'Umb.Modal.Entity.CreateOptionActionList'; |
Oops, something went wrong.