Merge pull request #882 from umbraco/bugfix-create-nested-documents

This commit is contained in:
Niels Lyngsø
2023-09-14 20:22:29 +02:00
committed by GitHub
11 changed files with 95 additions and 149 deletions

View File

@@ -1,18 +0,0 @@
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
export interface UmbAllowedDocumentTypesModalData {
parentId: string | null;
parentName?: string;
}
export interface UmbAllowedDocumentTypesModalResult {
documentTypeKey: string;
}
export const UMB_ALLOWED_DOCUMENT_TYPES_MODAL = new UmbModalToken<
UmbAllowedDocumentTypesModalData,
UmbAllowedDocumentTypesModalResult
>('Umb.Modal.AllowedDocumentTypes', {
type: 'sidebar',
size: 'small',
});

View File

@@ -0,0 +1,17 @@
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
export interface UmbCreateDocumentModalData {
id: string | null;
}
export interface UmbCreateDocumentModalResult {
documentTypeId: string;
}
export const UMB_CREATE_DOCUMENT_MODAL = new UmbModalToken<UmbCreateDocumentModalData, UmbCreateDocumentModalResult>(
'Umb.Modal.CreateDocument',
{
type: 'sidebar',
size: 'small',
},
);

View File

@@ -1,5 +1,5 @@
export * from './modal-token.js';
export * from './allowed-document-types-modal.token.js';
export * from './create-document-modal.token.js';
export * from './change-password-modal.token.js';
export * from './code-editor-modal.token.js';
export * from './confirm-modal.token.js';

View File

@@ -1,6 +1,5 @@
import { manifests as entityActionsManifests } from './entity-actions/manifests.js';
import { manifests as menuItemManifests } from './menu-item/manifests.js';
import { manifests as modalManifests } from './modals/manifests.js';
import { manifests as repositoryManifests } from './repository/manifests.js';
import { manifests as treeManifests } from './tree/manifests.js';
import { manifests as workspaceManifests } from './workspace/manifests.js';
@@ -8,7 +7,6 @@ import { manifests as workspaceManifests } from './workspace/manifests.js';
export const manifests = [
...entityActionsManifests,
...menuItemManifests,
...modalManifests,
...repositoryManifests,
...treeManifests,
...workspaceManifests,

View File

@@ -1,12 +0,0 @@
import type { ManifestModal } from '@umbraco-cms/backoffice/extension-registry';
const modals: Array<ManifestModal> = [
{
type: 'modal',
alias: 'Umb.Modal.AllowedDocumentTypes',
name: 'Allowed Document Types Modal',
loader: () => import('./allowed-document-types/allowed-document-types-modal.element.js'),
},
];
export const manifests = [...modals];

View File

@@ -1,14 +1,14 @@
import { html, nothing, customElement, state, ifDefined } from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { UmbAllowedDocumentTypesModalData, UmbAllowedDocumentTypesModalResult } from '@umbraco-cms/backoffice/modal';
import { UmbCreateDocumentModalData, UmbCreateDocumentModalResult } from '@umbraco-cms/backoffice/modal';
import { UmbModalBaseElement } from '@umbraco-cms/internal/modal';
import { DocumentTypeTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
import { UmbDocumentRepository } from '@umbraco-cms/backoffice/document';
@customElement('umb-allowed-document-types-modal')
export class UmbAllowedDocumentTypesModalElement extends UmbModalBaseElement<
UmbAllowedDocumentTypesModalData,
UmbAllowedDocumentTypesModalResult
@customElement('umb-create-document-modal')
export class UmbCreateDocumentModalElement extends UmbModalBaseElement<
UmbCreateDocumentModalData,
UmbCreateDocumentModalResult
> {
#documentRepository = new UmbDocumentRepository(this);
@@ -16,29 +16,19 @@ export class UmbAllowedDocumentTypesModalElement extends UmbModalBaseElement<
private _allowedDocumentTypes: DocumentTypeTreeItemResponseModel[] = [];
@state()
private _headline?: string;
private _headline: string = 'Create';
public connectedCallback() {
super.connectedCallback();
async firstUpdated() {
const documentId = this.data?.id || null;
const parentId = this.data?.parentId;
const parentName = this.data?.parentName;
if (parentName) {
this._headline = `Create at '${parentName}'`;
} else {
this._headline = `Create`;
}
if (parentId) {
// TODO: Support root aka. id of null? or maybe its an active prop, like 'atRoot'.
// TODO: show error
this.#retrieveAllowedDocumentTypesOf(documentId);
this._retrieveAllowedChildrenOf(parentId);
} else {
this._retrieveAllowedChildrenOfRoot();
if (documentId) {
this.#retrieveHeadline(documentId);
}
}
private async _retrieveAllowedChildrenOf(id: string) {
async #retrieveAllowedDocumentTypesOf(id: string | null) {
const { data } = await this.#documentRepository.requestAllowedDocumentTypesOf(id);
if (data) {
@@ -47,12 +37,12 @@ export class UmbAllowedDocumentTypesModalElement extends UmbModalBaseElement<
}
}
private async _retrieveAllowedChildrenOfRoot() {
const { data } = await this.#documentRepository.requestAllowedDocumentTypesOf(null);
async #retrieveHeadline(id: string) {
if (!id) return;
const { data } = await this.#documentRepository.requestById(id);
if (data) {
// TODO: implement pagination, or get 1000?
this._allowedDocumentTypes = data.items;
// TODO: we need to get the correct variant context here
this._headline = `Create at ${data.variants?.[0].name}`;
}
}
@@ -63,9 +53,9 @@ export class UmbAllowedDocumentTypesModalElement extends UmbModalBaseElement<
#onClick(event: PointerEvent) {
event.stopPropagation();
const target = event.target as HTMLButtonElement;
const documentTypeKey = target.dataset.id;
if (!documentTypeKey) throw new Error('No document type id found');
this.modalContext?.submit({ documentTypeKey });
const documentTypeId = target.dataset.id;
if (!documentTypeId) throw new Error('No document type id found');
this.modalContext?.submit({ documentTypeId });
}
render() {
@@ -89,10 +79,10 @@ export class UmbAllowedDocumentTypesModalElement extends UmbModalBaseElement<
static styles = [UmbTextStyles];
}
export default UmbAllowedDocumentTypesModalElement;
export default UmbCreateDocumentModalElement;
declare global {
interface HTMLElementTagNameMap {
'umb-allowed-document-types-modal': UmbAllowedDocumentTypesModalElement;
'umb-create-document-modal': UmbCreateDocumentModalElement;
}
}

View File

@@ -4,7 +4,7 @@ import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api
import {
UmbModalManagerContext,
UMB_MODAL_MANAGER_CONTEXT_TOKEN,
UMB_ALLOWED_DOCUMENT_TYPES_MODAL,
UMB_CREATE_DOCUMENT_MODAL as UMB_CREATE_DOCUMENT_MODAL,
} from '@umbraco-cms/backoffice/modal';
import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api';
@@ -20,43 +20,24 @@ export class UmbCreateDocumentEntityAction extends UmbEntityActionBase<UmbDocume
}
async execute() {
if (this.unique) {
await this._executeWithParent();
} else {
await this._executeAtRoot();
}
}
private async _executeWithParent() {
// TODO: what to do if modal service is not available?
if (!this.repository) return;
const { data } = await this.repository.requestById(this.unique);
if (data && data.contentTypeId) {
// TODO: We need to get the APP language context, use its VariantId to retrieve the right variant. The variant of which we get the name from.
this._openModal(data.contentTypeId, data.variants?.[0]?.name);
}
this._openModal(this.unique || null);
}
private async _executeAtRoot() {
this._openModal(null);
}
private async _openModal(parentId: string | null, parentName?: string) {
private async _openModal(id: string | null) {
// TODO: what to do if modal service is not available?
if (!this.#modalContext) return;
const modalContext = this.#modalContext.open(UMB_ALLOWED_DOCUMENT_TYPES_MODAL, {
parentId: parentId,
parentName: parentName,
const modalContext = this.#modalContext.open(UMB_CREATE_DOCUMENT_MODAL, {
id,
});
const { documentTypeKey } = await modalContext.onSubmit();
const { documentTypeId: documentTypeKey } = await modalContext.onSubmit();
// TODO: how do we want to generate these urls?
history.pushState(
null,
'',
`section/content/workspace/document/create/${this.unique ?? 'null'}/${documentTypeKey}`
`section/content/workspace/document/create/${this.unique ?? 'null'}/${documentTypeKey}`,
);
}
}

View File

@@ -0,0 +1,31 @@
import { DOCUMENT_REPOSITORY_ALIAS } from '../../repository/manifests.js';
import { UmbCreateDocumentEntityAction } from './create.action.js';
import { ManifestEntityAction, ManifestModal } from '@umbraco-cms/backoffice/extension-registry';
import { DOCUMENT_ENTITY_TYPE, DOCUMENT_ROOT_ENTITY_TYPE } from '@umbraco-cms/backoffice/document';
const entityActions: Array<ManifestEntityAction> = [
{
type: 'entityAction',
alias: 'Umb.EntityAction.Document.Create',
name: 'Create Document Entity Action',
weight: 1000,
meta: {
icon: 'umb:add',
label: 'Create',
repositoryAlias: DOCUMENT_REPOSITORY_ALIAS,
api: UmbCreateDocumentEntityAction,
entityTypes: [DOCUMENT_ROOT_ENTITY_TYPE, DOCUMENT_ENTITY_TYPE],
},
},
];
const modals: Array<ManifestModal> = [
{
type: 'modal',
alias: 'Umb.Modal.CreateDocument',
name: 'Create Document Modal',
loader: () => import('./create-document-modal.element.js'),
},
];
export const manifests = [...entityActions, ...modals];

View File

@@ -1,6 +1,5 @@
import { DOCUMENT_REPOSITORY_ALIAS } from '../repository/manifests.js';
import { DOCUMENT_ENTITY_TYPE, DOCUMENT_ROOT_ENTITY_TYPE } from '../index.js';
import { UmbCreateDocumentEntityAction } from './create/create.action.js';
import { UmbPublishDocumentEntityAction } from './publish.action.js';
import { UmbDocumentCultureAndHostnamesEntityAction } from './culture-and-hostnames.action.js';
import { UmbCreateDocumentBlueprintEntityAction } from './create-blueprint.action.js';
@@ -8,28 +7,17 @@ import { UmbDocumentPublicAccessEntityAction } from './public-access.action.js';
import { UmbDocumentPermissionsEntityAction } from './permissions.action.js';
import { UmbUnpublishDocumentEntityAction } from './unpublish.action.js';
import { UmbRollbackDocumentEntityAction } from './rollback.action.js';
import { manifests as createManifests } from './create/manifests.js';
import {
UmbCopyEntityAction,
UmbMoveEntityAction,
UmbTrashEntityAction,
UmbSortChildrenOfEntityAction,
} from '@umbraco-cms/backoffice/entity-action';
import { ManifestEntityAction, ManifestModal } from '@umbraco-cms/backoffice/extension-registry';
import { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
const entityActions: Array<ManifestEntityAction> = [
{
type: 'entityAction',
alias: 'Umb.EntityAction.Document.Create',
name: 'Create Document Entity Action',
weight: 1000,
meta: {
icon: 'umb:add',
label: 'Create',
repositoryAlias: DOCUMENT_REPOSITORY_ALIAS,
api: UmbCreateDocumentEntityAction,
entityTypes: [DOCUMENT_ROOT_ENTITY_TYPE, DOCUMENT_ENTITY_TYPE],
},
},
const entityActions: Array<ManifestTypes> = [
...createManifests,
{
type: 'entityAction',
alias: 'Umb.EntityAction.Document.Trash',
@@ -170,13 +158,4 @@ const entityActions: Array<ManifestEntityAction> = [
},
];
const modals: Array<ManifestModal> = [
{
type: 'modal',
alias: 'Umb.Modal.CreateDocument',
name: 'Create Document Modal',
loader: () => import('../../document-types/modals/allowed-document-types/allowed-document-types-modal.element.js'),
},
];
export const manifests = [...entityActions, ...modals];
export const manifests = [...entityActions];

View File

@@ -178,12 +178,12 @@ export class UmbDocumentRepository
this.#store?.append(item);
// TODO: Update tree store with the new item? or ask tree to request the new item?
// TODO: Revisit this call, as we should be able to update tree on client.
await this.requestRootTreeItems();
const notification = { data: { message: `Document created` } };
this.#notificationContext?.peek('positive', notification);
// TODO: Revisit this call, as we should be able to update tree on client.
await this.requestRootTreeItems();
return { data: item };
}
@@ -206,11 +206,11 @@ export class UmbDocumentRepository
//this.#treeStore?.updateItem(item.id, { name: item.name });// Port data to tree store.
// TODO: would be nice to align the stores on methods/methodNames.
// TODO: Revisit this call, as we should be able to update tree on client.
await this.requestRootTreeItems();
const notification = { data: { message: `Document saved` } };
this.#notificationContext?.peek('positive', notification);
// TODO: Revisit this call, as we should be able to update tree on client.
await this.requestRootTreeItems();
}
return { error };

View File

@@ -86,40 +86,21 @@ export class UmbDocumentServerDataSource
* @return {*}
* @memberof UmbDocumentServerDataSource
*/
async insert(document: CreateDocumentRequestModel & { id: string }) {
async insert(document: CreateDocumentRequestModel) {
if (!document.id) throw new Error('Id is missing');
// TODO: Hack to remove some props that ruins the document-type post end-point.
const unFroozenDocument = { ...document };
(unFroozenDocument as any).id = undefined;
(unFroozenDocument.variants as any) =
unFroozenDocument.variants?.map((variant) => {
return { ...variant };
}) ?? [];
return tryExecuteAndNotify(this.#host, DocumentResource.postDocument({ requestBody: unFroozenDocument }));
return tryExecuteAndNotify(this.#host, DocumentResource.postDocument({ requestBody: document }));
}
/**
* Updates a Document on the server
* @param {Document} Document
* @param {string} id
* @param {UpdateDocumentRequestModel} document
* @return {*}
* @memberof UmbDocumentServerDataSource
*/
async update(id: string, document: UpdateDocumentRequestModel) {
if (!id) throw new Error('Id is missing');
// TODO: Hack to remove some props that ruins the document-type post end-point.
const unFroozenDocument = { ...document };
(unFroozenDocument as any).id = undefined;
(unFroozenDocument.variants as any) =
unFroozenDocument.variants?.map((variant) => {
return { ...variant };
}) ?? [];
return tryExecuteAndNotify(this.#host, DocumentResource.putDocumentById({ id, requestBody: unFroozenDocument }));
return tryExecuteAndNotify(this.#host, DocumentResource.putDocumentById({ id, requestBody: document }));
}
/**
@@ -172,7 +153,6 @@ export class UmbDocumentServerDataSource
/**
* Get the allowed document types for a given parent id
* @param {string} id
* @return {*}
* @memberof UmbDocumentTypeServerDataSource
*/
async getAllowedDocumentTypesOf(id: string | null) {