Skip to content

Commit

Permalink
Merge pull request #1306 from umbraco/feature/document-type-structure…
Browse files Browse the repository at this point in the history
…-collection-ui

Feature: Document Type Structure - configure collection UI
  • Loading branch information
leekelleher authored Feb 29, 2024
2 parents d981d7c + 9ddd116 commit 4f9bfbc
Show file tree
Hide file tree
Showing 10 changed files with 210 additions and 17 deletions.
3 changes: 3 additions & 0 deletions src/assets/lang/da-dk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1655,6 +1655,9 @@ export default {
'<strong>NOTE!</strong> The cleanup of historically content versions are disabled globally. These settings will not take effect before it is enabled.',
changeDataTypeHelpText:
'Changing a data type with stored values is disabled. To allow this you can change the Umbraco:CMS:DataTypes:CanBeChanged setting in appsettings.json.',
collections: 'Samlinger',
collectionsDescription:
'Konfigurerer indholdselementet til at vise listen over dets underordnede elementer, underordnede elementer vil ikke blive vist i træet.',
},
languages: {
addLanguage: 'Tilføj sprog',
Expand Down
3 changes: 3 additions & 0 deletions src/assets/lang/en-us.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1652,6 +1652,9 @@ export default {
'<strong>NOTE!</strong> The cleanup of historically content versions are disabled globally. These settings will not take effect before it is enabled.',
changeDataTypeHelpText:
'Changing a data type with stored values is disabled. To allow this you can change the Umbraco:CMS:DataTypes:CanBeChanged setting in appsettings.json.',
collections: 'Collections',
collectionsDescription:
'Configures the content item to show list of its children, the children will not be shown in the tree.',
},
languages: {
addLanguage: 'Add language',
Expand Down
1 change: 1 addition & 0 deletions src/packages/core/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export * from './field-dropdown-list/index.js';
export * from './footer-layout/index.js';
export * from './header-app/index.js';
export * from './history/index.js';
export * from './input-collection-configuration/index.js';
export * from './input-color/index.js';
export * from './input-date/index.js';
export * from './input-dropdown/index.js';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './input-collection-configuration.element.js';
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { html, customElement, property, css, state, nothing } from '@umbraco-cms/backoffice/external/lit';
import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbRepositoryItemsManager } from '@umbraco-cms/backoffice/repository';
import { UMB_DATATYPE_WORKSPACE_MODAL, UMB_DATA_TYPE_ITEM_REPOSITORY_ALIAS } from '@umbraco-cms/backoffice/data-type';
import {
UmbModalRouteRegistrationController,
UMB_DATA_TYPE_PICKER_FLOW_DATA_TYPE_PICKER_MODAL,
} from '@umbraco-cms/backoffice/modal';
import type { UmbDataTypeItemModel } from '@umbraco-cms/backoffice/data-type';

@customElement('umb-input-collection-configuration')
export class UmbInputCollectionConfigurationElement extends FormControlMixin(UmbLitElement) {
protected getFormElement() {
return undefined;
}

#itemManager = new UmbRepositoryItemsManager<UmbDataTypeItemModel>(
this,
UMB_DATA_TYPE_ITEM_REPOSITORY_ALIAS,
(x) => x.unique,
);

#createDataTypeModal: UmbModalRouteRegistrationController;

#propertyEditorUiAlias = 'Umb.PropertyEditorUi.CollectionView';

@state()
private _dataTypePickerModalPath?: string;

@state()
private _item?: UmbDataTypeItemModel;

@property({ attribute: 'default-value' })
defaultValue?: string;

#setValue(value: string) {
this.value = value;
this.#itemManager.setUniques(value ? [value] : []);
this.dispatchEvent(new UmbChangeEvent());
}

constructor() {
super();

this.observe(this.#itemManager.items, (items) => {
this._item = items[0];
});

new UmbModalRouteRegistrationController(this, UMB_DATA_TYPE_PICKER_FLOW_DATA_TYPE_PICKER_MODAL)
.addAdditionalPath(':uiAlias')
.onSetup((routingInfo) => {
return {
data: {
propertyEditorUiAlias: routingInfo.uiAlias,
},
value: undefined,
};
})
.onSubmit((submitData) => {
if (submitData?.createNewWithPropertyEditorUiAlias) {
this.#createDataType();
} else {
this.#setValue(submitData?.dataTypeId ?? this.defaultValue ?? '');
}
})
.observeRouteBuilder((routeBuilder) => {
this._dataTypePickerModalPath = routeBuilder({ uiAlias: this.#propertyEditorUiAlias });
});

this.#createDataTypeModal = new UmbModalRouteRegistrationController(this, UMB_DATATYPE_WORKSPACE_MODAL)
.addAdditionalPath(':uiAlias')
.onSetup((params) => {
return { data: { entityType: 'data-type', preset: { editorUiAlias: params.uiAlias } } };
})
.onSubmit((value) => {
this.#setValue(value?.unique ?? this.defaultValue ?? '');
});
}

connectedCallback() {
super.connectedCallback();

if (this.value) {
this.#itemManager.setUniques([this.value as string]);
}
}

#clearDataType() {
this.#setValue('');
}

#createDataType() {
this.#createDataTypeModal.open({ uiAlias: this.#propertyEditorUiAlias }, 'create/null');
}

render() {
return !this.value ? this.#renderCreate() : this.#renderConfigured();
}

#renderCreate() {
if (!this._dataTypePickerModalPath) return nothing;
return html`<uui-button
id="create-button"
color="default"
look="placeholder"
label="Configure as a collection"
href=${this._dataTypePickerModalPath}></uui-button>`;
}

#renderConfigured() {
if (!this._item || !this._dataTypePickerModalPath) return nothing;
return html`
<uui-ref-list>
<uui-ref-node-data-type standalone name=${this._item.name} detail=${this._item.unique}>
<uui-action-bar slot="actions">
<uui-button
label=${this.localize.term('general_choose')}
href=${this._dataTypePickerModalPath}></uui-button>
<uui-button @click=${this.#clearDataType} label=${this.localize.term('general_remove')}></uui-button>
</uui-action-bar>
</uui-ref-node-data-type>
</uui-ref-list>
`;
}

static styles = [
css`
#create-button {
width: 100%;
}
`,
];
}

export default UmbInputCollectionConfigurationElement;

declare global {
interface HTMLElementTagNameMap {
'umb-input-collection-configuration': UmbInputCollectionConfigurationElement;
}
}
3 changes: 2 additions & 1 deletion src/packages/core/content-type/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { CompositionTypeModel, PropertyTypeModelBaseModel } from '@umbraco-cms/backoffice/external/backend-api';
import type { UmbReferenceByUnique } from '@umbraco-cms/backoffice/models';

export type UmbPropertyContainerTypes = 'Group' | 'Tab';
export interface UmbPropertyTypeContainerModel {
Expand All @@ -24,7 +25,7 @@ export interface UmbContentTypeModel {
containers: Array<UmbPropertyTypeContainerModel>;
allowedContentTypes: Array<UmbContentTypeSortModel>;
compositions: Array<UmbContentTypeCompositionModel>;
collection: { unique: string } | null;
collection: UmbReferenceByUnique | null;
}

export interface UmbPropertyTypeScaffoldModel extends Omit<UmbPropertyTypeModel, 'dataType'> {
Expand Down
2 changes: 2 additions & 0 deletions src/packages/data-type/repository/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ export { UmbCopyDataTypeRepository, COPY_DATA_TYPE_REPOSITORY_ALIAS } from './co
export { UmbDataTypeDetailRepository, UMB_DATA_TYPE_DETAIL_REPOSITORY_ALIAS } from './detail/index.js';
export { UmbDataTypeItemRepository, UMB_DATA_TYPE_ITEM_REPOSITORY_ALIAS } from './item/index.js';
export { UmbMoveDataTypeRepository, MOVE_DATA_TYPE_REPOSITORY_ALIAS } from './move/index.js';

export type { UmbDataTypeItemModel } from './item/index.js';
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ export class UmbDocumentTypeDetailServerDataSource implements UmbDetailDataSourc
allowedTemplates: model.allowedTemplates,
defaultTemplate: model.defaultTemplate ? { id: model.defaultTemplate.id } : null,
cleanup: model.cleanup,
collection: model.collection?.unique ? { id: model.collection?.unique } : null,
};

const { data, error } = await tryExecuteAndNotify(
Expand Down Expand Up @@ -252,6 +253,7 @@ export class UmbDocumentTypeDetailServerDataSource implements UmbDetailDataSourc
allowedTemplates: model.allowedTemplates,
defaultTemplate: model.defaultTemplate ? { id: model.defaultTemplate.id } : null,
cleanup: model.cleanup,
collection: model.collection?.unique ? { id: model.collection?.unique } : null,
};

const { error } = await tryExecuteAndNotify(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { UmbDocumentTypeDetailRepository } from '../repository/detail/document-type-detail.repository.js';
import type { UmbDocumentTypeDetailModel } from '../types.js';
import type { UmbContentTypeCompositionModel, UmbContentTypeSortModel } from '@umbraco-cms/backoffice/content-type';
import { UmbContentTypePropertyStructureManager } from '@umbraco-cms/backoffice/content-type';
import type { UmbSaveableWorkspaceContextInterface } from '@umbraco-cms/backoffice/workspace';
import { UmbEditableWorkspaceContextBase } from '@umbraco-cms/backoffice/workspace';
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
import { UmbBooleanState, UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
import type { UmbContentTypeCompositionModel, UmbContentTypeSortModel } from '@umbraco-cms/backoffice/content-type';
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
import type { UmbReferenceByUnique } from '@umbraco-cms/backoffice/models';
import type { UmbSaveableWorkspaceContextInterface } from '@umbraco-cms/backoffice/workspace';

type EntityType = UmbDocumentTypeDetailModel;
export class UmbDocumentTypeWorkspaceContext
Expand All @@ -31,6 +32,7 @@ export class UmbDocumentTypeWorkspaceContext
readonly isElement;
readonly allowedContentTypes;
readonly compositions;
readonly collection;

// Document type specific:
readonly allowedTemplateIds;
Expand All @@ -57,6 +59,7 @@ export class UmbDocumentTypeWorkspaceContext
this.isElement = this.structure.ownerContentTypeObservablePart((data) => data?.isElement);
this.allowedContentTypes = this.structure.ownerContentTypeObservablePart((data) => data?.allowedContentTypes);
this.compositions = this.structure.ownerContentTypeObservablePart((data) => data?.compositions);
this.collection = this.structure.ownerContentTypeObservablePart((data) => data?.collection);

// Document type specific:
this.allowedTemplateIds = this.structure.ownerContentTypeObservablePart((data) => data?.allowedTemplates);
Expand Down Expand Up @@ -123,6 +126,9 @@ export class UmbDocumentTypeWorkspaceContext
setCompositions(compositions: Array<UmbContentTypeCompositionModel>) {
this.structure.updateOwnerContentType({ compositions });
}
setCollection(collection: UmbReferenceByUnique) {
this.structure.updateOwnerContentType({ collection });
}

// Document type specific:
setAllowedTemplateIds(allowedTemplates: Array<{ id: string }>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import type { UmbDocumentTypeWorkspaceContext } from '../../document-type-worksp
import type { UmbInputDocumentTypeElement } from '../../../components/input-document-type/input-document-type.element.js';
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { UUIToggleElement } from '@umbraco-cms/backoffice/external/uui';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UMB_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace';
import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/extension-registry';
import type { UmbContentTypeSortModel } from '@umbraco-cms/backoffice/content-type';
import type { UmbInputCollectionConfigurationElement } from '@umbraco-cms/backoffice/components';
import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/extension-registry';
import type { UUIToggleElement } from '@umbraco-cms/backoffice/external/uui';

@customElement('umb-document-type-workspace-view-structure')
export class UmbDocumentTypeWorkspaceViewStructureElement extends UmbLitElement implements UmbWorkspaceViewElement {
Expand All @@ -18,6 +19,9 @@ export class UmbDocumentTypeWorkspaceViewStructureElement extends UmbLitElement
@state()
private _allowedContentTypeUniques?: Array<string>;

@state()
private _collection?: string | null;

constructor() {
super();

Expand All @@ -30,14 +34,32 @@ export class UmbDocumentTypeWorkspaceViewStructureElement extends UmbLitElement

private _observeDocumentType() {
if (!this.#workspaceContext) return;
this.observe(this.#workspaceContext.allowedAsRoot, (allowedAsRoot) => (this._allowedAtRoot = allowedAsRoot));
this.observe(this.#workspaceContext.allowedContentTypes, (allowedContentTypes) => {
const oldValue = this._allowedContentTypeUniques;
this._allowedContentTypeUniques = allowedContentTypes
?.map((x) => x.contentType.unique)
.filter((x) => x !== undefined) as Array<string>;
this.requestUpdate('_allowedContentTypeUniques', oldValue);
});

this.observe(
this.#workspaceContext.allowedAsRoot,
(allowedAsRoot) => (this._allowedAtRoot = allowedAsRoot),
'_allowedAsRootObserver',
);

this.observe(
this.#workspaceContext.allowedContentTypes,
(allowedContentTypes) => {
const oldValue = this._allowedContentTypeUniques;
this._allowedContentTypeUniques = allowedContentTypes
?.map((x) => x.contentType.unique)
.filter((x) => x !== undefined) as Array<string>;
this.requestUpdate('_allowedContentTypeUniques', oldValue);
},
'_allowedContentTypesObserver',
);

this.observe(
this.#workspaceContext.collection,
(collection) => {
this._collection = collection?.unique;
},
'_collectionObserver',
);
}

render() {
Expand Down Expand Up @@ -77,9 +99,18 @@ export class UmbDocumentTypeWorkspaceViewStructureElement extends UmbLitElement
</umb-property-layout>
</uui-box>
<uui-box headline="Presentation">
<umb-property-layout alias="Root" label="Collection view">
<div slot="description">Provides an overview of child content and hides it in the tree.</div>
<div slot="editor"><uui-toggle label="Display children in a Collection view"></uui-toggle></div>
<umb-property-layout alias="collection" label="${this.localize.term('contentTypeEditor_collections')}">
<div slot="description">${this.localize.term('contentTypeEditor_collectionsDescription')}</div>
<div slot="editor">
<umb-input-collection-configuration
default-value="c0808dd3-8133-4e4b-8ce8-e2bea84a96a4"
.value=${this._collection ?? ''}
@change=${(e: CustomEvent) => {
const unique = (e.target as UmbInputCollectionConfigurationElement).value as string;
this.#workspaceContext?.setCollection({ unique });
}}>
</umb-input-collection-configuration>
</div>
</umb-property-layout>
</uui-box>
`;
Expand Down

0 comments on commit 4f9bfbc

Please sign in to comment.