Merge remote-tracking branch 'origin/main' into feature/workspace-context-as-extension

# Conflicts:
#	src/packages/documents/document-types/workspace/document-type-workspace.context.ts
This commit is contained in:
Niels Lyngsø
2023-11-15 21:36:14 +01:00
145 changed files with 1917 additions and 1672 deletions

View File

@@ -44,7 +44,7 @@ jobs:
- name: Comment on PR
# azure/static-web-apps-deploy doesn't support workflow_dispatch, so we need to manually comment on the PR
if: github.event_name == 'workflow_dispatch' && inputs.issue_number != null
uses: actions/github-script@v6
uses: actions/github-script@v7
env:
ISSUE_NUMBER: ${{ inputs.issue_number }}
SITE_URL: ${{ steps.builddeploy.outputs.static_web_app_url }}

View File

@@ -12,7 +12,7 @@ jobs:
pull-requests: write
steps:
- name: Fetch random comment 🗣️ and add it to the PR
uses: actions/github-script@v6
uses: actions/github-script@v7
with:
script: |
const response = await fetch('https://collaboratorsv2.euwest01.umbraco.io/umbraco/api/comments/PostComment', {

View File

@@ -10,10 +10,10 @@ import { setCustomElements } from '@storybook/web-components';
import { startMockServiceWorker } from '../src/mocks';
import { UMB_MODAL_MANAGER_CONTEXT_TOKEN, UmbModalManagerContext } from '../src/packages/core/modal';
import { UmbDataTypeStore } from '../src/packages/settings/data-types/repository/data-type.store.ts';
import { UmbDocumentStore } from '../src/packages/documents/documents/repository/document.store.ts';
import { UmbDocumentTreeStore } from '../src/packages/documents/documents/repository/document.tree.store.ts';
import { UmbDocumentTypeStore } from '../src/packages/documents/document-types/repository/document-type.store.ts';
import { UmbDataTypeTreeStore } from '../src/packages/core/data-type/tree/data-type.tree.store';
import { UmbDocumentStore } from '../src/packages/documents/documents/repository/document.store';
import { UmbDocumentTreeStore } from '../src/packages/documents/documents/repository/document.tree.store';
import { UmbDocumentTypeStore } from '../src/packages/documents/document-types/repository/document-type.store';
import { umbExtensionsRegistry } from '../src/packages/core/extension-registry';
import { UmbIconRegistry } from '../src/shared/icon-registry/icon.registry';
import { UmbLitElement } from '../src/shared/lit-element';
@@ -21,7 +21,6 @@ import { umbLocalizationRegistry } from '../src/packages/core/localization';
import customElementManifests from '../dist-cms/custom-elements.json';
import '../src/libs/context-api/provide/context-provider.element';
import '../src/libs/controller-api/controller-host-initializer.element.ts';
import '../src/packages/core/components';
import { manifests as documentManifests } from '../src/packages/documents';
@@ -61,7 +60,7 @@ customElements.define('umb-storybook', UmbStoryBookElement);
const storybookProvider = (story) => html` <umb-storybook>${story()}</umb-storybook> `;
const dataTypeStoreProvider = (story) => html`
<umb-controller-host-provider .create=${(host) => new UmbDataTypeStore(host)}
<umb-controller-host-provider .create=${(host) => new UmbDataTypeTreeStore(host)}
>${story()}</umb-controller-host-provider
>
`;

File diff suppressed because it is too large Load Diff

View File

@@ -150,13 +150,13 @@
"@rollup/plugin-commonjs": "^25.0.4",
"@rollup/plugin-json": "^6.0.1",
"@rollup/plugin-node-resolve": "^15.2.1",
"@storybook/addon-a11y": "7.5.2",
"@storybook/addon-actions": "7.5.2",
"@storybook/addon-essentials": "7.5.2",
"@storybook/addon-links": "7.5.2",
"@storybook/addon-a11y": "7.5.3",
"@storybook/addon-actions": "7.5.3",
"@storybook/addon-essentials": "7.5.3",
"@storybook/addon-links": "7.5.3",
"@storybook/mdx2-csf": "^1.1.0",
"@storybook/web-components": "7.5.2",
"@storybook/web-components-vite": "7.5.2",
"@storybook/web-components": "7.5.3",
"@storybook/web-components-vite": "7.5.3",
"@types/chai": "^4.3.5",
"@types/lodash-es": "^4.17.8",
"@types/mocha": "^10.0.1",
@@ -191,7 +191,7 @@
"rollup-plugin-esbuild": "^5.0.0",
"rollup-plugin-import-css": "^3.3.4",
"rollup-plugin-web-worker-loader": "^1.6.1",
"storybook": "7.5.2",
"storybook": "7.5.3",
"tiny-glob": "^0.2.9",
"tsc-alias": "^1.8.7",
"typescript": "^5.1.6",

View File

@@ -1,6 +1,6 @@
import { handlers as dataTypeHandlers } from './handlers/data-type/index.js';
import { handlers as relationTypeHandlers } from './handlers/relation-type.handlers.js';
import { handlers as documentTypeHandlers } from './handlers/document-type.handlers.js';
import { handlers as documentTypeHandlers } from './handlers/document-type/index.js';
import { handlers as installHandlers } from './handlers/install.handlers.js';
import * as manifestsHandlers from './handlers/manifests.handlers.js';
import { handlers as publishedStatusHandlers } from './handlers/published-status.handlers.js';

View File

@@ -4,6 +4,7 @@ import {
DocumentTypeTreeItemResponseModel,
DocumentTypeResponseModel,
ContentTypeCompositionTypeModel,
DocumentTypeItemResponseModel,
} from '@umbraco-cms/backoffice/backend-api';
export const data: Array<DocumentTypeResponseModel> = [
@@ -1166,6 +1167,20 @@ class UmbDocumentTypeData extends UmbEntityData<DocumentTypeResponseModel> {
const items = this.treeData.filter((item) => allowedTypeKeys.includes(item.id ?? ''));
return items.map((item) => item);
}
getItems(ids: Array<string>): Array<DocumentTypeItemResponseModel> {
const items = this.data.filter((item) => ids.includes(item.id ?? ''));
return items.map((item) => createDocumentTypeItem(item));
}
}
const createDocumentTypeItem = (item: DocumentTypeResponseModel): DocumentTypeItemResponseModel => {
return {
id: item.id,
name: item.name,
isElement: item.isElement,
icon: item.icon,
};
};
export const umbDocumentTypeData = new UmbDocumentTypeData();

View File

@@ -87,7 +87,7 @@ h1 {
path: 'Folder 1/Stylesheet File 3.css',
name: 'Stylesheet File 3.css',
type: 'stylesheet',
hasChildren: true,
hasChildren: false,
isFolder: false,
content: `h1 {
color: pink;
@@ -225,9 +225,10 @@ ${rule.selector} {
}
insertStyleSheet(item: CreateTextFileViewModelBaseModel) {
const parentPath = item.parentPath ? `${item.parentPath}/` : '';
const newItem: StylesheetDBItem = {
...item,
path: `${item.parentPath}/${item.name}.css`,
path: `${parentPath}${item.name}`,
isFolder: false,
hasChildren: false,
type: 'stylesheet',
@@ -238,7 +239,6 @@ ${rule.selector} {
return newItem;
}
insert(item: StylesheetDBItem) {
const exits = this.data.find((i) => i.path === item.path);

View File

@@ -1,5 +1,5 @@
import { handlers as dataTypeHandlers } from './handlers/data-type/index.js';
import { handlers as documentTypeHandlers } from './handlers/document-type.handlers.js';
import { handlers as documentTypeHandlers } from './handlers/document-type/index.js';
import { handlers as installHandlers } from './handlers/install.handlers.js';
import * as manifestsHandlers from './handlers/manifests.handlers.js';
import { handlers as publishedStatusHandlers } from './handlers/published-status.handlers.js';

View File

@@ -1,99 +0,0 @@
const { rest } = window.MockServiceWorker;
import { umbDocumentTypeData } from '../data/document-type.data.js';
import type { DocumentTypeResponseModel } from '@umbraco-cms/backoffice/backend-api';
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
// TODO: add schema
export const handlers = [
rest.post(umbracoPath(`/document-type`), async (req, res, ctx) => {
const data = await req.json();
if (!data) return;
// TODO: This is something that is missing in the Full model, but which we need to for the tree model. This should be fixed in the Full model.
data.parentId ??= null;
const created = umbDocumentTypeData.insert(data);
// TODO: remove this hack, as we get the right end-point, in that case we will be in control of the Ids. (I choose this URL to make it clear thats its a hack/mocked URL)
return res(ctx.status(200), ctx.set({ location: '/header/location/id/' + created.id }));
}),
rest.put(umbracoPath(`/document-type/:id`), async (req, res, ctx) => {
const id = req.params.id as string;
if (!id) return;
const data = await req.json();
if (!data) return;
const saved = umbDocumentTypeData.save(id, data);
return res(ctx.status(200), ctx.json(saved));
}),
rest.get('/umbraco/management/api/v1/document-type/details/:id', (req, res, ctx) => {
const id = req.params.id as string;
if (!id) return;
const document = umbDocumentTypeData.getById(id);
return res(ctx.status(200), ctx.json([document]));
}),
rest.post<DocumentTypeResponseModel>('/umbraco/management/api/v1/document-type/details/save', (req, res, ctx) => {
const data = req.body;
if (!data) return;
const saved = umbDocumentTypeData.save(data.id!, data);
return res(ctx.status(200), ctx.json(saved));
}),
rest.get('/umbraco/management/api/v1/tree/document-type/root', (req, res, ctx) => {
const rootItems = umbDocumentTypeData.getTreeRoot();
const response = {
total: rootItems.length,
items: rootItems,
};
return res(ctx.status(200), ctx.json(response));
}),
rest.get('/umbraco/management/api/v1/tree/document-type/children', (req, res, ctx) => {
const parentId = req.url.searchParams.get('parentId');
if (!parentId) return;
const children = umbDocumentTypeData.getTreeItemChildren(parentId);
const response = {
total: children.length,
items: children,
};
return res(ctx.status(200), ctx.json(response));
}),
rest.get('/umbraco/management/api/v1/tree/document-type/item', (req, res, ctx) => {
const ids = req.url.searchParams.getAll('id');
if (!ids) return;
const items = umbDocumentTypeData.getTreeItem(ids);
return res(ctx.status(200), ctx.json(items));
}),
rest.get('/umbraco/management/api/v1/document-type/:id', (req, res, ctx) => {
const id = req.params.id as string;
if (!id) return;
const documentType = umbDocumentTypeData.getById(id);
return res(ctx.status(200), ctx.json(documentType));
}),
rest.get('/umbraco/management/api/v1/document-type/allowed-children-of/:id', (req, res, ctx) => {
const id = req.params.id as string;
if (!id) return;
const items = umbDocumentTypeData.getAllowedTypesOf(id);
return res(ctx.status(200), ctx.json(items));
}),
];

View File

@@ -0,0 +1,36 @@
const { rest } = window.MockServiceWorker;
import { umbDocumentTypeData } from '../../data/document-type.data.js';
import { slug } from './slug.js';
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
export const handlers = [
rest.get(umbracoPath(`${slug}/:id`), (req, res, ctx) => {
const id = req.params.id as string;
if (!id) return;
const document = umbDocumentTypeData.getById(id);
return res(ctx.status(200), ctx.json(document));
}),
rest.delete(umbracoPath(`${slug}/:id`), (req, res, ctx) => {
const id = req.params.id as string;
if (!id) return;
const document = umbDocumentTypeData.getById(id);
return res(ctx.status(200), ctx.json(document));
}),
rest.put(umbracoPath(`${slug}/:id`), async (req, res, ctx) => {
const id = req.params.id as string;
if (!id) return;
const data = await req.json();
if (!data) return;
const saved = umbDocumentTypeData.save(id, data);
return res(ctx.status(200), ctx.json(saved));
}),
rest.post(umbracoPath(`${slug}`), async (req, res, ctx) => {
const data = await req.json();
if (!data) return;
umbDocumentTypeData.insert(data);
return res(ctx.status(200));
}),
];

View File

@@ -0,0 +1,5 @@
import { handlers as treeHandlers } from './tree.handlers.js';
import { handlers as detailHandlers } from './detail.handlers.js';
import { handlers as itemHandlers } from './item.handlers.js';
export const handlers = [...treeHandlers, ...itemHandlers, ...detailHandlers];

View File

@@ -0,0 +1,13 @@
const { rest } = window.MockServiceWorker;
import { umbDocumentTypeData } from '../../data/document-type.data.js';
import { slug } from './slug.js';
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
export const handlers = [
rest.get(umbracoPath(`${slug}/item`), (req, res, ctx) => {
const ids = req.url.searchParams.getAll('id');
if (!ids) return;
const items = umbDocumentTypeData.getItems(ids);
return res(ctx.status(200), ctx.json(items));
}),
];

View File

@@ -0,0 +1 @@
export const slug = '/document-type';

View File

@@ -0,0 +1,29 @@
const { rest } = window.MockServiceWorker;
import { umbDocumentTypeData } from '../../data/document-type.data.js';
import { slug } from './slug.js';
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
export const handlers = [
rest.get(umbracoPath(`/tree${slug}/root`), (req, res, ctx) => {
const rootItems = umbDocumentTypeData.getTreeRoot();
const response = {
total: rootItems.length,
items: rootItems,
};
return res(ctx.status(200), ctx.json(response));
}),
rest.get(umbracoPath(`/tree${slug}/children`), (req, res, ctx) => {
const parentId = req.url.searchParams.get('parentId');
if (!parentId) return;
const children = umbDocumentTypeData.getTreeItemChildren(parentId);
const response = {
total: children.length,
items: children,
};
return res(ctx.status(200), ctx.json(response));
}),
];

View File

@@ -39,8 +39,8 @@ const detailHandlers = [
const response = umbStylesheetData.getStylesheet(path);
return res(ctx.status(200), ctx.json(response));
}),
rest.post(umbracoPath('/stylesheet'), (req, res, ctx) => {
const requestBody = req.json() as CreateTextFileViewModelBaseModel;
rest.post(umbracoPath('/stylesheet'), async (req, res, ctx) => {
const requestBody = (await req.json()) as CreateTextFileViewModelBaseModel;
if (!requestBody) return res(ctx.status(400, 'no body found'));
const response = umbStylesheetData.insertStyleSheet(requestBody);
return res(ctx.status(200), ctx.json(response));
@@ -53,7 +53,7 @@ const detailHandlers = [
return res(ctx.status(200), ctx.json(response));
}),
rest.put(umbracoPath('/stylesheet'), async (req, res, ctx) => {
const requestBody = await req.json() as UpdateStylesheetRequestModel;
const requestBody = (await req.json()) as UpdateStylesheetRequestModel;
if (!requestBody) return res(ctx.status(400, 'no body found'));
umbStylesheetData.updateData(requestBody);
return res(ctx.status(200));
@@ -75,7 +75,6 @@ const detailHandlers = [
}),
];
const rulesHandlers = [
rest.post(umbracoPath('/stylesheet/rich-text/extract-rules'), async (req, res, ctx) => {
const requestBody = req.json() as ExtractRichTextStylesheetRulesRequestModel;

View File

@@ -1,3 +1,4 @@
import { DATA_TYPE_ITEM_REPOSITORY_ALIAS } from '../../repository/index.js';
import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
import { UMB_DATA_TYPE_PICKER_MODAL } from '@umbraco-cms/backoffice/modal';
@@ -5,6 +6,6 @@ import { DataTypeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
export class UmbDataTypePickerContext extends UmbPickerInputContext<DataTypeItemResponseModel> {
constructor(host: UmbControllerHostElement) {
super(host, 'Umb.Repository.DataType', UMB_DATA_TYPE_PICKER_MODAL);
super(host, DATA_TYPE_ITEM_REPOSITORY_ALIAS, UMB_DATA_TYPE_PICKER_MODAL);
}
}

View File

@@ -84,13 +84,13 @@ export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) {
this.addValidator(
'rangeUnderflow',
() => this.minMessage,
() => !!this.min && this.#pickerContext.getSelection().length < this.min
() => !!this.min && this.#pickerContext.getSelection().length < this.min,
);
this.addValidator(
'rangeOverflow',
() => this.maxMessage,
() => !!this.max && this.#pickerContext.getSelection().length > this.max
() => !!this.max && this.#pickerContext.getSelection().length > this.max,
);
this.observe(this.#pickerContext.selection, (selection) => (super.value = selection.join(',')));

View File

@@ -1,47 +1,11 @@
import { UmbDataTypeRepositoryBase } from '../data-type-repository-base.js';
import { UmbDataTypeItemServerDataSource } from './data-type-item.server.data.js';
import { UMB_DATA_TYPE_ITEM_STORE_CONTEXT } from './data-type-item.store.js';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbItemDataSource, UmbItemRepository } from '@umbraco-cms/backoffice/repository';
import { UmbItemRepositoryBase } from '@umbraco-cms/backoffice/repository';
import { DataTypeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
export class UmbDataTypeItemRepository
extends UmbDataTypeRepositoryBase
implements UmbItemRepository<DataTypeItemResponseModel>
{
#itemSource: UmbItemDataSource<DataTypeItemResponseModel>;
export class UmbDataTypeItemRepository extends UmbItemRepositoryBase<DataTypeItemResponseModel> {
constructor(host: UmbControllerHost) {
super(host);
this.#itemSource = new UmbDataTypeItemServerDataSource(host);
}
/**
* Requests the Data Type items for the given ids
* @param {Array<string>} ids
* @return {*}
* @memberof UmbDataTypeItemRepository
*/
async requestItems(ids: Array<string>) {
if (!ids) throw new Error('Ids are missing');
await this._init;
const { data, error } = await this.#itemSource.getItems(ids);
if (data) {
this._itemStore!.appendItems(data);
}
return { data, error, asObservable: () => this._itemStore!.items(ids) };
}
/**
* Returns a promise with an observable of the Data Type items for the given ids
* @param {Array<string>} ids
* @return {Promise<Observable<DataTypeItemResponseModel[]>>}
* @memberof UmbDataTypeItemRepository
*/
async items(ids: Array<string>) {
await this._init;
return this._itemStore!.items(ids);
super(host, UmbDataTypeItemServerDataSource, UMB_DATA_TYPE_ITEM_STORE_CONTEXT);
}
}

View File

@@ -1,24 +1,20 @@
import { UmbTreeRepositoryBase } from '../../tree/tree-repository-base.js';
import { DATA_TYPE_ROOT_ENTITY_TYPE } from '../entities.js';
import { UmbDataTypeRepositoryBase } from '../repository/data-type-repository-base.js';
import { UmbDataTypeTreeServerDataSource } from './data-type.tree.server.data.js';
import type { UmbTreeRepository, UmbTreeDataSource } from '@umbraco-cms/backoffice/repository';
import { UMB_DATA_TYPE_TREE_STORE_CONTEXT } from './data-type.tree.store.js';
import { UmbDataTypeTreeItemModel, UmbDataTypeTreeRootModel } from './types.js';
import { type UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { FolderTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
import { UmbApi } from '@umbraco-cms/backoffice/extension-api';
export class UmbDataTypeTreeRepository
extends UmbDataTypeRepositoryBase
implements UmbTreeRepository<FolderTreeItemResponseModel>, UmbApi
{
#treeSource: UmbTreeDataSource<FolderTreeItemResponseModel>;
export class UmbDataTypeTreeRepository
extends UmbTreeRepositoryBase<UmbDataTypeTreeItemModel, UmbDataTypeTreeRootModel>
implements UmbApi
{
constructor(host: UmbControllerHost) {
super(host);
this.#treeSource = new UmbDataTypeTreeServerDataSource(this);
super(host, UmbDataTypeTreeServerDataSource, UMB_DATA_TYPE_TREE_STORE_CONTEXT);
}
async requestTreeRoot() {
await this._init;
const data = {
id: null,
type: DATA_TYPE_ROOT_ENTITY_TYPE,
@@ -29,40 +25,4 @@ export class UmbDataTypeTreeRepository
return { data };
}
async requestRootTreeItems() {
await this._init;
const { data, error } = await this.#treeSource.getRootItems();
if (data) {
this._treeStore!.appendItems(data.items);
}
return { data, error, asObservable: () => this._treeStore!.rootItems };
}
async requestTreeItemsOf(parentId: string | null) {
await this._init;
if (parentId === undefined) throw new Error('Parent id is missing');
const { data, error } = await this.#treeSource.getChildrenOf(parentId);
if (data) {
this._treeStore!.appendItems(data.items);
}
return { data, error, asObservable: () => this._treeStore!.childrenOf(parentId) };
}
async rootTreeItems() {
await this._init;
return this._treeStore!.rootItems;
}
async treeItemsOf(parentId: string | null) {
if (parentId === undefined) throw new Error('Parent id is missing');
await this._init;
return this._treeStore!.childrenOf(parentId);
}
}

View File

@@ -1,5 +1,5 @@
import type { UmbTreeDataSource } from '@umbraco-cms/backoffice/repository';
import { DataTypeResource } from '@umbraco-cms/backoffice/backend-api';
import type { UmbTreeDataSource } from '@umbraco-cms/backoffice/tree';
import { DataTypeResource, DataTypeTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
@@ -9,7 +9,7 @@ import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
* @class UmbDataTypeTreeServerDataSource
* @implements {DocumentTreeDataSource}
*/
export class UmbDataTypeTreeServerDataSource implements UmbTreeDataSource {
export class UmbDataTypeTreeServerDataSource implements UmbTreeDataSource<DataTypeTreeItemResponseModel> {
#host: UmbControllerHost;
/**
@@ -48,7 +48,7 @@ export class UmbDataTypeTreeServerDataSource implements UmbTreeDataSource {
this.#host,
DataTypeResource.getTreeDataTypeChildren({
parentId,
})
}),
);
}
}
@@ -65,7 +65,7 @@ export class UmbDataTypeTreeServerDataSource implements UmbTreeDataSource {
this.#host,
DataTypeResource.getDataTypeItem({
id: ids,
})
}),
);
}
}

View File

@@ -1,6 +1,6 @@
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/store';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/tree';
/**
* @export

View File

@@ -0,0 +1,5 @@
import { type DataTypeTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
import type { UmbEntityTreeItemModel, UmbEntityTreeRootModel } from '@umbraco-cms/backoffice/tree';
export type UmbDataTypeTreeItemModel = DataTypeTreeItemResponseModel & UmbEntityTreeItemModel;
export type UmbDataTypeTreeRootModel = DataTypeTreeItemResponseModel & UmbEntityTreeRootModel;

View File

@@ -1,5 +1,6 @@
import type { ManifestApi } from '@umbraco-cms/backoffice/extension-api';
import { UmbItemStore, UmbStoreBase, UmbTreeStore } from '@umbraco-cms/backoffice/store';
import { type ManifestApi } from '@umbraco-cms/backoffice/extension-api';
import { UmbItemStore, UmbStoreBase } from '@umbraco-cms/backoffice/store';
import { type UmbTreeStore } from '@umbraco-cms/backoffice/tree';
export interface ManifestStore extends ManifestApi<UmbStoreBase> {
type: 'store';

View File

@@ -7,7 +7,7 @@ import {
UmbModalBaseElement,
} from '@umbraco-cms/backoffice/modal';
import { generateAlias } from '@umbraco-cms/backoffice/utils';
import { UMB_DOCUMENT_TYPE_STORE_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/document-type';
import { UMB_DOCUMENT_TYPE_DETAIL_STORE_CONTEXT } from '@umbraco-cms/backoffice/document-type';
// TODO: Could base take a token to get its types?.
// TODO: Missing a workspace context... unless this should not be a workspace any way.
@customElement('umb-property-settings-modal')
@@ -53,7 +53,7 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement<
super.connectedCallback();
// TODO: This is actually not good enough, we need to be able to get to the DOCUMENT_WORKSPACE_CONTEXT, so we can have a look at the draft/runtime version of the document. Otherwise 'Vary by culture' is first updated when saved.
this.consumeContext(UMB_DOCUMENT_TYPE_STORE_CONTEXT_TOKEN, (instance) => {
this.consumeContext(UMB_DOCUMENT_TYPE_DETAIL_STORE_CONTEXT, (instance) => {
this.observe(
instance.byId(this.data?.documentTypeId),
(documentType) => {

View File

@@ -14,6 +14,6 @@ export const UMB_DOCUMENT_TYPE_PICKER_MODAL = new UmbModalToken<
size: 'small',
},
{
treeAlias: 'Umb.Tree.DocumentTypes',
treeAlias: 'Umb.Tree.DocumentType',
},
);

View File

@@ -5,7 +5,5 @@ export * from './data-source.interface.js';
export * from './extend-data-source-paged-response-data.function.js';
export * from './extend-data-source-response-data.function.js';
export * from './folder-data-source.interface.js';
export * from './item-data-source.interface.js';
export * from './move-data-source.interface.js';
export * from './tree-data-source.interface.js';
export * from './types.js';

View File

@@ -1,5 +0,0 @@
import type { DataSourceResponse } from '@umbraco-cms/backoffice/repository';
export interface UmbItemDataSource<ItemType> {
getItems(unique: Array<string>): Promise<DataSourceResponse<Array<ItemType>>>;
}

View File

@@ -1,9 +0,0 @@
import type { UmbPagedData } from './types.js';
import type { DataSourceResponse } from './data-source-response.interface.js';
export interface UmbTreeDataSource<ItemType = any, PagedItemType = UmbPagedData<ItemType>> {
getRootItems(): Promise<DataSourceResponse<PagedItemType>>;
getChildrenOf(parentUnique: string | null): Promise<DataSourceResponse<PagedItemType>>;
// TODO: remove this when all repositories are migrated to the new items interface
getItems(unique: Array<string>): Promise<DataSourceResponse<Array<any>>>;
}

View File

@@ -1,4 +1,4 @@
export interface UmbPagedData<T> {
total: number;
items: Array<T>;
}
}

View File

@@ -1,10 +1,10 @@
export * from './data-source/index.js';
export * from './detail-repository.interface.js';
export * from './tree-repository.interface.js';
export * from './folder-repository.interface.js';
export * from './collection-repository.interface.js';
export * from './item-repository.interface.js';
export * from './move-repository.interface.js';
export * from './copy-repository.interface.js';
export * from './repository-items.manager.js';
export * from './repository-base.js';
export * from './item/index.js';

View File

@@ -0,0 +1,3 @@
export * from './item-data-source.interface.js';
export * from './item-repository-base.js';
export * from './item-repository.interface.js';

View File

@@ -0,0 +1,9 @@
import { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import type { DataSourceResponse } from '@umbraco-cms/backoffice/repository';
export interface UmbItemDataSourceConstructor<ItemType = any> {
new (host: UmbControllerHost): UmbItemDataSource<ItemType>;
}
export interface UmbItemDataSource<ItemType = any> {
getItems(unique: Array<string>): Promise<DataSourceResponse<Array<ItemType>>>;
}

View File

@@ -0,0 +1,55 @@
import { UmbRepositoryBase } from '../repository-base.js';
import { UmbItemDataSource, UmbItemDataSourceConstructor } from './item-data-source.interface.js';
import { UmbItemRepository } from './item-repository.interface.js';
import { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbItemStore } from '@umbraco-cms/backoffice/store';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
export class UmbItemRepositoryBase<ItemType = any> extends UmbRepositoryBase implements UmbItemRepository<ItemType> {
protected _init: Promise<unknown>;
protected _itemStore?: UmbItemStore;
#itemSource: UmbItemDataSource;
constructor(
host: UmbControllerHost,
itemSource: UmbItemDataSourceConstructor,
itemStoreContextAlias: string | UmbContextToken<any, any>,
) {
super(host);
this.#itemSource = new itemSource(host);
this._init = this.consumeContext(itemStoreContextAlias, (instance) => {
this._itemStore = instance as UmbItemStore;
}).asPromise();
}
/**
* Requests the items for the given uniques
* @param {Array<string>} uniques
* @return {*}
* @memberof UmbItemRepositoryBase
*/
async requestItems(uniques: Array<string>) {
if (!uniques) throw new Error('Uniques are missing');
await this._init;
const { data, error } = await this.#itemSource.getItems(uniques);
if (data) {
this._itemStore!.appendItems(data);
}
return { data, error, asObservable: () => this._itemStore!.items(uniques) };
}
/**
* Returns a promise with an observable of the items for the given uniques
* @param {Array<string>} uniques
* @return {*}
* @memberof UmbItemRepositoryBase
*/
async items(uniques: Array<string>) {
await this._init;
return this._itemStore!.items(uniques);
}
}

View File

@@ -1,8 +1,8 @@
import type { Observable } from '@umbraco-cms/backoffice/external/rxjs';
import { ItemResponseModelBaseModel, ProblemDetails } from '@umbraco-cms/backoffice/backend-api';
import { ProblemDetails } from '@umbraco-cms/backoffice/backend-api';
import { UmbApi } from '@umbraco-cms/backoffice/extension-api';
export interface UmbItemRepository<ItemType extends ItemResponseModelBaseModel> extends UmbApi {
export interface UmbItemRepository<ItemType = any> extends UmbApi {
requestItems: (uniques: string[]) => Promise<{
data?: Array<ItemType> | undefined;
error?: ProblemDetails | undefined;

View File

@@ -1,7 +1,7 @@
import { UmbBaseController, UmbControllerHost } from "@umbraco-cms/backoffice/controller-api";
import { UmbBaseController, UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
export class UmbRepositoryBase extends UmbBaseController {
constructor(host: UmbControllerHost) {
super(host);
}
}
constructor(host: UmbControllerHost) {
super(host);
}
}

View File

@@ -1,4 +1,4 @@
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, nothing, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import type { UmbRoute, UmbRouterSlotChangeEvent, UmbRouterSlotInitEvent } from '@umbraco-cms/backoffice/router';
import {
@@ -110,8 +110,8 @@ export class UmbSectionMainViewElement extends UmbLitElement {
const dashboardPath = this.#constructDashboardPath(dashboard);
return html`
<uui-tab
.label="${dashboardName}"
href="${this._routerPath}/${dashboardPath}"
label="${dashboardName}"
?active="${this._activePath === dashboardPath}"></uui-tab>
`;
})}
@@ -129,8 +129,8 @@ export class UmbSectionMainViewElement extends UmbLitElement {
const viewPath = this.#constructViewPath(view);
return html`
<uui-tab
.label="${viewName}"
href="${this._routerPath}/${viewPath}"
label="${viewName}"
?active="${this._activePath === viewPath}">
<uui-icon slot="icon" name=${view.meta.icon}></uui-icon>
${viewName}

View File

@@ -0,0 +1,31 @@
import { UmbStoreBase } from './store-base.js';
import { UmbItemStore } from './item-store.interface.js';
import type { FileItemResponseModelBaseModel } from '@umbraco-cms/backoffice/backend-api';
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
import { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
/**
* @export
* @class UmbFileSystemItemStore
* @extends {UmbStoreBase}
* @description - Data Store for File system items
*/
export class UmbFileSystemItemStore<T extends FileItemResponseModelBaseModel>
extends UmbStoreBase<T>
implements UmbItemStore<T>
{
constructor(host: UmbControllerHost, storeAlias: string) {
super(host, storeAlias, new UmbArrayState<T>([], (x) => x.path));
}
/**
* Return an observable to observe file system items
* @param {Array<string>} paths
* @return {*}
* @memberof UmbFileSystemItemStore
*/
items(paths: Array<string>) {
return this._data.asObservablePart((items) => items.filter((item) => paths.includes(item.path ?? '')));
}
}

View File

@@ -1,8 +1,6 @@
export * from './entity-tree-store.js';
export * from './file-system-tree.store.js';
export * from './item-store.interface.js';
export * from './store-base.js';
export * from './store.interface.js';
export * from './store.js';
export * from './tree-store.interface.js';
export * from './entity-item.store.js';
export * from './file-system-item.store.js';

View File

@@ -1,5 +1,5 @@
import { UmbStoreBase } from './store-base.js';
import type { UmbTreeStore } from './tree-store.interface.js';
import { type UmbTreeStore } from './tree-store.interface.js';
import { UmbStoreBase } from '@umbraco-cms/backoffice/store';
import { EntityTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';

View File

@@ -1,5 +1,5 @@
import { UmbStoreBase } from './store-base.js';
import { UmbTreeStore } from './tree-store.interface.js';
import { type UmbTreeStore } from './tree-store.interface.js';
import { UmbStoreBase } from '@umbraco-cms/backoffice/store';
import { FileSystemTreeItemPresentationModel } from '@umbraco-cms/backoffice/backend-api';
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
@@ -31,9 +31,11 @@ export class UmbFileSystemTreeStore
* @memberof UmbFileSystemTreeStore
*/
childrenOf(parentPath: string | null) {
return this._data.asObservablePart((items) =>
items.filter((item) => item.path?.startsWith(parentPath + '/') || parentPath === null)
);
if (parentPath === null) {
return this.rootItems;
}
return this._data.asObservablePart((items) => items.filter((item) => item.path?.startsWith(parentPath + '/')));
}
/**

View File

@@ -1,3 +1,4 @@
export * from './components/index.js';
export * from './entity-tree-item/index.js';
export * from './file-system-tree-item/index.js';
export * from './tree-item/index.js';
@@ -5,19 +6,11 @@ export * from './tree-item-base/index.js';
export * from './tree-menu-item/index.js';
export * from './tree.context.js';
export * from './tree.element.js';
export * from './components/index.js';
export * from './types.js';
export * from './tree-repository.interface.js';
export * from './tree-data-source.interface.js';
export * from './tree-store.interface.js';
export * from './entity-tree-store.js';
export * from './file-system-tree.store.js';
export interface UmbTreeRootModel {
type: string;
name: string;
hasChildren: boolean;
icon?: string;
}
export interface UmbTreeRootEntityModel extends UmbTreeRootModel {
id: string | null;
}
export interface UmbTreeRootFileSystemModel extends UmbTreeRootModel {
path: string | null;
}
export { UmbTreeRepositoryBase } from './tree-repository-base.js';

View File

@@ -0,0 +1,14 @@
import type { UmbPagedData, DataSourceResponse } from '@umbraco-cms/backoffice/repository';
import { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
export interface UmbTreeDataSourceConstructor<TreeItemType = any, TreeRootType = any> {
new (host: UmbControllerHost): UmbTreeDataSource<TreeItemType, TreeRootType>;
}
export interface UmbTreeDataSource<TreeItemType = any, TreeRootType = any> {
getTreeRoot?(): Promise<DataSourceResponse<TreeRootType>>;
getRootItems(): Promise<DataSourceResponse<UmbPagedData<TreeItemType>>>;
getChildrenOf(parentUnique: string | null): Promise<DataSourceResponse<UmbPagedData<TreeItemType>>>;
// TODO: remove this when all repositories are migrated to the new items interface
getItems(unique: Array<string>): Promise<DataSourceResponse<Array<any>>>;
}

View File

@@ -0,0 +1,104 @@
import { UmbTreeStore } from './tree-store.interface.js';
import type { UmbEntityTreeItemModel, UmbEntityTreeRootModel } from './types.js';
import { UmbTreeRepository } from './tree-repository.interface.js';
import type { UmbTreeDataSource, UmbTreeDataSourceConstructor } from './tree-data-source.interface.js';
import { UmbRepositoryBase } from '@umbraco-cms/backoffice/repository';
import { type UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbApi } from '@umbraco-cms/backoffice/extension-api';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
export class UmbTreeRepositoryBase<
TreeItemType extends UmbEntityTreeItemModel,
TreeRootType extends UmbEntityTreeRootModel,
>
extends UmbRepositoryBase
implements UmbTreeRepository<TreeItemType, TreeRootType>, UmbApi
{
protected _init: Promise<unknown>;
protected _treeStore?: UmbTreeStore;
#treeSource: UmbTreeDataSource;
constructor(
host: UmbControllerHost,
treeSource: UmbTreeDataSourceConstructor,
treeStoreContextAlias: string | UmbContextToken<any, any>,
) {
super(host);
this.#treeSource = new treeSource(this);
this._init = this.consumeContext(treeStoreContextAlias, (instance) => {
this._treeStore = instance as UmbTreeStore;
}).asPromise();
}
/**
* Request the tree root item
* @return {*}
* @memberof UmbTreeRepositoryBase
*/
async requestTreeRoot() {
if (!this.#treeSource.getTreeRoot?.()) {
return { data: undefined, error: undefined };
}
return this.#treeSource.getTreeRoot();
}
/**
* Requests root items of a tree
* @return {*}
* @memberof UmbTreeRepositoryBase
*/
async requestRootTreeItems() {
await this._init;
const { data, error } = await this.#treeSource.getRootItems();
if (data) {
this._treeStore!.appendItems(data.items);
}
return { data, error, asObservable: () => this._treeStore!.rootItems };
}
/**
* Requests tree items of a given parent
* @param {(string | null)} parentUnique
* @return {*}
* @memberof UmbTreeRepositoryBase
*/
async requestTreeItemsOf(parentUnique: string | null) {
if (parentUnique === undefined) throw new Error('Parent unique is missing');
await this._init;
const { data, error } = await this.#treeSource.getChildrenOf(parentUnique);
if (data) {
this._treeStore!.appendItems(data.items);
}
return { data, error, asObservable: () => this._treeStore!.childrenOf(parentUnique) };
}
/**
* Returns a promise with an observable of tree root items
* @return {*}
* @memberof UmbTreeRepositoryBase
*/
async rootTreeItems() {
await this._init;
return this._treeStore!.rootItems;
}
/**
* Returns a promise with an observable of children items of a given parent
* @param {(string | null)} parentUnique
* @return {*}
* @memberof UmbTreeRepositoryBase
*/
async treeItemsOf(parentUnique: string | null) {
if (parentUnique === undefined) throw new Error('Parent unique is missing');
await this._init;
return this._treeStore!.childrenOf(parentUnique);
}
}

View File

@@ -1,30 +1,39 @@
import { type UmbPagedData } from './data-source/types.js';
import type { UmbTreeItemModelBase, UmbTreeItemModel, UmbEntityTreeRootModel } from './types.js';
import type { UmbPagedData } from '@umbraco-cms/backoffice/repository';
import { type Observable } from '@umbraco-cms/backoffice/external/rxjs';
import type { UmbTreeRootEntityModel, UmbTreeRootModel } from '@umbraco-cms/backoffice/tree';
import { ProblemDetails, EntityTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
import { ProblemDetails } from '@umbraco-cms/backoffice/backend-api';
import { UmbApi } from '@umbraco-cms/backoffice/extension-api';
export interface UmbTreeRepository<
TreeItemType extends EntityTreeItemResponseModel,
TreeRootType extends UmbTreeRootModel = UmbTreeRootEntityModel
TreeItemType extends UmbTreeItemModel = UmbTreeItemModel,
TreeRootType extends UmbTreeItemModelBase = UmbEntityTreeRootModel,
> extends UmbApi {
requestTreeRoot: () => Promise<{
data?: TreeRootType;
error?: ProblemDetails;
}>;
requestRootTreeItems: () => Promise<{
data?: UmbPagedData<TreeItemType>;
error?: ProblemDetails;
asObservable?: () => Observable<TreeItemType[]>;
}>;
requestTreeItemsOf: (parentUnique: string | null) => Promise<{
data?: UmbPagedData<TreeItemType>;
error?: ProblemDetails;
asObservable?: () => Observable<TreeItemType[]>;
}>;
treeItemsOf: (parentUnique: string | null) => Promise<Observable<TreeItemType[]>>;
/* TODO: remove this. It is not used client side.
Logic to call the root endpoint should be in the data source
because it is a server decision to split them
*/
requestRootTreeItems: () => Promise<{
data?: UmbPagedData<TreeItemType>;
error?: ProblemDetails;
asObservable?: () => Observable<TreeItemType[]>;
}>;
// TODO: remove
rootTreeItems: () => Promise<Observable<TreeItemType[]>>;
// TODO: remove this when all repositories are migrated to the new interface items interface
requestItemsLegacy?: (uniques: string[]) => Promise<{
data?: Array<TreeItemType>;
@@ -32,10 +41,6 @@ export interface UmbTreeRepository<
asObservable?: () => Observable<any[]>;
}>;
rootTreeItems: () => Promise<Observable<TreeItemType[]>>;
treeItemsOf: (parentUnique: string | null) => Promise<Observable<TreeItemType[]>>;
// TODO: remove this when all repositories are migrated to the new items interface
itemsLegacy?: (uniques: string[]) => Promise<Observable<any[]>>;
}

View File

@@ -1,4 +1,4 @@
import { UmbStore } from './store.interface.js';
import { UmbStore } from '@umbraco-cms/backoffice/store';
import type { Observable } from '@umbraco-cms/backoffice/external/rxjs';
import { TreeItemPresentationModel } from '@umbraco-cms/backoffice/backend-api';
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';

View File

@@ -1,15 +1,21 @@
import { type UmbTreeItemModelBase } from './types.js';
import { type UmbTreeRepository } from './tree-repository.interface.js';
import { Observable } from '@umbraco-cms/backoffice/external/rxjs';
import { UmbPagedData, UmbTreeRepository } from '@umbraco-cms/backoffice/repository';
import { type ManifestRepository, type ManifestTree, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import { UmbPagedData } from '@umbraco-cms/backoffice/repository';
import {
type ManifestRepository,
type ManifestTree,
umbExtensionsRegistry,
} from '@umbraco-cms/backoffice/extension-registry';
import { UmbBooleanState } from '@umbraco-cms/backoffice/observable-api';
import { UmbBaseController, UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
import { UmbExtensionApiInitializer } from '@umbraco-cms/backoffice/extension-api';
import { ProblemDetails, TreeItemPresentationModel } from '@umbraco-cms/backoffice/backend-api';
import { ProblemDetails } from '@umbraco-cms/backoffice/backend-api';
import { UmbSelectionManager } from '@umbraco-cms/backoffice/utils';
import { UmbSelectionChangeEvent } from '@umbraco-cms/backoffice/event';
// TODO: update interface
export interface UmbTreeContext<TreeItemType extends TreeItemPresentationModel> extends UmbBaseController {
export interface UmbTreeContext<TreeItemType extends UmbTreeItemModelBase> extends UmbBaseController {
readonly selectable: Observable<boolean>;
readonly selection: Observable<Array<string | null>>;
setSelectable(value: boolean): void;
@@ -27,7 +33,7 @@ export interface UmbTreeContext<TreeItemType extends TreeItemPresentationModel>
}>;
}
export class UmbTreeContextBase<TreeItemType extends TreeItemPresentationModel>
export class UmbTreeContextBase<TreeItemType extends UmbTreeItemModelBase>
extends UmbBaseController
implements UmbTreeContext<TreeItemType>
{
@@ -153,9 +159,15 @@ export class UmbTreeContextBase<TreeItemType extends TreeItemPresentationModel>
const repositoryAlias = treeManifest.meta.repositoryAlias;
if (!repositoryAlias) throw new Error('Tree must have a repository alias.');
new UmbExtensionApiInitializer<ManifestRepository<UmbTreeRepository<TreeItemType>>>(this, umbExtensionsRegistry, repositoryAlias, [this._host], (permitted, ctrl) => {
this.repository = permitted ? ctrl.api : undefined;
this.#checkIfInitialized();
});
new UmbExtensionApiInitializer<ManifestRepository<UmbTreeRepository<TreeItemType>>>(
this,
umbExtensionsRegistry,
repositoryAlias,
[this._host],
(permitted, ctrl) => {
this.repository = permitted ? ctrl.api : undefined;
this.#checkIfInitialized();
},
);
}
}

View File

@@ -0,0 +1,27 @@
export interface UmbTreeItemModelBase {
type?: string; // TODO: remove option to be undefined when we have our own types
name?: string;
hasChildren?: boolean;
icon?: string | null;
}
export interface UmbTreeItemModel extends UmbTreeItemModelBase {
parentId?: string | null; // TODO: remove option to be undefined when server returns the same or when we get our own types
}
export interface UmbEntityTreeItemModel extends UmbTreeItemModel {
id?: string; // TODO: remove option to be undefined when server returns the same or when we get our own types
}
export interface UmbFileSystemTreeItemModel extends UmbTreeItemModel {
path?: string; // TODO: remove option to be undefined when server returns the same or when we get our own types
}
// Root
export interface UmbEntityTreeRootModel extends UmbTreeItemModelBase {
id: null;
}
export interface UmbFileSystemTreeRootModel extends UmbTreeItemModelBase {
path: null;
}

View File

@@ -1,54 +1,16 @@
import { UmbDictionaryRepository } from '../../repository/dictionary.repository.js';
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
import { UmbSectionSidebarContext, UMB_SECTION_SIDEBAR_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/section';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
import {
UmbModalManagerContext,
UMB_MODAL_MANAGER_CONTEXT_TOKEN,
UMB_CREATE_DICTIONARY_MODAL,
} from '@umbraco-cms/backoffice/modal';
export default class UmbCreateDictionaryEntityAction extends UmbEntityActionBase<UmbDictionaryRepository> {
static styles = [UmbTextStyles];
#modalContext?: UmbModalManagerContext;
#sectionSidebarContext!: UmbSectionSidebarContext;
constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) {
super(host, repositoryAlias, unique);
this.consumeContext(UMB_MODAL_MANAGER_CONTEXT_TOKEN, (instance) => {
this.#modalContext = instance;
});
this.consumeContext(UMB_SECTION_SIDEBAR_CONTEXT_TOKEN, (instance) => {
this.#sectionSidebarContext = instance;
});
}
async execute() {
// TODO: what to do if modal service is not available?
if (!this.#modalContext) return;
if (!this.repository) return;
// TODO: how can we get the current entity detail in the modal? Passing the observable
// feels a bit hacky. Works, but hacky.
const modalContext = this.#modalContext?.open(UMB_CREATE_DICTIONARY_MODAL, {
parentId: this.unique,
parentName: this.#sectionSidebarContext.headline,
});
const { name, parentId } = await modalContext.onSubmit();
if (!name || parentId === undefined) return;
const { data: url } = await this.repository.create({ name, parentId });
if (!url) return;
//TODO: Why do we need to extract the id like this?
const id = url.substring(url.lastIndexOf('/') + 1);
history.pushState({}, '', `/section/dictionary/workspace/dictionary-item/edit/${id}`);
history.pushState({}, '', `/section/dictionary/workspace/dictionary-item/create/${this.unique ?? 'null'}`);
}
}

View File

@@ -3,7 +3,8 @@ import { UmbDictionaryDetailServerDataSource } from './sources/dictionary.detail
import { UmbDictionaryTreeStore, UMB_DICTIONARY_TREE_STORE_CONTEXT_TOKEN } from './dictionary.tree.store.js';
import { UmbDictionaryTreeServerDataSource } from './sources/dictionary.tree.server.data.js';
import { UmbBaseController, UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
import { UmbTreeDataSource, UmbDetailRepository, UmbTreeRepository } from '@umbraco-cms/backoffice/repository';
import { UmbDetailRepository } from '@umbraco-cms/backoffice/repository';
import { UmbTreeRepository, UmbTreeDataSource } from '@umbraco-cms/backoffice/tree';
import {
CreateDictionaryItemRequestModel,
DictionaryOverviewResponseModel,
@@ -14,7 +15,8 @@ import {
import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification';
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
export class UmbDictionaryRepository extends UmbBaseController
export class UmbDictionaryRepository
extends UmbBaseController
implements
UmbTreeRepository<EntityTreeItemResponseModel>,
UmbDetailRepository<
@@ -109,6 +111,20 @@ export class UmbDictionaryRepository extends UmbBaseController
return { data, error, asObservable: () => this.#treeStore!.items(ids) };
}
async requestItems(ids: Array<string>) {
// TODO: There is a bug where the item gets removed from the tree before we confirm the delete via the modal. It doesn't delete the item unless we confirm the delete.
if (!ids) throw new Error('Dictionary Ids are missing');
await this.#init;
const { data, error } = await this.#treeSource.getItems(ids);
if (data) {
this.#treeStore?.appendItems(data);
}
return { data, error, asObservable: () => this.#treeStore!.items(ids) };
}
async rootTreeItems() {
await this.#init;
return this.#treeStore!.rootItems;

View File

@@ -1,5 +1,5 @@
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/store';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/tree';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
/**
@@ -20,5 +20,5 @@ export class UmbDictionaryTreeStore extends UmbEntityTreeStore {
}
export const UMB_DICTIONARY_TREE_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbDictionaryTreeStore>(
'UmbDictionaryTreeStore'
'UmbDictionaryTreeStore',
);

View File

@@ -1,6 +1,6 @@
import { DictionaryResource } from '@umbraco-cms/backoffice/backend-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import type { UmbTreeDataSource } from '@umbraco-cms/backoffice/repository';
import type { UmbTreeDataSource } from '@umbraco-cms/backoffice/tree';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
/**
@@ -48,7 +48,7 @@ export class UmbDictionaryTreeServerDataSource implements UmbTreeDataSource {
this.#host,
DictionaryResource.getTreeDictionaryChildren({
parentId,
})
}),
);
}
}
@@ -68,7 +68,7 @@ export class UmbDictionaryTreeServerDataSource implements UmbTreeDataSource {
this.#host,
DictionaryResource.getDictionaryItem({
id: ids,
})
}),
);
}
}

View File

@@ -68,9 +68,8 @@ export class UmbDictionaryWorkspaceContext
const { data } = await this.repository.createScaffold(parentId);
if (!data) return;
this.setIsNew(true);
// TODO: This is a hack to get around the fact that the data is not typed correctly.
// Create and response models are different. We need to look into this.
this.#data.next(data as unknown as DictionaryItemResponseModel);
this.#data.next(data as DictionaryItemResponseModel);
}
async save() {

View File

@@ -26,7 +26,6 @@ export class UmbWorkspaceDictionaryElement extends UmbLitElement {
component: () => this.#element,
setup: async (_component, info) => {
const parentId = info.match.params.parentId === 'null' ? null : info.match.params.parentId;
await this.#workspaceContext.create(parentId);
new UmbWorkspaceIsNewRedirectController(

View File

@@ -1,9 +1,9 @@
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/store';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/tree';
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
export const UMB_DOCUMENT_BLUEPRINT_TREE_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbDocumentBlueprintTreeStore>(
'UmbDocumentBlueprintTreeStore'
'UmbDocumentBlueprintTreeStore',
);
/**

View File

@@ -0,0 +1,11 @@
import { DOCUMENT_TYPE_ITEM_REPOSITORY_ALIAS } from '../../repository/index.js';
import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
import { UMB_DOCUMENT_TYPE_PICKER_MODAL } from '@umbraco-cms/backoffice/modal';
import { DocumentTypeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
export class UmbDocumentTypePickerContext extends UmbPickerInputContext<DocumentTypeItemResponseModel> {
constructor(host: UmbControllerHostElement) {
super(host, DOCUMENT_TYPE_ITEM_REPOSITORY_ALIAS, UMB_DOCUMENT_TYPE_PICKER_MODAL);
}
}

View File

@@ -0,0 +1,143 @@
import { UmbDocumentTypePickerContext } from './document-type-input.context.js';
import { css, html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
import type { DocumentTypeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
@customElement('umb-document-type-input')
export class UmbDocumentTypeInputElement extends FormControlMixin(UmbLitElement) {
/**
* This is a minimum amount of selected items in this input.
* @type {number}
* @attr
* @default 0
*/
@property({ type: Number })
public get min(): number {
return this.#pickerContext.min;
}
public set min(value: number) {
this.#pickerContext.min = value;
}
/**
* Min validation message.
* @type {boolean}
* @attr
* @default
*/
@property({ type: String, attribute: 'min-message' })
minMessage = 'This field need more items';
/**
* This is a maximum amount of selected items in this input.
* @type {number}
* @attr
* @default Infinity
*/
@property({ type: Number })
public get max(): number {
return this.#pickerContext.max;
}
public set max(value: number) {
this.#pickerContext.max = value;
}
/**
* Max validation message.
* @type {boolean}
* @attr
* @default
*/
@property({ type: String, attribute: 'min-message' })
maxMessage = 'This field exceeds the allowed amount of items';
public get selectedIds(): Array<string> {
return this.#pickerContext.getSelection();
}
public set selectedIds(ids: Array<string>) {
this.#pickerContext.setSelection(ids);
}
@property()
public set value(idsString: string) {
// Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection.
this.selectedIds = idsString.split(/[ ,]+/);
}
@property()
get pickableFilter() {
return this.#pickerContext.pickableFilter;
}
set pickableFilter(newVal) {
this.#pickerContext.pickableFilter = newVal;
}
@state()
private _items?: Array<DocumentTypeItemResponseModel>;
#pickerContext = new UmbDocumentTypePickerContext(this);
constructor() {
super();
this.addValidator(
'rangeUnderflow',
() => this.minMessage,
() => !!this.min && this.#pickerContext.getSelection().length < this.min,
);
this.addValidator(
'rangeOverflow',
() => this.maxMessage,
() => !!this.max && this.#pickerContext.getSelection().length > this.max,
);
this.observe(this.#pickerContext.selection, (selection) => (super.value = selection.join(',')));
this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems));
}
protected getFormElement() {
return undefined;
}
render() {
return html`
<uui-ref-list>${this._items?.map((item) => this._renderItem(item))}</uui-ref-list>
<uui-button id="add-button" look="placeholder" @click=${() => this.#pickerContext.openPicker()} label="open"
>Add</uui-button
>
`;
}
private _renderItem(item: DocumentTypeItemResponseModel) {
if (!item.id) return;
return html`
<uui-ref-node-document-type name=${item.name}>
<uui-action-bar slot="actions">
<uui-button
@click=${() => this.#pickerContext.requestRemoveItem(item.id!)}
label="Remove Document Type ${item.name}"
>Remove</uui-button
>
</uui-action-bar>
</uui-ref-node-document-type>
`;
}
static styles = [
css`
#add-button {
width: 100%;
}
`,
];
}
export default UmbDocumentTypeInputElement;
declare global {
interface HTMLElementTagNameMap {
'umb-document-type-input': UmbDocumentTypeInputElement;
}
}

View File

@@ -1 +1 @@
import './input-document-type/input-document-type.element.js';
import './document-type-input/document-type-input.element.js';

View File

@@ -1,138 +0,0 @@
import {
UmbDocumentTypeTreeStore,
UMB_DOCUMENT_TYPE_TREE_STORE_CONTEXT_TOKEN,
} from '../../repository/document-type.tree.store.js';
import { css, html, nothing, ifDefined, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { DocumentTypeResponseModel, EntityTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
import {
UmbModalManagerContext,
UMB_MODAL_MANAGER_CONTEXT_TOKEN,
UMB_CONFIRM_MODAL,
UMB_DOCUMENT_TYPE_PICKER_MODAL,
} from '@umbraco-cms/backoffice/modal';
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
import { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
@customElement('umb-input-document-type')
export class UmbInputDocumentTypeElement extends FormControlMixin(UmbLitElement) {
// TODO: do we need both selectedIds and value? If we just use value we follow the same pattern as native form controls.
private _selectedIds: Array<string> = [];
@property({ type: Array })
public get selectedIds(): Array<string> {
return this._selectedIds;
}
public set selectedIds(ids: Array<string>) {
this._selectedIds = ids ?? [];
super.value = this._selectedIds.join(',');
this._observePickedDocuments();
}
@property()
public set value(idsString: string) {
if (idsString !== this._value) {
this.selectedIds = idsString.split(/[ ,]+/);
}
}
@state()
private _items?: Array<DocumentTypeResponseModel>;
private _modalContext?: UmbModalManagerContext;
private _documentTypeStore?: UmbDocumentTypeTreeStore;
private _pickedItemsObserver?: UmbObserverController<EntityTreeItemResponseModel[]>;
constructor() {
super();
this.consumeContext(UMB_DOCUMENT_TYPE_TREE_STORE_CONTEXT_TOKEN, (instance) => {
this._documentTypeStore = instance;
this._observePickedDocuments();
});
this.consumeContext(UMB_MODAL_MANAGER_CONTEXT_TOKEN, (instance) => {
this._modalContext = instance;
});
}
protected getFormElement() {
return undefined;
}
private _observePickedDocuments() {
this._pickedItemsObserver?.destroy();
if (!this._documentTypeStore) return;
// TODO: consider changing this to the list data endpoint when it is available
this._pickedItemsObserver = this.observe(this._documentTypeStore.items(this._selectedIds), (items) => {
this._items = items;
});
}
private _openPicker() {
// We send a shallow copy(good enough as its just an array of ids) of our this._selectedIds, as we don't want the modal to manipulate our data:
const modalContext = this._modalContext?.open(UMB_DOCUMENT_TYPE_PICKER_MODAL, {
multiple: true,
selection: [...this._selectedIds],
});
modalContext?.onSubmit().then(({ selection }: any) => {
this._setSelection(selection);
});
}
private async _removeItem(item: DocumentTypeResponseModel) {
const modalContext = this._modalContext?.open(UMB_CONFIRM_MODAL, {
color: 'danger',
headline: `Remove ${item.name}?`,
content: 'Are you sure you want to remove this item',
confirmLabel: 'Remove',
});
await modalContext?.onSubmit();
const newSelection = this._selectedIds.filter((value) => value !== item.id);
this._setSelection(newSelection);
}
private _setSelection(newSelection: Array<string>) {
this.selectedIds = newSelection;
this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }));
}
render() {
return html`
<uui-ref-list> ${this._items?.map((item) => this._renderItem(item))} </uui-ref-list>
<uui-button id="add-button" look="placeholder" @click=${this._openPicker} label="open">Add</uui-button>
`;
}
private _renderItem(item: DocumentTypeResponseModel) {
// TODO: remove when we have a way to handle trashed items
const tempItem = item as DocumentTypeResponseModel & { isTrashed: boolean };
return html`
<uui-ref-node name=${ifDefined(item.name === null ? undefined : item.name)} detail=${ifDefined(item.id)}>
<uui-icon slot="icon" name="${ifDefined(item.icon)}"></uui-icon>
${tempItem.isTrashed ? html` <uui-tag size="s" slot="tag" color="danger">Trashed</uui-tag> ` : nothing}
<uui-action-bar slot="actions">
<uui-button @click=${() => this._removeItem(item)} label="Remove document ${item.name}">Remove</uui-button>
</uui-action-bar>
</uui-ref-node>
`;
}
static styles = [
css`
#add-button {
width: 100%;
}
`,
];
}
export default UmbInputDocumentTypeElement;
declare global {
interface HTMLElementTagNameMap {
'umb-input-document-type': UmbInputDocumentTypeElement;
}
}

View File

@@ -1,10 +1,10 @@
import { UmbDocumentTypeRepository } from '../../repository/document-type.repository.js';
import { UmbDocumentTypeDetailRepository } from '../../repository/detail/document-type-detail.repository.js';
import { UMB_DOCUMENT_TYPE_CREATE_OPTIONS_MODAL } from './modal/index.js';
import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
import { UmbModalManagerContext, UMB_MODAL_MANAGER_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/modal';
export class UmbCreateDataTypeEntityAction extends UmbEntityActionBase<UmbDocumentTypeRepository> {
export class UmbCreateDataTypeEntityAction extends UmbEntityActionBase<UmbDocumentTypeDetailRepository> {
#modalManagerContext?: UmbModalManagerContext;
constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) {

View File

@@ -3,7 +3,7 @@ import {
DOCUMENT_TYPE_FOLDER_ENTITY_TYPE,
DOCUMENT_TYPE_ROOT_ENTITY_TYPE,
} from '../../index.js';
import { DOCUMENT_TYPE_REPOSITORY_ALIAS } from '../../repository/manifests.js';
import { DOCUMENT_TYPE_DETAIL_REPOSITORY_ALIAS } from '../../repository/index.js';
import { UmbCreateDataTypeEntityAction } from './create.action.js';
import { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
@@ -17,7 +17,7 @@ const entityActions: Array<ManifestTypes> = [
meta: {
icon: 'icon-add',
label: 'Create...',
repositoryAlias: DOCUMENT_TYPE_REPOSITORY_ALIAS,
repositoryAlias: DOCUMENT_TYPE_DETAIL_REPOSITORY_ALIAS,
entityTypes: [DOCUMENT_TYPE_ENTITY_TYPE, DOCUMENT_TYPE_ROOT_ENTITY_TYPE, DOCUMENT_TYPE_FOLDER_ENTITY_TYPE],
},
},

View File

@@ -1,7 +1,7 @@
import { DOCUMENT_TYPE_REPOSITORY_ALIAS } from '../../../repository/manifests.js';
import { DOCUMENT_TYPE_DETAIL_REPOSITORY_ALIAS } from '../../../repository/index.js';
import { UmbDocumentTypeCreateOptionsModalData } from './index.js';
import { html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import {
UmbModalManagerContext,
UmbModalContext,
@@ -30,7 +30,7 @@ export class UmbDataTypeCreateOptionsModalElement extends UmbLitElement {
#onClick(event: PointerEvent) {
event.stopPropagation();
const folderModalHandler = this.#modalContext?.open(UMB_FOLDER_MODAL, {
repositoryAlias: DOCUMENT_TYPE_REPOSITORY_ALIAS,
repositoryAlias: DOCUMENT_TYPE_DETAIL_REPOSITORY_ALIAS,
});
folderModalHandler?.onSubmit().then(() => this.modalContext?.submit());
}

View File

@@ -1,4 +1,4 @@
import { DOCUMENT_TYPE_REPOSITORY_ALIAS } from '../repository/manifests.js';
import { DOCUMENT_TYPE_DETAIL_REPOSITORY_ALIAS } from '../repository/index.js';
import { manifests as createManifests } from './create/manifests.js';
import {
UmbCopyEntityAction,
@@ -20,7 +20,7 @@ const entityActions: Array<ManifestEntityAction> = [
meta: {
icon: 'icon-trash',
label: 'Delete',
repositoryAlias: DOCUMENT_TYPE_REPOSITORY_ALIAS,
repositoryAlias: DOCUMENT_TYPE_DETAIL_REPOSITORY_ALIAS,
entityTypes: [entityType],
},
},
@@ -33,7 +33,7 @@ const entityActions: Array<ManifestEntityAction> = [
meta: {
icon: 'icon-enter',
label: 'Move',
repositoryAlias: DOCUMENT_TYPE_REPOSITORY_ALIAS,
repositoryAlias: DOCUMENT_TYPE_DETAIL_REPOSITORY_ALIAS,
entityTypes: [entityType],
},
},
@@ -46,7 +46,7 @@ const entityActions: Array<ManifestEntityAction> = [
meta: {
icon: 'icon-documents',
label: 'Copy',
repositoryAlias: DOCUMENT_TYPE_REPOSITORY_ALIAS,
repositoryAlias: DOCUMENT_TYPE_DETAIL_REPOSITORY_ALIAS,
entityTypes: [entityType],
},
},
@@ -59,7 +59,7 @@ const entityActions: Array<ManifestEntityAction> = [
meta: {
icon: 'icon-navigation-vertical',
label: 'Sort',
repositoryAlias: DOCUMENT_TYPE_REPOSITORY_ALIAS,
repositoryAlias: DOCUMENT_TYPE_DETAIL_REPOSITORY_ALIAS,
entityTypes: [entityType],
},
},

View File

@@ -1,3 +1,4 @@
import { DOCUMENT_TYPE_TREE_ALIAS } from '../tree/manifests.js';
import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
const menuItem: ManifestTypes = {
@@ -7,7 +8,7 @@ const menuItem: ManifestTypes = {
name: 'Document Types Menu Item',
weight: 900,
meta: {
treeAlias: 'Umb.Tree.DocumentTypes',
treeAlias: DOCUMENT_TYPE_TREE_ALIAS,
label: 'Document Types',
icon: 'icon-folder',
menus: ['Umb.Menu.Settings'],

View File

@@ -1,16 +1,12 @@
import { UmbDocumentTypeTreeServerDataSource } from './sources/document-type.tree.server.data.js';
import { UmbDocumentTypeServerDataSource } from './sources/document-type.server.data.js';
import { UmbDocumentTypeTreeStore, UMB_DOCUMENT_TYPE_TREE_STORE_CONTEXT_TOKEN } from './document-type.tree.store.js';
import { UmbDocumentTypeStore, UMB_DOCUMENT_TYPE_STORE_CONTEXT_TOKEN } from './document-type.store.js';
import { UMB_DOCUMENT_TYPE_ITEM_STORE_CONTEXT_TOKEN, UmbDocumentTypeItemStore } from './document-type-item.store.js';
import { UmbDocumentTypeItemServerDataSource } from './sources/document-type-item.server.data.js';
import type { UmbTreeDataSource, UmbTreeRepository, UmbDetailRepository } from '@umbraco-cms/backoffice/repository';
import { UMB_DOCUMENT_TYPE_TREE_STORE_CONTEXT, UmbDocumentTypeTreeStore } from '../../tree/document-type.tree.store.js';
import { UMB_DOCUMENT_TYPE_ITEM_STORE_CONTEXT, UmbDocumentTypeItemStore } from '../item/document-type-item.store.js';
import { UmbDocumentTypeServerDataSource } from './document-type.server.data.js';
import { UmbDocumentTypeDetailStore, UMB_DOCUMENT_TYPE_DETAIL_STORE_CONTEXT } from './document-type-detail.store.js';
import { type UmbDetailRepository } from '@umbraco-cms/backoffice/repository';
import { UmbBaseController, type UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api';
import {
CreateDocumentTypeRequestModel,
DocumentTypeResponseModel,
EntityTreeItemResponseModel,
FolderTreeItemResponseModel,
UpdateDocumentTypeRequestModel,
} from '@umbraco-cms/backoffice/backend-api';
@@ -19,21 +15,19 @@ import { UmbApi } from '@umbraco-cms/backoffice/extension-api';
type ItemType = DocumentTypeResponseModel;
export class UmbDocumentTypeRepository extends UmbBaseController
export class UmbDocumentTypeDetailRepository
extends UmbBaseController
implements
UmbTreeRepository<EntityTreeItemResponseModel>,
UmbDetailRepository<CreateDocumentTypeRequestModel, any, UpdateDocumentTypeRequestModel, DocumentTypeResponseModel>,
UmbApi
{
#init!: Promise<unknown>;
#treeSource: UmbTreeDataSource;
#treeStore?: UmbDocumentTypeTreeStore;
#detailDataSource: UmbDocumentTypeServerDataSource;
#detailStore?: UmbDocumentTypeStore;
#detailStore?: UmbDocumentTypeDetailStore;
#itemSource: UmbDocumentTypeItemServerDataSource;
#itemStore?: UmbDocumentTypeItemStore;
#notificationContext?: UmbNotificationContext;
@@ -42,20 +36,18 @@ export class UmbDocumentTypeRepository extends UmbBaseController
super(host);
// TODO: figure out how spin up get the correct data source
this.#treeSource = new UmbDocumentTypeTreeServerDataSource(this);
this.#detailDataSource = new UmbDocumentTypeServerDataSource(this);
this.#itemSource = new UmbDocumentTypeItemServerDataSource(this);
this.#init = Promise.all([
this.consumeContext(UMB_DOCUMENT_TYPE_TREE_STORE_CONTEXT_TOKEN, (instance) => {
this.consumeContext(UMB_DOCUMENT_TYPE_TREE_STORE_CONTEXT, (instance) => {
this.#treeStore = instance;
}),
this.consumeContext(UMB_DOCUMENT_TYPE_STORE_CONTEXT_TOKEN, (instance) => {
this.consumeContext(UMB_DOCUMENT_TYPE_DETAIL_STORE_CONTEXT, (instance) => {
this.#detailStore = instance;
}),
this.consumeContext(UMB_DOCUMENT_TYPE_ITEM_STORE_CONTEXT_TOKEN, (instance) => {
this.consumeContext(UMB_DOCUMENT_TYPE_ITEM_STORE_CONTEXT, (instance) => {
this.#itemStore = instance;
}),
@@ -65,86 +57,6 @@ export class UmbDocumentTypeRepository extends UmbBaseController
]);
}
// TODO: Move
async requestTreeRoot() {
await this.#init;
const data = {
id: null,
type: 'document-type-root',
name: 'Document Types',
icon: 'icon-folder',
hasChildren: true,
};
return { data };
}
async requestRootTreeItems() {
await this.#init;
const { data, error } = await this.#treeSource.getRootItems();
if (data) {
this.#treeStore?.appendItems(data.items);
}
return { data, error, asObservable: () => this.#treeStore!.rootItems };
}
async requestTreeItemsOf(parentId: string | null) {
await this.#init;
if (parentId === undefined) throw new Error('Parent id is missing');
const { data, error } = await this.#treeSource.getChildrenOf(parentId);
if (data) {
this.#treeStore?.appendItems(data.items);
}
return { data, error, asObservable: () => this.#treeStore!.childrenOf(parentId) };
}
async requestItems(ids: Array<string>) {
if (!ids) throw new Error('Document Type Ids are missing');
await this.#init;
const { data, error } = await this.#itemSource.getItems(ids);
if (data) {
this.#itemStore?.appendItems(data);
}
return { data, error, asObservable: () => this.#itemStore!.items(ids) };
}
async requestItemsLegacy(ids: Array<string>) {
await this.#init;
if (!ids) {
throw new Error('Ids are missing');
}
const { data, error } = await this.#treeSource.getItems(ids);
return { data, error, asObservable: () => this.#treeStore!.items(ids) };
}
async rootTreeItems() {
await this.#init;
return this.#treeStore!.rootItems;
}
async treeItemsOf(parentId: string | null) {
await this.#init;
return this.#treeStore!.childrenOf(parentId);
}
async itemsLegacy(ids: Array<string>) {
await this.#init;
return this.#treeStore!.items(ids);
}
// DETAILS:
async createScaffold(parentId: string | null) {
@@ -241,7 +153,7 @@ export class UmbDocumentTypeRepository extends UmbBaseController
// Consider to look up the data before fetching from the server.
// Consider notify a workspace if a template is deleted from the store while someone is editing it.
// TODO: would be nice to align the stores on methods/methodNames.
this.#detailStore?.remove([id]);
this.#detailStore?.removeItem(id);
this.#treeStore?.removeItem(id);
this.#itemStore?.removeItem(id);
}

View File

@@ -10,7 +10,7 @@ import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api
* @extends {UmbStoreBase}
* @description - Data Store for Document Types
*/
export class UmbDocumentTypeStore extends UmbStoreBase<DocumentTypeResponseModel> {
export class UmbDocumentTypeDetailStore extends UmbStoreBase<DocumentTypeResponseModel> {
/**
* Creates an instance of UmbDocumentTypeStore.
* @param {UmbControllerHostElement} host
@@ -19,37 +19,21 @@ export class UmbDocumentTypeStore extends UmbStoreBase<DocumentTypeResponseModel
constructor(host: UmbControllerHostElement) {
super(
host,
UMB_DOCUMENT_TYPE_STORE_CONTEXT_TOKEN.toString(),
new UmbArrayState<DocumentTypeResponseModel>([], (x) => x.id)
UMB_DOCUMENT_TYPE_DETAIL_STORE_CONTEXT.toString(),
new UmbArrayState<DocumentTypeResponseModel>([], (x) => x.id),
);
}
/**
* Append a document-type to the store
* @param {DocumentTypeModel} document
* @memberof UmbDocumentTypeStore
*/
append(document: DocumentTypeResponseModel) {
this._data.append([document]);
}
/**
* Append a document-type to the store
* @param {DocumentTypeModel} document
* @memberof UmbDocumentTypeStore
* @param {DocumentTypeResponseModel['id']} id
* @return {*}
* @memberof UmbDocumentTypeDetailStore
*/
byId(id: DocumentTypeResponseModel['id']) {
return this._data.asObservablePart((x) => x.find((y) => y.id === id));
}
/**
* Removes document-types in the store with the given uniques
* @param {string[]} uniques
* @memberof UmbDocumentTypeStore
*/
remove(uniques: Array<DocumentTypeResponseModel['id']>) {
this._data.remove(uniques);
}
}
export const UMB_DOCUMENT_TYPE_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbDocumentTypeStore>('UmbDocumentTypeStore');
export const UMB_DOCUMENT_TYPE_DETAIL_STORE_CONTEXT = new UmbContextToken<UmbDocumentTypeDetailStore>(
'UmbDocumentTypeDetailStore',
);

View File

@@ -0,0 +1,3 @@
export { UmbDocumentTypeDetailRepository } from './document-type-detail.repository.js';
export { DOCUMENT_TYPE_DETAIL_REPOSITORY_ALIAS, DOCUMENT_TYPE_DETAIL_STORE_ALIAS } from './manifests.js';
export { UMB_DOCUMENT_TYPE_DETAIL_STORE_CONTEXT } from './document-type-detail.store.js';

View File

@@ -0,0 +1,22 @@
import { UmbDocumentTypeDetailRepository } from './document-type-detail.repository.js';
import { UmbDocumentTypeDetailStore } from './document-type-detail.store.js';
import { ManifestRepository, ManifestStore } from '@umbraco-cms/backoffice/extension-registry';
export const DOCUMENT_TYPE_DETAIL_REPOSITORY_ALIAS = 'Umb.Repository.DocumentType.Detail';
export const DOCUMENT_TYPE_DETAIL_STORE_ALIAS = 'Umb.Store.DocumentType.Detail';
const detailRepository: ManifestRepository = {
type: 'repository',
alias: DOCUMENT_TYPE_DETAIL_REPOSITORY_ALIAS,
name: 'Document Types Repository',
api: UmbDocumentTypeDetailRepository,
};
const detailStore: ManifestStore = {
type: 'store',
alias: DOCUMENT_TYPE_DETAIL_STORE_ALIAS,
name: 'Document Type Store',
api: UmbDocumentTypeDetailStore,
};
export const manifests = [detailRepository, detailStore];

View File

@@ -1,3 +1,2 @@
export * from './document-type.repository.js';
export * from './document-type.store.js';
export * from './document-type.tree.store.js';
export * from './item/index.js';
export * from './detail/index.js';

View File

@@ -0,0 +1,11 @@
import { UmbDocumentTypeItemModel } from './types.js';
import { UmbDocumentTypeItemServerDataSource } from './document-type-item.server.data.js';
import { UMB_DOCUMENT_TYPE_ITEM_STORE_CONTEXT } from './document-type-item.store.js';
import { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbItemRepositoryBase } from '@umbraco-cms/backoffice/repository';
export class UmbDocumentTypeItemRepository extends UmbItemRepositoryBase<UmbDocumentTypeItemModel> {
constructor(host: UmbControllerHost) {
super(host, UmbDocumentTypeItemServerDataSource, UMB_DOCUMENT_TYPE_ITEM_STORE_CONTEXT);
}
}

View File

@@ -23,7 +23,7 @@ export class UmbDocumentTypeItemStore
constructor(host: UmbControllerHostElement) {
super(
host,
UMB_DOCUMENT_TYPE_ITEM_STORE_CONTEXT_TOKEN.toString(),
UMB_DOCUMENT_TYPE_ITEM_STORE_CONTEXT.toString(),
new UmbArrayState<DocumentTypeItemResponseModel>([], (x) => x.id),
);
}
@@ -33,6 +33,6 @@ export class UmbDocumentTypeItemStore
}
}
export const UMB_DOCUMENT_TYPE_ITEM_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbDocumentTypeItemStore>(
export const UMB_DOCUMENT_TYPE_ITEM_STORE_CONTEXT = new UmbContextToken<UmbDocumentTypeItemStore>(
'UmbDocumentTypeItemStore',
);

View File

@@ -0,0 +1,3 @@
export { UmbDocumentTypeItemRepository } from './document-type-item.repository.js';
export { DOCUMENT_TYPE_ITEM_REPOSITORY_ALIAS, DOCUMENT_TYPE_ITEM_STORE_ALIAS } from './manifests.js';
export * from './types.js';

View File

@@ -0,0 +1,22 @@
import { UmbDocumentTypeItemRepository } from './document-type-item.repository.js';
import { UmbDocumentTypeItemStore } from './document-type-item.store.js';
import { ManifestItemStore, ManifestRepository } from '@umbraco-cms/backoffice/extension-registry';
export const DOCUMENT_TYPE_ITEM_REPOSITORY_ALIAS = 'Umb.Repository.DocumentType.Item';
export const DOCUMENT_TYPE_ITEM_STORE_ALIAS = 'Umb.Store.DocumentType.Item';
const itemRepository: ManifestRepository = {
type: 'repository',
alias: DOCUMENT_TYPE_ITEM_REPOSITORY_ALIAS,
name: 'Document Type Item Repository',
api: UmbDocumentTypeItemRepository,
};
const itemStore: ManifestItemStore = {
type: 'itemStore',
alias: DOCUMENT_TYPE_ITEM_STORE_ALIAS,
name: 'Document Type Item Store',
api: UmbDocumentTypeItemStore,
};
export const manifests = [itemRepository, itemStore];

View File

@@ -0,0 +1,3 @@
import { DocumentTypeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
export type UmbDocumentTypeItemModel = DocumentTypeItemResponseModel;

View File

@@ -1,46 +1,4 @@
import { UmbDocumentTypeItemStore } from './document-type-item.store.js';
import { UmbDocumentTypeRepository } from './document-type.repository.js';
import { UmbDocumentTypeStore } from './document-type.store.js';
import { UmbDocumentTypeTreeStore } from './document-type.tree.store.js';
import {
ManifestItemStore,
ManifestRepository,
ManifestStore,
ManifestTreeStore,
} from '@umbraco-cms/backoffice/extension-registry';
import { manifests as detailManifests } from './detail/manifests.js';
import { manifests as itemManifests } from './item/manifests.js';
export const DOCUMENT_TYPE_REPOSITORY_ALIAS = 'Umb.Repository.DocumentType';
const repository: ManifestRepository = {
type: 'repository',
alias: DOCUMENT_TYPE_REPOSITORY_ALIAS,
name: 'Document Types Repository',
api: UmbDocumentTypeRepository,
};
export const DOCUMENT_TYPE_STORE_ALIAS = 'Umb.Store.DocumentType';
export const DOCUMENT_TYPE_TREE_STORE_ALIAS = 'Umb.Store.DocumentTypeTree';
export const DOCUMENT_TYPE_ITEM_STORE_ALIAS = 'Umb.Store.DocumentTypeItem';
const store: ManifestStore = {
type: 'store',
alias: DOCUMENT_TYPE_STORE_ALIAS,
name: 'Document Type Store',
api: UmbDocumentTypeStore,
};
const treeStore: ManifestTreeStore = {
type: 'treeStore',
alias: DOCUMENT_TYPE_TREE_STORE_ALIAS,
name: 'Document Type Tree Store',
api: UmbDocumentTypeTreeStore,
};
const itemStore: ManifestItemStore = {
type: 'itemStore',
alias: DOCUMENT_TYPE_ITEM_STORE_ALIAS,
name: 'Document Type Item Store',
api: UmbDocumentTypeItemStore,
};
export const manifests = [repository, store, treeStore, itemStore];
export const manifests = [...detailManifests, ...itemManifests];

View File

@@ -0,0 +1,28 @@
import { DOCUMENT_TYPE_ROOT_ENTITY_TYPE } from '../index.js';
import { UmbDocumentTypeTreeServerDataSource } from './document-type.tree.server.data-source.js';
import { UMB_DOCUMENT_TYPE_TREE_STORE_CONTEXT } from './document-type.tree.store.js';
import { UmbDocumentTypeTreeItemModel, UmbDocumentTypeTreeRootModel } from './types.js';
import { UmbTreeRepositoryBase } from '@umbraco-cms/backoffice/tree';
import { type UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbApi } from '@umbraco-cms/backoffice/extension-api';
export class UmbDocumentTypeTreeRepository
extends UmbTreeRepositoryBase<UmbDocumentTypeTreeItemModel, UmbDocumentTypeTreeRootModel>
implements UmbApi
{
constructor(host: UmbControllerHost) {
super(host, UmbDocumentTypeTreeServerDataSource, UMB_DOCUMENT_TYPE_TREE_STORE_CONTEXT);
}
async requestTreeRoot() {
const data = {
id: null,
type: DOCUMENT_TYPE_ROOT_ENTITY_TYPE,
name: 'Document Types',
icon: 'icon-folder',
hasChildren: true,
};
return { data };
}
}

View File

@@ -1,10 +1,10 @@
import type { UmbTreeDataSource } from '@umbraco-cms/backoffice/repository';
import type { UmbTreeDataSource } from '@umbraco-cms/backoffice/tree';
import { DocumentTypeResource } from '@umbraco-cms/backoffice/backend-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
/**
* A data source for the Document tree that fetches data from the server
* A data source for the Document Type tree that fetches data from the server
* @export
* @class UmbDocumentTypeTreeServerDataSource
* @implements {UmbTreeDataSource}
@@ -12,35 +12,6 @@ import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
export class UmbDocumentTypeTreeServerDataSource implements UmbTreeDataSource {
#host: UmbControllerHost;
// TODO: how do we handle trashed items?
async trashItems(ids: Array<string>) {
// TODO: use backend cli when available.
return tryExecuteAndNotify(
this.#host,
fetch('/umbraco/management/api/v1/document-type/trash', {
method: 'POST',
body: JSON.stringify(ids),
headers: {
'Content-Type': 'application/json',
},
})
);
}
async moveItems(ids: Array<string>, destination: string) {
// TODO: use backend cli when available.
return tryExecuteAndNotify(
this.#host,
fetch('/umbraco/management/api/v1/document-type/move', {
method: 'POST',
body: JSON.stringify({ ids: ids, destination }),
headers: {
'Content-Type': 'application/json',
},
})
);
}
/**
* Creates an instance of UmbDocumentTypeTreeServerDataSource.
* @param {UmbControllerHost} host
@@ -77,7 +48,7 @@ export class UmbDocumentTypeTreeServerDataSource implements UmbTreeDataSource {
this.#host,
DocumentTypeResource.getTreeDocumentTypeChildren({
parentId,
})
}),
);
}
}
@@ -97,7 +68,7 @@ export class UmbDocumentTypeTreeServerDataSource implements UmbTreeDataSource {
this.#host,
DocumentTypeResource.getDocumentTypeItem({
id: ids,
})
}),
);
}
}

View File

@@ -1,14 +1,13 @@
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/store';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/tree';
/**
* @export
* @class UmbDocumentTypeTreeStore
* @extends {UmbStoreBase}
* @description - Tree Data Store for Document-Types
* @description - Tree Data Store for Document Types
*/
// TODO: consider if tree store could be turned into a general EntityTreeStore class?
export class UmbDocumentTypeTreeStore extends UmbEntityTreeStore {
/**
* Creates an instance of UmbDocumentTypeTreeStore.
@@ -16,10 +15,10 @@ export class UmbDocumentTypeTreeStore extends UmbEntityTreeStore {
* @memberof UmbDocumentTypeTreeStore
*/
constructor(host: UmbControllerHostElement) {
super(host, UMB_DOCUMENT_TYPE_TREE_STORE_CONTEXT_TOKEN.toString());
super(host, UMB_DOCUMENT_TYPE_TREE_STORE_CONTEXT.toString());
}
}
export const UMB_DOCUMENT_TYPE_TREE_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbDocumentTypeTreeStore>(
'UmbDocumentTypeTreeStore'
export const UMB_DOCUMENT_TYPE_TREE_STORE_CONTEXT = new UmbContextToken<UmbDocumentTypeTreeStore>(
'UmbDocumentTypeTreeStore',
);

View File

@@ -1,14 +1,36 @@
import { DOCUMENT_TYPE_REPOSITORY_ALIAS } from '../repository/manifests.js';
import type { ManifestTree, ManifestTreeItem } from '@umbraco-cms/backoffice/extension-registry';
import { UmbDocumentTypeTreeRepository } from './document-type-tree.repository.js';
import { UmbDocumentTypeTreeStore } from './document-type.tree.store.js';
import type {
ManifestRepository,
ManifestTree,
ManifestTreeItem,
ManifestTreeStore,
} from '@umbraco-cms/backoffice/extension-registry';
export const DOCUMENT_TYPE_TREE_ALIAS = 'Umb.Tree.DocumentTypes';
export const DOCUMENT_TYPE_TREE_REPOSITORY_ALIAS = 'Umb.Repository.DocumentType.Tree';
export const DOCUMENT_TYPE_TREE_STORE_ALIAS = 'Umb.Store.DocumentType.Tree';
export const DOCUMENT_TYPE_TREE_ALIAS = 'Umb.Tree.DocumentType';
const treeRepository: ManifestRepository = {
type: 'repository',
alias: DOCUMENT_TYPE_TREE_REPOSITORY_ALIAS,
name: 'Document Type Tree Repository',
api: UmbDocumentTypeTreeRepository,
};
const treeStore: ManifestTreeStore = {
type: 'treeStore',
alias: DOCUMENT_TYPE_TREE_STORE_ALIAS,
name: 'Document Type Tree Store',
api: UmbDocumentTypeTreeStore,
};
const tree: ManifestTree = {
type: 'tree',
alias: DOCUMENT_TYPE_TREE_ALIAS,
name: 'Document Types Tree',
name: 'Document Type Tree',
meta: {
repositoryAlias: DOCUMENT_TYPE_REPOSITORY_ALIAS,
repositoryAlias: DOCUMENT_TYPE_TREE_REPOSITORY_ALIAS,
},
};
@@ -22,4 +44,4 @@ const treeItem: ManifestTreeItem = {
},
};
export const manifests = [tree, treeItem];
export const manifests = [treeRepository, treeStore, tree, treeItem];

View File

@@ -0,0 +1,5 @@
import type { DocumentTypeTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
import type { UmbEntityTreeItemModel, UmbEntityTreeRootModel } from '@umbraco-cms/backoffice/tree';
export type UmbDocumentTypeTreeItemModel = DocumentTypeTreeItemResponseModel & UmbEntityTreeItemModel;
export type UmbDocumentTypeTreeRootModel = DocumentTypeTreeItemResponseModel & UmbEntityTreeRootModel;

View File

@@ -1,6 +1,9 @@
import { UmbDocumentTypeRepository } from '../repository/document-type.repository.js';
import { UmbDocumentTypeDetailRepository } from '../repository/detail/document-type-detail.repository.js';
import { UmbContentTypePropertyStructureManager } from '@umbraco-cms/backoffice/content-type';
import { UmbEditableWorkspaceContextBase, UmbSaveableWorkspaceContextInterface } from '@umbraco-cms/backoffice/workspace';
import {
UmbEditableWorkspaceContextBase,
UmbSaveableWorkspaceContextInterface,
} from '@umbraco-cms/backoffice/workspace';
import type {
ContentTypeCompositionModel,
ContentTypeSortModel,
@@ -12,7 +15,7 @@ import { UmbBooleanState } from '@umbraco-cms/backoffice/observable-api';
type EntityType = DocumentTypeResponseModel;
export class UmbDocumentTypeWorkspaceContext
extends UmbEditableWorkspaceContextBase<UmbDocumentTypeRepository, EntityType>
extends UmbEditableWorkspaceContextBase<UmbDocumentTypeDetailRepository, EntityType>
implements UmbSaveableWorkspaceContextInterface<EntityType | undefined>
{
// Draft is located in structure manager
@@ -42,7 +45,7 @@ export class UmbDocumentTypeWorkspaceContext
isSorting = this.#isSorting.asObservable();
constructor(host: UmbControllerHostElement) {
super(host, 'Umb.Workspace.DocumentType', new UmbDocumentTypeRepository(host));
super(host, 'Umb.Workspace.DocumentType', new UmbDocumentTypeDetailRepository(host));
this.structure = new UmbContentTypePropertyStructureManager(this.host, this.repository);

View File

@@ -1,7 +1,7 @@
import { UmbDocumentTypeWorkspaceContext } from '../../document-type-workspace.context.js';
import type { UmbInputDocumentTypeElement } from '../../../components/input-document-type/input-document-type.element.js';
import type { UmbDocumentTypeInputElement } from '../../../components/document-type-input/document-type-input.element.js';
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { UUIToggleElement } from '@umbraco-cms/backoffice/external/uui';
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
import { UMB_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace';
@@ -62,10 +62,10 @@ export class UmbDocumentTypeWorkspaceViewStructureElement
</div>
<div slot="editor">
<!-- TODO: maybe we want to somehow display the hierarchy, but not necessary in the same way as old backoffice? -->
<umb-input-document-type
<umb-document-type-input
.selectedIds=${this._allowedContentTypeIDs ?? []}
@change="${(e: CustomEvent) => {
const sortedContentTypesList = (e.target as UmbInputDocumentTypeElement).selectedIds.map(
const sortedContentTypesList = (e.target as UmbDocumentTypeInputElement).selectedIds.map(
(id, index) => ({
id: id,
sortOrder: index,
@@ -73,7 +73,7 @@ export class UmbDocumentTypeWorkspaceViewStructureElement
);
this.#workspaceContext?.setAllowedContentTypes(sortedContentTypesList);
}}">
</umb-input-document-type>
</umb-document-type-input>
</div>
</umb-workspace-property-layout>
</uui-box>

View File

@@ -3,12 +3,15 @@ import {
UMB_DOCUMENT_RECYCLE_BIN_TREE_STORE_CONTEXT,
UmbDocumentRecycleBinTreeStore,
} from './document-recycle.bin.tree.store.js';
import type { UmbTreeDataSource, UmbTreeRepository } from '@umbraco-cms/backoffice/repository';
import type { UmbTreeRepository, UmbTreeDataSource } from '@umbraco-cms/backoffice/tree';
import { UmbBaseController, type UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api';
import { DocumentTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
export class UmbDocumentRecycleBinRepository extends UmbBaseController implements UmbTreeRepository<DocumentTreeItemResponseModel> {
export class UmbDocumentRecycleBinRepository
extends UmbBaseController
implements UmbTreeRepository<DocumentTreeItemResponseModel>
{
#init!: Promise<unknown>;
#treeSource: UmbTreeDataSource;

View File

@@ -1,5 +1,5 @@
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/store';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/tree';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
/**

View File

@@ -1,6 +1,6 @@
import type { UmbTreeDataSource } from '@umbraco-cms/backoffice/repository';
import { type UmbTreeDataSource } from '@umbraco-cms/backoffice/tree';
import { DocumentResource } from '@umbraco-cms/backoffice/backend-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { type UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
/**

View File

@@ -4,7 +4,8 @@ import { UmbDocumentTreeStore, UMB_DOCUMENT_TREE_STORE_CONTEXT_TOKEN } from './d
import { UmbDocumentTreeServerDataSource } from './sources/document.tree.server.data.js';
import { UMB_DOCUMENT_ITEM_STORE_CONTEXT_TOKEN, type UmbDocumentItemStore } from './document-item.store.js';
import { UmbDocumentItemServerDataSource } from './sources/document-item.server.data.js';
import type { UmbTreeDataSource, UmbTreeRepository, UmbDetailRepository } from '@umbraco-cms/backoffice/repository';
import type { UmbDetailRepository } from '@umbraco-cms/backoffice/repository';
import type { UmbTreeRepository, UmbTreeDataSource } from '@umbraco-cms/backoffice/tree';
import { UmbBaseController, UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
import {
DocumentResponseModel,
@@ -15,7 +16,8 @@ import {
import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification';
import { UmbApi } from '@umbraco-cms/backoffice/extension-api';
export class UmbDocumentRepository extends UmbBaseController
export class UmbDocumentRepository
extends UmbBaseController
implements
UmbTreeRepository<DocumentTreeItemResponseModel>,
UmbDetailRepository<CreateDocumentRequestModel, any, UpdateDocumentRequestModel, DocumentResponseModel>,

View File

@@ -1,5 +1,5 @@
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/store';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/tree';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
/**

View File

@@ -1,6 +1,6 @@
import type { UmbTreeDataSource } from '@umbraco-cms/backoffice/repository';
import { type UmbTreeDataSource } from '@umbraco-cms/backoffice/tree';
import { DocumentResource } from '@umbraco-cms/backoffice/backend-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { type UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
/**
@@ -23,7 +23,7 @@ export class UmbDocumentTreeServerDataSource implements UmbTreeDataSource {
headers: {
'Content-Type': 'application/json',
},
})
}),
);
}
@@ -37,7 +37,7 @@ export class UmbDocumentTreeServerDataSource implements UmbTreeDataSource {
headers: {
'Content-Type': 'application/json',
},
})
}),
);
}
@@ -77,7 +77,7 @@ export class UmbDocumentTreeServerDataSource implements UmbTreeDataSource {
this.#host,
DocumentResource.getTreeDocumentChildren({
parentId,
})
}),
);
}
}
@@ -97,7 +97,7 @@ export class UmbDocumentTreeServerDataSource implements UmbTreeDataSource {
this.#host,
DocumentResource.getDocumentItem({
id: ids,
})
}),
);
}
}

View File

@@ -1,5 +1,5 @@
import { UmbDocumentRepository } from '../repository/document.repository.js';
import { UmbDocumentTypeRepository } from '../../document-types/repository/document-type.repository.js';
import { UmbDocumentTypeDetailRepository } from '../../document-types/repository/detail/document-type-detail.repository.js';
import { UmbDocumentVariantContext } from '../variant-context/document-variant-context.js';
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
import { UmbContentTypePropertyStructureManager } from '@umbraco-cms/backoffice/content-type';
@@ -54,7 +54,10 @@ export class UmbDocumentWorkspaceContext
// TODO: Get Workspace Alias via Manifest.
super(host, 'Umb.Workspace.Document', new UmbDocumentRepository(host));
this.structure = new UmbContentTypePropertyStructureManager(this.host, new UmbDocumentTypeRepository(this.host));
this.structure = new UmbContentTypePropertyStructureManager(
this.host,
new UmbDocumentTypeDetailRepository(this.host),
);
this.splitView = new UmbWorkspaceSplitViewManager(this.host);
new UmbObserverController(this.host, this.documentTypeKey, (id) => this.structure.loadType(id));
@@ -130,7 +133,7 @@ export class UmbDocumentWorkspaceContext
const variants = partialUpdateFrozenArray(
oldVariants,
{ name },
variantId ? (x) => variantId.compare(x) : () => true
variantId ? (x) => variantId.compare(x) : () => true,
);
this.#currentData.update({ variants });
}
@@ -142,7 +145,8 @@ export class UmbDocumentWorkspaceContext
async propertyValueByAlias<PropertyValueType = unknown>(propertyAlias: string, variantId?: UmbVariantId) {
return this.#currentData.asObservablePart(
(data) =>
data?.values?.find((x) => x?.alias === propertyAlias && (variantId ? variantId.compare(x) : true))?.value as PropertyValueType
data?.values?.find((x) => x?.alias === propertyAlias && (variantId ? variantId.compare(x) : true))
?.value as PropertyValueType,
);
}
@@ -156,20 +160,24 @@ export class UmbDocumentWorkspaceContext
const currentData = this.#currentData.value;
if (currentData) {
const newDataSet = currentData.values?.find(
(x) => x.alias === alias && (variantId ? variantId.compare(x) : true)
(x) => x.alias === alias && (variantId ? variantId.compare(x) : true),
);
return newDataSet?.value as ReturnType;
}
return undefined;
}
async setPropertyValue<PropertyValueType = unknown>(alias: string, value: PropertyValueType, variantId?: UmbVariantId) {
async setPropertyValue<PropertyValueType = unknown>(
alias: string,
value: PropertyValueType,
variantId?: UmbVariantId,
) {
const entry = { ...variantId?.toObject(), alias, value };
const currentData = this.#currentData.value;
if (currentData) {
const values = appendToFrozenArray(
currentData.values || [],
entry,
(x) => x.alias === alias && (variantId ? variantId.compare(x) : true)
(x) => x.alias === alias && (variantId ? variantId.compare(x) : true),
);
this.#currentData.update({ values });
}
@@ -221,9 +229,11 @@ export class UmbDocumentWorkspaceContext
export default UmbDocumentWorkspaceContext;
export const UMB_DOCUMENT_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbDocumentWorkspaceContext>(
export const UMB_DOCUMENT_WORKSPACE_CONTEXT = new UmbContextToken<
UmbSaveableWorkspaceContextInterface,
UmbDocumentWorkspaceContext
>(
'UmbWorkspaceContext',
// TODO: Refactor: make a better generic way to identify workspaces, maybe workspaceType or workspaceAlias?.
(context): context is UmbDocumentWorkspaceContext => context.getEntityType?.() === 'document'
(context): context is UmbDocumentWorkspaceContext => context.getEntityType?.() === 'document',
);

View File

@@ -7,13 +7,12 @@ import { UmbMediaTypeItemServerDataSource } from './sources/media-type-item.serv
import { UmbBaseController, UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification';
import {
UmbTreeRepository,
UmbTreeDataSource,
UmbDataSource,
UmbItemRepository,
UmbDetailRepository,
UmbItemDataSource,
} from '@umbraco-cms/backoffice/repository';
import { UmbTreeRepository, UmbTreeDataSource } from '@umbraco-cms/backoffice/tree';
import {
CreateMediaTypeRequestModel,
FolderTreeItemResponseModel,
@@ -23,7 +22,8 @@ import {
} from '@umbraco-cms/backoffice/backend-api';
import { UmbApi } from '@umbraco-cms/backoffice/extension-api';
export class UmbMediaTypeRepository extends UmbBaseController
export class UmbMediaTypeRepository
extends UmbBaseController
implements
UmbItemRepository<MediaTypeItemResponseModel>,
UmbTreeRepository<FolderTreeItemResponseModel>,

View File

@@ -1,5 +1,5 @@
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/store';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/tree';
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
/**
@@ -20,5 +20,5 @@ export class UmbMediaTypeTreeStore extends UmbEntityTreeStore {
}
export const UMB_MEDIA_TYPE_TREE_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbMediaTypeTreeStore>(
'UmbMediaTypeTreeStore'
'UmbMediaTypeTreeStore',
);

View File

@@ -1,6 +1,6 @@
import { MediaTypeResource } from '@umbraco-cms/backoffice/backend-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import type { UmbTreeDataSource } from '@umbraco-cms/backoffice/repository';
import { type UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { type UmbTreeDataSource } from '@umbraco-cms/backoffice/tree';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
/**
@@ -48,7 +48,7 @@ export class UmbMediaTypeTreeServerDataSource implements UmbTreeDataSource {
this.#host,
MediaTypeResource.getTreeMediaTypeChildren({
parentId,
})
}),
);
}
}
@@ -68,7 +68,7 @@ export class UmbMediaTypeTreeServerDataSource implements UmbTreeDataSource {
this.#host,
MediaTypeResource.getMediaTypeItem({
id: ids,
})
}),
);
}
}

View File

@@ -5,7 +5,7 @@ import { UmbMediaStore, UMB_MEDIA_STORE_CONTEXT_TOKEN } from './media.store.js';
import { UmbMediaDetailServerDataSource } from './sources/media.detail.server.data.js';
import { UmbMediaItemServerDataSource } from './sources/media-item.server.data.js';
import { UmbMediaItemStore } from './media-item.store.js';
import type { UmbTreeRepository, UmbTreeDataSource } from '@umbraco-cms/backoffice/repository';
import type { UmbTreeRepository, UmbTreeDataSource } from '@umbraco-cms/backoffice/tree';
import { UmbBaseController, UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
import {
CreateMediaRequestModel,
@@ -16,7 +16,8 @@ import { UmbDetailRepository } from '@umbraco-cms/backoffice/repository';
import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification';
import { UmbApi } from '@umbraco-cms/backoffice/extension-api';
export class UmbMediaRepository extends UmbBaseController
export class UmbMediaRepository
extends UmbBaseController
implements
UmbTreeRepository<EntityTreeItemResponseModel>,
UmbDetailRepository<CreateMediaRequestModel, any, UpdateMediaRequestModel, MediaDetails>,

View File

@@ -1,7 +1,7 @@
import { EntityTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/store';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/tree';
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
export const UMB_MEDIA_TREE_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbMediaTreeStore>('UmbMediaTreeStore');

View File

@@ -1,6 +1,6 @@
import type { UmbTreeDataSource } from '@umbraco-cms/backoffice/repository';
import { type UmbTreeDataSource } from '@umbraco-cms/backoffice/tree';
import { MediaResource } from '@umbraco-cms/backoffice/backend-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { type UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
/**
@@ -23,7 +23,7 @@ export class UmbMediaTreeServerDataSource implements UmbTreeDataSource {
headers: {
'Content-Type': 'application/json',
},
})
}),
);
}
@@ -37,7 +37,7 @@ export class UmbMediaTreeServerDataSource implements UmbTreeDataSource {
headers: {
'Content-Type': 'application/json',
},
})
}),
);
}
@@ -77,7 +77,7 @@ export class UmbMediaTreeServerDataSource implements UmbTreeDataSource {
this.#host,
MediaResource.getTreeMediaChildren({
parentId,
})
}),
);
}
}
@@ -97,7 +97,7 @@ export class UmbMediaTreeServerDataSource implements UmbTreeDataSource {
this.#host,
MediaResource.getTreeMediaItem({
id: ids,
})
}),
);
}
}

View File

@@ -5,12 +5,14 @@ import { UmbMemberGroupStore, UMB_MEMBER_GROUP_STORE_CONTEXT_TOKEN } from './mem
import { UmbMemberGroupTreeServerDataSource } from './sources/member-group.tree.server.data.js';
import { UmbBaseController, type UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification';
import type { UmbTreeDataSource, UmbDetailRepository, UmbTreeRepository } from '@umbraco-cms/backoffice/repository';
import { UmbDetailRepository } from '@umbraco-cms/backoffice/repository';
import type { UmbTreeRepository, UmbTreeDataSource } from '@umbraco-cms/backoffice/tree';
import { EntityTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
import { UmbApi } from '@umbraco-cms/backoffice/extension-api';
// TODO => Update type when backend updated
export class UmbMemberGroupRepository extends UmbBaseController
export class UmbMemberGroupRepository
extends UmbBaseController
implements UmbTreeRepository<EntityTreeItemResponseModel>, UmbDetailRepository<any, any, any, any>, UmbApi
{
#init!: Promise<unknown>;
@@ -24,7 +26,7 @@ export class UmbMemberGroupRepository extends UmbBaseController
#notificationContext?: UmbNotificationContext;
constructor(host: UmbControllerHost) {
super(host)
super(host);
// TODO: figure out how spin up get the correct data source
this.#treeSource = new UmbMemberGroupTreeServerDataSource(this);
this.#detailSource = new UmbMemberGroupDetailServerDataSource(this);

View File

@@ -1,5 +1,5 @@
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/store';
import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/tree';
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
/**
@@ -20,5 +20,5 @@ export class UmbMemberGroupTreeStore extends UmbEntityTreeStore {
}
export const UMB_MEMBER_GROUP_TREE_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbMemberGroupTreeStore>(
'UmbMemberGroupTreeStore'
'UmbMemberGroupTreeStore',
);

View File

@@ -1,6 +1,6 @@
import { MemberGroupResource } from '@umbraco-cms/backoffice/backend-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbTreeDataSource } from '@umbraco-cms/backoffice/repository';
import { type UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { type UmbTreeDataSource } from '@umbraco-cms/backoffice/tree';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
/**
@@ -56,7 +56,7 @@ export class UmbMemberGroupTreeServerDataSource implements UmbTreeDataSource {
this.#host,
MemberGroupResource.getMemberGroupItem({
id: ids,
})
}),
);
}
}

Some files were not shown because too many files have changed in this diff Show More