Compare commits

...
Author SHA1 Message Date
Niels Lyngsø 6e3ff8689d correct uui-text impl 2025-02-20 16:32:41 +01:00
Niels Lyngsø d7410a08e1 upper case Trash 2025-02-20 15:55:16 +01:00
Niels Lyngsø 6463334c2f Merge branch 'v15/dev' into v15/feature/delete-referenced-by
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/repository/document-reference.server.data.ts
#	src/Umbraco.Web.UI.Client/src/packages/media/media/item/manifests.ts
#	src/Umbraco.Web.UI.Client/src/packages/media/media/reference/repository/media-reference.server.data.ts
#	src/Umbraco.Web.UI.Client/src/packages/relations/relations/types.ts
#	src/Umbraco.Web.UI.Client/utils/all-umb-consts/index.ts
2025-02-20 15:54:05 +01:00
Mads Rasmussen aa8bbead4f Merge branch 'v15/feature/$type-data-mapper-extension' into v15/feature/delete-referenced-by 2025-02-20 09:26:01 +01:00
Mads Rasmussen 2b0ceabf0b align naming 2025-02-20 09:22:21 +01:00
Mads Rasmussen cc94607a27 Merge branch 'v15/feature/$type-data-mapper-extension' into v15/feature/delete-referenced-by 2025-02-19 09:45:46 +01:00
Mads Rasmussen 32c3d17c48 export extension types 2025-02-19 09:16:21 +01:00
Mads Rasmussen 9b070c0659 remove unused variant id 2025-02-19 08:42:12 +01:00
Niels Lyngsø 9b1534ff86 clean up 2025-02-18 21:07:34 +01:00
Niels Lyngsø a92ea32d8a member edit path pattern 2025-02-18 20:57:55 +01:00
Niels Lyngsø 3e067495c1 sort imports 2025-02-18 20:54:35 +01:00
Niels Lyngsø 608b1038c8 more clean up 2025-02-18 20:54:18 +01:00
Niels Lyngsø 8dd829384d clean up 2025-02-18 20:54:07 +01:00
Niels Lyngsø 6dcc897986 implement path pattern for media item 2025-02-18 20:53:59 +01:00
Niels Lyngsø c17d1983f2 add todo comment 2025-02-18 20:22:01 +01:00
Niels Lyngsø 7559785b3f Merge branch 'v15/dev' into v15/feature/$type-data-mapper-extension
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/item/document-item-ref.element.ts
2025-02-18 20:08:01 +01:00
Mads Rasmussen 3d6be7ada4 Update document-reference-table.element.ts 2025-02-18 10:08:22 +01:00
Mads Rasmussen a63bdcd2f4 Merge branch 'v15/dev' into v15/feature/delete-referenced-by 2025-02-18 10:06:48 +01:00
Mads Rasmussen aafc107364 Merge branch 'v15/task/limit-referenced-by-endpoints-to-dependencies-only' into v15/feature/delete-referenced-by 2025-02-18 09:22:34 +01:00
Andy Butland a17842499f Limit referenced-by document and media endpoints to references only. 2025-02-17 21:33:33 +01:00
Mads Rasmussen 7655089109 export constants 2025-02-17 19:51:28 +01:00
Mads Rasmussen cbd7ea4938 Update index.ts 2025-02-17 19:47:56 +01:00
Mads Rasmussen c37302ee16 override confirm methods in trash and delete actions 2025-02-17 19:47:15 +01:00
Mads Rasmussen 1f264f6cd3 Update trash-with-relation.action.ts 2025-02-17 18:18:05 +01:00
Mads Rasmussen e0eca329bb fix type 2025-02-17 17:23:45 +01:00
Mads Rasmussen 2823164bbb localize trash 2025-02-17 16:57:03 +01:00
Mads Rasmussen 0e206b685d clean up 2025-02-17 16:38:39 +01:00
Mads Rasmussen 6815160683 use deleteWithRelation kind for media 2025-02-17 15:42:10 +01:00
Mads Rasmussen 1443b9cda2 Update delete-with-relation-modal.element.ts 2025-02-17 15:28:50 +01:00
Mads Rasmussen f83ee80bcf show references when deleting a document 2025-02-17 15:27:57 +01:00
Mads Rasmussen 5a38296153 Merge branch 'v15/feature/$type-data-mapper-extension' into v15/feature/delete-referenced-by 2025-02-17 15:21:37 +01:00
Mads Rasmussen 8dd474d547 Merge branch 'v15/feature/display-current-variant-item-name' into v15/feature/$type-data-mapper-extension 2025-02-17 15:10:14 +01:00
Mads Rasmussen 0a62426515 align naming 2025-02-17 15:07:45 +01:00
Mads Rasmussen 2cbe1efecd Update index.ts 2025-02-17 13:59:15 +01:00
Mads Rasmussen ac8955e84d fix type errors 2025-02-17 13:56:52 +01:00
Mads Rasmussen edefa42f94 Merge branch 'v15/dev' into v15/feature/display-current-variant-item-name 2025-02-17 13:47:24 +01:00
Mads Rasmussen 1c5aedfc73 add management api mapper 2025-02-17 13:06:24 +01:00
Mads Rasmussen 2d3ca2928d use management api mapper 2025-02-17 12:31:26 +01:00
Mads Rasmussen 11b3e04501 require data source identifier 2025-02-17 12:27:41 +01:00
Mads Rasmussen 46b050a05b fix name collision 2025-02-17 10:52:20 +01:00
Mads Rasmussen ece64d9b98 Merge branch 'v15/feature/display-current-variant-item-name' into v15/feature/$type-data-mapper-extension 2025-02-17 10:41:58 +01:00
Mads Rasmussen c18e8e7fd6 Merge branch 'v15/dev' into v15/feature/display-current-variant-item-name 2025-02-17 10:37:15 +01:00
Mads Rasmussen 9e273f9c4c move to element 2025-02-16 20:03:23 +01:00
Mads Rasmussen 1e084b4d15 wip delete with relation 2025-02-16 19:40:54 +01:00
Mads Rasmussen e31186772e move trash 2025-02-16 19:29:55 +01:00
Mads Rasmussen d3e2db5859 implement for media 2025-02-14 16:24:02 +01:00
Mads Rasmussen dcc9b3d6e9 set standalone attribute 2025-02-14 16:20:46 +01:00
Mads Rasmussen 541753c9e4 fix length check 2025-02-14 16:07:26 +01:00
Mads Rasmussen a8324b6ba5 render descendants with references 2025-02-14 15:57:36 +01:00
Mads Rasmussen 161c9d5ef5 split trash with relation into its own action 2025-02-14 15:00:54 +01:00
Mads Rasmussen b518e789a7 add types for reference data source + repository 2025-02-14 13:37:23 +01:00
Mads Rasmussen 6b1891e48c Merge branch 'v15/feature/$type-data-mapper-extension' into v15/feature/delete-referenced-by 2025-02-14 13:36:48 +01:00
Mads Rasmussen 23fd63d7fd Merge branch 'v15/feature/display-current-variant-item-name' into v15/feature/$type-data-mapper-extension 2025-02-14 13:36:30 +01:00
Mads Rasmussen 83cf3c25ab Merge branch 'v15/dev' into v15/feature/display-current-variant-item-name 2025-02-14 13:33:39 +01:00
Mads Rasmussen c401187f95 Merge branch 'v15/feature/$type-data-mapper-extension' into v15/feature/delete-referenced-by 2025-02-14 12:17:37 +01:00
Mads Rasmussen ddbec2a14a return undefined if there is not edit path 2025-02-13 21:06:45 +01:00
Mads Rasmussen a73116021c prefix all ref routes 2025-02-13 16:59:37 +01:00
Mads Rasmussen 5f9d9d41da prefix info routes 2025-02-13 16:58:38 +01:00
Mads Rasmussen 57b11457e1 add data mapper 2025-02-13 14:57:46 +01:00
Mads Rasmussen 193d93a41b dot not allow conditions for data mappers 2025-02-13 14:14:21 +01:00
Mads Rasmussen bbc5fee737 update mock data 2025-02-13 13:56:19 +01:00
Mads Rasmussen 54814c19bf register media ref item 2025-02-13 13:53:57 +01:00
Mads Rasmussen 934e03b345 hardcode fake array 2025-02-13 13:07:53 +01:00
Mads Rasmussen 81a0805e92 add variants to model 2025-02-13 13:07:38 +01:00
Mads Rasmussen 575f3b22c1 Update media-references-workspace-info-app.element.ts 2025-02-13 12:56:27 +01:00
Mads Rasmussen 63e03ace30 add variants array to model 2025-02-13 12:55:50 +01:00
Mads Rasmussen 75face7e78 temp fake variants array 2025-02-13 12:55:39 +01:00
Mads Rasmussen fbf9f2f867 export types 2025-02-13 12:55:15 +01:00
Mads Rasmussen bb039685f2 make default ref item always readonly 2025-02-13 12:55:03 +01:00
Mads Rasmussen f43e32e59a make mapper name more generic 2025-02-13 12:54:34 +01:00
Mads Rasmussen 870cd86788 use reference items for media 2025-02-13 11:28:16 +01:00
Mads Rasmussen 9f62268601 Merge branch 'v15/feature/display-current-variant-item-name' into v15/feature/$type-data-mapper-extension 2025-02-13 11:16:59 +01:00
Mads Rasmussen ec95d71ea7 Merge branch 'v15/dev' into v15/feature/display-current-variant-item-name 2025-02-13 11:16:33 +01:00
Mads Rasmussen bafd96bd93 use ref list 2025-02-13 11:13:19 +01:00
Mads Rasmussen 1c8432ae4b add fallback 2025-02-13 10:57:05 +01:00
Mads Rasmussen f1dc763fb6 Merge branch 'v15/feature/display-current-variant-item-name' into v15/feature/$type-data-mapper-extension 2025-02-13 10:35:55 +01:00
Mads Rasmussen 6dea5f0d73 Merge branch 'v15/feature/entity-item-ref-extension' into v15/feature/display-current-variant-item-name 2025-02-13 10:34:02 +01:00
Mads Rasmussen 1b04ec779d use addUniquePaths for modal registration 2025-02-13 10:18:14 +01:00
Mads Rasmussen cf34d1972f fix types 2025-02-12 21:30:04 +01:00
Mads Rasmussen c075debaa8 use api prop instead of context 2025-02-12 20:55:11 +01:00
Mads Rasmussen 9b3f45d65a use api prop instead of context 2025-02-12 20:47:09 +01:00
Mads Rasmussen 41a0c11285 pass context type 2025-02-12 20:31:27 +01:00
Mads Rasmussen a1444b5b2e pass model type 2025-02-12 20:29:56 +01:00
Mads Rasmussen dc1b5ce930 update method names 2025-02-12 20:25:29 +01:00
Mads Rasmussen f218486ca6 update method name 2025-02-12 16:59:22 +01:00
Mads Rasmussen dbb744dda5 Merge branch 'v15/feature/entity-item-ref-extension' into v15/feature/display-current-variant-item-name 2025-02-12 16:50:32 +01:00
Mads Rasmussen d43c6cbeef Merge branch 'v15/dev' into v15/feature/entity-item-ref-extension 2025-02-12 16:50:09 +01:00
Mads Rasmussen 9b478241ee update observed value when a new item is set 2025-02-12 16:49:38 +01:00
Mads RasmussenandGitHub fe1fbea8bb Merge branch 'v15/dev' into v15/feature/entity-item-ref-extension 2025-02-12 12:34:18 +01:00
Mads Rasmussen ff164c7235 observe name and state 2025-02-11 22:20:47 +01:00
Mads Rasmussen f6ac0e45ac get icon from document type object 2025-02-11 22:16:41 +01:00
Mads Rasmussen cdcbf3197d align models 2025-02-11 21:44:15 +01:00
Mads Rasmussen 029cc3cfa6 use const 2025-02-11 20:44:10 +01:00
Mads Rasmussen ef1638b853 add observable state 2025-02-11 20:43:52 +01:00
Mads Rasmussen 6f7cc8e7c0 add data resolver to tree item 2025-02-11 19:16:12 +01:00
Mads Rasmussen 0ae2420efa use observables in document item ref 2025-02-11 19:13:55 +01:00
Mads Rasmussen 2b0ae998e1 add observables 2025-02-11 19:13:39 +01:00
Mads Rasmussen f45ae29d25 export resolver 2025-02-11 15:47:56 +01:00
Mads Rasmussen e47217e25c add more helpers to data resolver 2025-02-11 15:47:44 +01:00
Mads Rasmussen 9be6d8196c generate server models 2025-02-11 14:13:33 +01:00
Mads Rasmussen 212ae20ed7 Merge branch 'v15/feature/reference-types' into v15/feature/$type-data-mapper-extension 2025-02-11 14:12:59 +01:00
Mads Rasmussen cb4df7584b Merge branch 'v15/feature/entity-item-ref-extension' into v15/feature/$type-data-mapper-extension 2025-02-11 14:12:35 +01:00
Mads Rasmussen e8ad351133 Merge branch 'v15/dev' into v15/feature/entity-item-ref-extension 2025-02-11 14:12:14 +01:00
Mads Rasmussen 7fe30d7c75 Update document-item-ref.element.ts 2025-02-11 13:18:45 +01:00
Mads Rasmussen 0c15b411be render draft as a tag 2025-02-11 13:18:02 +01:00
Mads Rasmussen 2cb20c8f10 move logic to item data resolver 2025-02-11 13:14:43 +01:00
Sven Geusens 08d3add9af Added $type to ReferenceResponseModels 2025-02-11 12:59:38 +01:00
Mads Rasmussen 80b144ea0f implement for document item ref 2025-02-11 11:23:39 +01:00
Mads Rasmussen 4988c80f0c Merge branch 'v15/feature/entity-item-ref-extension' into v15/feature/$type-data-mapper-extension 2025-02-11 10:47:19 +01:00
Mads Rasmussen b52175078f fix console warning 2025-02-11 10:46:52 +01:00
Mads Rasmussen 3c67f00448 only recreate the controller if the entity type changes 2025-02-11 10:15:20 +01:00
Mads Rasmussen 494fcbe025 compare with old value 2025-02-11 10:03:26 +01:00
Mads Rasmussen 13d5feaf30 append unique 2025-02-11 10:03:15 +01:00
Mads Rasmussen 0f727288bc Update member-item-ref.element.ts 2025-02-11 09:54:02 +01:00
Mads Rasmussen ed0deb6284 remove unused id 2025-02-11 09:53:20 +01:00
Mads Rasmussen a76b30a93a add unique to modal router 2025-02-11 09:53:09 +01:00
Mads Rasmussen fa491109f1 add unique to modal route registration 2025-02-11 09:36:55 +01:00
Mads Rasmussen 4ffa3d6130 wip data mapper concept 2025-02-10 15:00:34 +01:00
Mads Rasmussen 4394db3cce show 3 references 2025-02-10 11:31:58 +01:00
Mads Rasmussen e446c42bae Merge branch 'v15/feature/entity-item-ref-extension' into v15/feature/delete-referenced-by 2025-02-10 11:26:41 +01:00
Mads Rasmussen 0afe46c04d add fallback element 2025-02-10 10:51:20 +01:00
Mads Rasmussen e940f6ebdf Merge branch 'v15/dev' into v15/feature/entity-item-ref-extension 2025-02-10 09:35:40 +01:00
Mads Rasmussen dbd27cc0b6 register media item ref 2025-02-09 19:55:21 +01:00
Mads Rasmussen 93aa0ea16f change to use entity-item-ref element 2025-02-09 19:54:54 +01:00
Mads Rasmussen c1276e478f add null check 2025-02-09 19:54:24 +01:00
Mads Rasmussen dea4393b12 Merge branch 'v15/feature/entity-item-ref-extension' into v15/feature/delete-referenced-by 2025-02-08 19:34:30 +01:00
Mads Rasmussen 95c12ec778 check for section permission 2025-02-08 19:33:06 +01:00
Mads Rasmussen 33f37591d8 remove unused 2025-02-08 19:32:45 +01:00
Mads Rasmussen efe75be3d7 remove unused 2025-02-07 21:48:38 +01:00
Mads Rasmussen 726d07dc59 remove open button 2025-02-07 14:57:04 +01:00
Mads Rasmussen 914953b3ee Fix user item ref 2025-02-07 14:54:48 +01:00
Mads Rasmussen d70fb9581a Update member-item-ref.element.ts 2025-02-07 14:33:59 +01:00
Mads Rasmussen 1088b04948 make editPath a state 2025-02-07 14:32:48 +01:00
Mads Rasmussen db9b9d3441 pass readonly and standalone props 2025-02-07 14:19:24 +01:00
Mads Rasmussen 1adf436e5c implement for user input 2025-02-07 14:06:31 +01:00
Mads Rasmussen f4547b5d3f move item repository 2025-02-07 13:44:13 +01:00
Mads Rasmussen 3aba5686cb add draft styling back 2025-02-07 13:34:31 +01:00
Mads Rasmussen a98e3db4f0 use member element 2025-02-07 13:34:21 +01:00
Mads Rasmussen b986ebd618 fix sorting again 2025-02-07 12:53:31 +01:00
Mads Rasmussen e1cbf73887 fix sorting again 2025-02-07 12:53:13 +01:00
Mads Rasmussen 964e86ca77 add null check 2025-02-07 12:53:04 +01:00
Mads Rasmussen d073ab50ed enable action slot 2025-02-07 12:43:42 +01:00
Mads Rasmussen 5b0444ffa2 implement for input member 2025-02-06 23:15:58 +01:00
Mads Rasmussen 5901d4a156 move item repo 2025-02-06 23:03:38 +01:00
Mads Rasmussen 0731f66f66 Update document-item-ref.element.ts 2025-02-06 22:36:08 +01:00
Mads Rasmussen 977b047d8e fix styling 2025-02-06 22:27:59 +01:00
Mads Rasmussen fd06887aa1 add ref list element 2025-02-06 22:27:54 +01:00
Mads Rasmussen 62f1bd7d43 clean up 2025-02-06 22:23:47 +01:00
Mads Rasmussen edb6a7c40f wip entity-item-ref extension point 2025-02-06 22:10:47 +01:00
Mads Rasmussen e7348f56eb Merge branch 'v15/dev' into v15/feature/delete-referenced-by 2025-02-06 14:44:41 +01:00
Mads Rasmussen f99562a47c add referenceRepository to media trash action 2025-02-06 12:54:46 +01:00
Mads Rasmussen 9ccb58acca make referenceRepo optional + adjust styling 2025-02-06 12:51:29 +01:00
Mads Rasmussen 01516bb142 add trash confirm modal 2025-02-06 10:34:17 +01:00
48 changed files with 861 additions and 81 deletions
@@ -510,6 +510,7 @@ export default {
confirmremoveusageof: 'Are you sure you want to remove the usage of <strong>%0%</strong>',
confirmlogout: 'Are you sure?',
confirmSure: 'Are you sure?',
confirmTrash: (name: string) => `Are you sure you want to move <strong>${name}</strong> to the Recycle Bin?`,
cut: 'Cut',
editDictionary: 'Edit dictionary item',
editLanguage: 'Edit language',
@@ -5,17 +5,19 @@ import { UUIRefNodeElement } from '@umbraco-cms/backoffice/external/uui';
@customElement('umb-ref-item')
export class UmbRefItemElement extends UmbElementMixin(UUIRefNodeElement) {
@property({ type: String })
icon = '';
icon? = '';
#iconElement = document.createElement('umb-icon');
protected override firstUpdated(_changedProperties: PropertyValues): void {
super.firstUpdated(_changedProperties);
// Temporary fix for the icon appending, this could in the future be changed to override a renderIcon method, or other ways to make this happen without appending children.
this.#iconElement.setAttribute('slot', 'icon');
this.#iconElement.setAttribute('name', this.icon);
this.appendChild(this.#iconElement);
if (this.icon) {
// Temporary fix for the icon appending, this could in the future be changed to override a renderIcon method, or other ways to make this happen without appending children.
this.#iconElement.setAttribute('slot', 'icon');
this.#iconElement.setAttribute('name', this.icon);
this.appendChild(this.#iconElement);
}
}
static override styles = [
@@ -1 +1,2 @@
export * from './create/constants.js';
export * from './delete/constants.js';
@@ -0,0 +1 @@
export { UMB_ENTITY_ACTION_DELETE_KIND_MANIFEST } from './delete.action.kind.js';
@@ -1,7 +1,7 @@
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 = {
export const UMB_ENTITY_ACTION_DELETE_KIND_MANIFEST: UmbExtensionManifestKind = {
type: 'kind',
alias: 'Umb.Kind.EntityAction.Delete',
matchKind: 'delete',
@@ -22,3 +22,5 @@ export const manifest: UmbExtensionManifestKind = {
},
},
};
export const manifest = UMB_ENTITY_ACTION_DELETE_KIND_MANIFEST;
@@ -7,13 +7,45 @@ import type { UmbDetailRepository, UmbItemRepository } from '@umbraco-cms/backof
import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action';
import { UmbLocalizationController } from '@umbraco-cms/backoffice/localization-api';
export class UmbDeleteEntityAction extends UmbEntityActionBase<MetaEntityActionDeleteKind> {
export class UmbDeleteEntityAction<
MetaKind extends MetaEntityActionDeleteKind = MetaEntityActionDeleteKind,
> extends UmbEntityActionBase<MetaKind> {
// TODO: make base type for item and detail models
#localize = new UmbLocalizationController(this);
override async execute() {
if (!this.args.unique) throw new Error('Cannot delete an item without a unique identifier.');
const item = await this.#requestItem();
await this._confirmDelete(item);
const detailRepository = await createExtensionApiByAlias<UmbDetailRepository<any>>(
this,
this.args.meta.detailRepositoryAlias,
);
await detailRepository.delete(this.args.unique);
await this.#notify();
}
async _confirmDelete(item: any) {
const headline = this.args.meta.confirm?.headline ?? '#actions_delete';
const message = this.args.meta.confirm?.message ?? '#defaultdialogs_confirmdelete';
// TODO: handle items with variants
await umbConfirmModal(this._host, {
headline,
content: this.#localize.string(message, item.name),
color: 'danger',
confirmLabel: '#general_delete',
});
}
async #requestItem() {
if (!this.args.unique) throw new Error('Cannot delete an item without a unique identifier.');
const itemRepository = await createExtensionApiByAlias<UmbItemRepository<any>>(
this,
this.args.meta.itemRepositoryAlias,
@@ -23,24 +55,12 @@ export class UmbDeleteEntityAction extends UmbEntityActionBase<MetaEntityActionD
const item = data?.[0];
if (!item) throw new Error('Item not found.');
const headline = this.args.meta.confirm?.headline ?? '#actions_delete';
const message = this.args.meta.confirm?.message ?? '#defaultdialogs_confirmdelete';
// TODO: handle items with variants
await umbConfirmModal(this._host, {
headline,
content: this.#localize.string(message, item.name),
color: 'danger',
confirmLabel: '#general_delete',
});
const detailRepository = await createExtensionApiByAlias<UmbDetailRepository<any>>(
this,
this.args.meta.detailRepositoryAlias,
);
await detailRepository.delete(this.args.unique);
return item;
}
async #notify() {
const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT);
const event = new UmbRequestReloadStructureForEntityEvent({
unique: this.args.unique,
entityType: this.args.entityType,
@@ -0,0 +1 @@
export type * from './delete/types.js';
@@ -1,5 +1,6 @@
import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity';
export type * from './common/types.js';
export type * from './default/types.js';
export type * from './entity-action-element.interface.js';
export type * from './entity-action.extension.js';
@@ -1 +1,2 @@
export * from './restore-from-recycle-bin/constants.js';
export * from './trash/constants.js';
@@ -0,0 +1 @@
export { UMB_ENTITY_ACTION_TRASH_KIND_MANIFEST } from './trash.action.kind.js';
@@ -1,7 +1,7 @@
import { UMB_ENTITY_ACTION_DEFAULT_KIND_MANIFEST } from '../../../entity-action/default/default.action.kind.js';
import type { UmbExtensionManifestKind } from '@umbraco-cms/backoffice/extension-registry';
export const manifest: UmbExtensionManifestKind = {
export const UMB_ENTITY_ACTION_TRASH_KIND_MANIFEST: UmbExtensionManifestKind = {
type: 'kind',
alias: 'Umb.Kind.EntityAction.Trash',
matchKind: 'trash',
@@ -12,13 +12,12 @@ export const manifest: UmbExtensionManifestKind = {
kind: 'trash',
api: () => import('./trash.action.js'),
weight: 1150,
forEntityTypes: [],
meta: {
icon: 'icon-trash',
label: '#actions_trash',
itemRepositoryAlias: '',
recycleBinRepositoryAlias: '',
additionalOptions: true,
},
},
};
export const manifest = UMB_ENTITY_ACTION_TRASH_KIND_MANIFEST;
@@ -1,19 +1,23 @@
import { UmbEntityActionBase } from '../../../entity-action/entity-action-base.js';
import { UmbRequestReloadStructureForEntityEvent } from '../../../entity-action/request-reload-structure-for-entity.event.js';
import type { UmbRecycleBinRepository } from '../../recycle-bin-repository.interface.js';
import type { MetaEntityActionTrashKind } from './types.js';
import { UmbEntityTrashedEvent } from './trash.event.js';
import { createExtensionApiByAlias } from '@umbraco-cms/backoffice/extension-registry';
import { umbConfirmModal } from '@umbraco-cms/backoffice/modal';
import type { UmbItemRepository } from '@umbraco-cms/backoffice/repository';
import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action';
import type { UmbItemRepository } from '@umbraco-cms/backoffice/repository';
import { UmbEntityActionBase, UmbRequestReloadStructureForEntityEvent } from '@umbraco-cms/backoffice/entity-action';
import { UmbLocalizationController } from '@umbraco-cms/backoffice/localization-api';
/**
* Entity action for trashing an item.
* @class UmbTrashEntityAction
* @augments {UmbEntityActionBase<MetaEntityActionTrashKind>}
*/
export class UmbTrashEntityAction extends UmbEntityActionBase<MetaEntityActionTrashKind> {
export class UmbTrashEntityAction<
MetaKindType extends MetaEntityActionTrashKind = MetaEntityActionTrashKind,
> extends UmbEntityActionBase<MetaKindType> {
#localize = new UmbLocalizationController(this);
/**
* Executes the action.
* @memberof UmbTrashEntityAction
@@ -21,6 +25,36 @@ export class UmbTrashEntityAction extends UmbEntityActionBase<MetaEntityActionTr
override async execute() {
if (!this.args.unique) throw new Error('Cannot trash an item without a unique identifier.');
const item = await this.#requestItem();
await this._confirmTrash(item);
const recycleBinRepository = await createExtensionApiByAlias<UmbRecycleBinRepository>(
this,
this.args.meta.recycleBinRepositoryAlias,
);
await recycleBinRepository.requestTrash({ unique: this.args.unique });
this.#notify();
}
protected async _confirmTrash(item: any) {
const headline = '#actions_trash';
const message = '#defaultdialogs_confirmTrash';
// TODO: handle items with variants
await umbConfirmModal(this._host, {
headline,
content: this.#localize.string(message, item.name),
color: 'danger',
confirmLabel: '#actions_trash',
});
}
async #requestItem() {
if (!this.args.unique) throw new Error('Cannot trash an item without a unique identifier.');
const itemRepository = await createExtensionApiByAlias<UmbItemRepository<any>>(
this,
this.args.meta.itemRepositoryAlias,
@@ -29,22 +63,7 @@ export class UmbTrashEntityAction extends UmbEntityActionBase<MetaEntityActionTr
const { data } = await itemRepository.requestItems([this.args.unique]);
const item = data?.[0];
if (!item) throw new Error('Item not found.');
// TODO: handle items with variants
await umbConfirmModal(this._host, {
headline: `Trash`,
content: `Are you sure you want to move ${item.name} to the recycle bin?`,
color: 'danger',
confirmLabel: 'Trash',
});
const recycleBinRepository = await createExtensionApiByAlias<UmbRecycleBinRepository>(
this,
this.args.meta.recycleBinRepositoryAlias,
);
await recycleBinRepository.requestTrash({ unique: this.args.unique });
this.#notify();
return item;
}
async #notify() {
@@ -2,6 +2,7 @@ import { UMB_DOCUMENT_DETAIL_REPOSITORY_ALIAS } from '../repository/index.js';
import { UMB_DOCUMENT_ITEM_REPOSITORY_ALIAS } from '../item/constants.js';
import { UMB_DOCUMENT_ENTITY_TYPE } from '../entity.js';
import { UMB_USER_PERMISSION_DOCUMENT_DELETE } from '../user-permissions/constants.js';
import { UMB_DOCUMENT_REFERENCE_REPOSITORY_ALIAS } from '../reference/constants.js';
import { manifests as createBlueprintManifests } from './create-blueprint/manifests.js';
import { manifests as createManifests } from './create/manifests.js';
import { manifests as cultureAndHostnamesManifests } from './culture-and-hostnames/manifests.js';
@@ -15,13 +16,14 @@ import { UMB_ENTITY_IS_TRASHED_CONDITION_ALIAS } from '@umbraco-cms/backoffice/r
const entityActions: Array<UmbExtensionManifest> = [
{
type: 'entityAction',
kind: 'delete',
kind: 'deleteWithRelation',
alias: 'Umb.EntityAction.Document.Delete',
name: 'Delete Document Entity Action',
forEntityTypes: [UMB_DOCUMENT_ENTITY_TYPE],
meta: {
itemRepositoryAlias: UMB_DOCUMENT_ITEM_REPOSITORY_ALIAS,
detailRepositoryAlias: UMB_DOCUMENT_DETAIL_REPOSITORY_ALIAS,
referenceRepositoryAlias: UMB_DOCUMENT_REFERENCE_REPOSITORY_ALIAS,
},
conditions: [
{
@@ -5,6 +5,7 @@ import {
UMB_USER_PERMISSION_DOCUMENT_DELETE,
UMB_USER_PERMISSION_DOCUMENT_MOVE,
} from '../../constants.js';
import { UMB_DOCUMENT_REFERENCE_REPOSITORY_ALIAS } from '../../reference/constants.js';
import { UMB_DOCUMENT_ITEM_REPOSITORY_ALIAS } from '../../item/constants.js';
import {
UMB_ENTITY_IS_NOT_TRASHED_CONDITION_ALIAS,
@@ -14,13 +15,14 @@ import {
export const manifests: Array<UmbExtensionManifest> = [
{
type: 'entityAction',
kind: 'trash',
kind: 'trashWithRelation',
alias: 'Umb.EntityAction.Document.RecycleBin.Trash',
name: 'Trash Document Entity Action',
forEntityTypes: [UMB_DOCUMENT_ENTITY_TYPE],
meta: {
itemRepositoryAlias: UMB_DOCUMENT_ITEM_REPOSITORY_ALIAS,
recycleBinRepositoryAlias: UMB_DOCUMENT_RECYCLE_BIN_REPOSITORY_ALIAS,
referenceRepositoryAlias: UMB_DOCUMENT_REFERENCE_REPOSITORY_ALIAS,
},
conditions: [
{
@@ -44,7 +44,8 @@ export class UmbDocumentReferenceTableElement extends UmbLitElement {
}
if (!data) return;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
this._items = data.items;
this._hasMoreReferences = data.total > this.#pageSize ? data.total - this.#pageSize : 0;
}
@@ -1,8 +1,9 @@
import { UmbDocumentReferenceServerDataSource } from './document-reference.server.data.js';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbEntityReferenceRepository } from '@umbraco-cms/backoffice/relations';
export class UmbDocumentReferenceRepository extends UmbControllerBase {
export class UmbDocumentReferenceRepository extends UmbControllerBase implements UmbEntityReferenceRepository {
#referenceSource: UmbDocumentReferenceServerDataSource;
constructor(host: UmbControllerHost) {
@@ -14,6 +15,11 @@ export class UmbDocumentReferenceRepository extends UmbControllerBase {
if (!unique) throw new Error(`unique is required`);
return this.#referenceSource.getReferencedBy(unique, skip, take);
}
async requestDescendantsWithReferences(unique: string, skip = 0, take = 20) {
if (!unique) throw new Error(`unique is required`);
return this.#referenceSource.getReferencedDescendants(unique, skip, take);
}
}
export default UmbDocumentReferenceRepository;
@@ -1,22 +1,32 @@
import { UMB_DOCUMENT_ENTITY_TYPE } from '../../entity.js';
import { DocumentService } from '@umbraco-cms/backoffice/external/backend-api';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity';
import type { UmbEntityReferenceDataSource, UmbReferenceItemModel } from '@umbraco-cms/backoffice/relations';
import type { UmbPagedModel, UmbDataSourceResponse } from '@umbraco-cms/backoffice/repository';
import { UmbManagementApiDataMapper } from '@umbraco-cms/backoffice/repository';
/**
* @class UmbDocumentReferenceServerDataSource
* @implements {RepositoryDetailDataSource}
*/
export class UmbDocumentReferenceServerDataSource extends UmbControllerBase {
export class UmbDocumentReferenceServerDataSource extends UmbControllerBase implements UmbEntityReferenceDataSource {
#dataMapper = new UmbManagementApiDataMapper(this);
/**
* Fetches the item for the given unique from the server
* @param {string} unique - The unique identifier of the item to fetch
* @returns {*}
* @param {number} skip - The number of items to skip
* @param {number} take - The number of items to take
* @returns {Promise<UmbDataSourceResponse<UmbPagedModel<UmbReferenceItemModel>>>} - Items that are referenced by the given unique
* @memberof UmbDocumentReferenceServerDataSource
*/
async getReferencedBy(unique: string, skip = 0, take = 20) {
async getReferencedBy(
unique: string,
skip = 0,
take = 20,
): Promise<UmbDataSourceResponse<UmbPagedModel<UmbReferenceItemModel>>> {
const { data, error } = await tryExecuteAndNotify(
this,
DocumentService.getDocumentByIdReferencedBy({ id: unique, skip, take }),
@@ -44,4 +54,36 @@ export class UmbDocumentReferenceServerDataSource extends UmbControllerBase {
return { data, error };
}
/**
* Returns any descendants of the given unique that is referenced by other items
* @param {string} unique - The unique identifier of the item to fetch descendants for
* @param {number} skip - The number of items to skip
* @param {number} take - The number of items to take
* @returns {Promise<UmbDataSourceResponse<UmbPagedModel<UmbEntityModel>>>} - Any descendants of the given unique that is referenced by other items
* @memberof UmbDocumentReferenceServerDataSource
*/
async getReferencedDescendants(
unique: string,
skip: number = 0,
take: number = 20,
): Promise<UmbDataSourceResponse<UmbPagedModel<UmbEntityModel>>> {
const { data, error } = await tryExecuteAndNotify(
this,
DocumentService.getDocumentByIdReferencedDescendants({ id: unique, skip, take }),
);
if (data) {
const items: Array<UmbEntityModel> = data.items.map((item) => {
return {
unique: item.id,
entityType: UMB_DOCUMENT_ENTITY_TYPE,
};
});
return { data: { items, total: data.total } };
}
return { data, error };
}
}
@@ -1,4 +1,8 @@
import { UMB_MEDIA_DETAIL_REPOSITORY_ALIAS, UMB_MEDIA_ITEM_REPOSITORY_ALIAS } from '../constants.js';
import {
UMB_MEDIA_DETAIL_REPOSITORY_ALIAS,
UMB_MEDIA_ITEM_REPOSITORY_ALIAS,
UMB_MEDIA_REFERENCE_REPOSITORY_ALIAS,
} from '../constants.js';
import { UMB_MEDIA_ENTITY_TYPE } from '../entity.js';
import { manifests as createManifests } from './create/manifests.js';
import { manifests as moveManifests } from './move-to/manifests.js';
@@ -11,11 +15,12 @@ export const manifests: Array<UmbExtensionManifest> = [
type: 'entityAction',
alias: 'Umb.EntityAction.Media.Delete',
name: 'Delete Media Entity Action ',
kind: 'delete',
kind: 'deleteWithRelation',
forEntityTypes: [UMB_MEDIA_ENTITY_TYPE],
meta: {
itemRepositoryAlias: UMB_MEDIA_ITEM_REPOSITORY_ALIAS,
detailRepositoryAlias: UMB_MEDIA_DETAIL_REPOSITORY_ALIAS,
referenceRepositoryAlias: UMB_MEDIA_REFERENCE_REPOSITORY_ALIAS,
},
conditions: [
{
@@ -4,7 +4,7 @@ export const manifests: Array<UmbExtensionManifest> = [
{
type: 'entityItemRef',
alias: 'Umb.EntityItemRef.Media',
name: 'Member Entity Item Reference',
name: 'Media Entity Item Reference',
element: () => import('./media-item-ref.element.js'),
forEntityTypes: [UMB_MEDIA_ENTITY_TYPE],
},
@@ -4,6 +4,7 @@ import {
UMB_MEDIA_ENTITY_TYPE,
} from '../../constants.js';
import { UMB_MEDIA_RECYCLE_BIN_ROOT_ENTITY_TYPE, UMB_MEDIA_RECYCLE_BIN_REPOSITORY_ALIAS } from '../constants.js';
import { UMB_MEDIA_REFERENCE_REPOSITORY_ALIAS } from '../../reference/constants.js';
import {
UMB_ENTITY_IS_NOT_TRASHED_CONDITION_ALIAS,
UMB_ENTITY_IS_TRASHED_CONDITION_ALIAS,
@@ -12,13 +13,14 @@ import {
export const manifests: Array<UmbExtensionManifest> = [
{
type: 'entityAction',
kind: 'trash',
kind: 'trashWithRelation',
alias: 'Umb.EntityAction.Media.RecycleBin.Trash',
name: 'Trash Media Entity Action',
forEntityTypes: [UMB_MEDIA_ENTITY_TYPE],
meta: {
itemRepositoryAlias: UMB_MEDIA_ITEM_REPOSITORY_ALIAS,
recycleBinRepositoryAlias: UMB_MEDIA_RECYCLE_BIN_REPOSITORY_ALIAS,
referenceRepositoryAlias: UMB_MEDIA_REFERENCE_REPOSITORY_ALIAS,
},
conditions: [
{
@@ -1,8 +1,9 @@
import { UmbMediaReferenceServerDataSource } from './media-reference.server.data.js';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbEntityReferenceRepository } from '@umbraco-cms/backoffice/relations';
export class UmbMediaReferenceRepository extends UmbControllerBase {
export class UmbMediaReferenceRepository extends UmbControllerBase implements UmbEntityReferenceRepository {
#referenceSource: UmbMediaReferenceServerDataSource;
constructor(host: UmbControllerHost) {
@@ -14,6 +15,11 @@ export class UmbMediaReferenceRepository extends UmbControllerBase {
if (!unique) throw new Error(`unique is required`);
return this.#referenceSource.getReferencedBy(unique, skip, take);
}
async requestDescendantsWithReferences(unique: string, skip = 0, take = 20) {
if (!unique) throw new Error(`unique is required`);
return this.#referenceSource.getReferencedDescendants(unique, skip, take);
}
}
export default UmbMediaReferenceRepository;
@@ -1,22 +1,32 @@
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { UMB_MEDIA_ENTITY_TYPE } from '../../entity.js';
import { MediaService } from '@umbraco-cms/backoffice/external/backend-api';
import { UmbManagementApiDataMapper } from '@umbraco-cms/backoffice/repository';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity';
import type { UmbEntityReferenceDataSource, UmbReferenceItemModel } from '@umbraco-cms/backoffice/relations';
import type { UmbPagedModel, UmbDataSourceResponse } from '@umbraco-cms/backoffice/repository';
/**
* @class UmbMediaReferenceServerDataSource
* @implements {RepositoryDetailDataSource}
*/
export class UmbMediaReferenceServerDataSource extends UmbControllerBase {
export class UmbMediaReferenceServerDataSource extends UmbControllerBase implements UmbEntityReferenceDataSource {
#dataMapper = new UmbManagementApiDataMapper(this);
/**
* Fetches the item for the given id from the server
* Fetches the item for the given unique from the server
* @param {string} unique - The unique identifier of the item to fetch
* @returns {*}
* @param {number} skip - The number of items to skip
* @param {number} take - The number of items to take
* @returns {Promise<UmbDataSourceResponse<UmbPagedModel<UmbReferenceItemModel>>>} - Items that are referenced by the given unique
* @memberof UmbMediaReferenceServerDataSource
*/
async getReferencedBy(unique: string, skip = 0, take = 20) {
async getReferencedBy(
unique: string,
skip: number = 0,
take: number = 20,
): Promise<UmbDataSourceResponse<UmbPagedModel<UmbReferenceItemModel>>> {
const { data, error } = await tryExecuteAndNotify(
this,
MediaService.getMediaByIdReferencedBy({ id: unique, skip, take }),
@@ -44,4 +54,36 @@ export class UmbMediaReferenceServerDataSource extends UmbControllerBase {
return { data, error };
}
/**
* Returns any descendants of the given unique that is referenced by other items
* @param {string} unique - The unique identifier of the item to fetch descendants for
* @param {number} skip - The number of items to skip
* @param {number} take - The number of items to take
* @returns {Promise<UmbDataSourceResponse<UmbPagedModel<UmbEntityModel>>>} - Any descendants of the given unique that is referenced by other items
* @memberof UmbMediaReferenceServerDataSource
*/
async getReferencedDescendants(
unique: string,
skip: number = 0,
take: number = 20,
): Promise<UmbDataSourceResponse<UmbPagedModel<UmbEntityModel>>> {
const { data, error } = await tryExecuteAndNotify(
this,
MediaService.getMediaByIdReferencedDescendants({ id: unique, skip, take }),
);
if (data) {
const items: Array<UmbEntityModel> = data.items.map((item) => {
return {
unique: item.id,
entityType: UMB_MEDIA_ENTITY_TYPE,
};
});
return { data: { items, total: data.total } };
}
return { data, error };
}
}
@@ -2,8 +2,9 @@ import { manifests as menuManifests } from './menu/manifests.js';
import { manifests as relationManifests } from './relations/manifests.js';
import { manifests as relationTypeManifests } from './relation-types/manifests.js';
import { manifests as workspaceManifests } from './workspace/manifests.js';
import type { UmbExtensionManifestKind } from '@umbraco-cms/backoffice/extension-registry';
export const manifests: Array<UmbExtensionManifest> = [
export const manifests: Array<UmbExtensionManifest | UmbExtensionManifestKind> = [
...menuManifests,
...relationManifests,
...relationTypeManifests,
@@ -1,2 +1,4 @@
export * from './collection/constants.js';
export { UMB_RELATION_ENTITY_TYPE } from './entity.js';
export * from './collection/constants.js';
export * from './entity-actions/delete/constants.js';
export * from './entity-actions/trash/constants.js';
@@ -0,0 +1 @@
export * from './modal/constants.js';
@@ -0,0 +1,15 @@
import type { UmbExtensionManifestKind } from '@umbraco-cms/backoffice/extension-registry';
import { UMB_ENTITY_ACTION_DELETE_KIND_MANIFEST } from '@umbraco-cms/backoffice/entity-action';
export const manifest: UmbExtensionManifestKind = {
type: 'kind',
alias: 'Umb.Kind.EntityAction.DeleteWithRelation',
matchKind: 'deleteWithRelation',
matchType: 'entityAction',
manifest: {
...UMB_ENTITY_ACTION_DELETE_KIND_MANIFEST.manifest,
type: 'entityAction',
kind: 'deleteWithRelation',
api: () => import('./delete-with-relation.action.js'),
},
};
@@ -0,0 +1,30 @@
import type { MetaEntityActionDeleteWithRelationKind } from './types.js';
import { UMB_DELETE_WITH_RELATION_CONFIRM_MODAL } from './modal/constants.js';
import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import { UmbDeleteEntityAction } from '@umbraco-cms/backoffice/entity-action';
/**
* Entity action for deleting an item with relations.
* @class UmbDeleteWithRelationEntityAction
* @augments {UmbEntityActionBase<MetaEntityActionDeleteWithRelationKind>}
*/
export class UmbDeleteWithRelationEntityAction extends UmbDeleteEntityAction<MetaEntityActionDeleteWithRelationKind> {
override async _confirmDelete() {
if (!this.args.unique) throw new Error('Cannot delete an item without a unique identifier.');
const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT);
const modal = modalManager.open(this, UMB_DELETE_WITH_RELATION_CONFIRM_MODAL, {
data: {
unique: this.args.unique,
entityType: this.args.entityType,
itemRepositoryAlias: this.args.meta.itemRepositoryAlias,
referenceRepositoryAlias: this.args.meta.referenceRepositoryAlias,
},
});
await modal.onSubmit();
}
}
export { UmbDeleteWithRelationEntityAction as api };
@@ -0,0 +1,2 @@
export * from './delete-with-relation.action.js';
export type * from './types.js';
@@ -0,0 +1,9 @@
import { manifest as deleteKindManifest } from './delete-with-relation.action.kind.js';
import { manifests as modalManifests } from './modal/manifests.js';
import type { UmbExtensionManifestKind } from '@umbraco-cms/backoffice/extension-registry';
export const manifests: Array<UmbExtensionManifest | UmbExtensionManifestKind> = [
deleteKindManifest,
...modalManifests,
];
@@ -0,0 +1 @@
export * from './delete-with-relation-modal.token.js';
@@ -0,0 +1,107 @@
import type {
UmbDeleteWithRelationConfirmModalData,
UmbDeleteWithRelationConfirmModalValue,
} from './delete-with-relation-modal.token.js';
import {
html,
customElement,
css,
state,
type PropertyValues,
nothing,
unsafeHTML,
} from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
import { umbFocus } from '@umbraco-cms/backoffice/lit-element';
import type { UmbItemRepository } from '@umbraco-cms/backoffice/repository';
import { createExtensionApiByAlias } from '@umbraco-cms/backoffice/extension-registry';
import '../../local-components/confirm-action-entity-references.element.js';
@customElement('umb-delete-with-relation-confirm-modal')
export class UmbDeleteWithRelationConfirmModalElement extends UmbModalBaseElement<
UmbDeleteWithRelationConfirmModalData,
UmbDeleteWithRelationConfirmModalValue
> {
@state()
_name?: string;
@state()
_referencesConfig?: any;
#itemRepository?: UmbItemRepository<any>;
protected override firstUpdated(_changedProperties: PropertyValues): void {
super.firstUpdated(_changedProperties);
this.#initData();
}
async #initData() {
if (!this.data) {
this.#itemRepository?.destroy();
return;
}
this.#itemRepository = await createExtensionApiByAlias<UmbItemRepository<any>>(this, this.data.itemRepositoryAlias);
const { data } = await this.#itemRepository.requestItems([this.data.unique]);
const item = data?.[0];
if (!item) throw new Error('Item not found.');
this._name = item.name;
this._referencesConfig = {
unique: this.data.unique,
itemRepositoryAlias: this.data.itemRepositoryAlias,
referenceRepositoryAlias: this.data.referenceRepositoryAlias,
};
}
override render() {
const headline = this.localize.string('#actions_delete');
const content = this.localize.string('#defaultdialogs_confirmdelete', this._name);
return html`
<uui-dialog-layout class="uui-text" headline=${headline}>
<p>${unsafeHTML(content)}</p>
${this._referencesConfig
? html`<umb-confirm-action-modal-entity-references
.config=${this._referencesConfig}></umb-confirm-action-modal-entity-references>`
: nothing}
<uui-button
slot="actions"
id="cancel"
label=${this.localize.term('general_cancel')}
@click=${this._rejectModal}></uui-button>
<uui-button
slot="actions"
id="confirm"
color="danger"
look="primary"
label=${this.localize.term('general_delete')}
@click=${this._submitModal}
${umbFocus()}></uui-button>
</uui-dialog-layout>
`;
}
static override styles = [
UmbTextStyles,
css`
uui-dialog-layout {
max-inline-size: 60ch;
}
`,
];
}
export { UmbDeleteWithRelationConfirmModalElement as element };
declare global {
interface HTMLElementTagNameMap {
'umb-delete-with-relation-confirm-modal': UmbDeleteWithRelationConfirmModalElement;
}
}
@@ -0,0 +1,19 @@
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
export interface UmbDeleteWithRelationConfirmModalData {
unique: string;
entityType: string;
itemRepositoryAlias: string;
referenceRepositoryAlias: string;
}
export type UmbDeleteWithRelationConfirmModalValue = undefined;
export const UMB_DELETE_WITH_RELATION_CONFIRM_MODAL = new UmbModalToken<
UmbDeleteWithRelationConfirmModalData,
UmbDeleteWithRelationConfirmModalValue
>('Umb.Modal.DeleteWithRelation', {
modal: {
type: 'dialog',
},
});
@@ -0,0 +1,8 @@
export const manifests: Array<UmbExtensionManifest> = [
{
type: 'modal',
alias: 'Umb.Modal.DeleteWithRelation',
name: 'Delete With Relation Modal',
element: () => import('./delete-with-relation-modal.element.js'),
},
];
@@ -0,0 +1,17 @@
import type { ManifestEntityAction, MetaEntityActionDeleteKind } from '@umbraco-cms/backoffice/entity-action';
export interface ManifestEntityActionDeleteWithRelationKind
extends ManifestEntityAction<MetaEntityActionDeleteWithRelationKind> {
type: 'entityAction';
kind: 'deleteWithRelation';
}
export interface MetaEntityActionDeleteWithRelationKind extends MetaEntityActionDeleteKind {
referenceRepositoryAlias: string;
}
declare global {
interface UmbExtensionManifestMap {
umbManifestEntityActionDeleteWithRelationKind: ManifestEntityActionDeleteWithRelationKind;
}
}
@@ -0,0 +1,172 @@
import type { UmbEntityReferenceRepository, UmbReferenceItemModel } from '../../reference/types.js';
import {
html,
customElement,
css,
state,
nothing,
type PropertyValues,
property,
} from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { UmbItemRepository } from '@umbraco-cms/backoffice/repository';
import { createExtensionApiByAlias } from '@umbraco-cms/backoffice/extension-registry';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
@customElement('umb-confirm-action-modal-entity-references')
export class UmbConfirmActionModalEntityReferencesElement extends UmbLitElement {
@property({ type: Object, attribute: false })
config?: {
itemRepositoryAlias: string;
referenceRepositoryAlias: string;
entityType: string;
unique: string;
};
@state()
_referencedByItems: Array<UmbReferenceItemModel> = [];
@state()
_totalReferencedByItems: number = 0;
@state()
_totalDescendantsWithReferences: number = 0;
@state()
_descendantsWithReferences: Array<any> = [];
#itemRepository?: UmbItemRepository<any>;
#referenceRepository?: UmbEntityReferenceRepository;
#limitItems = 3;
protected override firstUpdated(_changedProperties: PropertyValues): void {
super.firstUpdated(_changedProperties);
this.#initData();
}
async #initData() {
if (!this.config) {
this.#itemRepository?.destroy();
this.#referenceRepository?.destroy();
return;
}
if (!this.config?.referenceRepositoryAlias) {
throw new Error('Missing referenceRepositoryAlias in config.');
}
this.#referenceRepository = await createExtensionApiByAlias<UmbEntityReferenceRepository>(
this,
this.config?.referenceRepositoryAlias,
);
if (!this.config?.itemRepositoryAlias) {
throw new Error('Missing itemRepositoryAlias in config.');
}
this.#itemRepository = await createExtensionApiByAlias<UmbItemRepository<any>>(
this,
this.config.itemRepositoryAlias,
);
this.#loadReferencedBy();
this.#loadDescendantsWithReferences();
}
async #loadReferencedBy() {
if (!this.#referenceRepository) {
throw new Error('Failed to create reference repository.');
}
if (!this.config?.unique) {
throw new Error('Missing unique in data.');
}
const { data } = await this.#referenceRepository.requestReferencedBy(this.config.unique, 0, this.#limitItems);
if (data) {
this._referencedByItems = [...data.items];
this._totalReferencedByItems = data.total;
}
}
async #loadDescendantsWithReferences() {
if (!this.#referenceRepository) {
throw new Error('Failed to create reference repository.');
}
if (!this.#itemRepository) {
throw new Error('Failed to create item repository.');
}
// If the repository does not have the method, we don't need to load the referenced descendants.
if (!this.#referenceRepository.requestDescendantsWithReferences) return;
if (!this.config?.unique) {
throw new Error('Missing unique in data.');
}
const { data } = await this.#referenceRepository.requestDescendantsWithReferences(
this.config.unique,
0,
this.#limitItems,
);
if (data) {
this._totalDescendantsWithReferences = data.total;
const uniques = data.items.map((item) => item.unique).filter((unique) => unique) as Array<string>;
const { data: items } = await this.#itemRepository.requestItems(uniques);
this._descendantsWithReferences = items ?? [];
}
}
override render() {
return html`
${this.#renderItems('references_labelDependsOnThis', this._referencedByItems, this._totalReferencedByItems)}
${this.#renderItems(
'references_labelDependentDescendants',
this._descendantsWithReferences,
this._totalDescendantsWithReferences,
)}
`;
}
#renderItems(headline: string, items: Array<UmbReferenceItemModel>, total: number) {
if (total === 0) return nothing;
return html`
<h5 class="uui-h5" id="reference-headline">${this.localize.term(headline)}</h5>
<uui-ref-list>
${items.map(
(item) =>
html`<umb-entity-item-ref .item=${item} readonly ?standalone=${total === 1}></umb-entity-item-ref> `,
)}
</uui-ref-list>
${total > this.#limitItems
? html`<span>${this.localize.term('references_labelMoreReferences', total - this.#limitItems)}</span>`
: nothing}
`;
}
static override styles = [
UmbTextStyles,
css`
#reference-headline {
margin-bottom: var(--uui-size-3);
}
uui-ref-list {
margin-bottom: var(--uui-size-2);
}
`,
];
}
export { UmbConfirmActionModalEntityReferencesElement as element };
declare global {
interface HTMLElementTagNameMap {
'umb-confirm-action-modal-entity-references': UmbConfirmActionModalEntityReferencesElement;
}
}
@@ -0,0 +1 @@
export * from './modal/constants.js';
@@ -0,0 +1,2 @@
export * from './trash-with-relation.action.js';
export type * from './types.js';
@@ -0,0 +1,6 @@
import { manifest as trashKindManifest } from './trash-with-relation.action.kind.js';
import { manifests as modalManifests } from './modal/manifests.js';
import type { UmbExtensionManifestKind } from '@umbraco-cms/backoffice/extension-registry';
export const manifests: Array<UmbExtensionManifest | UmbExtensionManifestKind> = [trashKindManifest, ...modalManifests];
@@ -0,0 +1 @@
export * from './trash-with-relation-modal.token.js';
@@ -0,0 +1,8 @@
export const manifests: Array<UmbExtensionManifest> = [
{
type: 'modal',
alias: 'Umb.Modal.TrashWithRelation',
name: 'Trash With Relation Modal',
element: () => import('./trash-with-relation-modal.element.js'),
},
];
@@ -0,0 +1,105 @@
import type {
UmbTrashWithRelationConfirmModalData,
UmbTrashWithRelationConfirmModalValue,
} from './trash-with-relation-modal.token.js';
import {
html,
customElement,
css,
state,
type PropertyValues,
nothing,
unsafeHTML,
} from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
import { umbFocus } from '@umbraco-cms/backoffice/lit-element';
import type { UmbItemRepository } from '@umbraco-cms/backoffice/repository';
import { createExtensionApiByAlias } from '@umbraco-cms/backoffice/extension-registry';
// import of local component
import '../../local-components/confirm-action-entity-references.element.js';
@customElement('umb-trash-with-relation-confirm-modal')
export class UmbTrashWithRelationConfirmModalElement extends UmbModalBaseElement<
UmbTrashWithRelationConfirmModalData,
UmbTrashWithRelationConfirmModalValue
> {
@state()
_name?: string;
@state()
_referencesConfig?: any;
#itemRepository?: UmbItemRepository<any>;
protected override firstUpdated(_changedProperties: PropertyValues): void {
super.firstUpdated(_changedProperties);
this.#initData();
}
async #initData() {
if (!this.data) {
this.#itemRepository?.destroy();
return;
}
this.#itemRepository = await createExtensionApiByAlias<UmbItemRepository<any>>(this, this.data.itemRepositoryAlias);
const { data } = await this.#itemRepository.requestItems([this.data.unique]);
const item = data?.[0];
if (!item) throw new Error('Item not found.');
this._name = item.name;
this._referencesConfig = {
unique: this.data.unique,
itemRepositoryAlias: this.data.itemRepositoryAlias,
referenceRepositoryAlias: this.data.referenceRepositoryAlias,
};
}
override render() {
const headline = this.localize.string('#actions_trash');
const content = this.localize.string('#defaultdialogs_confirmTrash', this._name);
return html`
<uui-dialog-layout class="uui-text" headline=${headline}>
<p>${unsafeHTML(content)}</p>
${this._referencesConfig
? html`<umb-confirm-action-modal-entity-references
.config=${this._referencesConfig}></umb-confirm-action-modal-entity-references>`
: nothing}
<uui-button slot="actions" id="cancel" label="Cancel" @click=${this._rejectModal}></uui-button>
<uui-button
slot="actions"
id="confirm"
color="danger"
look="primary"
label=${this.localize.term('actions_trash')}
@click=${this._submitModal}
${umbFocus()}></uui-button>
</uui-dialog-layout>
`;
}
static override styles = [
UmbTextStyles,
css`
uui-dialog-layout {
max-inline-size: 60ch;
}
`,
];
}
export { UmbTrashWithRelationConfirmModalElement as element };
declare global {
interface HTMLElementTagNameMap {
'umb-trash-with-relation-confirm-modal': UmbTrashWithRelationConfirmModalElement;
}
}
@@ -0,0 +1,19 @@
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
export interface UmbTrashWithRelationConfirmModalData {
unique: string;
entityType: string;
itemRepositoryAlias: string;
referenceRepositoryAlias: string;
}
export type UmbTrashWithRelationConfirmModalValue = undefined;
export const UMB_TRASH_WITH_RELATION_CONFIRM_MODAL = new UmbModalToken<
UmbTrashWithRelationConfirmModalData,
UmbTrashWithRelationConfirmModalValue
>('Umb.Modal.TrashWithRelation', {
modal: {
type: 'dialog',
},
});
@@ -0,0 +1,15 @@
import type { UmbExtensionManifestKind } from '@umbraco-cms/backoffice/extension-registry';
import { UMB_ENTITY_ACTION_TRASH_KIND_MANIFEST } from '@umbraco-cms/backoffice/recycle-bin';
export const manifest: UmbExtensionManifestKind = {
type: 'kind',
alias: 'Umb.Kind.EntityAction.TrashWithRelation',
matchKind: 'trashWithRelation',
matchType: 'entityAction',
manifest: {
...UMB_ENTITY_ACTION_TRASH_KIND_MANIFEST.manifest,
type: 'entityAction',
kind: 'trashWithRelation',
api: () => import('./trash-with-relation.action.js'),
},
};
@@ -0,0 +1,28 @@
import type { MetaEntityActionTrashWithRelationKind } from './types.js';
import { UMB_TRASH_WITH_RELATION_CONFIRM_MODAL } from './modal/constants.js';
import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import { UmbTrashEntityAction } from '@umbraco-cms/backoffice/recycle-bin';
/**
* Entity action for trashing an item with relations.
* @class UmbTrashWithRelationEntityAction
* @augments {UmbEntityActionBase<MetaEntityActionTrashWithRelationKind>}
*/
export class UmbTrashWithRelationEntityAction extends UmbTrashEntityAction<MetaEntityActionTrashWithRelationKind> {
override async _confirmTrash(item: any) {
const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT);
const modal = modalManager.open(this, UMB_TRASH_WITH_RELATION_CONFIRM_MODAL, {
data: {
unique: item.unique,
entityType: item.entityType,
itemRepositoryAlias: this.args.meta.itemRepositoryAlias,
referenceRepositoryAlias: this.args.meta.referenceRepositoryAlias,
},
});
await modal.onSubmit();
}
}
export { UmbTrashWithRelationEntityAction as api };
@@ -0,0 +1,18 @@
import type { ManifestEntityAction } from '@umbraco-cms/backoffice/entity-action';
import type { MetaEntityActionTrashKind } from '@umbraco-cms/backoffice/recycle-bin';
export interface ManifestEntityActionTrashWithRelationKind
extends ManifestEntityAction<MetaEntityActionTrashWithRelationKind> {
type: 'entityAction';
kind: 'trashWithRelation';
}
export interface MetaEntityActionTrashWithRelationKind extends MetaEntityActionTrashKind {
referenceRepositoryAlias: string;
}
declare global {
interface UmbExtensionManifestMap {
umbManifestEntityActionTrashWithRelationKind: ManifestEntityActionTrashWithRelationKind;
}
}
@@ -1,3 +1,10 @@
import { manifests as collectionManifests } from './collection/manifests.js';
import { manifests as deleteManifests } from './entity-actions/delete/manifests.js';
import { manifests as trashManifests } from './entity-actions/trash/manifests.js';
import type { UmbExtensionManifestKind } from '@umbraco-cms/backoffice/extension-registry';
export const manifests: Array<UmbExtensionManifest> = [...collectionManifests];
export const manifests: Array<UmbExtensionManifest | UmbExtensionManifestKind> = [
...collectionManifests,
...deleteManifests,
...trashManifests,
];
@@ -0,0 +1,42 @@
import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity';
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
import type {
DefaultReferenceResponseModel,
DocumentReferenceResponseModel,
MediaReferenceResponseModel,
} from '@umbraco-cms/backoffice/external/backend-api';
import type { UmbDataSourceResponse, UmbPagedModel, UmbRepositoryResponse } from '@umbraco-cms/backoffice/repository';
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export interface UmbReferenceItemModel extends UmbEntityModel {}
export type UmbReferenceModel =
| DefaultReferenceResponseModel
| DocumentReferenceResponseModel
| MediaReferenceResponseModel;
export interface UmbEntityReferenceRepository extends UmbApi {
requestReferencedBy(
unique: string,
skip?: number,
take?: number,
): Promise<UmbRepositoryResponse<UmbPagedModel<UmbReferenceItemModel>>>;
requestDescendantsWithReferences?(
unique: string,
skip?: number,
take?: number,
): Promise<UmbRepositoryResponse<UmbPagedModel<UmbEntityModel>>>;
}
export interface UmbEntityReferenceDataSource {
getReferencedBy(
unique: string,
skip?: number,
take?: number,
): Promise<UmbDataSourceResponse<UmbPagedModel<UmbReferenceItemModel>>>;
getReferencedDescendants?(
unique: string,
skip?: number,
take?: number,
): Promise<UmbDataSourceResponse<UmbPagedModel<UmbEntityModel>>>;
}
@@ -1,10 +1,5 @@
import type { UmbRelationEntityType } from './entity.js';
import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity';
import type {
DefaultReferenceResponseModel,
DocumentReferenceResponseModel,
MediaReferenceResponseModel,
} from '@umbraco-cms/backoffice/external/backend-api';
export type * from './reference/types.js';
export interface UmbRelationDetailModel {
unique: string;
@@ -23,11 +18,3 @@ export interface UmbRelationDetailModel {
createDate: string;
comment: string | null;
}
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export interface UmbReferenceItemModel extends UmbEntityModel {}
export type UmbReferenceModel =
| DefaultReferenceResponseModel
| DocumentReferenceResponseModel
| MediaReferenceResponseModel;