delete group + inheritance display + links

This commit is contained in:
Niels Lyngsø
2024-04-30 22:24:03 +02:00
parent de4da8a773
commit c71c6c1a5b
7 changed files with 118 additions and 57 deletions

View File

@@ -240,6 +240,11 @@ export class UmbContentTypeContainerStructureHelper<T extends UmbContentTypeMode
return this.#ownerChildContainers.some((x) => x.id === containerId);
}
getContentTypeOfContainer(containerId?: string) {
if (!this.#structure || !containerId) return;
return this.#structure.getContentTypeOfContainer(containerId);
}
containersByNameAndType(name: string, type: UmbPropertyContainerTypes) {
return this.#childContainers.asObservablePart((cons) => cons.filter((x) => x.name === name && x.type === type));
}

View File

@@ -704,6 +704,12 @@ export class UmbContentTypeStructureManager<
});
}
getContentTypeOfContainer(containerId: string) {
return this.#contentTypes
.getValue()
.find((contentType) => contentType.containers.some((c) => c.id === containerId));
}
contentTypeOfProperty(propertyId: UmbPropertyTypeId) {
return this.#contentTypes.asObservablePart((contentTypes) =>
contentTypes.find((contentType) => contentType.properties.some((p) => p.id === propertyId)),

View File

@@ -1,6 +1,6 @@
import type { UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
import { UmbLitElement, umbFocus } from '@umbraco-cms/backoffice/lit-element';
import { css, html, customElement, property, state, nothing } from '@umbraco-cms/backoffice/external/lit';
import { css, html, customElement, property, state, nothing, repeat } from '@umbraco-cms/backoffice/external/lit';
import type {
UmbContentTypeContainerStructureHelper,
UmbContentTypeModel,
@@ -8,6 +8,7 @@ import type {
} from '@umbraco-cms/backoffice/content-type';
import './content-type-design-editor-properties.element.js';
import { umbConfirmModal } from '@umbraco-cms/backoffice/modal';
@customElement('umb-content-type-design-editor-group')
export class UmbContentTypeWorkspaceViewEditGroupElement extends UmbLitElement {
@@ -37,6 +38,9 @@ export class UmbContentTypeWorkspaceViewEditGroupElement extends UmbLitElement {
@property({ type: Boolean, attribute: 'sort-mode-active', reflect: true })
sortModeActive = false;
@property({ attribute: false })
editContentTypePath?: string;
@state()
_groupId?: string;
@@ -46,6 +50,9 @@ export class UmbContentTypeWorkspaceViewEditGroupElement extends UmbLitElement {
@state()
_inherited?: boolean;
@state()
_inheritedFrom?: Array<UmbContentTypeModel>;
#checkInherited() {
if (this.groupStructureHelper && this.group) {
// Check is this container matches with any other group. If so it is inherited aka. merged with others. [NL]
@@ -54,18 +61,22 @@ export class UmbContentTypeWorkspaceViewEditGroupElement extends UmbLitElement {
this.observe(
this.groupStructureHelper.containersByNameAndType(this.group.name, 'Group'),
(containers) => {
const hasAOwnerContainer = containers.some((con) =>
this.groupStructureHelper!.isOwnerChildContainer(con.id),
);
const ownerContainer = containers.find((con) => this.groupStructureHelper!.isOwnerChildContainer(con.id));
const hasAOwnerContainer = !!ownerContainer;
const pureOwnerContainer = hasAOwnerContainer && containers.length === 1;
// TODO: Check if requstUpdate is needed here, I do not think it is when i added it, but I just wanted to be safe when debugging [NL]
// TODO: Check if requestUpdate is needed here, I do not think it is when i added it, but I just wanted to be safe when debugging [NL]
const oldHasOwnerContainer = this._hasOwnerContainer;
const oldInherited = this._inherited;
const oldInheritedFrom = this._inheritedFrom;
this._hasOwnerContainer = hasAOwnerContainer;
this._inherited = !pureOwnerContainer;
this._inheritedFrom = containers
.filter((con) => con.id !== this.group!.id)
.map((con) => this.groupStructureHelper!.getContentTypeOfContainer(con.id));
this.requestUpdate('_hasOwnerContainer', oldHasOwnerContainer);
this.requestUpdate('_inherited', oldInherited);
this.requestUpdate('_inheritedFrom', oldInheritedFrom);
},
'observeGroupContainers',
);
@@ -112,6 +123,27 @@ export class UmbContentTypeWorkspaceViewEditGroupElement extends UmbLitElement {
}
}
async #requestRemove(e: Event) {
e.preventDefault();
e.stopImmediatePropagation();
if (!this.groupStructureHelper || !this._group) return;
// TODO: Do proper localization here: [NL]
await umbConfirmModal(this, {
headline: `${this.localize.term('actions_delete')} property`,
content: html`<umb-localize key="contentTypeEditor_confirmDeletePropertyMessage" .args=${[
this._group.name ?? this._group.id,
]}>
Are you sure you want to delete the group <strong>${this._group.name ?? this._group.id}</strong>
</umb-localize>
</div>`,
confirmLabel: this.localize.term('actions_delete'),
color: 'danger',
});
this.groupStructureHelper.removeContainer(this._group.id);
}
render() {
return this._inherited !== undefined && this._groupId
? html`
@@ -124,10 +156,9 @@ export class UmbContentTypeWorkspaceViewEditGroupElement extends UmbLitElement {
: '';
}
// TODO: impl UMB_EDIT_DOCUMENT_TYPE_PATH_PATTERN
#renderContainerHeader() {
return html`<div slot="header">
<div>
<uui-icon name=${this._inherited ? 'icon-merge' : 'icon-navigation'}></uui-icon>
<uui-input
label=${this.localize.term('contentTypeEditor_group')}
placeholder=${this.localize.term('placeholders_entername')}
@@ -136,17 +167,38 @@ export class UmbContentTypeWorkspaceViewEditGroupElement extends UmbLitElement {
@change=${this.#renameGroup}
@blur=${this.#blurGroup}
${this._group!.name === '' ? umbFocus() : nothing}></uui-input>
${this._inherited && this._inheritedFrom
? html`<uui-tag look="default" class="inherited">
<uui-icon name="icon-merge"></uui-icon>
<span
>${this.localize.term('contentTypeEditor_inheritedFrom')}
${repeat(
this._inheritedFrom,
(inherited) => inherited.unique,
(inherited) => html`
<a href=${this.editContentTypePath + 'edit/' + inherited.unique}>${inherited.name}</a>
`,
)}
</span>
</uui-tag>`
: null}
</div>
${this.sortModeActive
? html` <uui-input
type="number"
label=${this.localize.term('sort_sortOrder')}
@change=${(e: UUIInputEvent) =>
this._singleValueUpdate('sortOrder', parseInt(e.target.value as string) || 0)}
.value=${this.group!.sortOrder ?? 0}
?disabled=${!this._hasOwnerContainer}></uui-input>`
: ''}
</div> `;
<div slot="header-actions">
${this._inherited
? null
: html`<uui-button compact label="${this.localize.term('actions_delete')}" @click="${this.#requestRemove}">
<uui-icon name="delete"></uui-icon>
</uui-button>`}
${this.sortModeActive
? html` <uui-input
type="number"
label=${this.localize.term('sort_sortOrder')}
@change=${(e: UUIInputEvent) =>
this._singleValueUpdate('sortOrder', parseInt(e.target.value as string) || 0)}
.value=${this.group!.sortOrder ?? 0}
?disabled=${!this._hasOwnerContainer}></uui-input>`
: ''}
</div> `;
}
static styles = [

View File

@@ -104,6 +104,9 @@ export class UmbContentTypeDesignEditorPropertiesElement extends UmbLitElement {
#propertyStructureHelper = new UmbContentTypePropertyStructureHelper<UmbContentTypeModel>(this);
@property({ attribute: false })
editContentTypePath?: string;
@state()
private _propertyStructure: Array<UmbPropertyTypeModel> = [];
@@ -113,9 +116,6 @@ export class UmbContentTypeDesignEditorPropertiesElement extends UmbLitElement {
@state()
private _modalRouteBuilderNewProperty?: UmbModalRouteBuilder;
@state()
private _editContentTypePath?: string;
@state()
private _sortModeActive?: boolean;
@@ -142,18 +142,6 @@ export class UmbContentTypeDesignEditorPropertiesElement extends UmbLitElement {
this.consumeContext(UMB_CONTENT_TYPE_WORKSPACE_CONTEXT, async (workspaceContext) => {
this.#propertyStructureHelper.setStructureManager(workspaceContext.structure);
const entityType = workspaceContext.getEntityType();
this.#workspaceModal?.destroy();
this.#workspaceModal = new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL)
.addAdditionalPath(entityType)
.onSetup(async () => {
return { data: { entityType: entityType, preset: {} } };
})
.observeRouteBuilder((routeBuilder) => {
this._editContentTypePath = routeBuilder({});
});
this.observe(
workspaceContext.structure.ownerContentType,
(contentType) => {
@@ -208,7 +196,7 @@ export class UmbContentTypeDesignEditorPropertiesElement extends UmbLitElement {
return html`
<umb-content-type-design-editor-property
data-umb-property-id=${property.id}
.editContentTypePath=${this._editContentTypePath}
.editContentTypePath=${this.editContentTypePath}
?sort-mode-active=${this._sortModeActive}
.propertyStructureHelper=${this.#propertyStructureHelper}
.property=${property}>

View File

@@ -258,6 +258,7 @@ export class UmbContentTypeDesignEditorPropertyElement extends UmbLitElement {
</div>
<uui-button
id="editor"
look="secondary"
label=${this.localize.term('contentTypeEditor_editorSettings')}
href=${ifDefined(this._modalRoute)}>
${this.renderPropertyTags()}
@@ -415,7 +416,6 @@ export class UmbContentTypeDesignEditorPropertyElement extends UmbLitElement {
#editor {
position: relative;
background-color: var(--uui-color-background);
}
#alias-input,
#label-input,

View File

@@ -12,6 +12,7 @@ import {
import './content-type-design-editor-properties.element.js';
import './content-type-design-editor-group.element.js';
import { type UmbSorterConfig, UmbSorterController } from '@umbraco-cms/backoffice/sorter';
import { UMB_WORKSPACE_MODAL, UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal';
const SORTER_CONFIG: UmbSorterConfig<UmbPropertyTypeContainerModel, UmbContentTypeWorkspaceViewEditGroupElement> = {
getUniqueOfElement: (element) => element.group?.id,
@@ -71,16 +72,17 @@ export class UmbContentTypeDesignEditorTabElement extends UmbLitElement {
},
});
private _containerId?: string | null;
#workspaceModal?: UmbModalRouteRegistrationController;
#containerId?: string | null;
@property({ type: String })
public get containerId(): string | null | undefined {
return this._containerId;
return this.#containerId;
}
public set containerId(value: string | null | undefined) {
const oldValue = this._containerId;
if (value === this._containerId) return;
this._containerId = value;
const oldValue = this.#containerId;
if (value === this.#containerId) return;
this.#containerId = value;
this.#groupStructureHelper.setContainerId(value);
this.requestUpdate('containerId', oldValue);
}
@@ -94,6 +96,9 @@ export class UmbContentTypeDesignEditorTabElement extends UmbLitElement {
@state()
_sortModeActive?: boolean;
@state()
_editContentTypePath?: string;
#groupStructureHelper = new UmbContentTypeContainerStructureHelper<UmbContentTypeModel>(this);
constructor() {
@@ -101,6 +106,18 @@ export class UmbContentTypeDesignEditorTabElement extends UmbLitElement {
this.consumeContext(UMB_CONTENT_TYPE_WORKSPACE_CONTEXT, (context) => {
this.#groupStructureHelper.setStructureManager(context.structure);
const entityType = context.getEntityType();
this.#workspaceModal?.destroy();
this.#workspaceModal = new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL)
.addAdditionalPath(entityType)
.onSetup(async () => {
return { data: { entityType: entityType, preset: {} } };
})
.observeRouteBuilder((routeBuilder) => {
this._editContentTypePath = routeBuilder({});
});
});
this.consumeContext(UMB_CONTENT_TYPE_DESIGN_EDITOR_CONTEXT, (context) => {
this.observe(
@@ -138,19 +155,11 @@ export class UmbContentTypeDesignEditorTabElement extends UmbLitElement {
// Idea, maybe we can gather the sortOrder from the last group rendered and add 1 to it?
const len = this._groups.length;
const sortOrder = len === 0 ? 0 : this._groups[len - 1].sortOrder + 1;
this.#groupStructureHelper.addContainer(this._containerId, sortOrder);
this.#groupStructureHelper.addContainer(this.#containerId, sortOrder);
};
render() {
return html`
${
this._sortModeActive
? html`<uui-button
id="convert-to-tab"
label=${this.localize.term('contentTypeEditor_convertToTab') + '(Not implemented)'}
look="placeholder"></uui-button>`
: ''
}
${
this._hasProperties
? html`
@@ -169,6 +178,7 @@ export class UmbContentTypeDesignEditorTabElement extends UmbLitElement {
<umb-content-type-design-editor-group
class="container-handle"
?sort-mode-active=${this._sortModeActive}
.editContentTypePath=${this._editContentTypePath}
.group=${group}
.groupStructureHelper=${this.#groupStructureHelper as any}>
</umb-content-type-design-editor-group>

View File

@@ -276,7 +276,6 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements
if (tab) {
const path = this._routerPath + '/tab/' + encodeFolderName(tab.name && tab.name !== '' ? tab.name : '-');
window.history.replaceState(null, '', path);
console.log('new tab', path);
this.#focusInput();
}
}
@@ -525,14 +524,6 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements
static styles = [
UmbTextStyles,
css`
#buttons-wrapper {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
align-items: stretch;
}
:host {
position: relative;
display: flex;
@@ -541,6 +532,14 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements
--uui-tab-background: var(--uui-color-surface);
}
#buttons-wrapper {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
align-items: stretch;
}
[drag-placeholder] {
opacity: 0.5;
}
@@ -553,6 +552,7 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements
#header {
width: 100%;
min-height: var(--uui-size-15);
display: flex;
align-items: center;
justify-content: space-between;