tree picker create action button

This commit is contained in:
Niels Lyngsø
2024-04-23 12:38:17 +02:00
parent acaa068578
commit 0326b87cfd
5 changed files with 100 additions and 46 deletions

View File

@@ -19,7 +19,11 @@ import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UMB_BLOCK_GRID_TYPE, type UmbBlockGridTypeGroupType } from '@umbraco-cms/backoffice/block-grid';
import type { UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
import { UMB_PROPERTY_DATASET_CONTEXT, type UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property';
import {
UMB_PROPERTY_CONTEXT,
UMB_PROPERTY_DATASET_CONTEXT,
type UmbPropertyDatasetContext,
} from '@umbraco-cms/backoffice/property';
import { UMB_WORKSPACE_MODAL, UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal';
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
@@ -70,6 +74,9 @@ export class UmbPropertyEditorUIBlockGridTypeConfigurationElement
this.#mapValuesToBlockGroups();
}
@state()
public _alias?: string;
@property({ type: Object, attribute: false })
public config?: UmbPropertyEditorConfigCollection;
@@ -86,8 +93,13 @@ export class UmbPropertyEditorUIBlockGridTypeConfigurationElement
constructor() {
super();
this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, async (instance) => {
this.#datasetContext = instance;
this.consumeContext(UMB_PROPERTY_CONTEXT, async (context) => {
this._alias = context.getAlias();
});
this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, async (context) => {
this.#datasetContext = context;
//this.#observeBlocks();
this.#observeBlockGroups();
});
@@ -203,6 +215,7 @@ export class UmbPropertyEditorUIBlockGridTypeConfigurationElement
return html`<div id="groups">
${this._notGroupedBlockTypes
? html`<umb-input-block-type
.propertyAlias=${this._alias}
.value=${this._notGroupedBlockTypes}
.workspacePath=${this._workspacePath}
@change=${this.#onChange}
@@ -217,6 +230,7 @@ export class UmbPropertyEditorUIBlockGridTypeConfigurationElement
${group.key ? this.#renderGroupInput(group.key, group.name) : nothing}
<umb-input-block-type
data-umb-group-key=${group.key}
.propertyAlias=${this._alias + '_' + group.key}
.value=${group.blocks}
.workspacePath=${this._workspacePath}
@change=${this.#onChange}

View File

@@ -1,13 +1,13 @@
import type { UmbBlockTypeCardElement } from '../block-type-card/index.js';
import type { UmbBlockTypeBaseModel, UmbBlockTypeWithGroupKey } from '../../types.js';
import { UMB_MODAL_MANAGER_CONTEXT, umbConfirmModal } from '@umbraco-cms/backoffice/modal';
import { UmbModalRouteRegistrationController, umbConfirmModal } from '@umbraco-cms/backoffice/modal';
import '../block-type-card/index.js';
import { css, html, customElement, property, state, repeat } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property';
import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property';
import { UmbDeleteEvent } from '@umbraco-cms/backoffice/event';
import { UMB_DOCUMENT_TYPE_PICKER_MODAL } from '@umbraco-cms/backoffice/document-type';
import { UMB_DOCUMENT_TYPE_PICKER_MODAL, UMB_DOCUMENT_TYPE_ENTITY_TYPE } from '@umbraco-cms/backoffice/document-type';
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
/** TODO: Look into sending a "change" event when there is a change, rather than create, delete, and change event. Make sure it doesn't break move for RTE/List/Grid. [LI] */
@@ -29,9 +29,11 @@ export class UmbInputBlockTypeElement<
this.dispatchEvent(new CustomEvent('change', { detail: { item } }));
},
onEnd: () => {
// TODO: Investigate if onEnd is called when a container move has been performed, if not then I would say it should be. [NL]
this.dispatchEvent(new CustomEvent('change', { detail: { moveComplete: true } }));
},
});
#elementPickerModal;
@property({ type: Array, attribute: false })
public set value(items) {
@@ -42,9 +44,20 @@ export class UmbInputBlockTypeElement<
return this._items;
}
@property({ type: String })
public set propertyAlias(value: string | undefined) {
this.#elementPickerModal.setUniquePathValue('propertyAlias', value);
}
public get propertyAlias(): string | undefined {
return undefined;
}
@property({ type: String })
workspacePath?: string;
@state()
private _pickerPath?: string;
@state()
private _items: Array<BlockType> = [];
@@ -60,31 +73,42 @@ export class UmbInputBlockTypeElement<
this.#filter = value as Array<UmbBlockTypeBaseModel>;
});
});
}
async create() {
const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT);
this.#elementPickerModal = new UmbModalRouteRegistrationController(this, UMB_DOCUMENT_TYPE_PICKER_MODAL)
.addUniquePaths(['propertyAlias'])
.onSetup(() => {
return {
data: {
hideTreeRoot: true,
multiple: false,
createAction: {
entityType: UMB_DOCUMENT_TYPE_ENTITY_TYPE,
preset: { isElementType: true },
},
pickableFilter: (docType) =>
// Only pick elements:
docType.isElement &&
// Prevent picking the an already used element type:
this.#filter &&
this.#filter.find((x) => x.contentElementTypeKey === docType.unique) === undefined,
},
value: {
selection: [],
},
};
})
.onSubmit((value) => {
const selectedElementType = value.selection[0];
// TODO: Make as mode for the Picker Modal, so the click to select immediately submits the modal(And in that mode we do not want to see a Submit button).
const modalContext = modalManager.open(this, UMB_DOCUMENT_TYPE_PICKER_MODAL, {
data: {
hideTreeRoot: true,
multiple: false,
pickableFilter: (docType) =>
// Only pick elements:
docType.isElement &&
// Prevent picking the an already used element type:
this.#filter &&
this.#filter.find((x) => x.contentElementTypeKey === docType.unique) === undefined,
},
});
const modalValue = await modalContext?.onSubmit();
const selectedElementType = modalValue.selection[0];
if (selectedElementType) {
this.dispatchEvent(new CustomEvent('create', { detail: { contentElementTypeKey: selectedElementType } }));
}
if (selectedElementType) {
this.dispatchEvent(new CustomEvent('create', { detail: { contentElementTypeKey: selectedElementType } }));
}
})
.observeRouteBuilder((routeBuilder) => {
const oldPath = this._pickerPath;
this._pickerPath = routeBuilder({});
this.requestUpdate('_pickerPath', oldPath);
});
}
deleteItem(contentElementTypeKey: string) {
@@ -131,12 +155,14 @@ export class UmbInputBlockTypeElement<
};
#renderButton() {
return html`
<uui-button id="add-button" look="placeholder" @click=${() => this.create()} label="open">
<uui-icon name="icon-add"></uui-icon>
Add
</uui-button>
`;
return this._pickerPath
? html`
<uui-button id="add-button" look="placeholder" href=${this._pickerPath} label="open">
<uui-icon name="icon-add"></uui-icon>
Add
</uui-button>
`
: null;
}
static styles = [

View File

@@ -1,6 +1,6 @@
import type { UmbTreeSelectionConfiguration } from '../types.js';
import type { UmbTreePickerModalData, UmbTreePickerModalValue } from './tree-picker-modal.token.js';
import { html, customElement, state, ifDefined } from '@umbraco-cms/backoffice/external/lit';
import { html, customElement, state, ifDefined, nothing } from '@umbraco-cms/backoffice/external/lit';
import {
UMB_WORKSPACE_MODAL,
UmbModalBaseElement,
@@ -21,9 +21,6 @@ export class UmbTreePickerModalElement<TreeItemType extends UmbTreeItemModelBase
selection: [],
};
@state()
_createButton: boolean = false;
@state()
_createPath?: string;
@@ -47,14 +44,22 @@ export class UmbTreePickerModalElement<TreeItemType extends UmbTreeItemModelBase
// To remove the hardcoded URLs for workspaces of entity types, we could make an create event from the tree, which either this or the sidebar impl. will pick up and react to. [NL]
// Or maybe the tree item context base can handle this? [NL]
// Maybe its a general item context problem to be solved. [NL]
if (this._createButton) {
const createActionData = this.data?.createAction;
console.log('createActionData', createActionData);
if (createActionData) {
new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL)
.addAdditionalPath('document-type')
.onSetup(() => {
return { data: { entityType: 'document-type', preset: {} } };
.onSetup(async () => {
return { data: createActionData };
})
.onSubmit((value) => {
console.log('got', value);
//this.value = value;
//this.modalContext?.dispatchEvent(new UmbSelectedEvent());
})
.observeRouteBuilder((routeBuilder) => {
this._createPath = routeBuilder({});
const oldPath = this._createPath;
this._createPath = routeBuilder({}) + 'create';
this.requestUpdate('_createPath', oldPath);
});
}
}
@@ -95,6 +100,12 @@ export class UmbTreePickerModalElement<TreeItemType extends UmbTreeItemModelBase
</uui-box>
<div slot="actions">
<uui-button label=${this.localize.term('general_close')} @click=${this._rejectModal}></uui-button>
${this._createPath
? html` <uui-button
label=${this.localize.term('content_createEmpty')}
look="secondary"
href=${this._createPath}></uui-button>`
: nothing}
<uui-button
label=${this.localize.term('general_choose')}
look="primary"

View File

@@ -1,9 +1,12 @@
import { UMB_TREE_PICKER_MODAL_ALIAS } from './constants.js';
import type { UmbPickerModalData, UmbPickerModalValue } from '@umbraco-cms/backoffice/modal';
import type { UmbPickerModalData, UmbPickerModalValue, UmbWorkspaceModalData } from '@umbraco-cms/backoffice/modal';
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
export interface UmbTreePickerModalCreateActionData extends UmbWorkspaceModalData {}
export interface UmbTreePickerModalData<TreeItemType = any> extends UmbPickerModalData<TreeItemType> {
treeAlias?: string;
// Consider if it makes sense to move this into the UmbPickerModalData interface, but for now this is a TreePicker feature. [NL]
createAction?: UmbTreePickerModalCreateActionData;
}
export interface UmbTreePickerModalValue extends UmbPickerModalValue {}

View File

@@ -1,13 +1,13 @@
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { CSSResultGroup } from '@umbraco-cms/backoffice/external/lit';
import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
import type { UmbWorkspaceData } from '@umbraco-cms/backoffice/modal';
import type { UmbWorkspaceModalData } from '@umbraco-cms/backoffice/modal';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
@customElement('umb-workspace-modal')
export class UmbWorkspaceModalElement extends UmbLitElement {
@property({ attribute: false })
data?: UmbWorkspaceData;
data?: UmbWorkspaceModalData;
/**
* TODO: Consider if this binding and events integration is the right for communicating back the modal handler. Or if we should go with some Context API. like a Modal Context API.