Merge remote-tracking branch 'origin/main' into feature/block-editor-type-workspace
# Conflicts: # package.json # src/packages/documents/document-types/components/index.ts # src/packages/documents/document-types/index.ts
This commit is contained in:
@@ -135,6 +135,7 @@ Ensure all property editors are properly localized.
|
|||||||
- [ ] Toggle
|
- [ ] Toggle
|
||||||
- [ ] Tree Picker
|
- [ ] Tree Picker
|
||||||
- [ ] StartNode
|
- [ ] StartNode
|
||||||
|
- [x] DynamicRoot
|
||||||
- [ ] Upload Field
|
- [ ] Upload Field
|
||||||
- [ ] User Picker
|
- [ ] User Picker
|
||||||
- [ ] Value Type
|
- [ ] Value Type
|
||||||
@@ -235,4 +236,4 @@ Then we need your help! With Bellissima we added new localization keys, and we s
|
|||||||
- [ ] `tr-TR` - Turkish (Turkey)
|
- [ ] `tr-TR` - Turkish (Turkey)
|
||||||
- [ ] `ua-UA` - Ukrainian (Ukraine)
|
- [ ] `ua-UA` - Ukrainian (Ukraine)
|
||||||
- [ ] `zh-CN` - Chinese (China)
|
- [ ] `zh-CN` - Chinese (China)
|
||||||
- [ ] `zh-TW` - Chinese (Taiwan)
|
- [ ] `zh-TW` - Chinese (Taiwan)
|
||||||
|
|||||||
1862
src/Umbraco.Web.UI.Client/package-lock.json
generated
1862
src/Umbraco.Web.UI.Client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -50,6 +50,7 @@
|
|||||||
"./repository": "./dist-cms/packages/core/repository/index.js",
|
"./repository": "./dist-cms/packages/core/repository/index.js",
|
||||||
"./temporary-file": "./dist-cms/packages/core/temporary-file/index.js",
|
"./temporary-file": "./dist-cms/packages/core/temporary-file/index.js",
|
||||||
"./block": "./dist-cms/packages/block/index.js",
|
"./block": "./dist-cms/packages/block/index.js",
|
||||||
|
"./audit-log": "./dist-cms/packages/audit-log/index.js",
|
||||||
"./dictionary": "./dist-cms/packages/dictionary/dictionary/index.js",
|
"./dictionary": "./dist-cms/packages/dictionary/dictionary/index.js",
|
||||||
"./document": "./dist-cms/packages/documents/documents/index.js",
|
"./document": "./dist-cms/packages/documents/documents/index.js",
|
||||||
"./document-blueprint": "./dist-cms/packages/documents/document-blueprints/index.js",
|
"./document-blueprint": "./dist-cms/packages/documents/document-blueprints/index.js",
|
||||||
@@ -63,7 +64,8 @@
|
|||||||
"./data-type": "./dist-cms/packages/core/data-type/index.js",
|
"./data-type": "./dist-cms/packages/core/data-type/index.js",
|
||||||
"./language": "./dist-cms/packages/settings/languages/index.js",
|
"./language": "./dist-cms/packages/settings/languages/index.js",
|
||||||
"./logviewer": "./dist-cms/packages/settings/logviewer/index.js",
|
"./logviewer": "./dist-cms/packages/settings/logviewer/index.js",
|
||||||
"./relation-type": "./dist-cms/packages/settings/relation-types/index.js",
|
"./relation-type": "./dist-cms/packages/relations/relation-types/index.js",
|
||||||
|
"./relation": "./dist-cms/packages/relations/relations/index.js",
|
||||||
"./tags": "./dist-cms/packages/tags/index.js",
|
"./tags": "./dist-cms/packages/tags/index.js",
|
||||||
"./static-file": "./dist-cms/packages/static-file/index.js",
|
"./static-file": "./dist-cms/packages/static-file/index.js",
|
||||||
"./partial-view": "./dist-cms/packages/templating/partial-views/index.js",
|
"./partial-view": "./dist-cms/packages/templating/partial-views/index.js",
|
||||||
@@ -144,11 +146,11 @@
|
|||||||
"element-internals-polyfill": "^1.3.9",
|
"element-internals-polyfill": "^1.3.9",
|
||||||
"lit": "^2.8.0",
|
"lit": "^2.8.0",
|
||||||
"lodash-es": "4.17.21",
|
"lodash-es": "4.17.21",
|
||||||
"marked": "^11.1.0",
|
"marked": "^11.1.1",
|
||||||
"monaco-editor": "^0.45.0",
|
"monaco-editor": "^0.45.0",
|
||||||
"rxjs": "^7.8.1",
|
"rxjs": "^7.8.1",
|
||||||
"tinymce-i18n": "^23.12.4",
|
|
||||||
"tinymce": "^6.8.2",
|
"tinymce": "^6.8.2",
|
||||||
|
"tinymce-i18n": "^23.12.4",
|
||||||
"uuid": "^9.0.1"
|
"uuid": "^9.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -159,54 +161,55 @@
|
|||||||
"@rollup/plugin-commonjs": "^25.0.7",
|
"@rollup/plugin-commonjs": "^25.0.7",
|
||||||
"@rollup/plugin-json": "^6.1.0",
|
"@rollup/plugin-json": "^6.1.0",
|
||||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||||
"@storybook/addon-a11y": "7.6.5",
|
"@rollup/plugin-replace": "^5.0.5",
|
||||||
"@storybook/addon-actions": "7.6.5",
|
"@storybook/addon-a11y": "7.6.7",
|
||||||
"@storybook/addon-essentials": "7.6.5",
|
"@storybook/addon-actions": "7.6.7",
|
||||||
"@storybook/addon-links": "7.6.5",
|
"@storybook/addon-essentials": "7.6.7",
|
||||||
|
"@storybook/addon-links": "7.6.7",
|
||||||
"@storybook/mdx2-csf": "^1.1.0",
|
"@storybook/mdx2-csf": "^1.1.0",
|
||||||
"@storybook/web-components-vite": "7.6.5",
|
"@storybook/web-components-vite": "7.6.7",
|
||||||
"@storybook/web-components": "7.6.5",
|
"@storybook/web-components": "7.6.7",
|
||||||
"@types/chai": "^4.3.5",
|
"@types/chai": "^4.3.5",
|
||||||
"@types/lodash-es": "^4.17.8",
|
"@types/lodash-es": "^4.17.8",
|
||||||
"@types/mocha": "^10.0.1",
|
"@types/mocha": "^10.0.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.14.0",
|
"@typescript-eslint/eslint-plugin": "^6.14.0",
|
||||||
"@typescript-eslint/parser": "^6.14.0",
|
"@typescript-eslint/parser": "^6.14.0",
|
||||||
"@web/dev-server-esbuild": "^0.4.1",
|
"@web/dev-server-esbuild": "^1.0.1",
|
||||||
"@web/dev-server-import-maps": "^0.1.1",
|
"@web/dev-server-import-maps": "^0.2.0",
|
||||||
"@web/dev-server-rollup": "^0.6.0",
|
"@web/dev-server-rollup": "^0.6.1",
|
||||||
"@web/test-runner-playwright": "^0.11.0",
|
|
||||||
"@web/test-runner": "^0.18.0",
|
"@web/test-runner": "^0.18.0",
|
||||||
|
"@web/test-runner-playwright": "^0.11.0",
|
||||||
"babel-loader": "^9.1.3",
|
"babel-loader": "^9.1.3",
|
||||||
|
"eslint": "^8.56.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-import-resolver-typescript": "^3.6.1",
|
"eslint-import-resolver-typescript": "^3.6.1",
|
||||||
"eslint-plugin-import": "^2.29.1",
|
"eslint-plugin-import": "^2.29.1",
|
||||||
"eslint-plugin-lit-a11y": "^4.1.1",
|
|
||||||
"eslint-plugin-lit": "^1.10.1",
|
"eslint-plugin-lit": "^1.10.1",
|
||||||
|
"eslint-plugin-lit-a11y": "^4.1.1",
|
||||||
"eslint-plugin-local-rules": "^2.0.1",
|
"eslint-plugin-local-rules": "^2.0.1",
|
||||||
"eslint-plugin-storybook": "^0.6.15",
|
"eslint-plugin-storybook": "^0.6.15",
|
||||||
"eslint-plugin-wc": "^2.0.4",
|
"eslint-plugin-wc": "^2.0.4",
|
||||||
"eslint": "^8.56.0",
|
|
||||||
"lucide-static": "^0.290.0",
|
"lucide-static": "^0.290.0",
|
||||||
"msw": "^1.3.2",
|
"msw": "^1.3.2",
|
||||||
"openapi-typescript-codegen": "^0.25.0",
|
"openapi-typescript-codegen": "^0.25.0",
|
||||||
"playwright-msw": "^3.0.1",
|
"playwright-msw": "^3.0.1",
|
||||||
"plop": "^4.0.0",
|
"plop": "^4.0.0",
|
||||||
"prettier": "3.0.3",
|
"prettier": "3.0.3",
|
||||||
"react-dom": "^18.2.0",
|
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
"remark-gfm": "^3.0.1",
|
"remark-gfm": "^3.0.1",
|
||||||
|
"rollup": "^4.9.4",
|
||||||
"rollup-plugin-esbuild": "^6.1.0",
|
"rollup-plugin-esbuild": "^6.1.0",
|
||||||
"rollup-plugin-import-css": "^3.3.5",
|
"rollup-plugin-import-css": "^3.4.0",
|
||||||
"rollup-plugin-web-worker-loader": "^1.6.1",
|
"rollup-plugin-web-worker-loader": "^1.6.1",
|
||||||
"rollup": "^4.9.0",
|
"storybook": "7.6.7",
|
||||||
"storybook": "7.6.5",
|
|
||||||
"tiny-glob": "^0.2.9",
|
"tiny-glob": "^0.2.9",
|
||||||
"tsc-alias": "^1.8.8",
|
"tsc-alias": "^1.8.8",
|
||||||
|
"typescript": "^5.3.3",
|
||||||
"typescript-json-schema": "^0.62.0",
|
"typescript-json-schema": "^0.62.0",
|
||||||
"typescript": "^5.3.2",
|
"vite": "^5.0.11",
|
||||||
"vite-plugin-static-copy": "^0.17.0",
|
"vite-plugin-static-copy": "^1.0.0",
|
||||||
"vite-tsconfig-paths": "^4.2.0",
|
"vite-tsconfig-paths": "^4.2.3",
|
||||||
"vite": "^4.4.12",
|
|
||||||
"web-component-analyzer": "^2.0.0"
|
"web-component-analyzer": "^2.0.0"
|
||||||
},
|
},
|
||||||
"msw": {
|
"msw": {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { UmbBackofficeContext, UMB_BACKOFFICE_CONTEXT_TOKEN } from './backoffice.context.js';
|
import { UmbBackofficeContext } from './backoffice.context.js';
|
||||||
import { UmbServerExtensionRegistrator } from './server-extension-registrator.controller.js';
|
import { UmbServerExtensionRegistrator } from './server-extension-registrator.controller.js';
|
||||||
import { css, html, customElement } from '@umbraco-cms/backoffice/external/lit';
|
import { css, html, customElement } from '@umbraco-cms/backoffice/external/lit';
|
||||||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||||
@@ -12,9 +12,11 @@ import './components/index.js';
|
|||||||
|
|
||||||
// TODO: temp solution to load core packages
|
// TODO: temp solution to load core packages
|
||||||
const CORE_PACKAGES = [
|
const CORE_PACKAGES = [
|
||||||
|
import('../../packages/audit-log/umbraco-package.js'),
|
||||||
import('../../packages/core/umbraco-package.js'),
|
import('../../packages/core/umbraco-package.js'),
|
||||||
import('../../packages/settings/umbraco-package.js'),
|
import('../../packages/settings/umbraco-package.js'),
|
||||||
import('../../packages/documents/umbraco-package.js'),
|
import('../../packages/documents/umbraco-package.js'),
|
||||||
|
import('../../packages/relations/umbraco-package.js'),
|
||||||
import('../../packages/media/umbraco-package.js'),
|
import('../../packages/media/umbraco-package.js'),
|
||||||
import('../../packages/members/umbraco-package.js'),
|
import('../../packages/members/umbraco-package.js'),
|
||||||
import('../../packages/block/umbraco-package.js'),
|
import('../../packages/block/umbraco-package.js'),
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export class UmbBackofficeMainElement extends UmbLitElement {
|
|||||||
|
|
||||||
private _onRouteChange = async (event: UmbRouterSlotChangeEvent) => {
|
private _onRouteChange = async (event: UmbRouterSlotChangeEvent) => {
|
||||||
const currentPath = event.target.localActiveViewPath || '';
|
const currentPath = event.target.localActiveViewPath || '';
|
||||||
const section = this._sections.find((s) => this._routePrefix + (s.manifest as any).meta.pathname === currentPath);
|
const section = this._sections.find((s) => this._routePrefix + s.manifest?.meta.pathname === currentPath);
|
||||||
if (!section) return;
|
if (!section) return;
|
||||||
await section.asPromise();
|
await section.asPromise();
|
||||||
if (section.manifest) {
|
if (section.manifest) {
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
import './installer-database.element.js';
|
import './installer-database.element.js';
|
||||||
|
|
||||||
import { Meta, Story } from '@storybook/web-components';
|
import { Meta, Story } from '@storybook/web-components';
|
||||||
import { html } from '@umbraco-cms/backoffice/external/lit';
|
|
||||||
const { rest } = window.MockServiceWorker;
|
|
||||||
|
|
||||||
import { installerContextProvider } from '../shared/utils.story-helpers.js';
|
import { installerContextProvider } from '../shared/utils.story-helpers.js';
|
||||||
|
|
||||||
import type { UmbInstallerDatabaseElement } from './installer-database.element.js';
|
import type { UmbInstallerDatabaseElement } from './installer-database.element.js';
|
||||||
import type { InstallSettingsResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
import { html } from '@umbraco-cms/backoffice/external/lit';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: 'Apps/Installer/Steps',
|
title: 'Apps/Installer/Steps',
|
||||||
component: 'umb-installer-database',
|
component: 'umb-installer-database',
|
||||||
|
|||||||
@@ -1151,6 +1151,8 @@ export default {
|
|||||||
},
|
},
|
||||||
contentPicker: {
|
contentPicker: {
|
||||||
allowedItemTypes: 'Du kan kun vælge følgende type(r) dokumenter: %0%',
|
allowedItemTypes: 'Du kan kun vælge følgende type(r) dokumenter: %0%',
|
||||||
|
defineDynamicRoot: 'Definer Dynamisk Udgangspunkt',
|
||||||
|
defineRootNode: 'Vælg udgangspunkt',
|
||||||
pickedTrashedItem: 'Du har valgt et dokument som er slettet eller lagt i papirkurven',
|
pickedTrashedItem: 'Du har valgt et dokument som er slettet eller lagt i papirkurven',
|
||||||
pickedTrashedItems: 'Du har valgt dokumenter som er slettede eller lagt i papirkurven',
|
pickedTrashedItems: 'Du har valgt dokumenter som er slettede eller lagt i papirkurven',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1148,6 +1148,8 @@ export default {
|
|||||||
},
|
},
|
||||||
contentPicker: {
|
contentPicker: {
|
||||||
allowedItemTypes: 'You can only select items of type(s): %0%',
|
allowedItemTypes: 'You can only select items of type(s): %0%',
|
||||||
|
defineDynamicRoot: 'Specify a Dynamic Root',
|
||||||
|
defineRootNode: 'Pick root node',
|
||||||
pickedTrashedItem: 'You have picked a content item currently deleted or in the recycle bin',
|
pickedTrashedItem: 'You have picked a content item currently deleted or in the recycle bin',
|
||||||
pickedTrashedItems: 'You have picked content items currently deleted or in the recycle bin',
|
pickedTrashedItems: 'You have picked content items currently deleted or in the recycle bin',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import styles from 'monaco-editor/min/vs/editor/editor.main.css';
|
import styles from 'monaco-editor/min/vs/editor/editor.main.css?inline';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker.js?worker';
|
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker.js?worker';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ export const UmbClassMixin = <T extends ClassConstructor>(superClass: T) => {
|
|||||||
public destroy() {
|
public destroy() {
|
||||||
if (this._host) {
|
if (this._host) {
|
||||||
this._host.removeController(this);
|
this._host.removeController(this);
|
||||||
this._host = undefined as any;
|
this._host = undefined as never;
|
||||||
}
|
}
|
||||||
super.destroy();
|
super.destroy();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { UmbBaseController } from './controller-base.class.js';
|
|||||||
*/
|
*/
|
||||||
export abstract class UmbContextBase<
|
export abstract class UmbContextBase<
|
||||||
ContextType,
|
ContextType,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
GivenContextToken extends UmbContextToken<any, ContextType> = UmbContextToken<any, ContextType>,
|
GivenContextToken extends UmbContextToken<any, ContextType> = UmbContextToken<any, ContextType>,
|
||||||
> extends UmbBaseController {
|
> extends UmbBaseController {
|
||||||
constructor(host: UmbControllerHost, contextToken: GivenContextToken | string) {
|
constructor(host: UmbControllerHost, contextToken: GivenContextToken | string) {
|
||||||
|
|||||||
@@ -157,10 +157,12 @@ describe('UmbContextConsumer', () => {
|
|||||||
type A = { prop: string };
|
type A = { prop: string };
|
||||||
|
|
||||||
function discriminator(instance: unknown): instance is A {
|
function discriminator(instance: unknown): instance is A {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
return typeof (instance as any).prop === 'string';
|
return typeof (instance as any).prop === 'string';
|
||||||
}
|
}
|
||||||
|
|
||||||
function badDiscriminator(instance: unknown): instance is A {
|
function badDiscriminator(instance: unknown): instance is A {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
return typeof (instance as any).notExistingProp === 'string';
|
return typeof (instance as any).notExistingProp === 'string';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
import { handlers as auditLogHandlers } from './handlers/audit-log.handlers.js';
|
||||||
import { handlers as dataTypeHandlers } from './handlers/data-type/index.js';
|
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/index.js';
|
import { handlers as documentTypeHandlers } from './handlers/document-type/index.js';
|
||||||
import { handlers as installHandlers } from './handlers/install.handlers.js';
|
import { handlers as installHandlers } from './handlers/install.handlers.js';
|
||||||
import * as manifestsHandlers from './handlers/manifests.handlers.js';
|
import * as manifestsHandlers from './handlers/manifests.handlers.js';
|
||||||
@@ -11,6 +11,8 @@ import { handlers as telemetryHandlers } from './handlers/telemetry.handlers.js'
|
|||||||
import { handlers as userGroupsHandlers } from './handlers/user-group/index.js';
|
import { handlers as userGroupsHandlers } from './handlers/user-group/index.js';
|
||||||
import { handlers as examineManagementHandlers } from './handlers/examine-management.handlers.js';
|
import { handlers as examineManagementHandlers } from './handlers/examine-management.handlers.js';
|
||||||
import { handlers as modelsBuilderHandlers } from './handlers/modelsbuilder.handlers.js';
|
import { handlers as modelsBuilderHandlers } from './handlers/modelsbuilder.handlers.js';
|
||||||
|
import { relationHandlers, relationTypeHandlers } from './handlers/relations/index.js';
|
||||||
|
import { handlers as objectTypeHandlers } from './handlers/object-type/index.js';
|
||||||
import { handlers as healthCheckHandlers } from './handlers/health-check.handlers.js';
|
import { handlers as healthCheckHandlers } from './handlers/health-check.handlers.js';
|
||||||
import { handlers as profilingHandlers } from './handlers/performance-profiling.handlers.js';
|
import { handlers as profilingHandlers } from './handlers/performance-profiling.handlers.js';
|
||||||
import { handlers as documentHandlers } from './handlers/document/index.js';
|
import { handlers as documentHandlers } from './handlers/document/index.js';
|
||||||
@@ -21,6 +23,7 @@ import { handlers as memberGroupHandlers } from './handlers/member-group.handler
|
|||||||
import { handlers as memberHandlers } from './handlers/member.handlers.js';
|
import { handlers as memberHandlers } from './handlers/member.handlers.js';
|
||||||
import { handlers as memberTypeHandlers } from './handlers/member-type.handlers.js';
|
import { handlers as memberTypeHandlers } from './handlers/member-type.handlers.js';
|
||||||
import { handlers as templateHandlers } from './handlers/template.handlers.js';
|
import { handlers as templateHandlers } from './handlers/template.handlers.js';
|
||||||
|
import { handlers as trackedReferenceHandlers } from './handlers/tracked-reference.handlers.js';
|
||||||
import { handlers as languageHandlers } from './handlers/language.handlers.js';
|
import { handlers as languageHandlers } from './handlers/language.handlers.js';
|
||||||
import { handlers as cultureHandlers } from './handlers/culture.handlers.js';
|
import { handlers as cultureHandlers } from './handlers/culture.handlers.js';
|
||||||
import { handlers as redirectManagementHandlers } from './handlers/redirect-management.handlers.js';
|
import { handlers as redirectManagementHandlers } from './handlers/redirect-management.handlers.js';
|
||||||
@@ -36,6 +39,7 @@ import { handlers as scriptHandlers } from './handlers/scripts.handlers.js';
|
|||||||
|
|
||||||
const handlers = [
|
const handlers = [
|
||||||
serverHandlers.serverVersionHandler,
|
serverHandlers.serverVersionHandler,
|
||||||
|
...auditLogHandlers,
|
||||||
...configHandlers,
|
...configHandlers,
|
||||||
...cultureHandlers,
|
...cultureHandlers,
|
||||||
...dataTypeHandlers,
|
...dataTypeHandlers,
|
||||||
@@ -58,6 +62,8 @@ const handlers = [
|
|||||||
...profilingHandlers,
|
...profilingHandlers,
|
||||||
...publishedStatusHandlers,
|
...publishedStatusHandlers,
|
||||||
...redirectManagementHandlers,
|
...redirectManagementHandlers,
|
||||||
|
...relationHandlers,
|
||||||
|
...objectTypeHandlers,
|
||||||
...relationTypeHandlers,
|
...relationTypeHandlers,
|
||||||
...rteEmbedHandlers,
|
...rteEmbedHandlers,
|
||||||
...scriptHandlers,
|
...scriptHandlers,
|
||||||
@@ -66,6 +72,7 @@ const handlers = [
|
|||||||
...tagHandlers,
|
...tagHandlers,
|
||||||
...telemetryHandlers,
|
...telemetryHandlers,
|
||||||
...templateHandlers,
|
...templateHandlers,
|
||||||
|
...trackedReferenceHandlers,
|
||||||
...upgradeHandlers,
|
...upgradeHandlers,
|
||||||
...userGroupsHandlers,
|
...userGroupsHandlers,
|
||||||
...userHandlers,
|
...userHandlers,
|
||||||
|
|||||||
58
src/Umbraco.Web.UI.Client/src/mocks/data/audit-log.data.ts
Normal file
58
src/Umbraco.Web.UI.Client/src/mocks/data/audit-log.data.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { data as userData } from './user/user.data.js';
|
||||||
|
import { data as documentData } from './document.data.js';
|
||||||
|
import {
|
||||||
|
AuditLogResponseModel,
|
||||||
|
AuditLogWithUsernameResponseModel,
|
||||||
|
AuditTypeModel,
|
||||||
|
} from '@umbraco-cms/backoffice/backend-api';
|
||||||
|
|
||||||
|
const userId = userData[0].id;
|
||||||
|
const userName = userData[0].name;
|
||||||
|
const userAvatars = userData[0].avatarUrls;
|
||||||
|
|
||||||
|
const documentId = documentData[0].id;
|
||||||
|
|
||||||
|
export const logs: Array<AuditLogResponseModel> = [
|
||||||
|
{
|
||||||
|
userId: userId,
|
||||||
|
entityId: documentId,
|
||||||
|
entityType: 'Document',
|
||||||
|
timestamp: '2021-09-14T09:32:49.0000000Z',
|
||||||
|
logType: AuditTypeModel.SAVE,
|
||||||
|
comment: undefined,
|
||||||
|
parameters: undefined,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
userId: userId,
|
||||||
|
entityId: documentId,
|
||||||
|
entityType: 'Document',
|
||||||
|
timestamp: '2022-09-14T11:30:49.0000000Z',
|
||||||
|
logType: AuditTypeModel.SAVE,
|
||||||
|
comment: undefined,
|
||||||
|
parameters: undefined,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
userId: userId,
|
||||||
|
entityId: documentId,
|
||||||
|
entityType: 'Document',
|
||||||
|
timestamp: '2022-09-15T09:35:49.0000000Z',
|
||||||
|
logType: AuditTypeModel.SAVE,
|
||||||
|
comment: undefined,
|
||||||
|
parameters: undefined,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
userId: userId,
|
||||||
|
entityId: documentId,
|
||||||
|
entityType: 'Document',
|
||||||
|
timestamp: '2023-01-09T12:00:00.0000000Z',
|
||||||
|
logType: AuditTypeModel.PUBLISH,
|
||||||
|
comment: undefined,
|
||||||
|
parameters: undefined,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const logsWithUser: Array<AuditLogWithUsernameResponseModel> = logs.map((log) => ({
|
||||||
|
...log,
|
||||||
|
userName: userName,
|
||||||
|
userAvatars: userAvatars,
|
||||||
|
}));
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { UmbEntityData } from '../entity.data.js';
|
||||||
|
import type { ObjectTypeResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||||
|
|
||||||
|
export const data: Array<ObjectTypeResponseModel> = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
name: 'Media',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
name: 'Content',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
name: 'User',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4',
|
||||||
|
name: 'Document',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// Temp mocked database
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
class UmbObjectTypeData extends UmbEntityData<ObjectTypeResponseModel> {
|
||||||
|
constructor() {
|
||||||
|
super(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const umbObjectTypeData = new UmbObjectTypeData();
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { UmbEntityData } from './entity.data.js';
|
import { UmbEntityData } from '../entity.data.js';
|
||||||
import { createEntityTreeItem } from './utils.js';
|
import { createEntityTreeItem } from '../utils.js';
|
||||||
import type { EntityTreeItemResponseModel, RelationTypeResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
import type { EntityTreeItemResponseModel, RelationTypeResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||||
|
|
||||||
// TODO: investigate why we don't get an entity type as part of the RelationTypeResponseModel
|
// TODO: investigate why we don't get an entity type as part of the RelationTypeResponseModel
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
import { UmbEntityData } from '../entity.data.js';
|
||||||
|
import type { RelationResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||||
|
|
||||||
|
export const data: Array<RelationResponseModel> = [
|
||||||
|
{
|
||||||
|
parentId: 'e0d39ff5-71d8-453f-b682-9d8d31ee5e06',
|
||||||
|
parentName: 'Relate Document On Copy',
|
||||||
|
childId: '1',
|
||||||
|
childName: 'Child 1',
|
||||||
|
createDate: '2021-01-01',
|
||||||
|
comment: 'Comment 1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parentId: 'e0d39ff5-71d8-453f-b682-9d8d31ee5e06',
|
||||||
|
parentName: 'Relate Document On Copy',
|
||||||
|
childId: '2',
|
||||||
|
childName: 'Child 2',
|
||||||
|
createDate: '2021-01-01',
|
||||||
|
comment: 'Comment 2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parentId: 'e0d39ff5-71d8-453f-b682-9d8d31ee5e06',
|
||||||
|
parentName: 'Relate Document On Copy',
|
||||||
|
childId: '3',
|
||||||
|
childName: 'Child 3',
|
||||||
|
createDate: '2021-01-01',
|
||||||
|
comment: 'Comment 3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parentId: 'e0d39ff5-71d8-453f-b682-9d8d31ee5e06',
|
||||||
|
parentName: 'Relate Document On Copy',
|
||||||
|
childId: '4',
|
||||||
|
childName: 'Child 4',
|
||||||
|
createDate: '2021-01-01',
|
||||||
|
comment: 'Comment 4',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parentId: 'ac68cde6-763f-4231-a751-1101b57defd2',
|
||||||
|
parentName: 'Relate Document On Copy',
|
||||||
|
childId: '5',
|
||||||
|
childName: 'Child 5',
|
||||||
|
createDate: '2021-01-01',
|
||||||
|
comment: 'Comment 5',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parentId: 'ac68cde6-763f-4231-a751-1101b57defd2',
|
||||||
|
parentName: 'Relate Document On Copy',
|
||||||
|
childId: '6',
|
||||||
|
childName: 'Child 6',
|
||||||
|
createDate: '2021-01-01',
|
||||||
|
comment: 'Comment 6',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parentId: '6f9b800c-762c-42d4-85d9-bf40a77d689e',
|
||||||
|
parentName: 'Relate Document On Copy',
|
||||||
|
childId: '7',
|
||||||
|
childName: 'Child 7',
|
||||||
|
createDate: '2021-01-01',
|
||||||
|
comment: 'Comment 7',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parentId: 'd421727d-43de-4205-b4c6-037404f309ad',
|
||||||
|
parentName: 'Relate Document On Copy',
|
||||||
|
childId: '8',
|
||||||
|
childName: 'Child 8',
|
||||||
|
createDate: '2021-01-01',
|
||||||
|
comment: 'Comment 8',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parentId: 'd421727d-43de-4205-b4c6-037404f309ad',
|
||||||
|
parentName: 'Relate Document On Copy',
|
||||||
|
childId: '9',
|
||||||
|
childName: 'Child 9',
|
||||||
|
createDate: '2021-01-01',
|
||||||
|
comment: 'Comment 9',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parentId: 'e9a0a28e-2d5b-4229-ac00-66f2df230513',
|
||||||
|
parentName: 'Relate Document On Copy',
|
||||||
|
childId: '10',
|
||||||
|
childName: 'Child 10',
|
||||||
|
createDate: '2021-01-01',
|
||||||
|
comment: 'Comment 10',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parentId: 'e9a0a28e-2d5b-4229-ac00-66f2df230513',
|
||||||
|
parentName: 'Relate Document On Copy',
|
||||||
|
childId: '11',
|
||||||
|
childName: 'Child 11',
|
||||||
|
createDate: '2021-01-01',
|
||||||
|
comment: 'Comment 11',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// Temp mocked database
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
class UmbRelationData extends UmbEntityData<RelationResponseModel> {
|
||||||
|
constructor() {
|
||||||
|
super(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
getRelationsByParentId(id: string) {
|
||||||
|
const test = this.data.filter((relation) => relation.parentId === id);
|
||||||
|
return { items: test, total: test.length };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const umbRelationData = new UmbRelationData();
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { RelationItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||||
|
|
||||||
|
export const items: Array<RelationItemResponseModel> = [
|
||||||
|
{
|
||||||
|
nodeId: 'simple-document-id',
|
||||||
|
nodeName: 'Simple Document',
|
||||||
|
nodeType: 'document',
|
||||||
|
nodePublished: true,
|
||||||
|
contentTypeIcon: 'icon-document',
|
||||||
|
contentTypeName: 'Simple Document Type',
|
||||||
|
contentTypeAlias: 'blogPost',
|
||||||
|
relationTypeIsBidirectional: false,
|
||||||
|
relationTypeIsDependency: true,
|
||||||
|
relationTypeName: 'Related Document',
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { handlers as auditLogHandlers } from './handlers/audit-log.handlers.js';
|
||||||
import { handlers as dataTypeHandlers } from './handlers/data-type/index.js';
|
import { handlers as dataTypeHandlers } from './handlers/data-type/index.js';
|
||||||
import { handlers as documentTypeHandlers } from './handlers/document-type/index.js';
|
import { handlers as documentTypeHandlers } from './handlers/document-type/index.js';
|
||||||
import { handlers as installHandlers } from './handlers/install.handlers.js';
|
import { handlers as installHandlers } from './handlers/install.handlers.js';
|
||||||
@@ -15,11 +16,13 @@ import { handlers as languageHandlers } from './handlers/language.handlers.js';
|
|||||||
import { handlers as redirectManagementHandlers } from './handlers/redirect-management.handlers.js';
|
import { handlers as redirectManagementHandlers } from './handlers/redirect-management.handlers.js';
|
||||||
import { handlers as packageHandlers } from './handlers/package.handlers.js';
|
import { handlers as packageHandlers } from './handlers/package.handlers.js';
|
||||||
import { handlers as configHandlers } from './handlers/config.handlers.js';
|
import { handlers as configHandlers } from './handlers/config.handlers.js';
|
||||||
|
import { handlers as trackedReferenceHandlers } from './handlers/tracked-reference.handlers.js';
|
||||||
|
|
||||||
export const handlers = [
|
export const handlers = [
|
||||||
serverHandlers.serverRunningHandler,
|
serverHandlers.serverRunningHandler,
|
||||||
serverHandlers.serverVersionHandler,
|
serverHandlers.serverVersionHandler,
|
||||||
manifestsHandlers.manifestEmptyHandler,
|
manifestsHandlers.manifestEmptyHandler,
|
||||||
|
...auditLogHandlers,
|
||||||
...installHandlers,
|
...installHandlers,
|
||||||
...upgradeHandlers,
|
...upgradeHandlers,
|
||||||
...userHandlers,
|
...userHandlers,
|
||||||
@@ -35,4 +38,5 @@ export const handlers = [
|
|||||||
...redirectManagementHandlers,
|
...redirectManagementHandlers,
|
||||||
...packageHandlers,
|
...packageHandlers,
|
||||||
...configHandlers,
|
...configHandlers,
|
||||||
|
...trackedReferenceHandlers,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import { logs, logsWithUser } from '../data/audit-log.data.js';
|
||||||
|
const { rest } = window.MockServiceWorker;
|
||||||
|
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
|
||||||
|
import {
|
||||||
|
PagedAuditLogResponseModel,
|
||||||
|
PagedAuditLogWithUsernameResponseModel,
|
||||||
|
} from '@umbraco-cms/backoffice/backend-api';
|
||||||
|
|
||||||
|
export const handlers = [
|
||||||
|
rest.get(umbracoPath('/audit-log'), (_req, res, ctx) => {
|
||||||
|
const PagedAuditLog = {
|
||||||
|
total: logsWithUser.length,
|
||||||
|
items: logsWithUser,
|
||||||
|
};
|
||||||
|
return res(ctx.status(200), ctx.json<PagedAuditLogWithUsernameResponseModel>(PagedAuditLog));
|
||||||
|
}),
|
||||||
|
rest.get(umbracoPath('/audit-log/:id'), (_req, res, ctx) => {
|
||||||
|
const id = _req.params.id as string;
|
||||||
|
if (!id) return;
|
||||||
|
|
||||||
|
const foundLogs = logs.filter((log) => log.entityId === id);
|
||||||
|
const PagedAuditLog = {
|
||||||
|
total: foundLogs.length,
|
||||||
|
items: foundLogs,
|
||||||
|
};
|
||||||
|
|
||||||
|
return res(ctx.status(200), ctx.json<PagedAuditLogResponseModel>(PagedAuditLog));
|
||||||
|
}),
|
||||||
|
rest.get(umbracoPath('/audit-log/type/:logType'), (_req, res, ctx) => {
|
||||||
|
const logType = _req.params.logType as string;
|
||||||
|
if (!logType) return;
|
||||||
|
|
||||||
|
const foundLogs = logs.filter((log) => log.entityType === logType);
|
||||||
|
const PagedAuditLog = {
|
||||||
|
total: foundLogs.length,
|
||||||
|
items: foundLogs,
|
||||||
|
};
|
||||||
|
|
||||||
|
return res(ctx.status(200), ctx.json<PagedAuditLogResponseModel>(PagedAuditLog));
|
||||||
|
}),
|
||||||
|
];
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import { handlers as itemHandlers } from './item.handlers.js';
|
||||||
|
|
||||||
|
export const handlers = [...itemHandlers];
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
const { rest } = window.MockServiceWorker;
|
||||||
|
import { umbObjectTypeData } from '../../data/object-type/object-type.data.js';
|
||||||
|
import { UMB_SLUG } from './slug.js';
|
||||||
|
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
|
||||||
|
|
||||||
|
export const handlers = [
|
||||||
|
rest.get(umbracoPath(`${UMB_SLUG}`), (req, res, ctx) => {
|
||||||
|
const response = umbObjectTypeData.getAll();
|
||||||
|
return res(ctx.status(200), ctx.json(response));
|
||||||
|
}),
|
||||||
|
];
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export const UMB_SLUG = '/object-types';
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
const { rest } = window.MockServiceWorker;
|
|
||||||
import { umbRelationTypeData } from '../data/relation-type.data.js';
|
|
||||||
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
|
|
||||||
|
|
||||||
// TODO: add schema
|
|
||||||
export const handlers = [
|
|
||||||
rest.delete<string[]>('/umbraco/backoffice/relation-type/:id', async (req, res, ctx) => {
|
|
||||||
const id = req.params.id as string;
|
|
||||||
if (!id) return;
|
|
||||||
|
|
||||||
umbRelationTypeData.delete([id]);
|
|
||||||
|
|
||||||
return res(ctx.status(200));
|
|
||||||
}),
|
|
||||||
|
|
||||||
rest.get('/umbraco/management/api/v1/tree/relation-type/root', (req, res, ctx) => {
|
|
||||||
const rootItems = umbRelationTypeData.getTreeRoot();
|
|
||||||
const response = {
|
|
||||||
total: rootItems.length,
|
|
||||||
items: rootItems,
|
|
||||||
};
|
|
||||||
return res(ctx.status(200), ctx.json(response));
|
|
||||||
}),
|
|
||||||
|
|
||||||
rest.get('/umbraco/management/api/v1/tree/relation-type/children', (req, res, ctx) => {
|
|
||||||
const parentId = req.url.searchParams.get('parentId');
|
|
||||||
if (!parentId) return;
|
|
||||||
|
|
||||||
const children = umbRelationTypeData.getTreeItemChildren(parentId);
|
|
||||||
|
|
||||||
const response = {
|
|
||||||
total: children.length,
|
|
||||||
items: children,
|
|
||||||
};
|
|
||||||
|
|
||||||
return res(ctx.status(200), ctx.json(response));
|
|
||||||
}),
|
|
||||||
|
|
||||||
rest.get('/umbraco/management/api/v1/tree/relation-type/item', (req, res, ctx) => {
|
|
||||||
const ids = req.url.searchParams.getAll('id');
|
|
||||||
if (!ids) return;
|
|
||||||
const items = umbRelationTypeData.getTreeItem(ids);
|
|
||||||
return res(ctx.status(200), ctx.json(items));
|
|
||||||
}),
|
|
||||||
|
|
||||||
rest.get(umbracoPath('/relation-type/:id'), (req, res, ctx) => {
|
|
||||||
const id = req.params.id as string;
|
|
||||||
if (!id) return;
|
|
||||||
|
|
||||||
const RelationType = umbRelationTypeData.getById(id);
|
|
||||||
|
|
||||||
return res(ctx.status(200), ctx.json(RelationType));
|
|
||||||
}),
|
|
||||||
|
|
||||||
rest.post(umbracoPath('/relation-type/:id'), async (req, res, ctx) => {
|
|
||||||
const id = req.params.id as string;
|
|
||||||
if (!id) return;
|
|
||||||
const data = await req.json();
|
|
||||||
if (!data) return;
|
|
||||||
|
|
||||||
umbRelationTypeData.insert(data);
|
|
||||||
|
|
||||||
return res(ctx.status(200));
|
|
||||||
}),
|
|
||||||
|
|
||||||
rest.put(umbracoPath('/relation-type/:id'), async (req, res, ctx) => {
|
|
||||||
const id = req.params.id as string;
|
|
||||||
if (!id) return;
|
|
||||||
const data = await req.json();
|
|
||||||
if (!data) return;
|
|
||||||
|
|
||||||
umbRelationTypeData.save(id, data);
|
|
||||||
|
|
||||||
return res(ctx.status(200));
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './relation/index.js';
|
||||||
|
export * from './relation-type/index.js';
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
const { rest } = window.MockServiceWorker;
|
||||||
|
import { umbRelationTypeData } from '../../../data/relations/relation-type.data.js';
|
||||||
|
import { UMB_SLUG } from './slug.js';
|
||||||
|
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
|
||||||
|
|
||||||
|
// TODO: add schema
|
||||||
|
export const handlers = [
|
||||||
|
rest.delete<string[]>(umbracoPath(`${UMB_SLUG}/:id`), async (req, res, ctx) => {
|
||||||
|
const id = req.params.id as string;
|
||||||
|
if (!id) return;
|
||||||
|
|
||||||
|
umbRelationTypeData.delete([id]);
|
||||||
|
|
||||||
|
return res(ctx.status(200));
|
||||||
|
}),
|
||||||
|
|
||||||
|
rest.get(umbracoPath(`${UMB_SLUG}/:id`), (req, res, ctx) => {
|
||||||
|
const id = req.params.id as string;
|
||||||
|
if (!id) return;
|
||||||
|
|
||||||
|
const RelationType = umbRelationTypeData.getById(id);
|
||||||
|
|
||||||
|
return res(ctx.status(200), ctx.json(RelationType));
|
||||||
|
}),
|
||||||
|
|
||||||
|
rest.post(umbracoPath(`${UMB_SLUG}/:id`), async (req, res, ctx) => {
|
||||||
|
const id = req.params.id as string;
|
||||||
|
if (!id) return;
|
||||||
|
const data = await req.json();
|
||||||
|
if (!data) return;
|
||||||
|
|
||||||
|
umbRelationTypeData.insert(data);
|
||||||
|
|
||||||
|
return res(ctx.status(200));
|
||||||
|
}),
|
||||||
|
|
||||||
|
rest.put(umbracoPath(`${UMB_SLUG}/:id`), async (req, res, ctx) => {
|
||||||
|
const id = req.params.id as string;
|
||||||
|
if (!id) return;
|
||||||
|
const data = await req.json();
|
||||||
|
if (!data) return;
|
||||||
|
|
||||||
|
umbRelationTypeData.save(id, data);
|
||||||
|
|
||||||
|
return res(ctx.status(200));
|
||||||
|
}),
|
||||||
|
];
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import { handlers as detailHandlers } from './detail.handlers.js';
|
||||||
|
import { handlers as treeHandlers } from './tree.handlers.js';
|
||||||
|
|
||||||
|
export const relationTypeHandlers = [...detailHandlers, ...treeHandlers];
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export const UMB_SLUG = '/relation-type';
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
const { rest } = window.MockServiceWorker;
|
||||||
|
import { umbRelationTypeData } from '../../../data/relations/relation-type.data.js';
|
||||||
|
import { UMB_SLUG } from './slug.js';
|
||||||
|
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
|
||||||
|
|
||||||
|
export const handlers = [
|
||||||
|
rest.get(umbracoPath(`/tree${UMB_SLUG}/root`), (req, res, ctx) => {
|
||||||
|
const rootItems = umbRelationTypeData.getTreeRoot();
|
||||||
|
const response = {
|
||||||
|
total: rootItems.length,
|
||||||
|
items: rootItems,
|
||||||
|
};
|
||||||
|
return res(ctx.status(200), ctx.json(response));
|
||||||
|
}),
|
||||||
|
|
||||||
|
rest.get(umbracoPath(`/tree${UMB_SLUG}/children`), (req, res, ctx) => {
|
||||||
|
const parentId = req.url.searchParams.get('parentId');
|
||||||
|
if (!parentId) return;
|
||||||
|
|
||||||
|
const children = umbRelationTypeData.getTreeItemChildren(parentId);
|
||||||
|
|
||||||
|
const response = {
|
||||||
|
total: children.length,
|
||||||
|
items: children,
|
||||||
|
};
|
||||||
|
|
||||||
|
return res(ctx.status(200), ctx.json(response));
|
||||||
|
}),
|
||||||
|
|
||||||
|
rest.get(umbracoPath(`/tree${UMB_SLUG}/item`), (req, res, ctx) => {
|
||||||
|
const ids = req.url.searchParams.getAll('id');
|
||||||
|
if (!ids) return;
|
||||||
|
const items = umbRelationTypeData.getTreeItem(ids);
|
||||||
|
return res(ctx.status(200), ctx.json(items));
|
||||||
|
}),
|
||||||
|
];
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import { handlers as itemHandlers } from './item.handlers.js';
|
||||||
|
|
||||||
|
export const relationHandlers = [...itemHandlers];
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
const { rest } = window.MockServiceWorker;
|
||||||
|
import { umbRelationData } from '../../../data/relations/relation.data.js';
|
||||||
|
import { UMB_SLUG } from './slug.js';
|
||||||
|
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
|
||||||
|
|
||||||
|
export const handlers = [
|
||||||
|
rest.get(umbracoPath(`${UMB_SLUG}/type/:id`), (req, res, ctx) => {
|
||||||
|
const id = req.params.id as string;
|
||||||
|
if (!id) return;
|
||||||
|
|
||||||
|
const response = umbRelationData.getRelationsByParentId(id);
|
||||||
|
|
||||||
|
return res(ctx.status(200), ctx.json(response));
|
||||||
|
}),
|
||||||
|
];
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export const UMB_SLUG = '/relation';
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { items } from '../data/tracked-reference.data.js';
|
||||||
|
const { rest } = window.MockServiceWorker;
|
||||||
|
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
|
||||||
|
import { PagedRelationItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||||
|
|
||||||
|
export const handlers = [
|
||||||
|
rest.get(umbracoPath('/tracked-reference/:id'), (_req, res, ctx) => {
|
||||||
|
const id = _req.params.id as string;
|
||||||
|
if (!id) return;
|
||||||
|
|
||||||
|
const PagedTrackedReference = {
|
||||||
|
total: items.length,
|
||||||
|
items: items,
|
||||||
|
};
|
||||||
|
|
||||||
|
return res(ctx.status(200), ctx.json<PagedRelationItemResponseModel>(PagedTrackedReference));
|
||||||
|
}),
|
||||||
|
];
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import { manifests as repositoryManifests } from './repository/manifests.js';
|
||||||
|
|
||||||
|
export const manifests = [...repositoryManifests];
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
import { UmbAuditLogServerDataSource } from './audit-log.server.data.js';
|
||||||
|
import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api';
|
||||||
|
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||||
|
import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification';
|
||||||
|
import { AuditTypeModel, DirectionModel } from '@umbraco-cms/backoffice/backend-api';
|
||||||
|
import { UmbBaseController } from '@umbraco-cms/backoffice/class-api';
|
||||||
|
|
||||||
|
export class UmbAuditLogRepository extends UmbBaseController {
|
||||||
|
#dataSource: UmbAuditLogServerDataSource;
|
||||||
|
#notificationService?: UmbNotificationContext;
|
||||||
|
#init;
|
||||||
|
|
||||||
|
constructor(host: UmbControllerHostElement) {
|
||||||
|
super(host);
|
||||||
|
this.#dataSource = new UmbAuditLogServerDataSource(host);
|
||||||
|
|
||||||
|
this.#init = new UmbContextConsumerController(host, UMB_NOTIFICATION_CONTEXT_TOKEN, (instance) => {
|
||||||
|
this.#notificationService = instance;
|
||||||
|
}).asPromise();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLog({
|
||||||
|
orderDirection,
|
||||||
|
sinceDate,
|
||||||
|
skip = 0,
|
||||||
|
take = 100,
|
||||||
|
}: {
|
||||||
|
orderDirection?: DirectionModel;
|
||||||
|
sinceDate?: string;
|
||||||
|
skip?: number;
|
||||||
|
take?: number;
|
||||||
|
}) {
|
||||||
|
await this.#init;
|
||||||
|
|
||||||
|
return this.#dataSource.getAuditLog({ orderDirection, sinceDate, skip, take });
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAuditLogByUnique({
|
||||||
|
id,
|
||||||
|
orderDirection,
|
||||||
|
skip = 0,
|
||||||
|
take = 100,
|
||||||
|
}: {
|
||||||
|
id: string;
|
||||||
|
orderDirection?: DirectionModel;
|
||||||
|
skip?: number;
|
||||||
|
take?: number;
|
||||||
|
}) {
|
||||||
|
await this.#init;
|
||||||
|
return this.#dataSource.getAuditLogById({ id, orderDirection, skip, take });
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAuditLogTypeByLogType({
|
||||||
|
logType,
|
||||||
|
sinceDate,
|
||||||
|
skip,
|
||||||
|
take,
|
||||||
|
}: {
|
||||||
|
logType: AuditTypeModel;
|
||||||
|
sinceDate?: string;
|
||||||
|
skip?: number;
|
||||||
|
take?: number;
|
||||||
|
}) {
|
||||||
|
await this.#init;
|
||||||
|
return this.#dataSource.getAuditLogTypeByLogType({ logType, sinceDate, skip, take });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import { AuditLogResource, DirectionModel, AuditTypeModel } 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 Data Type items that fetches data from the server
|
||||||
|
* @export
|
||||||
|
* @class UmbAuditLogServerDataSource
|
||||||
|
*/
|
||||||
|
export class UmbAuditLogServerDataSource {
|
||||||
|
#host: UmbControllerHost;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of UmbAuditLogServerDataSource.
|
||||||
|
* @param {UmbControllerHost} host
|
||||||
|
* @memberof UmbAuditLogServerDataSource
|
||||||
|
*/
|
||||||
|
constructor(host: UmbControllerHost) {
|
||||||
|
this.#host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the items for the given ids from the server
|
||||||
|
* @param {Array<string>} ids
|
||||||
|
* @return {*}
|
||||||
|
* @memberof UmbAuditLogServerDataSource
|
||||||
|
*/
|
||||||
|
async getAuditLog({
|
||||||
|
orderDirection,
|
||||||
|
sinceDate,
|
||||||
|
skip,
|
||||||
|
take,
|
||||||
|
}: {
|
||||||
|
orderDirection?: DirectionModel;
|
||||||
|
sinceDate?: string;
|
||||||
|
skip?: number;
|
||||||
|
take?: number;
|
||||||
|
}) {
|
||||||
|
return await tryExecuteAndNotify(
|
||||||
|
this.#host,
|
||||||
|
AuditLogResource.getAuditLog({ orderDirection, sinceDate, skip, take }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAuditLogById({
|
||||||
|
id,
|
||||||
|
orderDirection,
|
||||||
|
sinceDate,
|
||||||
|
skip,
|
||||||
|
take,
|
||||||
|
}: {
|
||||||
|
id: string;
|
||||||
|
orderDirection?: DirectionModel;
|
||||||
|
sinceDate?: string;
|
||||||
|
skip?: number;
|
||||||
|
take?: number;
|
||||||
|
}) {
|
||||||
|
return await tryExecuteAndNotify(
|
||||||
|
this.#host,
|
||||||
|
AuditLogResource.getAuditLogById({ id, orderDirection, sinceDate, skip, take }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAuditLogTypeByLogType({
|
||||||
|
logType,
|
||||||
|
sinceDate,
|
||||||
|
skip,
|
||||||
|
take,
|
||||||
|
}: {
|
||||||
|
logType: AuditTypeModel;
|
||||||
|
sinceDate?: string;
|
||||||
|
skip?: number;
|
||||||
|
take?: number;
|
||||||
|
}) {
|
||||||
|
return await tryExecuteAndNotify(
|
||||||
|
this.#host,
|
||||||
|
AuditLogResource.getAuditLogTypeByLogType({ logType, sinceDate, skip, take }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export { UMB_AUDIT_LOG_REPOSITORY_ALIAS as AUDIT_LOG_REPOSITORY_ALIAS } from './manifests.js';
|
||||||
|
export { UmbAuditLogRepository } from './audit-log.repository.js';
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { UmbAuditLogRepository } from './audit-log.repository.js';
|
||||||
|
import type { ManifestRepository } from '@umbraco-cms/backoffice/extension-registry';
|
||||||
|
|
||||||
|
export const UMB_AUDIT_LOG_REPOSITORY_ALIAS = 'Umb.Repository.AuditLog';
|
||||||
|
|
||||||
|
const repository: ManifestRepository = {
|
||||||
|
type: 'repository',
|
||||||
|
alias: UMB_AUDIT_LOG_REPOSITORY_ALIAS,
|
||||||
|
name: 'AuditLog Repository',
|
||||||
|
api: UmbAuditLogRepository,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const manifests = [repository];
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
export const name = 'Umbraco.Core.AuditLog';
|
||||||
|
export const extensions = [
|
||||||
|
{
|
||||||
|
name: 'Audit Log Bundle',
|
||||||
|
alias: 'Umb.Bundle.AuditLog',
|
||||||
|
type: 'bundle',
|
||||||
|
js: () => import('./manifests.js'),
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
|
import { UMB_APP_CONTEXT } from '@umbraco-cms/backoffice/app';
|
||||||
|
import { css, html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
|
||||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||||
|
|
||||||
@@ -13,20 +14,30 @@ export class UmbHistoryItemElement extends UmbLitElement {
|
|||||||
@property({ type: String })
|
@property({ type: String })
|
||||||
detail?: string;
|
detail?: string;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private _serverUrl?: string;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.consumeContext(UMB_APP_CONTEXT, (instance) => {
|
||||||
|
this._serverUrl = instance.getServerUrl();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`<div id="wrapper">
|
return html`
|
||||||
<div class="user-info">
|
<div class="user-info">
|
||||||
<uui-avatar .name="${this.name ?? 'Unknown'}" ?src="${this.src}"></uui-avatar>
|
<uui-avatar
|
||||||
|
.name="${this.name ?? 'Unknown'}"
|
||||||
|
.imgSrc="${this.src ? this._serverUrl + this.src : ''}"></uui-avatar>
|
||||||
<div>
|
<div>
|
||||||
<span class="name">${this.name}</span>
|
<span class="name">${this.name}</span>
|
||||||
<span class="detail">${this.detail}</span>
|
<span class="detail">${this.detail}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="slots-wrapper">
|
<slot id="description"></slot>
|
||||||
<slot id="description"></slot>
|
<slot id="actions-container" name="actions"></slot>
|
||||||
<slot id="actions-container" name="actions"></slot>
|
`;
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static styles = [
|
static styles = [
|
||||||
@@ -34,20 +45,7 @@ export class UmbHistoryItemElement extends UmbLitElement {
|
|||||||
css`
|
css`
|
||||||
:host {
|
:host {
|
||||||
--avatar-size: calc(2em + 4px);
|
--avatar-size: calc(2em + 4px);
|
||||||
display: block;
|
display: contents;
|
||||||
}
|
|
||||||
|
|
||||||
#wrapper {
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
gap: calc(2 * var(--uui-size-space-5));
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.slots-wrapper {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
flex: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
slot[name='actions'] {
|
slot[name='actions'] {
|
||||||
@@ -70,14 +68,17 @@ export class UmbHistoryItemElement extends UmbLitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.user-info {
|
.user-info {
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
gap: var(--uui-size-space-5);
|
gap: var(--uui-size-space-5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-info div {
|
.user-info div {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail {
|
.detail {
|
||||||
font-size: var(--uui-size-4);
|
font-size: var(--uui-size-4);
|
||||||
color: var(--uui-color-text-alt);
|
color: var(--uui-color-text-alt);
|
||||||
|
|||||||
@@ -5,19 +5,24 @@ import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
|||||||
@customElement('umb-history-list')
|
@customElement('umb-history-list')
|
||||||
export class UmbHistoryListElement extends UmbLitElement {
|
export class UmbHistoryListElement extends UmbLitElement {
|
||||||
render() {
|
render() {
|
||||||
return html`<div>
|
return html`<slot></slot> `;
|
||||||
<slot></slot>
|
|
||||||
</div>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static styles = [
|
static styles = [
|
||||||
UmbTextStyles,
|
UmbTextStyles,
|
||||||
css`
|
css`
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr auto;
|
||||||
|
align-items: center;
|
||||||
--avatar-size: calc(2em + 4px);
|
--avatar-size: calc(2em + 4px);
|
||||||
|
gap: var(--uui-size-6);
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** TODO: This doesn't work due to "display:contents" in umb-history-item, but is needed for the way I put the grid together.
|
||||||
|
* Find a different solution so we can have the grey line that links each history item together (this is purely a visual effect, no rush)
|
||||||
|
|
||||||
::slotted(*) {
|
::slotted(*) {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
@@ -25,7 +30,6 @@ export class UmbHistoryListElement extends UmbLitElement {
|
|||||||
::slotted(*:not(:last-child)) {
|
::slotted(*:not(:last-child)) {
|
||||||
margin-bottom: calc(2 * var(--uui-size-space-3));
|
margin-bottom: calc(2 * var(--uui-size-space-3));
|
||||||
}
|
}
|
||||||
|
|
||||||
::slotted(*:not(:last-child))::before {
|
::slotted(*:not(:last-child))::before {
|
||||||
content: '';
|
content: '';
|
||||||
border: 1px solid var(--uui-color-border);
|
border: 1px solid var(--uui-color-border);
|
||||||
@@ -35,6 +39,7 @@ export class UmbHistoryListElement extends UmbLitElement {
|
|||||||
top: var(--avatar-size);
|
top: var(--avatar-size);
|
||||||
left: calc(-1px + var(--avatar-size) / 2);
|
left: calc(-1px + var(--avatar-size) / 2);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export * from './input-number-range/index.js';
|
|||||||
export * from './input-radio-button-list/index.js';
|
export * from './input-radio-button-list/index.js';
|
||||||
export * from './input-section/index.js';
|
export * from './input-section/index.js';
|
||||||
export * from './input-slider/index.js';
|
export * from './input-slider/index.js';
|
||||||
export * from './input-start-node/index.js';
|
export * from './input-tree-picker-source/index.js';
|
||||||
export * from './input-tiny-mce/index.js';
|
export * from './input-tiny-mce/index.js';
|
||||||
export * from './input-toggle/index.js';
|
export * from './input-toggle/index.js';
|
||||||
export * from './input-upload-field/index.js';
|
export * from './input-upload-field/index.js';
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export * from './input-start-node.element.js';
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
import { UmbInputDocumentElement } from '@umbraco-cms/backoffice/document';
|
|
||||||
import { html, customElement, property, css, state } from '@umbraco-cms/backoffice/external/lit';
|
|
||||||
import { FormControlMixin, UUISelectEvent } from '@umbraco-cms/backoffice/external/uui';
|
|
||||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
|
||||||
import { UmbInputMediaElement } from '@umbraco-cms/backoffice/media';
|
|
||||||
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
|
||||||
|
|
||||||
export type ContentType = 'content' | 'member' | 'media';
|
|
||||||
|
|
||||||
export type StartNode = {
|
|
||||||
type?: ContentType;
|
|
||||||
id?: string | null;
|
|
||||||
query?: string | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
@customElement('umb-input-start-node')
|
|
||||||
export class UmbInputStartNodeElement extends FormControlMixin(UmbLitElement) {
|
|
||||||
protected getFormElement() {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _type: StartNode['type'] = 'content';
|
|
||||||
@property()
|
|
||||||
public set type(value: StartNode['type']) {
|
|
||||||
const oldValue = this._type;
|
|
||||||
|
|
||||||
this._options = this._options.map((option) =>
|
|
||||||
option.value === value ? { ...option, selected: true } : { ...option, selected: false },
|
|
||||||
);
|
|
||||||
this._type = value;
|
|
||||||
this.requestUpdate('type', oldValue);
|
|
||||||
}
|
|
||||||
public get type(): StartNode['type'] {
|
|
||||||
return this._type;
|
|
||||||
}
|
|
||||||
|
|
||||||
@property({ attribute: 'node-id' })
|
|
||||||
nodeId = '';
|
|
||||||
|
|
||||||
@property({ attribute: 'dynamic-path' })
|
|
||||||
dynamicPath = '';
|
|
||||||
|
|
||||||
@state()
|
|
||||||
_options: Array<Option> = [
|
|
||||||
{ value: 'content', name: 'Content' },
|
|
||||||
{ value: 'member', name: 'Members' },
|
|
||||||
{ value: 'media', name: 'Media' },
|
|
||||||
];
|
|
||||||
|
|
||||||
#onTypeChange(event: UUISelectEvent) {
|
|
||||||
this.type = event.target.value as StartNode['type'];
|
|
||||||
|
|
||||||
// Clear others
|
|
||||||
this.nodeId = '';
|
|
||||||
this.dynamicPath = '';
|
|
||||||
this.dispatchEvent(new UmbChangeEvent());
|
|
||||||
}
|
|
||||||
|
|
||||||
#onIdChange(event: CustomEvent) {
|
|
||||||
this.nodeId = (event.target as UmbInputDocumentElement | UmbInputMediaElement).selectedIds.join('');
|
|
||||||
this.dispatchEvent(new CustomEvent('change'));
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return html`<umb-input-dropdown-list
|
|
||||||
.options=${this._options}
|
|
||||||
@change="${this.#onTypeChange}"></umb-input-dropdown-list>
|
|
||||||
${this.#renderType()}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
#renderType() {
|
|
||||||
switch (this.type) {
|
|
||||||
case 'content':
|
|
||||||
return this.#renderTypeContent();
|
|
||||||
case 'media':
|
|
||||||
return this.#renderTypeMedia();
|
|
||||||
case 'member':
|
|
||||||
return this.#renderTypeMember();
|
|
||||||
default:
|
|
||||||
return 'No type found';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#renderTypeContent() {
|
|
||||||
const nodeId = this.nodeId ? [this.nodeId] : [];
|
|
||||||
//TODO: Dynamic paths
|
|
||||||
return html` <umb-input-document @change=${this.#onIdChange} .selectedIds=${nodeId} max="1"></umb-input-document> `;
|
|
||||||
}
|
|
||||||
|
|
||||||
#renderTypeMedia() {
|
|
||||||
const nodeId = this.nodeId ? [this.nodeId] : [];
|
|
||||||
//TODO => MediaTypes
|
|
||||||
return html` <umb-input-media @change=${this.#onIdChange} .selectedIds=${nodeId} max="1"></umb-input-media> `;
|
|
||||||
}
|
|
||||||
|
|
||||||
#renderTypeMember() {
|
|
||||||
const nodeId = this.nodeId ? [this.nodeId] : [];
|
|
||||||
//TODO => Members
|
|
||||||
return html` <umb-input-member @change=${this.#onIdChange} .selectedIds=${nodeId} max="1"></umb-input-member> `;
|
|
||||||
}
|
|
||||||
|
|
||||||
static styles = [
|
|
||||||
css`
|
|
||||||
:host {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: var(--uui-size-4);
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
export default UmbInputStartNodeElement;
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
'umb-input-start-node': UmbInputStartNodeElement;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './input-tree-picker-source.element.js';
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
import { UmbInputDocumentPickerRootElement } from '@umbraco-cms/backoffice/document';
|
||||||
|
import { html, customElement, property, css, state } from '@umbraco-cms/backoffice/external/lit';
|
||||||
|
import { FormControlMixin, UUISelectEvent } from '@umbraco-cms/backoffice/external/uui';
|
||||||
|
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||||
|
import { UmbInputMediaElement } from '@umbraco-cms/backoffice/media';
|
||||||
|
//import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||||
|
|
||||||
|
export type UmbTreePickerSource = {
|
||||||
|
type?: UmbTreePickerSourceType;
|
||||||
|
id?: string | null;
|
||||||
|
dynamicRoot?: UmbTreePickerDynamicRoot | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UmbTreePickerSourceType = 'content' | 'member' | 'media';
|
||||||
|
|
||||||
|
export type UmbTreePickerDynamicRoot = {
|
||||||
|
originAlias: string;
|
||||||
|
querySteps?: Array<UmbTreePickerDynamicRootQueryStep> | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UmbTreePickerDynamicRootQueryStep = {
|
||||||
|
alias: string;
|
||||||
|
anyOfDocTypeKeys: Array<string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
@customElement('umb-input-tree-picker-source')
|
||||||
|
export class UmbInputTreePickerSourceElement extends FormControlMixin(UmbLitElement) {
|
||||||
|
protected getFormElement() {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _type: UmbTreePickerSource['type'] = 'content';
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public set type(value: UmbTreePickerSource['type']) {
|
||||||
|
if (value === undefined) {
|
||||||
|
value = this._type;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldValue = this._type;
|
||||||
|
|
||||||
|
this._options = this._options.map((option) =>
|
||||||
|
option.value === value ? { ...option, selected: true } : { ...option, selected: false },
|
||||||
|
);
|
||||||
|
|
||||||
|
this._type = value;
|
||||||
|
|
||||||
|
this.requestUpdate('type', oldValue);
|
||||||
|
}
|
||||||
|
public get type(): UmbTreePickerSource['type'] {
|
||||||
|
return this._type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property({ attribute: 'node-id' })
|
||||||
|
nodeId?: string | null;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
dynamicRoot?: UmbTreePickerDynamicRoot | null;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
_options: Array<Option> = [
|
||||||
|
{ value: 'content', name: 'Content' },
|
||||||
|
{ value: 'media', name: 'Media' },
|
||||||
|
{ value: 'member', name: 'Members' },
|
||||||
|
];
|
||||||
|
|
||||||
|
#onTypeChange(event: UUISelectEvent) {
|
||||||
|
//console.log('onTypeChange');
|
||||||
|
|
||||||
|
this.type = event.target.value as UmbTreePickerSource['type'];
|
||||||
|
|
||||||
|
this.nodeId = '';
|
||||||
|
|
||||||
|
// TODO: Appears that the event gets bubbled up. Will need to review. [LK]
|
||||||
|
//this.dispatchEvent(new UmbChangeEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
#onIdChange(event: CustomEvent) {
|
||||||
|
//console.log('onIdChange', event.target);
|
||||||
|
switch (this.type) {
|
||||||
|
case 'content':
|
||||||
|
this.nodeId = (<UmbInputDocumentPickerRootElement>event.target).nodeId;
|
||||||
|
break;
|
||||||
|
case 'media':
|
||||||
|
this.nodeId = (<UmbInputMediaElement>event.target).selectedIds.join('');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dispatchEvent(new CustomEvent(event.type));
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`<umb-input-dropdown-list
|
||||||
|
.options=${this._options}
|
||||||
|
@change="${this.#onTypeChange}"></umb-input-dropdown-list>
|
||||||
|
${this.#renderType()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
#renderType() {
|
||||||
|
switch (this.type) {
|
||||||
|
case 'content':
|
||||||
|
return this.#renderTypeContent();
|
||||||
|
case 'media':
|
||||||
|
return this.#renderTypeMedia();
|
||||||
|
case 'member':
|
||||||
|
return this.#renderTypeMember();
|
||||||
|
default:
|
||||||
|
return 'No type found';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#renderTypeContent() {
|
||||||
|
return html`<umb-input-document-picker-root
|
||||||
|
@change=${this.#onIdChange}
|
||||||
|
.nodeId=${this.nodeId}></umb-input-document-picker-root>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
#renderTypeMedia() {
|
||||||
|
const nodeId = this.nodeId ? [this.nodeId] : [];
|
||||||
|
//TODO => MediaTypes
|
||||||
|
return html`<umb-input-media @change=${this.#onIdChange} .selectedIds=${nodeId} max="1"></umb-input-media>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
#renderTypeMember() {
|
||||||
|
const nodeId = this.nodeId ? [this.nodeId] : [];
|
||||||
|
//TODO => Members
|
||||||
|
return html`<umb-input-member @change=${this.#onIdChange} .selectedIds=${nodeId} max="1"></umb-input-member>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = [
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--uui-size-4);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UmbInputTreePickerSourceElement;
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'umb-input-tree-picker-source': UmbInputTreePickerSourceElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -155,7 +155,11 @@ export class UmbTableElement extends LitElement {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`<uui-table class="uui-text">
|
return html`<uui-table class="uui-text">
|
||||||
<uui-table-column style="width: 60px;"></uui-table-column>
|
<uui-table-column
|
||||||
|
.style=${when(
|
||||||
|
!(this.config.allowSelection === false && this.config.hideIcon === true),
|
||||||
|
() => 'width: 60px',
|
||||||
|
)}></uui-table-column>
|
||||||
<uui-table-head>
|
<uui-table-head>
|
||||||
${this._renderHeaderCheckboxCell()} ${this.columns.map((column) => this._renderHeaderCell(column))}
|
${this._renderHeaderCheckboxCell()} ${this.columns.map((column) => this._renderHeaderCell(column))}
|
||||||
</uui-table-head>
|
</uui-table-head>
|
||||||
|
|||||||
@@ -101,3 +101,14 @@ export const WithHiddenIcons: Story = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const WithHiddenIconsAndDisallowedSelections: Story = {
|
||||||
|
args: {
|
||||||
|
items: items,
|
||||||
|
columns: columns,
|
||||||
|
config: {
|
||||||
|
allowSelection: false,
|
||||||
|
hideIcon: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ export * from './variant/index.js';
|
|||||||
export * from './workspace/index.js';
|
export * from './workspace/index.js';
|
||||||
export * from './culture/index.js';
|
export * from './culture/index.js';
|
||||||
export * from './temporary-file/index.js';
|
export * from './temporary-file/index.js';
|
||||||
|
export * from './object-type/index.js';
|
||||||
|
|
||||||
const manifests: Array<ManifestTypes | UmbBackofficeManifestKind> = [
|
const manifests: Array<ManifestTypes | UmbBackofficeManifestKind> = [
|
||||||
...conditionManifests,
|
...conditionManifests,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { UmbTreeElement } from '../../../tree/tree.element.js';
|
import { UmbTreeElement, type UmbTreeSelectionConfiguration } from '@umbraco-cms/backoffice/tree';
|
||||||
import { css, html, nothing, customElement, query, state, styleMap } from '@umbraco-cms/backoffice/external/lit';
|
import { css, html, nothing, customElement, query, state, styleMap } from '@umbraco-cms/backoffice/external/lit';
|
||||||
import { UUIBooleanInputEvent, UUIInputElement } from '@umbraco-cms/backoffice/external/uui';
|
import { UUIBooleanInputEvent, UUIInputElement } from '@umbraco-cms/backoffice/external/uui';
|
||||||
import {
|
import {
|
||||||
@@ -13,6 +13,13 @@ import { UMB_DOCUMENT_TREE_ALIAS } from '@umbraco-cms/backoffice/document';
|
|||||||
|
|
||||||
@customElement('umb-link-picker-modal')
|
@customElement('umb-link-picker-modal')
|
||||||
export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPickerModalData, UmbLinkPickerModalValue> {
|
export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPickerModalData, UmbLinkPickerModalValue> {
|
||||||
|
@state()
|
||||||
|
private _selectionConfiguration: UmbTreeSelectionConfiguration = {
|
||||||
|
multiple: false,
|
||||||
|
selectable: true,
|
||||||
|
selection: [],
|
||||||
|
};
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
_selectedKey?: string;
|
_selectedKey?: string;
|
||||||
|
|
||||||
@@ -51,6 +58,7 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
|||||||
this.observe(this.modalContext.value, (value) => {
|
this.observe(this.modalContext.value, (value) => {
|
||||||
(this._link as any) = value.link;
|
(this._link as any) = value.link;
|
||||||
this._selectedKey = this._link?.udi ? getKeyFromUdi(this._link.udi) : undefined;
|
this._selectedKey = this._link?.udi ? getKeyFromUdi(this._link.udi) : undefined;
|
||||||
|
this._selectionConfiguration.selection = this._selectedKey ? [this._selectedKey] : [];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this._layout = this.data?.config;
|
this._layout = this.data?.config;
|
||||||
@@ -76,11 +84,13 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
|||||||
//TODO: Update icon, published, trashed
|
//TODO: Update icon, published, trashed
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const element = e.target as UmbTreeElement;
|
const element = e.target as UmbTreeElement;
|
||||||
const selectedKey = element.selection[element.selection.length - 1];
|
const selection = element.getSelection();
|
||||||
|
const selectedKey = selection[selection.length - 1];
|
||||||
|
|
||||||
if (!selectedKey) {
|
if (!selectedKey) {
|
||||||
this.#partialUpdateLink({ udi: '', url: undefined });
|
this.#partialUpdateLink({ udi: '', url: undefined });
|
||||||
this._selectedKey = undefined;
|
this._selectedKey = undefined;
|
||||||
|
this._selectionConfiguration.selection = [];
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -88,6 +98,7 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
|||||||
const udi = buildUdi(entityType, selectedKey);
|
const udi = buildUdi(entityType, selectedKey);
|
||||||
|
|
||||||
this._selectedKey = selectedKey;
|
this._selectedKey = selectedKey;
|
||||||
|
this._selectionConfiguration.selection = [this._selectedKey];
|
||||||
this.#partialUpdateLink({ udi: udi, url: udi });
|
this.#partialUpdateLink({ udi: udi, url: udi });
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
@@ -177,11 +188,9 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
|||||||
label=${this.localize.term('placeholders_search')}></uui-input>
|
label=${this.localize.term('placeholders_search')}></uui-input>
|
||||||
<umb-tree
|
<umb-tree
|
||||||
?hide-tree-root=${true}
|
?hide-tree-root=${true}
|
||||||
?multiple=${false}
|
|
||||||
alias=${UMB_DOCUMENT_TREE_ALIAS}
|
alias=${UMB_DOCUMENT_TREE_ALIAS}
|
||||||
@selection-change=${(event: CustomEvent) => this.#handleSelectionChange(event, 'document')}
|
@selection-change=${(event: CustomEvent) => this.#handleSelectionChange(event, 'document')}
|
||||||
.selection=${[this._selectedKey ?? '']}
|
.selectionConfiguration=${this._selectionConfiguration}></umb-tree>
|
||||||
selectable></umb-tree>
|
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
<uui-symbol-expand
|
<uui-symbol-expand
|
||||||
@@ -192,11 +201,9 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
|||||||
<div style="${styleMap({ display: !this.mediaExpanded ? 'block' : 'none' })}">
|
<div style="${styleMap({ display: !this.mediaExpanded ? 'block' : 'none' })}">
|
||||||
<umb-tree
|
<umb-tree
|
||||||
?hide-tree-root=${true}
|
?hide-tree-root=${true}
|
||||||
?multiple=${false}
|
|
||||||
alias="Umb.Tree.Media"
|
alias="Umb.Tree.Media"
|
||||||
@selection-change=${(event: CustomEvent) => this.#handleSelectionChange(event, 'media')}
|
@selection-change=${(event: CustomEvent) => this.#handleSelectionChange(event, 'media')}
|
||||||
.selection=${[this._selectedKey ?? '']}
|
.selectionConfiguration=${this._selectionConfiguration}></umb-tree>
|
||||||
selectable></umb-tree>
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { type UmbTreeElement } from '../../../tree/tree.element.js';
|
|
||||||
import { html, customElement, state, ifDefined } from '@umbraco-cms/backoffice/external/lit';
|
import { html, customElement, state, ifDefined } from '@umbraco-cms/backoffice/external/lit';
|
||||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||||
import { UmbTreePickerModalData, UmbPickerModalValue, UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
|
import { UmbTreePickerModalData, UmbPickerModalValue, UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
|
||||||
import { UmbSelectionChangeEvent } from '@umbraco-cms/backoffice/event';
|
import { UmbSelectionChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||||
import { UmbTreeItemModelBase } from '@umbraco-cms/backoffice/tree';
|
import { UmbTreeElement, UmbTreeItemModelBase, type UmbTreeSelectionConfiguration } from '@umbraco-cms/backoffice/tree';
|
||||||
|
|
||||||
@customElement('umb-tree-picker-modal')
|
@customElement('umb-tree-picker-modal')
|
||||||
export class UmbTreePickerModalElement<TreeItemType extends UmbTreeItemModelBase> extends UmbModalBaseElement<
|
export class UmbTreePickerModalElement<TreeItemType extends UmbTreeItemModelBase> extends UmbModalBaseElement<
|
||||||
@@ -11,10 +10,11 @@ export class UmbTreePickerModalElement<TreeItemType extends UmbTreeItemModelBase
|
|||||||
UmbPickerModalValue
|
UmbPickerModalValue
|
||||||
> {
|
> {
|
||||||
@state()
|
@state()
|
||||||
_selection: Array<string | null> = [];
|
_selectionConfiguration: UmbTreeSelectionConfiguration = {
|
||||||
|
multiple: false,
|
||||||
@state()
|
selectable: true,
|
||||||
_multiple = false;
|
selection: [],
|
||||||
|
};
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
@@ -22,17 +22,17 @@ export class UmbTreePickerModalElement<TreeItemType extends UmbTreeItemModelBase
|
|||||||
// TODO: We should make a nicer way to observe the value..
|
// TODO: We should make a nicer way to observe the value..
|
||||||
if (this.modalContext) {
|
if (this.modalContext) {
|
||||||
this.observe(this.modalContext.value, (value) => {
|
this.observe(this.modalContext.value, (value) => {
|
||||||
this._selection = value?.selection ?? [];
|
this._selectionConfiguration.selection = value?.selection ?? [];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this._multiple = this.data?.multiple ?? false;
|
this._selectionConfiguration.multiple = this.data?.multiple ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#onSelectionChange(e: CustomEvent) {
|
#onSelectionChange(e: CustomEvent) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const element = e.target as UmbTreeElement;
|
const element = e.target as UmbTreeElement;
|
||||||
this.value = { selection: element.selection };
|
this.value = { selection: element.getSelection() };
|
||||||
this.dispatchEvent(new UmbSelectionChangeEvent());
|
this.dispatchEvent(new UmbSelectionChangeEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,15 +44,13 @@ export class UmbTreePickerModalElement<TreeItemType extends UmbTreeItemModelBase
|
|||||||
?hide-tree-root=${this.data?.hideTreeRoot}
|
?hide-tree-root=${this.data?.hideTreeRoot}
|
||||||
alias=${ifDefined(this.data?.treeAlias)}
|
alias=${ifDefined(this.data?.treeAlias)}
|
||||||
@selection-change=${this.#onSelectionChange}
|
@selection-change=${this.#onSelectionChange}
|
||||||
.selection=${this._selection}
|
.selectionConfiguration=${this._selectionConfiguration}
|
||||||
selectable
|
|
||||||
.filter=${this.data?.filter}
|
.filter=${this.data?.filter}
|
||||||
.selectableFilter=${this.data?.pickableFilter}
|
.selectableFilter=${this.data?.pickableFilter}></umb-tree>
|
||||||
?multiple=${this._multiple}></umb-tree>
|
|
||||||
</uui-box>
|
</uui-box>
|
||||||
<div slot="actions">
|
<div slot="actions">
|
||||||
<uui-button label="Close" @click=${this._rejectModal}></uui-button>
|
<uui-button label=${this.localize.term('general_close')} @click=${this._rejectModal}></uui-button>
|
||||||
<uui-button label="Submit" look="primary" color="positive" @click=${this._submitModal}></uui-button>
|
<uui-button label=${this.localize.term('general_choose')} look="primary" color="positive" @click=${this._submitModal}></uui-button>
|
||||||
</div>
|
</div>
|
||||||
</umb-body-layout>
|
</umb-body-layout>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { UmbModalToken, UmbPickerModalValue, UmbTreePickerModalData } from '@umbraco-cms/backoffice/modal';
|
||||||
|
import { UmbEntityTreeItemModel } from '@umbraco-cms/backoffice/tree';
|
||||||
|
|
||||||
|
export type UmbMemberTypePickerModalData = UmbTreePickerModalData<UmbEntityTreeItemModel>;
|
||||||
|
export type UmbMemberTypePickerModalValue = UmbPickerModalValue;
|
||||||
|
|
||||||
|
export const UMB_MEMBER_TYPE_PICKER_MODAL = new UmbModalToken<UmbMemberTypePickerModalData, UmbMemberTypePickerModalValue>(
|
||||||
|
'Umb.Modal.TreePicker',
|
||||||
|
{
|
||||||
|
modal: {
|
||||||
|
type: 'sidebar',
|
||||||
|
size: 'small',
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
treeAlias: 'Umb.Tree.MemberType',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './object-type.repository.js';
|
||||||
|
export * from './input-object-type.element.js';
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import { UmbObjectTypeRepository } from './object-type.repository.js';
|
||||||
|
import { html, customElement, property, query, state } from '@umbraco-cms/backoffice/external/lit';
|
||||||
|
import { FormControlMixin, UUISelectElement } from '@umbraco-cms/backoffice/external/uui';
|
||||||
|
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||||
|
|
||||||
|
@customElement('umb-input-object-type')
|
||||||
|
export class UmbInputObjectTypeElement extends FormControlMixin(UmbLitElement) {
|
||||||
|
@query('uui-select')
|
||||||
|
private select!: UUISelectElement;
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public set value(value: UUISelectElement['value']) {
|
||||||
|
this.select.value = value;
|
||||||
|
}
|
||||||
|
public get value(): UUISelectElement['value'] {
|
||||||
|
return this.select.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private _options: UUISelectElement['options'] = [];
|
||||||
|
|
||||||
|
#repository: UmbObjectTypeRepository;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.#repository = new UmbObjectTypeRepository(this);
|
||||||
|
|
||||||
|
this.#repository.read().then(({ data, error }) => {
|
||||||
|
if (!data) return;
|
||||||
|
|
||||||
|
this._options = data.items.map((item) => ({ value: item.id, name: item.name ?? '' }));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getFormElement() {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
#onChange() {
|
||||||
|
this.dispatchEvent(new CustomEvent('change'));
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`<uui-select .options=${this._options} @change=${this.#onChange}></uui-select> `;
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UmbInputObjectTypeElement;
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'umb-input-object-type': UmbInputObjectTypeElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { ObjectTypesResource } from '@umbraco-cms/backoffice/backend-api';
|
||||||
|
import { UmbBaseController } from '@umbraco-cms/backoffice/class-api';
|
||||||
|
import { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||||
|
import { UmbApi } from '@umbraco-cms/backoffice/extension-api';
|
||||||
|
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
|
||||||
|
|
||||||
|
export class UmbObjectTypeRepository extends UmbBaseController implements UmbApi {
|
||||||
|
#host: UmbControllerHost;
|
||||||
|
|
||||||
|
constructor(host: UmbControllerHost) {
|
||||||
|
super(host);
|
||||||
|
|
||||||
|
this.#host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
async #read() {
|
||||||
|
return tryExecuteAndNotify(this.#host, ObjectTypesResource.getObjectTypes({}));
|
||||||
|
}
|
||||||
|
|
||||||
|
async read() {
|
||||||
|
const { data, error } = await this.#read();
|
||||||
|
|
||||||
|
return { data, error };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ import type { ManifestPropertyEditorSchema } from '@umbraco-cms/backoffice/exten
|
|||||||
|
|
||||||
export const manifest: ManifestPropertyEditorSchema = {
|
export const manifest: ManifestPropertyEditorSchema = {
|
||||||
type: 'propertyEditorSchema',
|
type: 'propertyEditorSchema',
|
||||||
name: 'Decimal',
|
name: 'Integer',
|
||||||
alias: 'Umbraco.Integer',
|
alias: 'Umbraco.Integer',
|
||||||
meta: {
|
meta: {
|
||||||
defaultPropertyEditorUiAlias: 'Umb.PropertyEditorUi.Integer',
|
defaultPropertyEditorUiAlias: 'Umb.PropertyEditorUi.Integer',
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/
|
|||||||
|
|
||||||
@customElement('umb-property-editor-ui-number')
|
@customElement('umb-property-editor-ui-number')
|
||||||
export class UmbPropertyEditorUINumberElement extends UmbLitElement implements UmbPropertyEditorUiElement {
|
export class UmbPropertyEditorUINumberElement extends UmbLitElement implements UmbPropertyEditorUiElement {
|
||||||
@property()
|
@property({ type: Number })
|
||||||
value = '';
|
value: undefined | number = undefined;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
private _max?: number;
|
private _max?: number;
|
||||||
@@ -26,7 +26,7 @@ export class UmbPropertyEditorUINumberElement extends UmbLitElement implements U
|
|||||||
}
|
}
|
||||||
|
|
||||||
private onInput(e: InputEvent) {
|
private onInput(e: InputEvent) {
|
||||||
this.value = (e.target as HTMLInputElement).value;
|
this.value = Number((e.target as HTMLInputElement).value);
|
||||||
this.dispatchEvent(new CustomEvent('property-value-change'));
|
this.dispatchEvent(new CustomEvent('property-value-change'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ import type { ManifestPropertyEditorUi } from '@umbraco-cms/backoffice/extension
|
|||||||
|
|
||||||
export const manifest: ManifestPropertyEditorUi = {
|
export const manifest: ManifestPropertyEditorUi = {
|
||||||
type: 'propertyEditorUi',
|
type: 'propertyEditorUi',
|
||||||
alias: 'Umb.PropertyEditorUi.TreePicker.StartNode',
|
alias: 'Umb.PropertyEditorUi.TreePicker.SourcePicker',
|
||||||
name: 'Tree Picker Start Node Property Editor UI',
|
name: 'Tree Picker Source Picker Property Editor UI',
|
||||||
js: () => import('./property-editor-ui-tree-picker-start-node.element.js'),
|
js: () => import('./property-editor-ui-tree-picker-source-picker.element.js'),
|
||||||
meta: {
|
meta: {
|
||||||
label: 'Tree Picker Start Node',
|
label: 'Tree Picker Source Picker',
|
||||||
icon: 'icon-page-add',
|
icon: 'icon-page-add',
|
||||||
group: 'pickers',
|
group: 'pickers',
|
||||||
propertyEditorSchemaAlias: '',
|
propertyEditorSchemaAlias: '',
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { type UmbTreePickerSource, UmbInputTreePickerSourceElement } from '@umbraco-cms/backoffice/components';
|
||||||
|
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
|
||||||
|
import { html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
|
||||||
|
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
|
||||||
|
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||||
|
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @element umb-property-editor-ui-tree-picker-source-picker
|
||||||
|
*/
|
||||||
|
@customElement('umb-property-editor-ui-tree-picker-source-picker')
|
||||||
|
export class UmbPropertyEditorUITreePickerSourcePickerElement extends UmbLitElement implements UmbPropertyEditorUiElement {
|
||||||
|
@property({ type: Object })
|
||||||
|
value?: UmbTreePickerSource;
|
||||||
|
|
||||||
|
@property({ type: Object, attribute: false })
|
||||||
|
public config?: UmbPropertyEditorConfigCollection;
|
||||||
|
|
||||||
|
#onChange(event: CustomEvent) {
|
||||||
|
const target = event.target as UmbInputTreePickerSourceElement;
|
||||||
|
|
||||||
|
this.value = {
|
||||||
|
type: target.type,
|
||||||
|
id: target.nodeId,
|
||||||
|
dynamicRoot: target.dynamicRoot,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.dispatchEvent(new CustomEvent('property-value-change'));
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`<umb-input-tree-picker-source
|
||||||
|
@change=${this.#onChange}
|
||||||
|
.type=${this.value?.type}
|
||||||
|
.nodeId=${this.value?.id}></umb-input-tree-picker-source>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = [UmbTextStyles];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UmbPropertyEditorUITreePickerSourcePickerElement;
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'umb-property-editor-ui-tree-picker-source-picker': UmbPropertyEditorUITreePickerSourcePickerElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { Meta, Story } from '@storybook/web-components';
|
||||||
|
import type { UmbPropertyEditorUITreePickerSourcePickerElement } from './property-editor-ui-tree-picker-source-picker.element.js';
|
||||||
|
import { html } from '@umbraco-cms/backoffice/external/lit';
|
||||||
|
|
||||||
|
import './property-editor-ui-tree-picker-source-picker.element.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Property Editor UIs/Tree Picker Start Node',
|
||||||
|
component: 'umb-property-editor-ui-tree-picker-source-picker',
|
||||||
|
id: 'umb-property-editor-ui-tree-picker-source-pickere',
|
||||||
|
} as Meta;
|
||||||
|
|
||||||
|
export const AAAOverview: Story<UmbPropertyEditorUITreePickerSourcePickerElement> = () =>
|
||||||
|
html`<umb-property-editor-ui-tree-picker-source-picker></umb-property-editor-ui-tree-picker-source-picker>`;
|
||||||
|
AAAOverview.storyName = 'Overview';
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
import { expect, fixture, html } from '@open-wc/testing';
|
import { expect, fixture, html } from '@open-wc/testing';
|
||||||
import { UmbPropertyEditorUITreePickerStartNodeElement } from './property-editor-ui-tree-picker-start-node.element.js';
|
import { UmbPropertyEditorUITreePickerSourcePickerElement } from './property-editor-ui-tree-picker-source-picker.element.js';
|
||||||
import { defaultA11yConfig } from '@umbraco-cms/internal/test-utils';
|
import { defaultA11yConfig } from '@umbraco-cms/internal/test-utils';
|
||||||
|
|
||||||
describe('UmbPropertyEditorUITreePickerStartNodeElement', () => {
|
describe('UmbPropertyEditorUITreePickerSourcePickerElement', () => {
|
||||||
let element: UmbPropertyEditorUITreePickerStartNodeElement;
|
let element: UmbPropertyEditorUITreePickerSourcePickerElement;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
element = await fixture(html`
|
element = await fixture(html`
|
||||||
<umb-property-editor-ui-tree-picker-start-node></umb-property-editor-ui-tree-picker-start-node>
|
<umb-property-editor-ui-tree-picker-source-picker></umb-property-editor-ui-tree-picker-source-picker>
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('is defined with its own instance', () => {
|
it('is defined with its own instance', () => {
|
||||||
expect(element).to.be.instanceOf(UmbPropertyEditorUITreePickerStartNodeElement);
|
expect(element).to.be.instanceOf(UmbPropertyEditorUITreePickerSourcePickerElement);
|
||||||
});
|
});
|
||||||
|
|
||||||
if ((window as any).__UMBRACO_TEST_RUN_A11Y_TEST) {
|
if ((window as any).__UMBRACO_TEST_RUN_A11Y_TEST) {
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import type { ManifestPropertyEditorUi } from '@umbraco-cms/backoffice/extension-registry';
|
||||||
|
|
||||||
|
export const manifest: ManifestPropertyEditorUi = {
|
||||||
|
type: 'propertyEditorUi',
|
||||||
|
alias: 'Umb.PropertyEditorUi.TreePicker.SourceTypePicker',
|
||||||
|
name: 'Tree Picker Source Type Picker Property Editor UI',
|
||||||
|
js: () => import('./property-editor-ui-tree-picker-source-type-picker.element.js'),
|
||||||
|
meta: {
|
||||||
|
label: 'Tree Picker Source Type Picker',
|
||||||
|
icon: 'icon-page-add',
|
||||||
|
group: 'pickers',
|
||||||
|
propertyEditorSchemaAlias: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
import { UmbDocumentTypeInputElement } from '@umbraco-cms/backoffice/document-type';
|
||||||
|
import { UmbMediaTypeInputElement } from '@umbraco-cms/backoffice/media-type';
|
||||||
|
import { UmbMemberTypeInputElement } from '@umbraco-cms/backoffice/member-type';
|
||||||
|
import type { UmbTreePickerSource } from '@umbraco-cms/backoffice/components';
|
||||||
|
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
|
||||||
|
import { customElement, html, property, state } from '@umbraco-cms/backoffice/external/lit';
|
||||||
|
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||||
|
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||||
|
import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @element umb-property-editor-ui-tree-picker-source-type-picker
|
||||||
|
*/
|
||||||
|
@customElement('umb-property-editor-ui-tree-picker-source-type-picker')
|
||||||
|
export class UmbPropertyEditorUITreePickerSourceTypePickerElement extends UmbLitElement implements UmbPropertyEditorUiElement {
|
||||||
|
#datasetContext?: typeof UMB_PROPERTY_DATASET_CONTEXT.TYPE;
|
||||||
|
|
||||||
|
@property({ type: Array })
|
||||||
|
value?: string[];
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private sourceType: string = 'content';
|
||||||
|
|
||||||
|
#initialized: boolean = false;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, (datasetContext) => {
|
||||||
|
this.#datasetContext = datasetContext;
|
||||||
|
this._observeProperty();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _observeProperty() {
|
||||||
|
if (!this.#datasetContext) return;
|
||||||
|
this.observe(
|
||||||
|
await this.#datasetContext.propertyValueByAlias('startNode'),
|
||||||
|
(value) => {
|
||||||
|
const startNode = value as UmbTreePickerSource;
|
||||||
|
if (startNode.type) {
|
||||||
|
// If we had a sourceType before, we can see this as a change and not the initial value,
|
||||||
|
// so let's reset the value, so we don't carry over content-types to the new source type.
|
||||||
|
if (this.#initialized && this.sourceType !== startNode.type) {
|
||||||
|
this.value = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sourceType = startNode.type;
|
||||||
|
|
||||||
|
if (!this.#initialized) {
|
||||||
|
this.#initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'observeValue',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#onChange(event: CustomEvent) {
|
||||||
|
switch (this.sourceType) {
|
||||||
|
case 'content':
|
||||||
|
this.value = (<UmbDocumentTypeInputElement>event.target).selectedIds;
|
||||||
|
break;
|
||||||
|
case 'media':
|
||||||
|
this.value = (<UmbMediaTypeInputElement>event.target).selectedIds;
|
||||||
|
break;
|
||||||
|
case 'member':
|
||||||
|
this.value = (<UmbMemberTypeInputElement>event.target).selectedIds;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dispatchEvent(new CustomEvent('property-value-change'));
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return this.#renderType();
|
||||||
|
}
|
||||||
|
|
||||||
|
#renderType() {
|
||||||
|
switch (this.sourceType) {
|
||||||
|
case 'content':
|
||||||
|
return this.#renderTypeContent();
|
||||||
|
case 'media':
|
||||||
|
return this.#renderTypeMedia();
|
||||||
|
case 'member':
|
||||||
|
return this.#renderTypeMember();
|
||||||
|
default:
|
||||||
|
return 'No source type found';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#renderTypeContent() {
|
||||||
|
return html`<umb-document-type-input
|
||||||
|
@change=${this.#onChange}
|
||||||
|
.selectedIds=${this.value || []}></umb-document-type-input>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
#renderTypeMedia() {
|
||||||
|
return html`<umb-media-type-input
|
||||||
|
@change=${this.#onChange}
|
||||||
|
.selectedIds=${this.value || []}></umb-media-type-input>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
#renderTypeMember() {
|
||||||
|
return html`<umb-input-member-type
|
||||||
|
@change=${this.#onChange}
|
||||||
|
.selectedIds=${this.value || []}></umb-input-member-type>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = [UmbTextStyles];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UmbPropertyEditorUITreePickerSourceTypePickerElement;
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'umb-property-editor-ui-tree-picker-source-type-picker': UmbPropertyEditorUITreePickerSourceTypePickerElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
import { StartNode, UmbInputStartNodeElement } from '@umbraco-cms/backoffice/components';
|
|
||||||
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
|
|
||||||
import { html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
|
|
||||||
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
|
|
||||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
|
||||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @element umb-property-editor-ui-tree-picker-start-node
|
|
||||||
*/
|
|
||||||
@customElement('umb-property-editor-ui-tree-picker-start-node')
|
|
||||||
export class UmbPropertyEditorUITreePickerStartNodeElement extends UmbLitElement implements UmbPropertyEditorUiElement {
|
|
||||||
@property({ type: Object })
|
|
||||||
value?: StartNode;
|
|
||||||
|
|
||||||
@property({ type: Object, attribute: false })
|
|
||||||
public config?: UmbPropertyEditorConfigCollection;
|
|
||||||
|
|
||||||
#onChange(event: CustomEvent) {
|
|
||||||
const target = event.target as UmbInputStartNodeElement;
|
|
||||||
|
|
||||||
this.value = {
|
|
||||||
type: target.type,
|
|
||||||
id: target.nodeId,
|
|
||||||
// TODO: Please check this makes sense, Check if we want to support XPath in this version, if not then make sure we handle DynamicRoot correct.
|
|
||||||
query: target.dynamicPath,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.dispatchEvent(new CustomEvent('property-value-change'));
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return html`<umb-input-start-node @change="${this.#onChange}" .type=${this.value?.type}></umb-input-start-node>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static styles = [UmbTextStyles];
|
|
||||||
}
|
|
||||||
|
|
||||||
export default UmbPropertyEditorUITreePickerStartNodeElement;
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
'umb-property-editor-ui-tree-picker-start-node': UmbPropertyEditorUITreePickerStartNodeElement;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import { Meta, Story } from '@storybook/web-components';
|
|
||||||
import type { UmbPropertyEditorUITreePickerStartNodeElement } from './property-editor-ui-tree-picker-start-node.element.js';
|
|
||||||
import { html } from '@umbraco-cms/backoffice/external/lit';
|
|
||||||
|
|
||||||
import './property-editor-ui-tree-picker-start-node.element.js';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
title: 'Property Editor UIs/Tree Picker Start Node',
|
|
||||||
component: 'umb-property-editor-ui-tree-picker-start-node',
|
|
||||||
id: 'umb-property-editor-ui-tree-picker-start-node',
|
|
||||||
} as Meta;
|
|
||||||
|
|
||||||
export const AAAOverview: Story<UmbPropertyEditorUITreePickerStartNodeElement> = () =>
|
|
||||||
html`<umb-property-editor-ui-tree-picker-start-node></umb-property-editor-ui-tree-picker-start-node>`;
|
|
||||||
AAAOverview.storyName = 'Overview';
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { manifest as startNode } from './config/start-node/manifests.js';
|
import { manifest as sourcePicker } from './config/source-picker/manifests.js';
|
||||||
|
import { manifest as sourceTypePicker } from './config/source-type-picker/manifests.js';
|
||||||
import type { ManifestPropertyEditorUi } from '@umbraco-cms/backoffice/extension-registry';
|
import type { ManifestPropertyEditorUi } from '@umbraco-cms/backoffice/extension-registry';
|
||||||
|
|
||||||
const manifest: ManifestPropertyEditorUi = {
|
const manifest: ManifestPropertyEditorUi = {
|
||||||
@@ -17,13 +18,13 @@ const manifest: ManifestPropertyEditorUi = {
|
|||||||
alias: 'startNode',
|
alias: 'startNode',
|
||||||
label: 'Node type',
|
label: 'Node type',
|
||||||
description: '',
|
description: '',
|
||||||
propertyEditorUiAlias: 'Umb.PropertyEditorUi.TreePicker.StartNode',
|
propertyEditorUiAlias: sourcePicker.alias,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
alias: 'filter',
|
alias: 'filter',
|
||||||
label: 'Allow items of type',
|
label: 'Allow items of type',
|
||||||
description: '',
|
description: 'Select the applicable types',
|
||||||
propertyEditorUiAlias: 'Umb.PropertyEditorUi.TreePicker',
|
propertyEditorUiAlias: sourceTypePicker.alias,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
alias: 'showOpenButton',
|
alias: 'showOpenButton',
|
||||||
@@ -36,6 +37,6 @@ const manifest: ManifestPropertyEditorUi = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const config: Array<ManifestPropertyEditorUi> = [startNode];
|
const config: Array<ManifestPropertyEditorUi> = [sourcePicker, sourceTypePicker];
|
||||||
|
|
||||||
export const manifests = [manifest, ...config];
|
export const manifests = [manifest, ...config];
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extensi
|
|||||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||||
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
|
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
|
||||||
import type { UmbInputTreeElement } from '@umbraco-cms/backoffice/tree';
|
import type { UmbInputTreeElement } from '@umbraco-cms/backoffice/tree';
|
||||||
import type { StartNode } from '@umbraco-cms/backoffice/components';
|
import type { UmbTreePickerSource } from '@umbraco-cms/backoffice/components';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @element umb-property-editor-ui-tree-picker
|
* @element umb-property-editor-ui-tree-picker
|
||||||
@@ -16,7 +16,7 @@ export class UmbPropertyEditorUITreePickerElement extends UmbLitElement implemen
|
|||||||
value = '';
|
value = '';
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
type?: StartNode['type'];
|
type?: UmbTreePickerSource['type'];
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
startNodeId?: string | null;
|
startNodeId?: string | null;
|
||||||
@@ -38,7 +38,7 @@ export class UmbPropertyEditorUITreePickerElement extends UmbLitElement implemen
|
|||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
|
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
|
||||||
const startNode: StartNode | undefined = config?.getValueByAlias('startNode');
|
const startNode: UmbTreePickerSource | undefined = config?.getValueByAlias('startNode');
|
||||||
if (startNode) {
|
if (startNode) {
|
||||||
this.type = startNode.type;
|
this.type = startNode.type;
|
||||||
this.startNodeId = startNode.id;
|
this.startNodeId = startNode.id;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui';
|
|||||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||||
import { UmbInputDocumentElement } from '@umbraco-cms/backoffice/document';
|
import { UmbInputDocumentElement } from '@umbraco-cms/backoffice/document';
|
||||||
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||||
import type { StartNode } from '@umbraco-cms/backoffice/components';
|
import type { UmbTreePickerSource } from '@umbraco-cms/backoffice/components';
|
||||||
|
|
||||||
@customElement('umb-input-tree')
|
@customElement('umb-input-tree')
|
||||||
export class UmbInputTreeElement extends FormControlMixin(UmbLitElement) {
|
export class UmbInputTreeElement extends FormControlMixin(UmbLitElement) {
|
||||||
@@ -11,16 +11,16 @@ export class UmbInputTreeElement extends FormControlMixin(UmbLitElement) {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _type: StartNode['type'] = undefined;
|
private _type: UmbTreePickerSource['type'] = undefined;
|
||||||
@property()
|
@property()
|
||||||
public set type(newType: StartNode['type']) {
|
public set type(newType: UmbTreePickerSource['type']) {
|
||||||
const oldType = this._type;
|
const oldType = this._type;
|
||||||
if (newType?.toLowerCase() !== this._type) {
|
if (newType?.toLowerCase() !== this._type) {
|
||||||
this._type = newType?.toLowerCase() as StartNode['type'];
|
this._type = newType?.toLowerCase() as UmbTreePickerSource['type'];
|
||||||
this.requestUpdate('type', oldType);
|
this.requestUpdate('type', oldType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public get type(): StartNode['type'] {
|
public get type(): UmbTreePickerSource['type'] {
|
||||||
return this._type;
|
return this._type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,47 +7,42 @@ import { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
|
|||||||
import './tree-item-default/tree-item.element.js';
|
import './tree-item-default/tree-item.element.js';
|
||||||
import './tree-item-base/tree-item-base.element.js';
|
import './tree-item-base/tree-item-base.element.js';
|
||||||
|
|
||||||
|
export type UmbTreeSelectionConfiguration = {
|
||||||
|
multiple?: boolean;
|
||||||
|
selectable?: boolean;
|
||||||
|
selection?: Array<string | null>;
|
||||||
|
};
|
||||||
|
|
||||||
@customElement('umb-tree')
|
@customElement('umb-tree')
|
||||||
export class UmbTreeElement extends UmbLitElement {
|
export class UmbTreeElement extends UmbLitElement {
|
||||||
@property({ type: String, reflect: true })
|
@property({ type: String, reflect: true })
|
||||||
get alias() {
|
|
||||||
return this.#treeContext.getTreeAlias();
|
|
||||||
}
|
|
||||||
set alias(newVal) {
|
set alias(newVal) {
|
||||||
this.#treeContext.setTreeAlias(newVal);
|
this.#treeContext.setTreeAlias(newVal);
|
||||||
}
|
}
|
||||||
|
get alias() {
|
||||||
@property({ type: Boolean, reflect: true })
|
return this.#treeContext.getTreeAlias();
|
||||||
get selectable() {
|
|
||||||
return this.#treeContext.selection.getSelectable();
|
|
||||||
}
|
|
||||||
set selectable(newVal) {
|
|
||||||
this.#treeContext.selection.setSelectable(newVal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@property({ type: Array })
|
private _selectionConfiguration: UmbTreeSelectionConfiguration = {
|
||||||
get selection() {
|
multiple: false,
|
||||||
return this.#treeContext.selection.getSelection();
|
selectable: true,
|
||||||
}
|
selection: [],
|
||||||
set selection(newVal) {
|
};
|
||||||
if (!Array.isArray(newVal)) return;
|
|
||||||
this.#treeContext?.selection.setSelection(newVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
@property({ type: Boolean, reflect: true })
|
@property({ type: Object })
|
||||||
get multiple() {
|
set selectionConfiguration(config: UmbTreeSelectionConfiguration) {
|
||||||
return this.#treeContext.selection.getMultiple();
|
this._selectionConfiguration = config;
|
||||||
|
this.#treeContext.selection.setMultiple(config.multiple ?? false);
|
||||||
|
this.#treeContext.selection.setSelectable(config.selectable ?? true);
|
||||||
|
this.#treeContext.selection.setSelection(config.selection ?? []);
|
||||||
}
|
}
|
||||||
set multiple(newVal) {
|
get selectionConfiguration(): UmbTreeSelectionConfiguration {
|
||||||
this.#treeContext.selection.setMultiple(newVal);
|
return this._selectionConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: what is the best name for this functionality?
|
// TODO: what is the best name for this functionality?
|
||||||
private _hideTreeRoot = false;
|
private _hideTreeRoot = false;
|
||||||
@property({ type: Boolean, attribute: 'hide-tree-root' })
|
@property({ type: Boolean, attribute: 'hide-tree-root' })
|
||||||
get hideTreeRoot() {
|
|
||||||
return this._hideTreeRoot;
|
|
||||||
}
|
|
||||||
set hideTreeRoot(newVal: boolean) {
|
set hideTreeRoot(newVal: boolean) {
|
||||||
const oldVal = this._hideTreeRoot;
|
const oldVal = this._hideTreeRoot;
|
||||||
this._hideTreeRoot = newVal;
|
this._hideTreeRoot = newVal;
|
||||||
@@ -57,22 +52,25 @@ export class UmbTreeElement extends UmbLitElement {
|
|||||||
|
|
||||||
this.requestUpdate('hideTreeRoot', oldVal);
|
this.requestUpdate('hideTreeRoot', oldVal);
|
||||||
}
|
}
|
||||||
|
get hideTreeRoot() {
|
||||||
|
return this._hideTreeRoot;
|
||||||
|
}
|
||||||
|
|
||||||
@property()
|
@property()
|
||||||
get selectableFilter() {
|
|
||||||
return this.#treeContext.selectableFilter;
|
|
||||||
}
|
|
||||||
set selectableFilter(newVal) {
|
set selectableFilter(newVal) {
|
||||||
this.#treeContext.selectableFilter = newVal;
|
this.#treeContext.selectableFilter = newVal;
|
||||||
}
|
}
|
||||||
|
get selectableFilter() {
|
||||||
|
return this.#treeContext.selectableFilter;
|
||||||
|
}
|
||||||
|
|
||||||
@property()
|
@property()
|
||||||
get filter() {
|
|
||||||
return this.#treeContext.filter;
|
|
||||||
}
|
|
||||||
set filter(newVal) {
|
set filter(newVal) {
|
||||||
this.#treeContext.filter = newVal;
|
this.#treeContext.filter = newVal;
|
||||||
}
|
}
|
||||||
|
get filter() {
|
||||||
|
return this.#treeContext.filter;
|
||||||
|
}
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
private _items: UmbTreeItemModelBase[] = [];
|
private _items: UmbTreeItemModelBase[] = [];
|
||||||
@@ -111,6 +109,10 @@ export class UmbTreeElement extends UmbLitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSelection() {
|
||||||
|
return this.#treeContext.selection.getSelection();
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html` ${this.#renderTreeRoot()} ${this.#renderRootItems()}`;
|
return html` ${this.#renderTreeRoot()} ${this.#renderRootItems()}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
UmbModalBaseElement,
|
UmbModalBaseElement,
|
||||||
} from '@umbraco-cms/backoffice/modal';
|
} from '@umbraco-cms/backoffice/modal';
|
||||||
import { UmbId } from '@umbraco-cms/backoffice/id';
|
import { UmbId } from '@umbraco-cms/backoffice/id';
|
||||||
import { UmbEntityTreeItemModel, UmbTreeElement } from '@umbraco-cms/backoffice/tree';
|
import { UmbEntityTreeItemModel, UmbTreeElement, type UmbTreeSelectionConfiguration } from '@umbraco-cms/backoffice/tree';
|
||||||
|
|
||||||
interface DictionaryItemPreview {
|
interface DictionaryItemPreview {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -21,6 +21,13 @@ export class UmbImportDictionaryModalLayout extends UmbModalBaseElement<
|
|||||||
UmbImportDictionaryModalData,
|
UmbImportDictionaryModalData,
|
||||||
UmbImportDictionaryModalValue
|
UmbImportDictionaryModalValue
|
||||||
> {
|
> {
|
||||||
|
@state()
|
||||||
|
private _selectionConfiguration: UmbTreeSelectionConfiguration = {
|
||||||
|
multiple: false,
|
||||||
|
selectable: true,
|
||||||
|
selection: [],
|
||||||
|
};
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
private _parentId?: string;
|
private _parentId?: string;
|
||||||
|
|
||||||
@@ -93,6 +100,7 @@ export class UmbImportDictionaryModalLayout extends UmbModalBaseElement<
|
|||||||
connectedCallback(): void {
|
connectedCallback(): void {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
this._parentId = this.data?.unique ?? undefined;
|
this._parentId = this.data?.unique ?? undefined;
|
||||||
|
this._selectionConfiguration.selection = this._parentId ? [this._parentId] : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
#dictionaryPreviewBuilder(htmlString: string) {
|
#dictionaryPreviewBuilder(htmlString: string) {
|
||||||
@@ -139,7 +147,7 @@ export class UmbImportDictionaryModalLayout extends UmbModalBaseElement<
|
|||||||
}
|
}
|
||||||
|
|
||||||
#onParentChange() {
|
#onParentChange() {
|
||||||
this._parentId = this._treeElement?.selection[0] ?? undefined;
|
this._parentId = this._treeElement?.getSelection()[0] ?? undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async #onFileInput() {
|
async #onFileInput() {
|
||||||
@@ -189,11 +197,9 @@ export class UmbImportDictionaryModalLayout extends UmbModalBaseElement<
|
|||||||
|
|
||||||
<umb-tree
|
<umb-tree
|
||||||
?hide-tree-root=${true}
|
?hide-tree-root=${true}
|
||||||
?multiple=${false}
|
|
||||||
alias=${UMB_DICTIONARY_TREE_ALIAS}
|
alias=${UMB_DICTIONARY_TREE_ALIAS}
|
||||||
@selection-change=${this.#onParentChange}
|
@selection-change=${this.#onParentChange}
|
||||||
.selection=${[this._parentId ?? '']}
|
.selectionConfiguration=${this._selectionConfiguration}></umb-tree>
|
||||||
selectable></umb-tree>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${this.#renderNavigate()}
|
${this.#renderNavigate()}
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
import './input-document-type/input-document-type.element.js';
|
import './input-document-type/input-document-type.element.js';
|
||||||
|
export * from './input-document-type/input-document-type.element.js';
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
export * from './input-document/input-document.element.js';
|
export * from './input-document/input-document.element.js';
|
||||||
export * from './input-document-granular-permission/input-document-granular-permission.element.js';
|
export * from './input-document-granular-permission/input-document-granular-permission.element.js';
|
||||||
|
export * from './input-document-picker-root/input-document-picker-root.element.js';
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
import { UmbDocumentPickerContext } from '../input-document/input-document.context.js';
|
||||||
|
import { html, customElement, property, state, ifDefined, repeat } from '@umbraco-cms/backoffice/external/lit';
|
||||||
|
import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui';
|
||||||
|
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||||
|
import type { DocumentItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||||
|
|
||||||
|
@customElement('umb-input-document-picker-root')
|
||||||
|
export class UmbInputDocumentPickerRootElement extends FormControlMixin(UmbLitElement) {
|
||||||
|
public get nodeId(): string | null | undefined {
|
||||||
|
return this.#documentPickerContext.getSelection()[0];
|
||||||
|
}
|
||||||
|
public set nodeId(id: string | null | undefined) {
|
||||||
|
const selection = id ? [id] : [];
|
||||||
|
this.#documentPickerContext.setSelection(selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public set value(id: string) {
|
||||||
|
this.nodeId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private _items?: Array<DocumentItemResponseModel>;
|
||||||
|
|
||||||
|
#documentPickerContext = new UmbDocumentPickerContext(this);
|
||||||
|
|
||||||
|
// TODO: DynamicRoot - once feature implemented, wire up context and picker UI. [LK]
|
||||||
|
#dynamicRootPickerContext = {
|
||||||
|
openPicker: () => {
|
||||||
|
throw new Error('DynamicRoot picker has not been implemented yet.');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.#documentPickerContext.max = 1;
|
||||||
|
|
||||||
|
this.observe(this.#documentPickerContext.selection, (selection) => (super.value = selection.join(',')));
|
||||||
|
this.observe(this.#documentPickerContext.selectedItems, (selectedItems) => (this._items = selectedItems));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getFormElement() {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
${this._items
|
||||||
|
? html` <uui-ref-list
|
||||||
|
>${repeat(
|
||||||
|
this._items,
|
||||||
|
(item) => item.id,
|
||||||
|
(item) => this._renderItem(item),
|
||||||
|
)}
|
||||||
|
</uui-ref-list>`
|
||||||
|
: ''}
|
||||||
|
${this.#renderButtons()}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
#renderButtons() {
|
||||||
|
if (this.nodeId) return;
|
||||||
|
|
||||||
|
//TODO: Dynamic paths
|
||||||
|
return html` <uui-button-group>
|
||||||
|
<uui-button
|
||||||
|
look="placeholder"
|
||||||
|
@click=${() => this.#documentPickerContext.openPicker()}
|
||||||
|
label=${this.localize.term('contentPicker_defineRootNode')}></uui-button>
|
||||||
|
<uui-button
|
||||||
|
look="placeholder"
|
||||||
|
@click=${() => this.#dynamicRootPickerContext.openPicker()}
|
||||||
|
label=${this.localize.term('contentPicker_defineDynamicRoot')}></uui-button>
|
||||||
|
</uui-button-group>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _renderItem(item: DocumentItemResponseModel) {
|
||||||
|
if (!item.id) return;
|
||||||
|
return html`
|
||||||
|
<uui-ref-node name=${ifDefined(item.name)} detail=${ifDefined(item.id)}>
|
||||||
|
<!-- TODO: implement is trashed <uui-tag size="s" slot="tag" color="danger">Trashed</uui-tag> -->
|
||||||
|
<uui-action-bar slot="actions">
|
||||||
|
<uui-button @click=${() => this.#documentPickerContext.openPicker()} label="Edit document ${item.name}"
|
||||||
|
>Edit</uui-button
|
||||||
|
>
|
||||||
|
<uui-button
|
||||||
|
@click=${() => this.#documentPickerContext.requestRemoveItem(item.id!)}
|
||||||
|
label="Remove document ${item.name}"
|
||||||
|
>Remove</uui-button
|
||||||
|
>
|
||||||
|
</uui-action-bar>
|
||||||
|
</uui-ref-node>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UmbInputDocumentPickerRootElement;
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'umb-input-document-picker-root': UmbInputDocumentPickerRootElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -115,7 +115,7 @@ export class UmbInputDocumentElement extends FormControlMixin(UmbLitElement) {
|
|||||||
id="add-button"
|
id="add-button"
|
||||||
look="placeholder"
|
look="placeholder"
|
||||||
@click=${() => this.#pickerContext.openPicker()}
|
@click=${() => this.#pickerContext.openPicker()}
|
||||||
label=${this.localize.term('general_add')}></uui-button>`;
|
label=${this.localize.term('general_choose')}></uui-button>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _renderItem(item: DocumentItemResponseModel) {
|
private _renderItem(item: DocumentItemResponseModel) {
|
||||||
@@ -127,7 +127,7 @@ export class UmbInputDocumentElement extends FormControlMixin(UmbLitElement) {
|
|||||||
<uui-button
|
<uui-button
|
||||||
@click=${() => this.#pickerContext.requestRemoveItem(item.id!)}
|
@click=${() => this.#pickerContext.requestRemoveItem(item.id!)}
|
||||||
label="Remove document ${item.name}"
|
label="Remove document ${item.name}"
|
||||||
>Remove</uui-button
|
>${this.localize.term('general_remove')}</uui-button
|
||||||
>
|
>
|
||||||
</uui-action-bar>
|
</uui-action-bar>
|
||||||
</uui-ref-node>
|
</uui-ref-node>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import './components/index.js';
|
import './components/index.js';
|
||||||
|
|
||||||
export * from './repository/index.js';
|
export * from './repository/index.js';
|
||||||
|
export * from './tracked-reference/index.js';
|
||||||
export * from './workspace/index.js';
|
export * from './workspace/index.js';
|
||||||
export * from './recycle-bin/index.js';
|
export * from './recycle-bin/index.js';
|
||||||
export * from './user-permissions/index.js';
|
export * from './user-permissions/index.js';
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { manifests as entityBulkActionManifests } from './entity-bulk-actions/ma
|
|||||||
import { manifests as propertyEditorManifests } from './property-editors/manifests.js';
|
import { manifests as propertyEditorManifests } from './property-editors/manifests.js';
|
||||||
import { manifests as userPermissionManifests } from './user-permissions/manifests.js';
|
import { manifests as userPermissionManifests } from './user-permissions/manifests.js';
|
||||||
import { manifests as recycleBinManifests } from './recycle-bin/manifests.js';
|
import { manifests as recycleBinManifests } from './recycle-bin/manifests.js';
|
||||||
|
import { manifests as trackedReferenceManifests } from './tracked-reference/manifests.js';
|
||||||
|
|
||||||
export const manifests = [
|
export const manifests = [
|
||||||
...collectionManifests,
|
...collectionManifests,
|
||||||
@@ -20,4 +21,5 @@ export const manifests = [
|
|||||||
...propertyEditorManifests,
|
...propertyEditorManifests,
|
||||||
...userPermissionManifests,
|
...userPermissionManifests,
|
||||||
...recycleBinManifests,
|
...recycleBinManifests,
|
||||||
|
...trackedReferenceManifests,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
//export * from './manifests.js';
|
||||||
|
export * from './repository/index.js';
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { manifests as repositoryManifests } from './repository/manifests.js';
|
||||||
|
|
||||||
|
export const UMB_TRACKED_REFERENCE_DOCUMENT = 'Umb.TrackedReference.Document';
|
||||||
|
|
||||||
|
export const manifests = [...repositoryManifests];
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { UmbDocumentTrackedReferenceServerDataSource } from './document-tracked-reference.server.data.js';
|
||||||
|
import { type UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||||
|
import { UmbBaseController } from '@umbraco-cms/backoffice/class-api';
|
||||||
|
|
||||||
|
export class UmbDocumentTrackedReferenceRepository extends UmbBaseController {
|
||||||
|
#trackedReferenceSource: UmbDocumentTrackedReferenceServerDataSource;
|
||||||
|
|
||||||
|
constructor(host: UmbControllerHostElement) {
|
||||||
|
super(host);
|
||||||
|
this.#trackedReferenceSource = new UmbDocumentTrackedReferenceServerDataSource(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
async requestTrackedReference(unique: string, skip = 0, take = 20, filterMustBeIsDependency = false) {
|
||||||
|
if (!unique) throw new Error(`unique is required`);
|
||||||
|
return this.#trackedReferenceSource.getTrackedReferenceById(unique, skip, take, filterMustBeIsDependency);
|
||||||
|
}
|
||||||
|
|
||||||
|
async requestTrackedReferenceDescendantsFromParentUnique(
|
||||||
|
parentUnique: string,
|
||||||
|
skip = 0,
|
||||||
|
take = 20,
|
||||||
|
filterMustBeIsDependency = false,
|
||||||
|
) {
|
||||||
|
if (!parentUnique) throw new Error(`unique is required`);
|
||||||
|
return this.#trackedReferenceSource.getTrackedReferenceDescendantsByParentId(
|
||||||
|
parentUnique,
|
||||||
|
skip,
|
||||||
|
take,
|
||||||
|
filterMustBeIsDependency,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async requestTrackedReferenceItems(uniques: string[], skip = 0, take = 20, filterMustBeIsDependency = true) {
|
||||||
|
if (!uniques) throw new Error(`unique is required`);
|
||||||
|
return this.#trackedReferenceSource.getTrackedReferenceItem(uniques, skip, take, filterMustBeIsDependency);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import { TrackedReferenceResource } from '@umbraco-cms/backoffice/backend-api';
|
||||||
|
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||||
|
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @export
|
||||||
|
* @class UmbUserGroupCollectionServerDataSource
|
||||||
|
* @implements {RepositoryDetailDataSource}
|
||||||
|
*/
|
||||||
|
export class UmbDocumentTrackedReferenceServerDataSource {
|
||||||
|
#host: UmbControllerHost;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of UmbDocumentTrackedReferenceServerDataSource.
|
||||||
|
* @param {UmbControllerHost} host
|
||||||
|
* @memberof UmbDocumentTrackedReferenceServerDataSource
|
||||||
|
*/
|
||||||
|
constructor(host: UmbControllerHost) {
|
||||||
|
this.#host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the item for the given id from the server
|
||||||
|
* @param {Array<string>} ids
|
||||||
|
* @return {*}
|
||||||
|
* @memberof UmbDataTypeItemServerDataSource
|
||||||
|
*/
|
||||||
|
async getTrackedReferenceById(id: string, skip = 0, take = 20, filterMustBeIsDependency = false) {
|
||||||
|
return await tryExecuteAndNotify(
|
||||||
|
this.#host,
|
||||||
|
TrackedReferenceResource.getTrackedReferenceById({ id, skip, take, filterMustBeIsDependency }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the item descendant for the given id from the server
|
||||||
|
* @param {Array<string>} ids
|
||||||
|
* @return {*}
|
||||||
|
* @memberof UmbDocumentTrackedReferenceServerDataSource
|
||||||
|
*/
|
||||||
|
async getTrackedReferenceDescendantsByParentId(
|
||||||
|
parentId: string,
|
||||||
|
skip = 0,
|
||||||
|
take = 20,
|
||||||
|
filterMustBeIsDependency = false,
|
||||||
|
) {
|
||||||
|
return await tryExecuteAndNotify(
|
||||||
|
this.#host,
|
||||||
|
TrackedReferenceResource.getTrackedReferenceDescendantsByParentId({
|
||||||
|
parentId,
|
||||||
|
skip,
|
||||||
|
take,
|
||||||
|
filterMustBeIsDependency,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the items for the given ids from the server
|
||||||
|
* @param {Array<string>} ids
|
||||||
|
* @return {*}
|
||||||
|
* @memberof UmbDocumentTrackedReferenceServerDataSource
|
||||||
|
*/
|
||||||
|
async getTrackedReferenceItem(id: string[], skip = 0, take = 20, filterMustBeIsDependency = true) {
|
||||||
|
return await tryExecuteAndNotify(
|
||||||
|
this.#host,
|
||||||
|
TrackedReferenceResource.getTrackedReferenceItem({
|
||||||
|
id,
|
||||||
|
skip,
|
||||||
|
take,
|
||||||
|
filterMustBeIsDependency,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './document-tracked-reference.repository.js';
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { UmbDocumentTrackedReferenceRepository } from './document-tracked-reference.repository.js';
|
||||||
|
import { ManifestRepository } from '@umbraco-cms/backoffice/extension-registry';
|
||||||
|
|
||||||
|
export const UMB_DOCUMENT_TRACKED_REFERENCE_REPOSITORY_ALIAS = 'Umb.Repository.Document.TrackedReference';
|
||||||
|
|
||||||
|
const repository: ManifestRepository = {
|
||||||
|
type: 'repository',
|
||||||
|
alias: UMB_DOCUMENT_TRACKED_REFERENCE_REPOSITORY_ALIAS,
|
||||||
|
name: 'Document Tracked Reference Repository',
|
||||||
|
api: UmbDocumentTrackedReferenceRepository,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const manifests = [repository];
|
||||||
@@ -44,7 +44,7 @@ const workspaceViews: Array<ManifestWorkspaceView> = [
|
|||||||
type: 'workspaceView',
|
type: 'workspaceView',
|
||||||
alias: 'Umb.WorkspaceView.Document.Info',
|
alias: 'Umb.WorkspaceView.Document.Info',
|
||||||
name: 'Document Workspace Info View',
|
name: 'Document Workspace Info View',
|
||||||
js: () => import('./views/info/document-info-workspace-view.element.js'),
|
js: () => import('./views/info/document-workspace-view-info.element.js'),
|
||||||
weight: 100,
|
weight: 100,
|
||||||
meta: {
|
meta: {
|
||||||
label: 'Info',
|
label: 'Info',
|
||||||
|
|||||||
@@ -1,374 +0,0 @@
|
|||||||
import { css, html, nothing, repeat, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
|
||||||
import { UUIPaginationEvent } from '@umbraco-cms/backoffice/external/uui';
|
|
||||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
|
||||||
import { UMB_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace';
|
|
||||||
import { UMB_WORKSPACE_MODAL, UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal';
|
|
||||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
|
||||||
interface HistoryNode {
|
|
||||||
userId?: number;
|
|
||||||
userAvatars?: [];
|
|
||||||
userName?: string;
|
|
||||||
timestamp?: string;
|
|
||||||
comment?: string;
|
|
||||||
entityType?: string;
|
|
||||||
logType?: HistoryLogType;
|
|
||||||
nodeId?: string;
|
|
||||||
parameters?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
type HistoryLogType = 'Publish' | 'Save' | 'Unpublish' | 'ContentVersionEnableCleanup' | 'ContentVersionPreventCleanup';
|
|
||||||
|
|
||||||
@customElement('umb-document-info-workspace-view')
|
|
||||||
export class UmbDocumentInfoWorkspaceViewElement extends UmbLitElement {
|
|
||||||
@state()
|
|
||||||
private _historyList: HistoryNode[] = [
|
|
||||||
{
|
|
||||||
userId: -1,
|
|
||||||
userAvatars: [],
|
|
||||||
userName: 'Lone Iversen',
|
|
||||||
timestamp: 'December 5, 2022 2:59 PM',
|
|
||||||
comment: undefined,
|
|
||||||
entityType: 'Document',
|
|
||||||
logType: 'Save',
|
|
||||||
nodeId: '1058',
|
|
||||||
parameters: undefined,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
userId: -1,
|
|
||||||
userAvatars: [],
|
|
||||||
userName: 'Lone Iversen',
|
|
||||||
timestamp: 'December 5, 2022 2:59 PM',
|
|
||||||
comment: undefined,
|
|
||||||
entityType: 'Document',
|
|
||||||
logType: 'Unpublish',
|
|
||||||
nodeId: '1058',
|
|
||||||
parameters: undefined,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
userId: -1,
|
|
||||||
userAvatars: [],
|
|
||||||
userName: 'Lone Iversen',
|
|
||||||
timestamp: 'December 5, 2022 2:59 PM',
|
|
||||||
comment: undefined,
|
|
||||||
entityType: 'Document',
|
|
||||||
logType: 'Publish',
|
|
||||||
nodeId: '1058',
|
|
||||||
parameters: undefined,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
userId: -1,
|
|
||||||
userAvatars: [],
|
|
||||||
userName: 'Lone Iversen',
|
|
||||||
timestamp: 'December 5, 2022 2:59 PM',
|
|
||||||
comment: undefined,
|
|
||||||
entityType: 'Document',
|
|
||||||
logType: 'Save',
|
|
||||||
nodeId: '1058',
|
|
||||||
parameters: undefined,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
userId: -1,
|
|
||||||
userAvatars: [],
|
|
||||||
userName: 'Lone Iversen',
|
|
||||||
timestamp: 'December 5, 2022 2:59 PM',
|
|
||||||
comment: undefined,
|
|
||||||
entityType: 'Document',
|
|
||||||
logType: 'Save',
|
|
||||||
nodeId: '1058',
|
|
||||||
parameters: undefined,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
@state()
|
|
||||||
private _total?: number;
|
|
||||||
|
|
||||||
@state()
|
|
||||||
private _currentPage = 1;
|
|
||||||
|
|
||||||
@state()
|
|
||||||
private _nodeName = '';
|
|
||||||
|
|
||||||
@state()
|
|
||||||
private _documentTypeId = '';
|
|
||||||
|
|
||||||
private _workspaceContext?: typeof UMB_WORKSPACE_CONTEXT.TYPE;
|
|
||||||
private itemsPerPage = 10;
|
|
||||||
|
|
||||||
@state()
|
|
||||||
private _editDocumentTypePath = '';
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL)
|
|
||||||
.addAdditionalPath('document-type')
|
|
||||||
.onSetup(() => {
|
|
||||||
return { data: { entityType: 'document-type', preset: {} } };
|
|
||||||
})
|
|
||||||
.observeRouteBuilder((routeBuilder) => {
|
|
||||||
this._editDocumentTypePath = routeBuilder({});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.consumeContext(UMB_WORKSPACE_CONTEXT, (nodeContext) => {
|
|
||||||
this._workspaceContext = nodeContext;
|
|
||||||
this._observeContent();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _observeContent() {
|
|
||||||
if (!this._workspaceContext) return;
|
|
||||||
|
|
||||||
this._nodeName = 'TBD, with variants this is not as simple.';
|
|
||||||
this._documentTypeId = (this._workspaceContext as any).getContentTypeId();
|
|
||||||
|
|
||||||
/*
|
|
||||||
this.observe(this._workspaceContext.name, (name) => {
|
|
||||||
this._nodeName = name || '';
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
#onPageChange(event: UUIPaginationEvent) {
|
|
||||||
if (this._currentPage === event.target.current) return;
|
|
||||||
this._currentPage = event.target.current;
|
|
||||||
//TODO: Run endpoint to get next history parts
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return html`<div class="container">
|
|
||||||
<uui-box headline=${this.localize.term('general_links')} style="--uui-box-default-padding: 0;">
|
|
||||||
${this.#renderLinksSection()}
|
|
||||||
</uui-box>
|
|
||||||
<uui-box headline=${this.localize.term('general_history')}>
|
|
||||||
<umb-history-list>
|
|
||||||
${repeat(
|
|
||||||
this._historyList,
|
|
||||||
(item) => item.timestamp,
|
|
||||||
(item) => this.#renderHistory(item),
|
|
||||||
)}
|
|
||||||
</umb-history-list>
|
|
||||||
${this.#renderHistoryPagination()}
|
|
||||||
</uui-box>
|
|
||||||
</div>
|
|
||||||
<div class="container">
|
|
||||||
<uui-box headline="General" id="general-section">${this.#renderGeneralSection()}</uui-box>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
#renderLinksSection() {
|
|
||||||
//repeat
|
|
||||||
return html`<div id="link-section">
|
|
||||||
<a href="http://google.com" target="_blank" class="link-item with-href">
|
|
||||||
<span class="link-language">da-DK</span>
|
|
||||||
<span class="link-content"> <uui-icon name="icon-out"></uui-icon>google.com </span>
|
|
||||||
</a>
|
|
||||||
<div class="link-item">
|
|
||||||
<span class="link-language">en-EN</span>
|
|
||||||
<span class="link-content italic"><umb-localize key="content_parentNotPublishedAnomaly"></umb-localize></span>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
#renderGeneralSection() {
|
|
||||||
return html`
|
|
||||||
<div class="general-item">
|
|
||||||
<strong>${this.localize.term('content_publishStatus')}</strong>
|
|
||||||
<span
|
|
||||||
><uui-tag color="positive" look="primary" label=${this.localize.term('content_published')}
|
|
||||||
><umb-localize key="content_published"></umb-localize></uui-tag
|
|
||||||
></span>
|
|
||||||
</div>
|
|
||||||
<div class="general-item">
|
|
||||||
<strong><umb-localize key="content_createDate"></umb-localize></strong>
|
|
||||||
<span><umb-localize-date date="${new Date()}"></umb-localize-date></span>
|
|
||||||
</div>
|
|
||||||
<div class="general-item">
|
|
||||||
<strong><umb-localize key="content_documentType"></umb-localize></strong>
|
|
||||||
<uui-button
|
|
||||||
href=${this._editDocumentTypePath + 'edit/' + this._documentTypeId}
|
|
||||||
label=${this.localize.term('general_edit')}></uui-button>
|
|
||||||
</div>
|
|
||||||
<div class="general-item">
|
|
||||||
<strong><umb-localize key="template_template"></umb-localize></strong>
|
|
||||||
<span>IMPLEMENT template picker?</span>
|
|
||||||
</div>
|
|
||||||
<div class="general-item">
|
|
||||||
<strong><umb-localize key="template_id"></umb-localize></strong>
|
|
||||||
<span>...</span>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
#renderHistory(history: HistoryNode) {
|
|
||||||
return html` <umb-history-item .name="${history.userName}" .detail="${this.localize.date(history.timestamp!)}">
|
|
||||||
<span class="log-type"
|
|
||||||
>${this.#renderTag(history.logType)} ${this.#renderTagDescription(history.logType, history)}</span
|
|
||||||
>
|
|
||||||
<uui-button label=${this.localize.term('actions_rollback')} look="secondary" slot="actions">
|
|
||||||
<uui-icon name="icon-undo"></uui-icon>
|
|
||||||
<umb-localize key="actions_rollback"></umb-localize>
|
|
||||||
</uui-button>
|
|
||||||
</umb-history-item>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
#renderHistoryPagination() {
|
|
||||||
if (!this._total) return nothing;
|
|
||||||
|
|
||||||
const totalPages = Math.ceil(this._total / this.itemsPerPage);
|
|
||||||
|
|
||||||
if (totalPages <= 1) return nothing;
|
|
||||||
|
|
||||||
return html`<div class="pagination">
|
|
||||||
<uui-pagination .total=${totalPages} @change="${this.#onPageChange}"></uui-pagination>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
#renderTag(type?: HistoryLogType) {
|
|
||||||
switch (type) {
|
|
||||||
case 'Publish':
|
|
||||||
return html`<uui-tag look="primary" color="positive" label=${this.localize.term('content_publish')}
|
|
||||||
><umb-localize key="content_publish"></umb-localize
|
|
||||||
></uui-tag>`;
|
|
||||||
case 'Unpublish':
|
|
||||||
return html`<uui-tag look="primary" color="warning" label=${this.localize.term('content_unpublish')}
|
|
||||||
><umb-localize key="content_unpublish"></umb-localize
|
|
||||||
></uui-tag>`;
|
|
||||||
case 'Save':
|
|
||||||
return html`<uui-tag look="primary" label=${this.localize.term('auditTrails_smallSave')}
|
|
||||||
><umb-localize key="auditTrails_smallSave"></umb-localize
|
|
||||||
></uui-tag>`;
|
|
||||||
case 'ContentVersionEnableCleanup':
|
|
||||||
return html`<uui-tag
|
|
||||||
look="secondary"
|
|
||||||
label=${this.localize.term('contentTypeEditor_historyCleanupEnableCleanup')}
|
|
||||||
><umb-localize key="contentTypeEditor_historyCleanupEnableCleanup"></umb-localize
|
|
||||||
></uui-tag>`;
|
|
||||||
case 'ContentVersionPreventCleanup':
|
|
||||||
return html`<uui-tag
|
|
||||||
look="secondary"
|
|
||||||
label=${this.localize.term('contentTypeEditor_historyCleanupPreventCleanup')}
|
|
||||||
><umb-localize key="contentTypeEditor_historyCleanupPreventCleanup"></umb-localize
|
|
||||||
></uui-tag>`;
|
|
||||||
default:
|
|
||||||
return 'Could not detect log type';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#renderTagDescription(type?: HistoryLogType, params?: HistoryNode) {
|
|
||||||
switch (type) {
|
|
||||||
case 'Publish':
|
|
||||||
return this.localize.term('auditTrails_publish');
|
|
||||||
case 'Unpublish':
|
|
||||||
return this.localize.term('auditTrails_unpublish');
|
|
||||||
case 'Save':
|
|
||||||
return this.localize.term('auditTrails_save');
|
|
||||||
case 'ContentVersionEnableCleanup':
|
|
||||||
return this.localize.term('auditTrails_contentversionenablecleanup', [params?.nodeId]);
|
|
||||||
case 'ContentVersionPreventCleanup':
|
|
||||||
return this.localize.term('auditTrails_contentversionpreventcleanup', [params?.nodeId]);
|
|
||||||
default:
|
|
||||||
return 'Could not detect log type';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static styles = [
|
|
||||||
UmbTextStyles,
|
|
||||||
css`
|
|
||||||
:host {
|
|
||||||
display: grid;
|
|
||||||
gap: var(--uui-size-layout-1);
|
|
||||||
padding: var(--uui-size-layout-1);
|
|
||||||
grid-template-columns: 1fr 350px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: var(--uui-size-layout-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//General section
|
|
||||||
|
|
||||||
#general-section {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.general-item {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: var(--uui-size-space-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.general-item:not(:last-child) {
|
|
||||||
margin-bottom: var(--uui-size-space-6);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link section
|
|
||||||
|
|
||||||
#link-section {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-item {
|
|
||||||
padding: var(--uui-size-space-4) var(--uui-size-space-6);
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 75px 1fr;
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-language {
|
|
||||||
color: var(--uui-color-divider-emphasis);
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-content.italic {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-item uui-icon {
|
|
||||||
margin-right: var(--uui-size-space-2);
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-item.with-href {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-item.with-href:hover {
|
|
||||||
background: var(--uui-color-divider);
|
|
||||||
}
|
|
||||||
|
|
||||||
//History section
|
|
||||||
|
|
||||||
uui-tag uui-icon {
|
|
||||||
margin-right: var(--uui-size-space-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.log-type {
|
|
||||||
display: flex;
|
|
||||||
gap: var(--uui-size-space-2);
|
|
||||||
}
|
|
||||||
uui-pagination {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
.pagination {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
margin-top: var(--uui-size-space-4);
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
export default UmbDocumentInfoWorkspaceViewElement;
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
'umb-document-info-workspace-view': UmbDocumentInfoWorkspaceViewElement;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
import { HistoryTagStyleAndText, TimeOptions } from './utils.js';
|
||||||
|
import { UmbAuditLogRepository } from '@umbraco-cms/backoffice/audit-log';
|
||||||
|
import {
|
||||||
|
css,
|
||||||
|
html,
|
||||||
|
customElement,
|
||||||
|
state,
|
||||||
|
property,
|
||||||
|
nothing,
|
||||||
|
repeat,
|
||||||
|
ifDefined,
|
||||||
|
} from '@umbraco-cms/backoffice/external/lit';
|
||||||
|
import { UUIPaginationEvent } from '@umbraco-cms/backoffice/external/uui';
|
||||||
|
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||||
|
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||||
|
import {
|
||||||
|
AuditLogBaseModel,
|
||||||
|
AuditLogWithUsernameResponseModel,
|
||||||
|
DirectionModel,
|
||||||
|
} from '@umbraco-cms/backoffice/backend-api';
|
||||||
|
import { UmbCurrentUserContext } from '@umbraco-cms/backoffice/current-user';
|
||||||
|
|
||||||
|
@customElement('umb-document-workspace-view-info-history')
|
||||||
|
export class UmbDocumentWorkspaceViewInfoHistoryElement extends UmbLitElement {
|
||||||
|
#logRepository: UmbAuditLogRepository;
|
||||||
|
#itemsPerPage = 10;
|
||||||
|
|
||||||
|
@property()
|
||||||
|
documentUnique = '';
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private _total?: number;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private _items?: Array<AuditLogWithUsernameResponseModel>;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private _currentPage = 1;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.#logRepository = new UmbAuditLogRepository(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(): void {
|
||||||
|
this.#getLogs();
|
||||||
|
}
|
||||||
|
|
||||||
|
async #getLogs() {
|
||||||
|
this._items = undefined; // Reset items to show loader
|
||||||
|
if (!this.documentUnique) return;
|
||||||
|
|
||||||
|
/*const { data } = await this.#logRepository.getAuditLogByUnique({
|
||||||
|
id: this.documentUnique,
|
||||||
|
orderDirection: DirectionModel.DESCENDING,
|
||||||
|
skip: (this._currentPage - 1) * this.#itemsPerPage,
|
||||||
|
take: this.#itemsPerPage,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!data) return;
|
||||||
|
this._total = data.total;
|
||||||
|
this._items = data.items;
|
||||||
|
*/
|
||||||
|
|
||||||
|
//TODO: I think there is an issue with the API (backend) - error with ID. Hacking for now.
|
||||||
|
// Uncomment previous code and delete the following when issue fixed.
|
||||||
|
// This should also make it load significantly faster
|
||||||
|
|
||||||
|
const { data } = await this.#logRepository.getLog({
|
||||||
|
orderDirection: DirectionModel.DESCENDING,
|
||||||
|
skip: 0,
|
||||||
|
take: 99999,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!data) return;
|
||||||
|
|
||||||
|
// Hack list to only get the items for the current document
|
||||||
|
const list = data.items.filter((item) => item.entityId === this.documentUnique);
|
||||||
|
this._total = list.length;
|
||||||
|
|
||||||
|
// Hack list to only get the items for the current page
|
||||||
|
this._items = list.slice(
|
||||||
|
(this._currentPage - 1) * this.#itemsPerPage,
|
||||||
|
(this._currentPage - 1) * this.#itemsPerPage + this.#itemsPerPage,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#onPageChange(event: UUIPaginationEvent) {
|
||||||
|
if (this._currentPage === event.target.current) return;
|
||||||
|
this._currentPage = event.target.current;
|
||||||
|
|
||||||
|
this.#getLogs();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`<uui-box headline=${this.localize.term('general_history')}>
|
||||||
|
${this._items ? this.#renderHistory() : html`<uui-loader-circle></uui-loader-circle> `}
|
||||||
|
</uui-box>
|
||||||
|
${this.#renderHistoryPagination()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
#renderHistory() {
|
||||||
|
if (this._items && this._items.length) {
|
||||||
|
return html`
|
||||||
|
<umb-history-list>
|
||||||
|
${repeat(
|
||||||
|
this._items,
|
||||||
|
(item) => item.timestamp,
|
||||||
|
(item) => {
|
||||||
|
const { text, style } = HistoryTagStyleAndText(item.logType);
|
||||||
|
return html`<umb-history-item
|
||||||
|
.name=${item.userName ?? 'Unknown'}
|
||||||
|
src=${ifDefined(
|
||||||
|
Array.isArray(item.userAvatars) ? item.userAvatars[item.userAvatars.length - 1] : undefined,
|
||||||
|
)}
|
||||||
|
detail=${this.localize.date(item.timestamp, TimeOptions)}>
|
||||||
|
<span class="log-type">
|
||||||
|
<uui-tag look=${style.look} color=${style.color}> ${this.localize.term(text.label)} </uui-tag>
|
||||||
|
${this.localize.term(text.desc, item.parameters)}
|
||||||
|
</span>
|
||||||
|
<uui-button label=${this.localize.term('actions_rollback')} look="secondary" slot="actions">
|
||||||
|
<uui-icon name="icon-undo"></uui-icon>
|
||||||
|
<umb-localize key="actions_rollback"></umb-localize>
|
||||||
|
</uui-button>
|
||||||
|
</umb-history-item>`;
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
</umb-history-list>
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
return html`${this.localize.term('content_noItemsToShow')}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#renderHistoryPagination() {
|
||||||
|
if (!this._total) return nothing;
|
||||||
|
|
||||||
|
const totalPages = Math.ceil(this._total / this.#itemsPerPage);
|
||||||
|
|
||||||
|
if (totalPages <= 1) return nothing;
|
||||||
|
|
||||||
|
return html`<div class="pagination">
|
||||||
|
<uui-pagination .total=${totalPages} @change="${this.#onPageChange}"></uui-pagination>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = [
|
||||||
|
UmbTextStyles,
|
||||||
|
css`
|
||||||
|
uui-loader-circle {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
uui-tag uui-icon {
|
||||||
|
margin-right: var(--uui-size-space-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-type {
|
||||||
|
flex-grow: 1;
|
||||||
|
gap: var(--uui-size-space-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
uui-pagination {
|
||||||
|
flex: 1;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.pagination {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: var(--uui-size-space-4);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UmbDocumentWorkspaceViewInfoHistoryElement;
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'umb-document-workspace-view-info-history': UmbDocumentWorkspaceViewInfoHistoryElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
import { css, html, customElement, state, nothing, repeat, property } from '@umbraco-cms/backoffice/external/lit';
|
||||||
|
import { UUIPaginationEvent } from '@umbraco-cms/backoffice/external/uui';
|
||||||
|
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||||
|
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||||
|
import { RelationItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||||
|
import { UmbDocumentTrackedReferenceRepository } from '@umbraco-cms/backoffice/document';
|
||||||
|
import { UMB_WORKSPACE_MODAL, UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal';
|
||||||
|
|
||||||
|
@customElement('umb-document-workspace-view-info-reference')
|
||||||
|
export class UmbDocumentWorkspaceViewInfoReferenceElement extends UmbLitElement {
|
||||||
|
#itemsPerPage = 10;
|
||||||
|
#trackedReferenceRepository;
|
||||||
|
|
||||||
|
@property()
|
||||||
|
documentUnique = '';
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private _editDocumentPath = '';
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private _currentPage = 1;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private _total = 0;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private _items?: Array<RelationItemResponseModel> = [];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.#trackedReferenceRepository = new UmbDocumentTrackedReferenceRepository(this);
|
||||||
|
|
||||||
|
new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL)
|
||||||
|
.addAdditionalPath('document')
|
||||||
|
.onSetup(() => {
|
||||||
|
return { data: { entityType: 'document', preset: {} } };
|
||||||
|
})
|
||||||
|
.observeRouteBuilder((routeBuilder) => {
|
||||||
|
this._editDocumentPath = routeBuilder({});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(): void {
|
||||||
|
this.#getReferences();
|
||||||
|
}
|
||||||
|
|
||||||
|
async #getReferences() {
|
||||||
|
const { data } = await this.#trackedReferenceRepository.requestTrackedReference(
|
||||||
|
this.documentUnique,
|
||||||
|
this._currentPage - 1 * this.#itemsPerPage,
|
||||||
|
this.#itemsPerPage,
|
||||||
|
);
|
||||||
|
if (!data) return;
|
||||||
|
|
||||||
|
this._total = data.total;
|
||||||
|
this._items = data.items;
|
||||||
|
}
|
||||||
|
|
||||||
|
#onPageChange(event: UUIPaginationEvent) {
|
||||||
|
if (this._currentPage === event.target.current) return;
|
||||||
|
this._currentPage = event.target.current;
|
||||||
|
|
||||||
|
this.#getReferences();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (this._items && this._items.length > 0) {
|
||||||
|
return html`<strong>
|
||||||
|
<umb-localize key="references_labelUsedByItems">Referenced by the following items</umb-localize>
|
||||||
|
</strong>
|
||||||
|
<uui-box style="--uui-box-default-padding:0">
|
||||||
|
<uui-table>
|
||||||
|
<uui-table-head>
|
||||||
|
<uui-table-head-cell></uui-table-head-cell>
|
||||||
|
<uui-table-head-cell><umb-localize key="general_name">Name</umb-localize></uui-table-head-cell>
|
||||||
|
<uui-table-head-cell><umb-localize key="general_status">Status</umb-localize></uui-table-head-cell>
|
||||||
|
<uui-table-head-cell><umb-localize key="general_typeName">Type Name</umb-localize></uui-table-head-cell>
|
||||||
|
<uui-table-head-cell><umb-localize key="general_type">Type</umb-localize></uui-table-head-cell>
|
||||||
|
<uui-table-head-cell>
|
||||||
|
<umb-localize key="relationType_relation">Relation</umb-localize>
|
||||||
|
</uui-table-head-cell>
|
||||||
|
</uui-table-head>
|
||||||
|
|
||||||
|
${repeat(
|
||||||
|
this._items,
|
||||||
|
(item) => item.nodeId,
|
||||||
|
(item) =>
|
||||||
|
html`<uui-table-row>
|
||||||
|
<uui-table-cell>
|
||||||
|
<uui-icon style=" vertical-align: middle;" name="icon-document"></uui-icon>
|
||||||
|
</uui-table-cell>
|
||||||
|
<uui-table-cell class="link-cell">
|
||||||
|
<uui-button label="Edit" href=${`${this._editDocumentPath}edit/${item.nodeId}`}>
|
||||||
|
${item.nodeName}
|
||||||
|
</uui-button>
|
||||||
|
</uui-table-cell>
|
||||||
|
<uui-table-cell>
|
||||||
|
${item.nodePublished
|
||||||
|
? this.localize.term('content_published')
|
||||||
|
: this.localize.term('content_unpublished')}
|
||||||
|
</uui-table-cell>
|
||||||
|
<uui-table-cell>${item.contentTypeName}</uui-table-cell>
|
||||||
|
<uui-table-cell>${item.nodeType}</uui-table-cell>
|
||||||
|
<uui-table-cell>${item.relationTypeName}</uui-table-cell>
|
||||||
|
</uui-table-row>`,
|
||||||
|
)}
|
||||||
|
</uui-table>
|
||||||
|
</uui-box>
|
||||||
|
${this.#renderReferencePagination()}`;
|
||||||
|
} else {
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#renderReferencePagination() {
|
||||||
|
if (!this._total) return nothing;
|
||||||
|
|
||||||
|
const totalPages = Math.ceil(this._total / this.#itemsPerPage);
|
||||||
|
|
||||||
|
if (totalPages <= 1) return nothing;
|
||||||
|
|
||||||
|
return html`<div class="pagination">
|
||||||
|
<uui-pagination .total=${totalPages} @change="${this.#onPageChange}"></uui-pagination>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = [
|
||||||
|
UmbTextStyles,
|
||||||
|
css`
|
||||||
|
.link-cell {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
uui-table-cell:not(.link-cell) {
|
||||||
|
color: var(--uui-color-text-alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
uui-pagination {
|
||||||
|
flex: 1;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: var(--uui-size-space-4);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UmbDocumentWorkspaceViewInfoReferenceElement;
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'umb-document-workspace-view-info-reference': UmbDocumentWorkspaceViewInfoReferenceElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
import { TimeOptions } from './utils.js';
|
||||||
|
import { css, html, customElement, state, repeat } from '@umbraco-cms/backoffice/external/lit';
|
||||||
|
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||||
|
import { UMB_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace';
|
||||||
|
import { UMB_WORKSPACE_MODAL, UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal';
|
||||||
|
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||||
|
import './document-workspace-view-info-history.element.js';
|
||||||
|
import './document-workspace-view-info-reference.element.js';
|
||||||
|
import { UmbDocumentWorkspaceContext } from '@umbraco-cms/backoffice/document';
|
||||||
|
import { ContentUrlInfoModel } from '@umbraco-cms/backoffice/backend-api';
|
||||||
|
import { UmbCurrentUserContext } from '@umbraco-cms/backoffice/current-user';
|
||||||
|
|
||||||
|
@customElement('umb-document-workspace-view-info')
|
||||||
|
export class UmbDocumentWorkspaceViewInfoElement extends UmbLitElement {
|
||||||
|
@state()
|
||||||
|
private _nodeName = '';
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private _documentTypeId = '';
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private _documentUnique = '';
|
||||||
|
|
||||||
|
private _workspaceContext?: typeof UMB_WORKSPACE_CONTEXT.TYPE;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private _editDocumentTypePath = '';
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private _urls?: Array<ContentUrlInfoModel>;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private _createDate = 'Unknown';
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL)
|
||||||
|
.addAdditionalPath('document-type')
|
||||||
|
.onSetup(() => {
|
||||||
|
return { data: { entityType: 'document-type', preset: {} } };
|
||||||
|
})
|
||||||
|
.observeRouteBuilder((routeBuilder) => {
|
||||||
|
this._editDocumentTypePath = routeBuilder({});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.consumeContext(UMB_WORKSPACE_CONTEXT, (nodeContext) => {
|
||||||
|
this._workspaceContext = nodeContext;
|
||||||
|
this._observeContent();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _observeContent() {
|
||||||
|
if (!this._workspaceContext) return;
|
||||||
|
|
||||||
|
this._nodeName = 'TBD, with variants this is not as simple.';
|
||||||
|
|
||||||
|
this._documentTypeId = (this._workspaceContext as UmbDocumentWorkspaceContext).getContentTypeId()!;
|
||||||
|
|
||||||
|
this.observe((this._workspaceContext as UmbDocumentWorkspaceContext).urls, (urls) => {
|
||||||
|
this._urls = urls;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.observe((this._workspaceContext as UmbDocumentWorkspaceContext).unique, (unique) => {
|
||||||
|
this._documentUnique = unique!;
|
||||||
|
});
|
||||||
|
|
||||||
|
/** TODO: Doubt this is the right way to get the create date... */
|
||||||
|
this.observe((this._workspaceContext as UmbDocumentWorkspaceContext).variants, (variants) => {
|
||||||
|
this._createDate = Array.isArray(variants) ? variants[0].createDate : 'Unknown';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`<div class="container">
|
||||||
|
<uui-box headline=${this.localize.term('general_links')} style="--uui-box-default-padding: 0;">
|
||||||
|
<div id="link-section">${this.#renderLinksSection()}</div>
|
||||||
|
</uui-box>
|
||||||
|
|
||||||
|
<umb-document-workspace-view-info-reference
|
||||||
|
.documentUnique=${this._documentUnique}></umb-document-workspace-view-info-reference>
|
||||||
|
|
||||||
|
<umb-document-workspace-view-info-history
|
||||||
|
.documentUnique=${this._documentUnique}></umb-document-workspace-view-info-history>
|
||||||
|
</div>
|
||||||
|
<div class="container">
|
||||||
|
<uui-box headline="General" id="general-section">${this.#renderGeneralSection()}</uui-box>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
#renderLinksSection() {
|
||||||
|
/** TODO Make sure link section is completed */
|
||||||
|
if (this._urls && this._urls.length) {
|
||||||
|
return html`
|
||||||
|
${repeat(
|
||||||
|
this._urls,
|
||||||
|
(url) => url.culture,
|
||||||
|
(url) => html`
|
||||||
|
<a href=${url.url} target="_blank" class="link-item with-href">
|
||||||
|
<span class="link-language">${url.culture}</span>
|
||||||
|
<span class="link-content"> ${url.url}</span>
|
||||||
|
<uui-icon name="icon-out"></uui-icon>
|
||||||
|
</a>
|
||||||
|
`,
|
||||||
|
)}
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
return html`<div class="link-item">
|
||||||
|
<span class="link-language">en-EN</span>
|
||||||
|
<span class="link-content italic"><umb-localize key="content_parentNotPublishedAnomaly"></umb-localize></span>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#renderGeneralSection() {
|
||||||
|
return html`
|
||||||
|
<div class="general-item">
|
||||||
|
<strong>${this.localize.term('content_publishStatus')}</strong>
|
||||||
|
<span>
|
||||||
|
<uui-tag color="positive" look="primary" label=${this.localize.term('content_published')}>
|
||||||
|
<umb-localize key="content_published"></umb-localize>
|
||||||
|
</uui-tag>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="general-item">
|
||||||
|
<strong><umb-localize key="content_createDate"></umb-localize></strong>
|
||||||
|
<span>
|
||||||
|
<umb-localize-date .date=${this._createDate} .options=${TimeOptions}></umb-localize-date>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="general-item">
|
||||||
|
<strong><umb-localize key="content_documentType"></umb-localize></strong>
|
||||||
|
<uui-button
|
||||||
|
look="secondary"
|
||||||
|
href=${this._editDocumentTypePath + 'edit/' + this._documentTypeId}
|
||||||
|
label=${this.localize.term('general_edit')}></uui-button>
|
||||||
|
</div>
|
||||||
|
<div class="general-item">
|
||||||
|
<strong><umb-localize key="template_template"></umb-localize></strong>
|
||||||
|
<uui-button look="secondary" label="Template picker TODO"></uui-button>
|
||||||
|
</div>
|
||||||
|
<div class="general-item">
|
||||||
|
<strong><umb-localize key="template_id"></umb-localize></strong>
|
||||||
|
<span>${this._documentTypeId}</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = [
|
||||||
|
UmbTextStyles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
display: grid;
|
||||||
|
gap: var(--uui-size-layout-1);
|
||||||
|
padding: var(--uui-size-layout-1);
|
||||||
|
grid-template-columns: 1fr 350px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--uui-size-layout-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//General section
|
||||||
|
|
||||||
|
#general-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.general-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--uui-size-space-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.general-item:not(:last-child) {
|
||||||
|
margin-bottom: var(--uui-size-space-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link section
|
||||||
|
|
||||||
|
#link-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-item {
|
||||||
|
padding: var(--uui-size-space-4) var(--uui-size-space-6);
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr auto;
|
||||||
|
gap: var(--uui-size-6);
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-language {
|
||||||
|
color: var(--uui-color-divider-emphasis);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-content.italic {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-item uui-icon {
|
||||||
|
margin-right: var(--uui-size-space-2);
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-item.with-href {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-item.with-href:hover {
|
||||||
|
background: var(--uui-color-divider);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UmbDocumentWorkspaceViewInfoElement;
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'umb-document-workspace-view-info': UmbDocumentWorkspaceViewInfoElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import './document-info-workspace-view.element.js';
|
import './document-workspace-view-info.element.js';
|
||||||
|
|
||||||
import { Meta, Story } from '@storybook/web-components';
|
import { Meta, Story } from '@storybook/web-components';
|
||||||
import type { UmbDocumentInfoWorkspaceViewElement } from './document-info-workspace-view.element.js';
|
import type { UmbDocumentWorkspaceViewInfoElement } from './document-workspace-view-info.element.js';
|
||||||
import { html } from '@umbraco-cms/backoffice/external/lit';
|
import { html } from '@umbraco-cms/backoffice/external/lit';
|
||||||
|
|
||||||
// import { data } from '../../../../../../core/mocks/data/document.data.js';
|
// import { data } from '../../../../../../core/mocks/data/document.data.js';
|
||||||
@@ -9,8 +9,8 @@ import { html } from '@umbraco-cms/backoffice/external/lit';
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: 'Workspaces/Documents/Views/Info',
|
title: 'Workspaces/Documents/Views/Info',
|
||||||
component: 'umb-document-info-workspace-view',
|
component: 'umb-document-workspace-view-info',
|
||||||
id: 'umb-document-info-workspace-view',
|
id: 'umb-document-workspace-view-info',
|
||||||
decorators: [
|
decorators: [
|
||||||
(story) => {
|
(story) => {
|
||||||
return html`TODO: make use of mocked workspace context??`;
|
return html`TODO: make use of mocked workspace context??`;
|
||||||
@@ -21,6 +21,6 @@ export default {
|
|||||||
],
|
],
|
||||||
} as Meta;
|
} as Meta;
|
||||||
|
|
||||||
export const AAAOverview: Story<UmbDocumentInfoWorkspaceViewElement> = () =>
|
export const AAAOverview: Story<UmbDocumentWorkspaceViewInfoElement> = () =>
|
||||||
html` <umb-document-info-workspace-view></umb-document-info-workspace-view>`;
|
html` <umb-document-workspace-view-info></umb-document-workspace-view-info>`;
|
||||||
AAAOverview.storyName = 'Overview';
|
AAAOverview.storyName = 'Overview';
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
import { AuditTypeModel } from '@umbraco-cms/backoffice/backend-api';
|
||||||
|
|
||||||
|
interface HistoryStyleMap {
|
||||||
|
look: 'default' | 'primary' | 'secondary' | 'outline' | 'placeholder';
|
||||||
|
color: 'default' | 'danger' | 'warning' | 'positive';
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HistoryLocalizeKeys {
|
||||||
|
label: string;
|
||||||
|
desc: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HistoryData {
|
||||||
|
style: HistoryStyleMap;
|
||||||
|
text: HistoryLocalizeKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return label, color, look, desc
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Helper function to get look and color for uui-tag and localization keys for the label and description.
|
||||||
|
* @param type AuditTypeModel
|
||||||
|
* @returns {HistoricData}
|
||||||
|
*/
|
||||||
|
export function HistoryTagStyleAndText(type: AuditTypeModel): HistoryData {
|
||||||
|
switch (type) {
|
||||||
|
case AuditTypeModel.SAVE:
|
||||||
|
return {
|
||||||
|
style: { look: 'primary', color: 'default' },
|
||||||
|
text: { label: 'auditTrails_smallSave', desc: 'auditTrails_save' },
|
||||||
|
};
|
||||||
|
|
||||||
|
case AuditTypeModel.PUBLISH:
|
||||||
|
return {
|
||||||
|
style: { look: 'primary', color: 'positive' },
|
||||||
|
text: { label: 'content_publish', desc: 'auditTrails_publish' },
|
||||||
|
};
|
||||||
|
|
||||||
|
case AuditTypeModel.UNPUBLISH:
|
||||||
|
return {
|
||||||
|
style: { look: 'primary', color: 'warning' },
|
||||||
|
text: { label: 'content_unpublish', desc: 'auditTrails_unpublish' },
|
||||||
|
};
|
||||||
|
|
||||||
|
case AuditTypeModel.CONTENT_VERSION_ENABLE_CLEANUP:
|
||||||
|
return {
|
||||||
|
style: { look: 'secondary', color: 'default' },
|
||||||
|
text: {
|
||||||
|
label: 'contentTypeEditor_historyCleanupEnableCleanup',
|
||||||
|
desc: 'auditTrails_contentversionenablecleanup',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
case AuditTypeModel.CONTENT_VERSION_PREVENT_CLEANUP:
|
||||||
|
return {
|
||||||
|
style: { look: 'secondary', color: 'default' },
|
||||||
|
text: {
|
||||||
|
label: 'contentTypeEditor_historyCleanupPreventCleanup',
|
||||||
|
desc: 'auditTrails_contentversionpreventcleanup',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
default:
|
||||||
|
return {
|
||||||
|
style: { look: 'placeholder', color: 'danger' },
|
||||||
|
text: { label: type, desc: 'TODO' },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TimeOptions: Intl.DateTimeFormatOptions = {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'long',
|
||||||
|
day: 'numeric',
|
||||||
|
hour: 'numeric',
|
||||||
|
minute: 'numeric',
|
||||||
|
second: 'numeric',
|
||||||
|
};
|
||||||
@@ -1 +1,3 @@
|
|||||||
import './media-type-input/media-type-input.element.js';
|
import './media-type-input/media-type-input.element.js';
|
||||||
|
|
||||||
|
export * from './media-type-input/media-type-input.element.js';
|
||||||
|
|||||||
@@ -12,3 +12,5 @@ export {
|
|||||||
UMB_MEDIA_TYPE_ENTITY_TYPE,
|
UMB_MEDIA_TYPE_ENTITY_TYPE,
|
||||||
UMB_MEDIA_TYPE_FOLDER_ENTITY_TYPE,
|
UMB_MEDIA_TYPE_FOLDER_ENTITY_TYPE,
|
||||||
} from './entity.js';
|
} from './entity.js';
|
||||||
|
|
||||||
|
export * from './components/index.js';
|
||||||
|
|||||||
@@ -101,9 +101,9 @@ export class UmbInputMediaElement extends FormControlMixin(UmbLitElement) {
|
|||||||
#renderButton() {
|
#renderButton() {
|
||||||
if (this._items && this.max && this._items.length >= this.max) return;
|
if (this._items && this.max && this._items.length >= this.max) return;
|
||||||
return html`
|
return html`
|
||||||
<uui-button id="add-button" look="placeholder" @click=${() => this.#pickerContext.openPicker()} label="open">
|
<uui-button id="add-button" look="placeholder" @click=${() => this.#pickerContext.openPicker()} label=${this.localize.term('general_choose')}>
|
||||||
<uui-icon name="icon-add"></uui-icon>
|
<uui-icon name="icon-add"></uui-icon>
|
||||||
Add
|
${this.localize.term('general_choose')}
|
||||||
</uui-button>
|
</uui-button>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { manifests as memberGroupManifests } from './member-groups/manifests.js'
|
|||||||
import { manifests as memberTypeManifests } from './member-types/manifests.js';
|
import { manifests as memberTypeManifests } from './member-types/manifests.js';
|
||||||
import { manifests as memberManifests } from './members/manifests.js';
|
import { manifests as memberManifests } from './members/manifests.js';
|
||||||
|
|
||||||
|
import './members/components/index.js';
|
||||||
|
|
||||||
export const manifests = [
|
export const manifests = [
|
||||||
...memberSectionManifests,
|
...memberSectionManifests,
|
||||||
...menuSectionManifests,
|
...menuSectionManifests,
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import './input-member-type/input-member-type.element.js';
|
||||||
|
|
||||||
|
export * from './input-member-type/input-member-type.element.js';
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { UMB_MEMBER_TYPE_PICKER_MODAL } from '../../../../core/modal/token/member-type-picker-modal.token.js';
|
||||||
|
import { UMB_MEMBER_TYPE_REPOSITORY_ALIAS } from '../../repository/index.js';
|
||||||
|
import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input';
|
||||||
|
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||||
|
import { MemberTypeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||||
|
|
||||||
|
export class UmbMemberTypePickerContext extends UmbPickerInputContext<MemberTypeItemResponseModel> {
|
||||||
|
constructor(host: UmbControllerHostElement) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
super(host, UMB_MEMBER_TYPE_REPOSITORY_ALIAS, UMB_MEMBER_TYPE_PICKER_MODAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
import { UmbMemberTypePickerContext } from './input-member-type.context.js';
|
||||||
|
import { css, html, customElement, property, state, ifDefined, repeat } from '@umbraco-cms/backoffice/external/lit';
|
||||||
|
import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui';
|
||||||
|
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||||
|
import type { MemberTypeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||||
|
import { splitStringToArray } from '@umbraco-cms/backoffice/utils';
|
||||||
|
|
||||||
|
@customElement('umb-input-member-type')
|
||||||
|
export class UmbMemberTypeInputElement 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 = splitStringToArray(idsString);
|
||||||
|
}
|
||||||
|
|
||||||
|
@property()
|
||||||
|
get pickableFilter() {
|
||||||
|
return this.#pickerContext.pickableFilter;
|
||||||
|
}
|
||||||
|
set pickableFilter(newVal) {
|
||||||
|
this.#pickerContext.pickableFilter = newVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private _items?: Array<MemberTypeItemResponseModel>;
|
||||||
|
|
||||||
|
#pickerContext = new UmbMemberTypePickerContext(this);
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
|
||||||
|
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 _openPicker() {
|
||||||
|
this.#pickerContext.openPicker({
|
||||||
|
hideTreeRoot: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getFormElement() {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
${this.#renderItems()}
|
||||||
|
${this.#renderAddButton()}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
#renderItems() {
|
||||||
|
if (!this._items) return;
|
||||||
|
// TODO: Add sorting. [LK]
|
||||||
|
return html`
|
||||||
|
<uui-ref-list
|
||||||
|
>${repeat(
|
||||||
|
this._items,
|
||||||
|
(item) => item.id,
|
||||||
|
(item) => this._renderItem(item),
|
||||||
|
)}</uui-ref-list
|
||||||
|
>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
#renderAddButton() {
|
||||||
|
if (this.max > 0 && this.selectedIds.length >= this.max) return;
|
||||||
|
return html`
|
||||||
|
<uui-button
|
||||||
|
id="add-button"
|
||||||
|
look="placeholder"
|
||||||
|
@click=${this._openPicker}
|
||||||
|
label="${this.localize.term('general_choose')}"
|
||||||
|
>${this.localize.term('general_choose')}</uui-button
|
||||||
|
>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _renderItem(item: MemberTypeItemResponseModel) {
|
||||||
|
if (!item.id) return;
|
||||||
|
return html`
|
||||||
|
<uui-ref-node-document-type name=${ifDefined(item.name)}>
|
||||||
|
<uui-action-bar slot="actions">
|
||||||
|
<uui-button
|
||||||
|
@click=${() => this.#pickerContext.requestRemoveItem(item.id!)}
|
||||||
|
label="Remove Member Type ${item.name}"
|
||||||
|
>${this.localize.term('general_remove')}</uui-button
|
||||||
|
>
|
||||||
|
</uui-action-bar>
|
||||||
|
</uui-ref-node-document-type>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = [
|
||||||
|
css`
|
||||||
|
#add-button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UmbMemberTypeInputElement;
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'umb-input-member-type': UmbMemberTypeInputElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import './components/index.js';
|
||||||
|
|
||||||
|
export * from './components/index.js';
|
||||||
|
export * from './repository/index.js';
|
||||||
|
export * from './entity.js';
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
|
import { manifests as entityActionsManifests } from './entity-actions/manifests.js';
|
||||||
import { manifests as menuItemManifests } from './menu-item/manifests.js';
|
import { manifests as menuItemManifests } from './menu-item/manifests.js';
|
||||||
import { manifests as treeManifests } from './tree/manifests.js';
|
|
||||||
import { manifests as repositoryManifests } from './repository/manifests.js';
|
import { manifests as repositoryManifests } from './repository/manifests.js';
|
||||||
|
import { manifests as treeManifests } from './tree/manifests.js';
|
||||||
import { manifests as workspaceManifests } from './workspace/manifests.js';
|
import { manifests as workspaceManifests } from './workspace/manifests.js';
|
||||||
import { manifests as entityActionManifests } from './entity-actions/manifests.js';
|
|
||||||
|
import './components/index.js';
|
||||||
|
|
||||||
export const manifests = [
|
export const manifests = [
|
||||||
|
...entityActionsManifests,
|
||||||
...menuItemManifests,
|
...menuItemManifests,
|
||||||
...treeManifests,
|
|
||||||
...repositoryManifests,
|
...repositoryManifests,
|
||||||
|
...treeManifests,
|
||||||
...workspaceManifests,
|
...workspaceManifests,
|
||||||
...entityActionManifests,
|
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
export { UmbMemberTypeRepository } from './member-type.repository.js';
|
export * from './member-type.repository.js';
|
||||||
|
export * from './manifests.js';
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user