From d0c5945f8f7a85effb2f7b485dc9ac62f1407c20 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 6 Mar 2023 12:50:00 +0000 Subject: [PATCH 001/156] Super rough work in progress - Currently trying to see how the JSON schema would look like by writing it hand before attempting to then write a script to help write the same JSON to a file by looping over types --- .../utils/json-schema/manual-schema.json | 75 +++++++++++++++++++ .../utils/json-schema/schema-generator.js | 4 + .../utils/json-schema/test-package.json | 17 +++++ 3 files changed, 96 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/utils/json-schema/manual-schema.json create mode 100644 src/Umbraco.Web.UI.Client/utils/json-schema/schema-generator.js create mode 100644 src/Umbraco.Web.UI.Client/utils/json-schema/test-package.json diff --git a/src/Umbraco.Web.UI.Client/utils/json-schema/manual-schema.json b/src/Umbraco.Web.UI.Client/utils/json-schema/manual-schema.json new file mode 100644 index 0000000000..fbbec668e3 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/utils/json-schema/manual-schema.json @@ -0,0 +1,75 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Umbraco Package", + "description": "JSON schema for creating an Umbraco pacakge with different manifest types", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the package" + }, + "version": { + "type": "string", + "description": "The version of the package" + }, + "extensions": { + "type": "array", + "description": "The extensions that are part of the package", + "minItems": 1, + "items": { + "type": "object", + "oneOf": [ + { "$ref": "#/definitions/rootManifest" } + ] + } + } + }, + "required": [ + "name", + "version", + "extensions" + ], + "additionalProperties": false, + "definitions": { + "manifesTypes":{ + "enum": [ + "collectionView", + "dashboardCollection", + "dashboard" + ] + }, + "rootManifest": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the extension" + }, + "alias": { + "type": "string", + "description": "The alias of the extension" + }, + "weight": { + "type": "integer", + "description": "The weight of the extension" + }, + "type": { + "$ref": "#/definitions/manifesTypes" + }, + "js": { + "type": "string", + "description": "The path to the javascript file" + }, + "elementName": { + "type": "string", + "description": "The name of the HTML web component element" + }, + "meta": { + "type": "object", + "description": "NOTE: This object & properties change depending on the ENUM type of extension" + } + }, + "required": [ "name", "alias", "type", "js" ] + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/utils/json-schema/schema-generator.js b/src/Umbraco.Web.UI.Client/utils/json-schema/schema-generator.js new file mode 100644 index 0000000000..b016f64ca5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/utils/json-schema/schema-generator.js @@ -0,0 +1,4 @@ +// TODO: Based on the manual schema as a guide +// Automate generation of the schema from looping over +// The types and properties found at /libs/extensions-registry/*.models.ts + diff --git a/src/Umbraco.Web.UI.Client/utils/json-schema/test-package.json b/src/Umbraco.Web.UI.Client/utils/json-schema/test-package.json new file mode 100644 index 0000000000..af6956c3af --- /dev/null +++ b/src/Umbraco.Web.UI.Client/utils/json-schema/test-package.json @@ -0,0 +1,17 @@ +{ + "$schema": "manual-schema.json", + "name": "My Package", + "version": "1.0.0", + "extensions": [ + { + "name": "My Extension", + "alias": "myextension", + "js": "myextension.js", + "type": "dashboard", + "weight": 10, + "meta": { + + } + } + ] +} \ No newline at end of file From afd7c78aa4cd2cdcc80df718d6ec11f17b88690e Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Mon, 6 Mar 2023 15:31:46 +0100 Subject: [PATCH 002/156] move ClassConstructor to avoid importing from another library --- .../libs/extensions-registry/models.ts | 3 ++- .../libs/extensions-registry/tree.models.ts | 3 +-- .../libs/extensions-registry/workspace-action.models.ts | 6 ++---- src/Umbraco.Web.UI.Client/libs/models/index.ts | 2 -- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts index 4e9bd27adf..4d6afd1b54 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts @@ -22,7 +22,6 @@ import type { ManifestWorkspaceAction } from './workspace-action.models'; import type { ManifestWorkspaceView } from './workspace-view.models'; import type { ManifestWorkspaceViewCollection } from './workspace-view-collection.models'; import type { ManifestRepository } from './repository.models'; -import type { ClassConstructor } from '@umbraco-cms/models'; export * from './collection-view.models'; export * from './dashboard-collection.models'; @@ -140,6 +139,8 @@ export interface ManifestWithMeta extends ManifestBase { meta: unknown; } +export type ClassConstructor = new (...args: any[]) => T; + export interface ManifestEntrypoint extends ManifestBase { type: 'entrypoint'; js: string; diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/tree.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/tree.models.ts index b0f83e99f7..a4576d7298 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/tree.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/tree.models.ts @@ -1,5 +1,4 @@ -import type { ManifestBase } from './models'; -import type { ClassConstructor } from '@umbraco-cms/models'; +import type { ClassConstructor, ManifestBase } from './models'; export interface ManifestTree extends ManifestBase { type: 'tree'; diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/workspace-action.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/workspace-action.models.ts index b18c358d5f..209e982f1d 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/workspace-action.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/workspace-action.models.ts @@ -1,7 +1,5 @@ import type { InterfaceColor, InterfaceLook } from '@umbraco-ui/uui-base/lib/types/index'; -import type { ManifestElement } from './models'; -import { UmbWorkspaceAction } from '@umbraco-cms/workspace'; -import type { ClassConstructor } from '@umbraco-cms/models'; +import type { ClassConstructor, ManifestElement } from './models'; export interface ManifestWorkspaceAction extends ManifestElement { type: 'workspaceAction'; @@ -13,5 +11,5 @@ export interface MetaWorkspaceAction { label?: string; //TODO: Use or implement additional label-key look?: InterfaceLook; color?: InterfaceColor; - api: ClassConstructor; + api: ClassConstructor; } diff --git a/src/Umbraco.Web.UI.Client/libs/models/index.ts b/src/Umbraco.Web.UI.Client/libs/models/index.ts index 6a677de13d..54fc943724 100644 --- a/src/Umbraco.Web.UI.Client/libs/models/index.ts +++ b/src/Umbraco.Web.UI.Client/libs/models/index.ts @@ -13,8 +13,6 @@ export * from '@umbraco-cms/extensions-registry'; // eslint-disable-next-line @typescript-eslint/no-explicit-any export type HTMLElementConstructor = new (...args: any[]) => T; -export type ClassConstructor = new (...args: any[]) => T; - // Users // TODO: would the right name be Node? as entity is just something with a Key. But node is something in a content structure, aka. with hasChildren and parentKey. export interface Entity { From e7b29d80bdcfeec4232e62d6de28725763cc8770 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Mon, 6 Mar 2023 15:32:27 +0100 Subject: [PATCH 003/156] add output model for server extensions --- .../extensions-registry/umbraco-package.ts | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts new file mode 100644 index 0000000000..21fca69507 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts @@ -0,0 +1,62 @@ +import type { + ManifestCollectionView, + ManifestCustom, + ManifestDashboard, + ManifestDashboardCollection, + ManifestEntityAction, + ManifestEntityBulkAction, + ManifestEntrypoint, + ManifestExternalLoginProvider, + ManifestHeaderApp, + ManifestHealthCheck, + ManifestMenu, + ManifestMenuItem, + ManifestMenuSectionSidebarApp, + ManifestPackageView, + ManifestPropertyAction, + ManifestPropertyEditorModel, + ManifestPropertyEditorUI, + ManifestRepository, + ManifestSection, + ManifestSectionSidebarApp, + ManifestSectionView, + ManifestTheme, + ManifestUserDashboard, + ManifestWorkspace, + ManifestWorkspaceView, + ManifestWorkspaceViewCollection, +} from './models'; + +export type ManifestJSONTypes = + | ManifestCollectionView + | ManifestCustom + | ManifestDashboard + | ManifestDashboardCollection + | ManifestEntityAction + | ManifestEntityBulkAction + | ManifestEntrypoint + | ManifestExternalLoginProvider + | ManifestHeaderApp + | ManifestHealthCheck + | ManifestPackageView + | ManifestPropertyAction + | ManifestPropertyEditorModel + | ManifestPropertyEditorUI + | ManifestRepository + | ManifestSection + | ManifestSectionSidebarApp + | ManifestSectionView + | ManifestMenuSectionSidebarApp + | ManifestMenu + | ManifestMenuItem + | ManifestTheme + | ManifestUserDashboard + | ManifestWorkspace + | ManifestWorkspaceView + | ManifestWorkspaceViewCollection; + +export class UmbracoPackage { + name?: string; + version?: string; + extensions?: ManifestJSONTypes[]; +} From 22f285918652253a23a1536cd16181a20957cd29 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Mon, 6 Mar 2023 15:50:41 +0100 Subject: [PATCH 004/156] build json schema for extensions --- src/Umbraco.Web.UI.Client/package-lock.json | 380 ++++++++++++++++++++ src/Umbraco.Web.UI.Client/package.json | 4 +- 2 files changed, 383 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index 7979cc6c6e..d947b4afaa 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -71,6 +71,7 @@ "storybook": "^7.0.0-beta.59", "tiny-glob": "^0.2.9", "typescript": "^4.9.5", + "typescript-json-schema": "^0.55.0", "vite": "^4.1.4", "vite-plugin-static-copy": "^0.13.0", "vite-tsconfig-paths": "^4.0.5", @@ -1999,6 +2000,28 @@ "node": ">=0.1.90" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -5096,6 +5119,30 @@ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, "node_modules/@types/accepts": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz", @@ -7321,6 +7368,15 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/address": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", @@ -7532,6 +7588,12 @@ "node": ">=10" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -8875,6 +8937,12 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "node_modules/cross-fetch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", @@ -13834,6 +13902,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "node_modules/make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", @@ -14975,6 +15049,12 @@ "tslib": "^2.0.3" } }, + "node_modules/path-equal": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/path-equal/-/path-equal-1.2.5.tgz", + "integrity": "sha512-i73IctDr3F2W+bsOWDyyVm/lqsXO47aY9nsFZUjTT/aljSbkxHxxCoyZ9UUrM8jK0JVod+An+rl48RCsvWM+9g==", + "dev": true + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -16488,6 +16568,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-stable-stringify": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz", + "integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -17543,6 +17632,58 @@ "node": ">=6.10" } }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/ts-simple-type": { "version": "2.0.0-next.0", "resolved": "https://registry.npmjs.org/ts-simple-type/-/ts-simple-type-2.0.0-next.0.tgz", @@ -17698,6 +17839,64 @@ "node": ">=4.2.0" } }, + "node_modules/typescript-json-schema": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.55.0.tgz", + "integrity": "sha512-BXaivYecUdiXWWNiUqXgY6A9cMWerwmhtO+lQE7tDZGs7Mf38sORDeQZugfYOZOHPZ9ulsD+w0LWjFDOQoXcwg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/node": "^16.9.2", + "glob": "^7.1.7", + "path-equal": "^1.1.2", + "safe-stable-stringify": "^2.2.0", + "ts-node": "^10.9.1", + "typescript": "~4.8.2", + "yargs": "^17.1.1" + }, + "bin": { + "typescript-json-schema": "bin/typescript-json-schema" + } + }, + "node_modules/typescript-json-schema/node_modules/@types/node": { + "version": "16.18.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.14.tgz", + "integrity": "sha512-wvzClDGQXOCVNU4APPopC2KtMYukaF1MN/W3xAmslx22Z4/IF1/izDMekuyoUlwfnDHYCIZGaj7jMwnJKBTxKw==", + "dev": true + }, + "node_modules/typescript-json-schema/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typescript-json-schema/node_modules/typescript": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/typical": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", @@ -18017,6 +18216,12 @@ "integrity": "sha512-dsNgbLaTrd6l3MMxTtouOCFw4CBFc/3a+GgYA2YyrJvyQ1u6q4pcu3ktLoUZ/VN/Aw9WsauazbgsgdfVWgAKQg==", "dev": true }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "node_modules/v8-to-istanbul": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", @@ -18660,6 +18865,15 @@ "node": ">= 4.0.0" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -20018,6 +20232,27 @@ "dev": true, "optional": true }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } + } + }, "@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -22171,6 +22406,30 @@ "magic-string": "^0.27.0" } }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, "@types/accepts": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz", @@ -24177,6 +24436,12 @@ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, "address": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", @@ -24342,6 +24607,12 @@ "readable-stream": "^3.6.0" } }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -25346,6 +25617,12 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "cross-fetch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", @@ -29039,6 +29316,12 @@ "semver": "^6.0.0" } }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", @@ -29904,6 +30187,12 @@ "tslib": "^2.0.3" } }, + "path-equal": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/path-equal/-/path-equal-1.2.5.tgz", + "integrity": "sha512-i73IctDr3F2W+bsOWDyyVm/lqsXO47aY9nsFZUjTT/aljSbkxHxxCoyZ9UUrM8jK0JVod+An+rl48RCsvWM+9g==", + "dev": true + }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -30991,6 +31280,12 @@ "is-regex": "^1.1.4" } }, + "safe-stable-stringify": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz", + "integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==", + "dev": true + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -31848,6 +32143,35 @@ "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", "dev": true }, + "ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } + } + }, "ts-simple-type": { "version": "2.0.0-next.0", "resolved": "https://registry.npmjs.org/ts-simple-type/-/ts-simple-type-2.0.0-next.0.tgz", @@ -31959,6 +32283,50 @@ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true }, + "typescript-json-schema": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.55.0.tgz", + "integrity": "sha512-BXaivYecUdiXWWNiUqXgY6A9cMWerwmhtO+lQE7tDZGs7Mf38sORDeQZugfYOZOHPZ9ulsD+w0LWjFDOQoXcwg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@types/node": "^16.9.2", + "glob": "^7.1.7", + "path-equal": "^1.1.2", + "safe-stable-stringify": "^2.2.0", + "ts-node": "^10.9.1", + "typescript": "~4.8.2", + "yargs": "^17.1.1" + }, + "dependencies": { + "@types/node": { + "version": "16.18.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.14.tgz", + "integrity": "sha512-wvzClDGQXOCVNU4APPopC2KtMYukaF1MN/W3xAmslx22Z4/IF1/izDMekuyoUlwfnDHYCIZGaj7jMwnJKBTxKw==", + "dev": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "typescript": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "dev": true + } + } + }, "typical": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", @@ -32188,6 +32556,12 @@ "integrity": "sha512-dsNgbLaTrd6l3MMxTtouOCFw4CBFc/3a+GgYA2YyrJvyQ1u6q4pcu3ktLoUZ/VN/Aw9WsauazbgsgdfVWgAKQg==", "dev": true }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "v8-to-istanbul": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", @@ -32653,6 +33027,12 @@ "integrity": "sha512-RXRJzMiK6U2ye0BlGGZnmpwJDPgakn6aNQ0A7gHRbD4I0uvK4TW6UqkK1V0pp9jskjJBAXd3dRrbzWkqJ+6cxA==", "dev": true }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 16befe9624..e230d7ba33 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -29,7 +29,7 @@ "dev": "vite", "build": "tsc && vite build --mode staging", "build:for:static": "tsc && vite build", - "build:for:cms": "tsc && vite build -c vite.cms.config.ts && node utils/build-libs.js", + "build:for:cms": "tsc && npm run generate:extensions:json && vite build -c vite.cms.config.ts && node utils/build-libs.js", "build:for:cms:watch": "vite build -c vite.cms.config.ts --watch", "preview": "vite preview --open", "test": "web-test-runner --coverage", @@ -43,6 +43,7 @@ "format:fix": "npm run format -- --write", "generate:api": "openapi --input https://raw.githubusercontent.com/umbraco/Umbraco-CMS/v13/dev/src/Umbraco.Cms.Api.Management/OpenApi.json --output libs/backend-api/src --postfix Resource --useOptions", "generate:api-dev": "openapi --input http://localhost:11000/umbraco/swagger/v1/swagger.json --output libs/backend-api/src --postfix Resource --useOptions", + "generate:extensions:json": "typescript-json-schema --out types/umbraco-package.schema.json libs/extensions-registry/umbraco-package.ts UmbracoPackage", "storybook": "npm run wc-analyze && storybook dev -p 6006", "storybook:build": "npm run wc-analyze && storybook build", "build-storybook": "npm run wc-analyze && storybook build", @@ -119,6 +120,7 @@ "storybook": "^7.0.0-beta.59", "tiny-glob": "^0.2.9", "typescript": "^4.9.5", + "typescript-json-schema": "^0.55.0", "vite": "^4.1.4", "vite-plugin-static-copy": "^0.13.0", "vite-tsconfig-paths": "^4.0.5", From b9af436888ab08a4a3b6c56bf021ed500d251730 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Mon, 6 Mar 2023 15:52:14 +0100 Subject: [PATCH 005/156] rename the file to match schema pattern --- src/Umbraco.Web.UI.Client/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index e230d7ba33..4f3f80687c 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -43,7 +43,7 @@ "format:fix": "npm run format -- --write", "generate:api": "openapi --input https://raw.githubusercontent.com/umbraco/Umbraco-CMS/v13/dev/src/Umbraco.Cms.Api.Management/OpenApi.json --output libs/backend-api/src --postfix Resource --useOptions", "generate:api-dev": "openapi --input http://localhost:11000/umbraco/swagger/v1/swagger.json --output libs/backend-api/src --postfix Resource --useOptions", - "generate:extensions:json": "typescript-json-schema --out types/umbraco-package.schema.json libs/extensions-registry/umbraco-package.ts UmbracoPackage", + "generate:extensions:json": "typescript-json-schema --out types/umbraco-package-schema.json libs/extensions-registry/umbraco-package.ts UmbracoPackage", "storybook": "npm run wc-analyze && storybook dev -p 6006", "storybook:build": "npm run wc-analyze && storybook build", "build-storybook": "npm run wc-analyze && storybook build", From a35d4d19f3d6f3c1d079bb8e01d909d5e250d315 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Mon, 6 Mar 2023 15:53:26 +0100 Subject: [PATCH 006/156] update vite configs to copy JSON schema to executable --- src/Umbraco.Web.UI.Client/vite.cms.config.ts | 17 +++++++++-- src/Umbraco.Web.UI.Client/vite.config.ts | 30 +++++++++----------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/vite.cms.config.ts b/src/Umbraco.Web.UI.Client/vite.cms.config.ts index d9156ae368..286c7d237b 100644 --- a/src/Umbraco.Web.UI.Client/vite.cms.config.ts +++ b/src/Umbraco.Web.UI.Client/vite.cms.config.ts @@ -1,9 +1,9 @@ import { defineConfig } from 'vite'; +import { viteStaticCopy } from 'vite-plugin-static-copy'; -import config from './vite.config'; +import { plugins } from './vite.config'; export default defineConfig({ - ...config, build: { lib: { entry: 'src/app.ts', @@ -15,5 +15,16 @@ export default defineConfig({ sourcemap: true, }, base: '/umbraco/backoffice/', - mode: 'production' + mode: 'production', + plugins: [ + ...plugins, + viteStaticCopy({ + targets: [ + { + src: 'types/umbraco-package-schema.json', + dest: '../../../../Umbraco.Web.UI.New', + }, + ], + }), + ], }); diff --git a/src/Umbraco.Web.UI.Client/vite.config.ts b/src/Umbraco.Web.UI.Client/vite.config.ts index a9a8182fc9..28f834cc03 100644 --- a/src/Umbraco.Web.UI.Client/vite.config.ts +++ b/src/Umbraco.Web.UI.Client/vite.config.ts @@ -1,25 +1,23 @@ -import { defineConfig } from 'vite'; +import { defineConfig, PluginOption } from 'vite'; import { viteStaticCopy } from 'vite-plugin-static-copy'; import viteTSConfigPaths from 'vite-tsconfig-paths'; +export const plugins: PluginOption[] = [ + viteStaticCopy({ + targets: [ + { + src: 'public-assets/icons/*.js', + dest: 'icons', + }, + ], + }), + viteTSConfigPaths(), +]; + // https://vitejs.dev/config/ export default defineConfig({ build: { sourcemap: true, }, - plugins: [ - viteStaticCopy({ - targets: [ - { - src: 'public-assets/icons/*.js', - dest: 'icons', - }, - { - src: 'public-assets/App_Plugins/*.js', - dest: 'App_Plugins', - }, - ], - }), - viteTSConfigPaths(), - ], + plugins, }); From c0894eae2769a2258403df476f5a1fc12076e3b8 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 6 Mar 2023 15:45:41 +0000 Subject: [PATCH 007/156] Rename run script npm run generate:jsonschema --- src/Umbraco.Web.UI.Client/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 4f3f80687c..c7c92b75d7 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -29,7 +29,7 @@ "dev": "vite", "build": "tsc && vite build --mode staging", "build:for:static": "tsc && vite build", - "build:for:cms": "tsc && npm run generate:extensions:json && vite build -c vite.cms.config.ts && node utils/build-libs.js", + "build:for:cms": "tsc && npm run generate:jsonschema && vite build -c vite.cms.config.ts && node utils/build-libs.js", "build:for:cms:watch": "vite build -c vite.cms.config.ts --watch", "preview": "vite preview --open", "test": "web-test-runner --coverage", @@ -43,7 +43,7 @@ "format:fix": "npm run format -- --write", "generate:api": "openapi --input https://raw.githubusercontent.com/umbraco/Umbraco-CMS/v13/dev/src/Umbraco.Cms.Api.Management/OpenApi.json --output libs/backend-api/src --postfix Resource --useOptions", "generate:api-dev": "openapi --input http://localhost:11000/umbraco/swagger/v1/swagger.json --output libs/backend-api/src --postfix Resource --useOptions", - "generate:extensions:json": "typescript-json-schema --out types/umbraco-package-schema.json libs/extensions-registry/umbraco-package.ts UmbracoPackage", + "generate:jsonschema": "typescript-json-schema --out types/umbraco-package-schema.json libs/extensions-registry/umbraco-package.ts UmbracoPackage", "storybook": "npm run wc-analyze && storybook dev -p 6006", "storybook:build": "npm run wc-analyze && storybook build", "build-storybook": "npm run wc-analyze && storybook build", From d38802bb67575d47a054f226456757cb86d36d7e Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 6 Mar 2023 15:55:33 +0000 Subject: [PATCH 008/156] Update example JSON file to the generated JSON schema --- .../utils/json-schema/test-package.json | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/utils/json-schema/test-package.json b/src/Umbraco.Web.UI.Client/utils/json-schema/test-package.json index af6956c3af..238b59e8c4 100644 --- a/src/Umbraco.Web.UI.Client/utils/json-schema/test-package.json +++ b/src/Umbraco.Web.UI.Client/utils/json-schema/test-package.json @@ -1,17 +1,10 @@ { - "$schema": "manual-schema.json", + "$schema": "../../types/umbraco-package-schema.json", "name": "My Package", "version": "1.0.0", "extensions": [ { - "name": "My Extension", - "alias": "myextension", - "js": "myextension.js", - "type": "dashboard", - "weight": 10, - "meta": { - - } + } ] } \ No newline at end of file From 217321d47ce4fa5c6d06c66712b5b2d91e5fdb92 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 6 Mar 2023 15:55:58 +0000 Subject: [PATCH 009/156] Start using JSDoc annotations to see what works Alot of source code diving here... --- .../libs/extensions-registry/umbraco-package.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts index 21fca69507..6dc74e4770 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts @@ -55,8 +55,24 @@ export type ManifestJSONTypes = | ManifestWorkspaceView | ManifestWorkspaceViewCollection; +/** + * Umbraco package manifest JSON + * @additionalProperties false + */ export class UmbracoPackage { + + /** + * @title The name of the Umbraco package + */ name?: string; + + /** + * @title The version of the Umbraco package + */ version?: string; + + /** + * @title An array of Umbraco package manifest types that will be installed + */ extensions?: ManifestJSONTypes[]; } From 2d970e8502933798e1beeaea5491224bad548929 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 6 Mar 2023 16:02:46 +0000 Subject: [PATCH 010/156] Ignore loader property from the base ManifestWithLoader --- src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts index 4d6afd1b54..bd64541bac 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts @@ -93,6 +93,10 @@ export interface ManifestBase { } export interface ManifestWithLoader extends ManifestBase { + /** + * Ignore this property when serializing to JSON Schema + * @ignore + */ loader?: () => Promise; } From fe77628aa3ec6f2bee6426e2cce34afe13f61c74 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 6 Mar 2023 20:25:25 +0000 Subject: [PATCH 011/156] Removed as too strict Was complaining that $schema property was invalid due to the additionalProperties flag --- .../libs/extensions-registry/umbraco-package.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts index 6dc74e4770..824de5e2ad 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts @@ -57,7 +57,6 @@ export type ManifestJSONTypes = /** * Umbraco package manifest JSON - * @additionalProperties false */ export class UmbracoPackage { From 1b8ea9586ea6b084b10a2a9dbd4cfb76d2a01b1f Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 6 Mar 2023 20:25:39 +0000 Subject: [PATCH 012/156] Remove unused files --- .../utils/json-schema/manual-schema.json | 75 ------------------- .../utils/json-schema/schema-generator.js | 4 - 2 files changed, 79 deletions(-) delete mode 100644 src/Umbraco.Web.UI.Client/utils/json-schema/manual-schema.json delete mode 100644 src/Umbraco.Web.UI.Client/utils/json-schema/schema-generator.js diff --git a/src/Umbraco.Web.UI.Client/utils/json-schema/manual-schema.json b/src/Umbraco.Web.UI.Client/utils/json-schema/manual-schema.json deleted file mode 100644 index fbbec668e3..0000000000 --- a/src/Umbraco.Web.UI.Client/utils/json-schema/manual-schema.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "Umbraco Package", - "description": "JSON schema for creating an Umbraco pacakge with different manifest types", - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the package" - }, - "version": { - "type": "string", - "description": "The version of the package" - }, - "extensions": { - "type": "array", - "description": "The extensions that are part of the package", - "minItems": 1, - "items": { - "type": "object", - "oneOf": [ - { "$ref": "#/definitions/rootManifest" } - ] - } - } - }, - "required": [ - "name", - "version", - "extensions" - ], - "additionalProperties": false, - "definitions": { - "manifesTypes":{ - "enum": [ - "collectionView", - "dashboardCollection", - "dashboard" - ] - }, - "rootManifest": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the extension" - }, - "alias": { - "type": "string", - "description": "The alias of the extension" - }, - "weight": { - "type": "integer", - "description": "The weight of the extension" - }, - "type": { - "$ref": "#/definitions/manifesTypes" - }, - "js": { - "type": "string", - "description": "The path to the javascript file" - }, - "elementName": { - "type": "string", - "description": "The name of the HTML web component element" - }, - "meta": { - "type": "object", - "description": "NOTE: This object & properties change depending on the ENUM type of extension" - } - }, - "required": [ "name", "alias", "type", "js" ] - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/utils/json-schema/schema-generator.js b/src/Umbraco.Web.UI.Client/utils/json-schema/schema-generator.js deleted file mode 100644 index b016f64ca5..0000000000 --- a/src/Umbraco.Web.UI.Client/utils/json-schema/schema-generator.js +++ /dev/null @@ -1,4 +0,0 @@ -// TODO: Based on the manual schema as a guide -// Automate generation of the schema from looping over -// The types and properties found at /libs/extensions-registry/*.models.ts - From b6d34a335f85484e4b1103a5121adb2b4598f3f7 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 6 Mar 2023 20:26:38 +0000 Subject: [PATCH 013/156] Dashboard - Add JSDoc for JSON Schema generation --- .../extensions-registry/dashboard.models.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/dashboard.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/dashboard.models.ts index 70bb0d379d..8cef6c0fff 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/dashboard.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/dashboard.models.ts @@ -6,7 +6,26 @@ export interface ManifestDashboard extends ManifestElement { } export interface MetaDashboard { + + /** + * A string array of section aliases to which this dashboard will appear such as + * 'Umb.Section.Content', 'Umb.Section.Settings', 'Umb.Section.Translation' + * + * @minItems 1 + * @uniqueItems true + */ sections: string[]; + + /** + * This is the URL path for the dashboard which is used for navigating or deep linking directly to the dashboard + * https://yoursite.com/section/settings/dashboard/my-dashboard-path + * + * @example 'my-dashboard-path' + */ pathname: string; + + /** + * The displayed name (label) for the tab of the dashboard + */ label?: string; } From c05ebb1c4e2839c703a898049e85479acfd55f73 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 6 Mar 2023 20:27:16 +0000 Subject: [PATCH 014/156] Update example file to ensure JSON schema is working as updating JSDocs --- .../utils/json-schema/test-package.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/utils/json-schema/test-package.json b/src/Umbraco.Web.UI.Client/utils/json-schema/test-package.json index 238b59e8c4..34edf0f9e9 100644 --- a/src/Umbraco.Web.UI.Client/utils/json-schema/test-package.json +++ b/src/Umbraco.Web.UI.Client/utils/json-schema/test-package.json @@ -4,7 +4,19 @@ "version": "1.0.0", "extensions": [ { + "name": "My Dashboard", + "alias": "myDashboard", + + "weight": -10, + "elementName": "my-dashboard", + "js": "js/my-dashboard.js", + "type": "dashboard", + "meta": { + "label": "My Dashboard", + "pathname": "my-dashboard", + "sections": ["Umb.Section.Content"] + } } ] } \ No newline at end of file From 80065c59de5d868ad52ae025d58ad1e8a6b51913 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 7 Mar 2023 11:37:18 +0000 Subject: [PATCH 015/156] More JSDoc comments for JSON Schema generation --- .../libs/extensions-registry/models.ts | 65 ++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts index bd64541bac..47bf776f89 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts @@ -86,25 +86,52 @@ export type ManifestTypeMap = { }; export interface ManifestBase { + + /** + * The type of extension such as dashboard etc... + */ type: string; + + /** + * The alias of the extension, ensure it is unique + */ alias: string; + + /** + * The friendly name of the extension + */ name: string; + + /** + * Extensions such as dashboards are ordered by weight with lower numbers being first in the list + */ weight?: number; } export interface ManifestWithLoader extends ManifestBase { /** * Ignore this property when serializing to JSON Schema + * found at /types/umbraco-package-schema.json * @ignore */ loader?: () => Promise; } export interface ManifestClass extends ManifestWithLoader { + /** + * The type of extension such as dashboard etc... + */ type: ManifestStandardTypes; + + /** + * The file location of the javascript file to load + */ js?: string; + className?: string; + class?: ClassConstructor; + //loader?: () => Promise; } @@ -113,10 +140,26 @@ export interface ManifestClassWithClassConstructor extends ManifestClass { } export interface ManifestElement extends ManifestWithLoader { + + /** + * The type of extension such as dashboard etc... + */ type: ManifestStandardTypes; + + /** + * The file location of the javascript file to load + */ js?: string; + + /** + * The HTML web component name to use such as 'my-dashboard' + * Note it is NOT but just the name + */ elementName?: string; - //loader?: () => Promise; + + /** + * This contains properties specific to the type of extension + */ meta?: unknown; } @@ -131,21 +174,41 @@ export interface MetaManifestWithView { } export interface ManifestElementWithElementName extends ManifestElement { + /** + * The HTML web component name to use such as 'my-dashboard' + * Note it is NOT but just the name + */ elementName: string; } export interface ManifestCustom extends ManifestBase { type: 'custom'; + + /** + * This contains properties specific to the type of extension + */ meta?: unknown; } export interface ManifestWithMeta extends ManifestBase { + /** + * This contains properties specific to the type of extension + */ meta: unknown; } export type ClassConstructor = new (...args: any[]) => T; +/** + * This type of extension gives full control and will simply load the specified JS file + * You could have custom logic to decide which extensions to load/register by using extensionRegistry + */ export interface ManifestEntrypoint extends ManifestBase { + type: 'entrypoint'; + + /** + * The file location of the javascript file to load in the backoffice + */ js: string; } From 8a167fe5a6d48cb5b2f5f671e81ad8030111f8eb Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 7 Mar 2023 12:08:39 +0000 Subject: [PATCH 016/156] JSDocs for JSON schmea for Theme Manifest --- .../libs/extensions-registry/theme.models.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/theme.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/theme.models.ts index ff2cdcb3f9..7618a21a31 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/theme.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/theme.models.ts @@ -1,8 +1,16 @@ import type { ManifestWithLoader } from "./models"; - // TODO: make or find type for JS Module with default export: Would be nice to support css file directly. + +/** + * Theme manifest for styling the backoffice of Umbraco such as dark, high contrast etc + */ export interface ManifestTheme extends ManifestWithLoader { type: 'theme'; + + /** + * File location of the CSS file of the theme + * @example 'themes/dark.theme.css' + */ css?: string; } From 76309b7732def762b84adb617738370134283b99 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 7 Mar 2023 12:23:58 +0000 Subject: [PATCH 017/156] User dashboard manifest However unsure the label & pathname are used at all? --- .../libs/extensions-registry/user-dashboard.models.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/user-dashboard.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/user-dashboard.models.ts index a9fd823c55..3262eed28d 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/user-dashboard.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/user-dashboard.models.ts @@ -1,5 +1,8 @@ import type { ManifestElement } from './models'; +/** + * A user dashboard extension is shown in the dialog that opens when the user clicks on the user avatar in the top right corner + */ export interface ManifestUserDashboard extends ManifestElement { type: 'userDashboard'; meta: MetaUserDashboard; From 5625a8c30dc91b9792a63312eda1eecfe465d283 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 7 Mar 2023 12:30:30 +0000 Subject: [PATCH 018/156] Remove unused meta properties for UserDashboard manifest interface https://umbraco.slack.com/archives/C04RZVARL81/p1678191653191159 --- .../libs/extensions-registry/user-dashboard.models.ts | 5 ----- .../src/backoffice/users/current-user/manifests.ts | 4 ---- 2 files changed, 9 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/user-dashboard.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/user-dashboard.models.ts index 3262eed28d..23f6acf325 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/user-dashboard.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/user-dashboard.models.ts @@ -5,10 +5,5 @@ import type { ManifestElement } from './models'; */ export interface ManifestUserDashboard extends ManifestElement { type: 'userDashboard'; - meta: MetaUserDashboard; } -export interface MetaUserDashboard { - label: string; - pathname: string; -} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/users/current-user/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/users/current-user/manifests.ts index 63d58c00a4..a76d311f4d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/users/current-user/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/users/current-user/manifests.ts @@ -7,10 +7,6 @@ export const userDashboards: Array = [ name: 'Themes User Dashboard', loader: () => import('./user-dashboard-themes.element'), weight: 1, - meta: { - label: 'Themes User Dashboard', - pathname: 'themes', - }, }, ]; From 91b65723ec6928ed5a77493645aa52a1bd317ed1 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 7 Mar 2023 13:56:18 +0000 Subject: [PATCH 019/156] Collection View JSDoc --- .../collection-view.models.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/collection-view.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/collection-view.models.ts index 7a5770e3fd..0f99af2f99 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/collection-view.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/collection-view.models.ts @@ -1,13 +1,35 @@ import type { ManifestElement } from './models'; +/** + * A collection view is a view that can be used to display a collection of entities. + * For example you may wish to display a collection of nodes as a table or grid of cards + */ export interface ManifestCollectionView extends ManifestElement { type: 'collectionView'; meta: MetaCollectionView; } export interface MetaCollectionView { + /** + * The friendly name of the collection view + */ label: string; + + /** + * An icon to represent the collection view + * @example 'umb:box' + * @example 'umb:grid' + */ icon: string; + + /** + * The entity type that this collection view is for + * @example 'media' + */ entityType: string; + + /** + * The URL pathname for this collection view that can be deep linked to by sharing the url + */ pathName: string; } From cda899958c0435d6f4eeb9afc24eab034dedd8e5 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 7 Mar 2023 14:17:52 +0000 Subject: [PATCH 020/156] Entity Action JSDocs for JSON schema --- .../entity-action.models.ts | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/entity-action.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/entity-action.models.ts index ddc7e5363b..7a0ae05f13 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/entity-action.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/entity-action.models.ts @@ -1,14 +1,43 @@ import type { ManifestElement } from './models'; +/** + * An action to perform on an entity + * For example for content you may wish to create a new document or move a document etc + */ export interface ManifestEntityAction extends ManifestElement { type: 'entityAction'; meta: MetaEntityAction; } export interface MetaEntityAction { + /** + * An icon to represent the action to be performed + * @example 'umb:box' + * @example 'umb:grid' + */ icon?: string; + + /** + * The friendly name of the action to perform + * @example 'Move' + * @example 'Create' + * @example 'Create Content Template' + */ label: string; + + /** + * The type of entity this action is for such as 'document' + * @example 'media' + * @example 'document' + */ entityType: string; - api: any; // create interface + + api: any; // TODO: create interface + + /** + * The alias for the repsoitory of the entity type this action is for + * such as 'Umb.Repository.Documents' + * @example 'Umb.Repository.Documents' + */ repositoryAlias: string; } From 5e9a12f2eb5f2b27d1bb540cdd57127e90fb6c83 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 7 Mar 2023 15:39:59 +0000 Subject: [PATCH 021/156] entity-bulk-action --- .../entity-action.models.ts | 3 +-- .../entity-bulk-action.models.ts | 21 ++++++++++++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/entity-action.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/entity-action.models.ts index 7a0ae05f13..55843a4114 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/entity-action.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/entity-action.models.ts @@ -2,7 +2,7 @@ import type { ManifestElement } from './models'; /** * An action to perform on an entity - * For example for content you may wish to create a new document or move a document etc + * For example for content you may wish to create a new document etc */ export interface ManifestEntityAction extends ManifestElement { type: 'entityAction'; @@ -19,7 +19,6 @@ export interface MetaEntityAction { /** * The friendly name of the action to perform - * @example 'Move' * @example 'Create' * @example 'Create Content Template' */ diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/entity-bulk-action.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/entity-bulk-action.models.ts index 51db3ce5fe..0c7bbd2fc1 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/entity-bulk-action.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/entity-bulk-action.models.ts @@ -1,13 +1,32 @@ import type { ManifestElement } from './models'; +/** + * An action to perform on multiple entities + * For example for content you may wish to move one or more documents in bulk + */ export interface ManifestEntityBulkAction extends ManifestElement { type: 'entityBulkAction'; meta: MetaEntityBulkAction; } export interface MetaEntityBulkAction { + /** + * + */ label: string; + + /** + * The friendly name of the action to perform + * @example 'Move' + */ entityType: string; - api: any; // create interface + + api: any; // TODO create interface + + /** + * The alias for the repsoitory of the entity type this action is for + * such as 'Umb.Repository.Documents' + * @example 'Umb.Repository.Documents' + */ repositoryAlias: string; } From 9fefde8ef7352aaeb84c9e3dddc0d84559d1d7fa Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 7 Mar 2023 21:23:14 +0000 Subject: [PATCH 022/156] JSDoc header app --- .../libs/extensions-registry/header-app.models.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/header-app.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/header-app.models.ts index 4a6f1d59d5..25c34b8907 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/header-app.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/header-app.models.ts @@ -1,10 +1,15 @@ import type { ManifestElement } from './models'; +/** + * Header apps are displayed in the top right corner of the backoffice + * The two provided header apps are the search and the user menu + */ export interface ManifestHeaderApp extends ManifestElement { type: 'headerApp'; meta: MetaHeaderApp; } +// TODO: Warren these don't seem to be used anywhere export interface MetaHeaderApp { pathname: string; label: string; From 60901982e31fdef2aa2fce204ac73a1e8f7fa826 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 9 Mar 2023 16:01:42 +0000 Subject: [PATCH 023/156] add --required parameter --- src/Umbraco.Web.UI.Client/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index c7c92b75d7..45704a09a5 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -43,7 +43,7 @@ "format:fix": "npm run format -- --write", "generate:api": "openapi --input https://raw.githubusercontent.com/umbraco/Umbraco-CMS/v13/dev/src/Umbraco.Cms.Api.Management/OpenApi.json --output libs/backend-api/src --postfix Resource --useOptions", "generate:api-dev": "openapi --input http://localhost:11000/umbraco/swagger/v1/swagger.json --output libs/backend-api/src --postfix Resource --useOptions", - "generate:jsonschema": "typescript-json-schema --out types/umbraco-package-schema.json libs/extensions-registry/umbraco-package.ts UmbracoPackage", + "generate:jsonschema": "typescript-json-schema --required --out types/umbraco-package-schema.json libs/extensions-registry/umbraco-package.ts UmbracoPackage", "storybook": "npm run wc-analyze && storybook dev -p 6006", "storybook:build": "npm run wc-analyze && storybook build", "build-storybook": "npm run wc-analyze && storybook build", From 7a588e7bc81630b8c431330e662fbaacd3da55b0 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 9 Mar 2023 16:02:03 +0000 Subject: [PATCH 024/156] export modified extensions list with more required attributes --- .../extensions-registry/umbraco-package.ts | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts index 824de5e2ad..cf3a7e7a77 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts @@ -1,12 +1,10 @@ import type { ManifestCollectionView, - ManifestCustom, ManifestDashboard, ManifestDashboardCollection, ManifestEntityAction, ManifestEntityBulkAction, ManifestEntrypoint, - ManifestExternalLoginProvider, ManifestHeaderApp, ManifestHealthCheck, ManifestMenu, @@ -29,13 +27,11 @@ import type { export type ManifestJSONTypes = | ManifestCollectionView - | ManifestCustom | ManifestDashboard | ManifestDashboardCollection | ManifestEntityAction | ManifestEntityBulkAction | ManifestEntrypoint - | ManifestExternalLoginProvider | ManifestHeaderApp | ManifestHealthCheck | ManifestPackageView @@ -55,11 +51,24 @@ export type ManifestJSONTypes = | ManifestWorkspaceView | ManifestWorkspaceViewCollection; +type LoadableManifestJSONTypes = ManifestJSONTypes & { + /** + * @title The file location of the javascript file to load + */ + js: string; + + /** + * @title The name of the exported custom element to use + * @description This is optional but useful if your module exports more than one custom element + * @example my-dashboard + */ + elementName?: string; +}; + /** * Umbraco package manifest JSON */ export class UmbracoPackage { - /** * @title The name of the Umbraco package */ @@ -70,8 +79,14 @@ export class UmbracoPackage { */ version?: string; + /** + * @title Decides if the package sends telemetry data for collection + * @default true + */ + allowTelemetry?: boolean; + /** * @title An array of Umbraco package manifest types that will be installed */ - extensions?: ManifestJSONTypes[]; + extensions?: LoadableManifestJSONTypes[]; } From 3e8ad07d5a87b0a7fd0ea760aa548faaf1be3891 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Fri, 10 Mar 2023 15:39:30 +0000 Subject: [PATCH 025/156] add example for version --- .../libs/extensions-registry/umbraco-package.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts index cf3a7e7a77..88d5d29604 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts @@ -75,7 +75,8 @@ export class UmbracoPackage { name?: string; /** - * @title The version of the Umbraco package + * @title The version of the Umbraco package in the style of semver + * @example 0.1.0 */ version?: string; From 956983f098e4b1d3c313b4df32ba664399fac642 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 14 Mar 2023 11:34:37 +0000 Subject: [PATCH 026/156] The joys of merge conflicts with package-lock.json - just rerun npm install --- src/Umbraco.Web.UI.Client/package-lock.json | 380 ++++++++++++++++++++ 1 file changed, 380 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index 45bc7cf754..185300282b 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -72,6 +72,7 @@ "storybook": "^7.0.0-rc.3", "tiny-glob": "^0.2.9", "typescript": "^4.9.5", + "typescript-json-schema": "^0.55.0", "vite": "^4.1.4", "vite-plugin-static-copy": "^0.13.0", "vite-tsconfig-paths": "^4.0.5", @@ -2000,6 +2001,28 @@ "node": ">=0.1.90" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -4761,6 +4784,30 @@ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, "node_modules/@types/accepts": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz", @@ -6970,6 +7017,15 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/address": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", @@ -7181,6 +7237,12 @@ "node": ">=10" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -8524,6 +8586,12 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "node_modules/cross-fetch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", @@ -13179,6 +13247,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "node_modules/make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", @@ -14320,6 +14394,12 @@ "tslib": "^2.0.3" } }, + "node_modules/path-equal": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/path-equal/-/path-equal-1.2.5.tgz", + "integrity": "sha512-i73IctDr3F2W+bsOWDyyVm/lqsXO47aY9nsFZUjTT/aljSbkxHxxCoyZ9UUrM8jK0JVod+An+rl48RCsvWM+9g==", + "dev": true + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -15867,6 +15947,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-stable-stringify": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz", + "integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -16922,6 +17011,58 @@ "node": ">=6.10" } }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/ts-simple-type": { "version": "2.0.0-next.0", "resolved": "https://registry.npmjs.org/ts-simple-type/-/ts-simple-type-2.0.0-next.0.tgz", @@ -17077,6 +17218,64 @@ "node": ">=4.2.0" } }, + "node_modules/typescript-json-schema": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.55.0.tgz", + "integrity": "sha512-BXaivYecUdiXWWNiUqXgY6A9cMWerwmhtO+lQE7tDZGs7Mf38sORDeQZugfYOZOHPZ9ulsD+w0LWjFDOQoXcwg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/node": "^16.9.2", + "glob": "^7.1.7", + "path-equal": "^1.1.2", + "safe-stable-stringify": "^2.2.0", + "ts-node": "^10.9.1", + "typescript": "~4.8.2", + "yargs": "^17.1.1" + }, + "bin": { + "typescript-json-schema": "bin/typescript-json-schema" + } + }, + "node_modules/typescript-json-schema/node_modules/@types/node": { + "version": "16.18.16", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.16.tgz", + "integrity": "sha512-ZOzvDRWp8dCVBmgnkIqYCArgdFOO9YzocZp8Ra25N/RStKiWvMOXHMz+GjSeVNe5TstaTmTWPucGJkDw0XXJWA==", + "dev": true + }, + "node_modules/typescript-json-schema/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typescript-json-schema/node_modules/typescript": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/typical": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", @@ -17396,6 +17595,12 @@ "integrity": "sha512-dsNgbLaTrd6l3MMxTtouOCFw4CBFc/3a+GgYA2YyrJvyQ1u6q4pcu3ktLoUZ/VN/Aw9WsauazbgsgdfVWgAKQg==", "dev": true }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "node_modules/v8-to-istanbul": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", @@ -18039,6 +18244,15 @@ "node": ">= 4.0.0" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -19397,6 +19611,27 @@ "dev": true, "optional": true }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } + } + }, "@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -21403,6 +21638,30 @@ "magic-string": "^0.27.0" } }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, "@types/accepts": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz", @@ -23402,6 +23661,12 @@ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, "address": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", @@ -23567,6 +23832,12 @@ "readable-stream": "^3.6.0" } }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -24571,6 +24842,12 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "cross-fetch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", @@ -28131,6 +28408,12 @@ "semver": "^6.0.0" } }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", @@ -28996,6 +29279,12 @@ "tslib": "^2.0.3" } }, + "path-equal": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/path-equal/-/path-equal-1.2.5.tgz", + "integrity": "sha512-i73IctDr3F2W+bsOWDyyVm/lqsXO47aY9nsFZUjTT/aljSbkxHxxCoyZ9UUrM8jK0JVod+An+rl48RCsvWM+9g==", + "dev": true + }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -30104,6 +30393,12 @@ "is-regex": "^1.1.4" } }, + "safe-stable-stringify": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz", + "integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==", + "dev": true + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -30961,6 +31256,35 @@ "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", "dev": true }, + "ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } + } + }, "ts-simple-type": { "version": "2.0.0-next.0", "resolved": "https://registry.npmjs.org/ts-simple-type/-/ts-simple-type-2.0.0-next.0.tgz", @@ -31072,6 +31396,50 @@ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true }, + "typescript-json-schema": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.55.0.tgz", + "integrity": "sha512-BXaivYecUdiXWWNiUqXgY6A9cMWerwmhtO+lQE7tDZGs7Mf38sORDeQZugfYOZOHPZ9ulsD+w0LWjFDOQoXcwg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@types/node": "^16.9.2", + "glob": "^7.1.7", + "path-equal": "^1.1.2", + "safe-stable-stringify": "^2.2.0", + "ts-node": "^10.9.1", + "typescript": "~4.8.2", + "yargs": "^17.1.1" + }, + "dependencies": { + "@types/node": { + "version": "16.18.16", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.16.tgz", + "integrity": "sha512-ZOzvDRWp8dCVBmgnkIqYCArgdFOO9YzocZp8Ra25N/RStKiWvMOXHMz+GjSeVNe5TstaTmTWPucGJkDw0XXJWA==", + "dev": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "typescript": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "dev": true + } + } + }, "typical": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", @@ -31301,6 +31669,12 @@ "integrity": "sha512-dsNgbLaTrd6l3MMxTtouOCFw4CBFc/3a+GgYA2YyrJvyQ1u6q4pcu3ktLoUZ/VN/Aw9WsauazbgsgdfVWgAKQg==", "dev": true }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "v8-to-istanbul": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", @@ -31766,6 +32140,12 @@ "integrity": "sha512-RXRJzMiK6U2ye0BlGGZnmpwJDPgakn6aNQ0A7gHRbD4I0uvK4TW6UqkK1V0pp9jskjJBAXd3dRrbzWkqJ+6cxA==", "dev": true }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", From 2a98c8576f0dbde69b3bfb5b4a105fe25b9d1166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 12 Apr 2023 09:35:05 +0200 Subject: [PATCH 027/156] fix import --- .../router/generate-route-path-builder.function.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/libs/router/generate-route-path-builder.function.ts diff --git a/src/Umbraco.Web.UI.Client/libs/router/generate-route-path-builder.function.ts b/src/Umbraco.Web.UI.Client/libs/router/generate-route-path-builder.function.ts new file mode 100644 index 0000000000..5b2e92b10d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/router/generate-route-path-builder.function.ts @@ -0,0 +1,12 @@ +import { stripSlash } from 'router-slot/util'; + +const PARAM_IDENTIFIER = /:([^\\/]+)/g; + +export function generateRoutePathBuilder(path: string) { + return (params: { [key: string]: string | number }) => + stripSlash( + path.replace(PARAM_IDENTIFIER, (substring: string, ...args: string[]) => { + return params[args[0]].toString(); + }) + ); +} From 5b4f61fc5bec4a6cb10fcaf70f554c036926f96e Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Wed, 12 Apr 2023 11:22:01 +0200 Subject: [PATCH 028/156] use all manifest types --- .../extensions-registry/umbraco-package.ts | 65 +------------------ 1 file changed, 2 insertions(+), 63 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts index 766226d672..85e0f1572d 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts @@ -1,65 +1,4 @@ -import type { - ManifestCollectionView, - ManifestDashboard, - ManifestDashboardCollection, - ManifestEntityAction, - ManifestEntityBulkAction, - ManifestEntrypoint, - ManifestHeaderApp, - ManifestHealthCheck, - ManifestMenu, - ManifestMenuItem, - ManifestPackageView, - ManifestPropertyAction, - ManifestPropertyEditorModel, - ManifestPropertyEditorUI, - ManifestRepository, - ManifestSection, - ManifestSectionSidebarApp, - ManifestSectionView, - ManifestTheme, - ManifestWorkspace, - ManifestWorkspaceView, - ManifestWorkspaceViewCollection, -} from './models'; - -export type ManifestJSONTypes = - | ManifestCollectionView - | ManifestDashboard - | ManifestDashboardCollection - | ManifestEntityAction - | ManifestEntityBulkAction - | ManifestEntrypoint - | ManifestHeaderApp - | ManifestHealthCheck - | ManifestPackageView - | ManifestPropertyAction - | ManifestPropertyEditorModel - | ManifestPropertyEditorUI - | ManifestRepository - | ManifestSection - | ManifestSectionSidebarApp - | ManifestSectionView - | ManifestMenu - | ManifestMenuItem - | ManifestTheme - | ManifestWorkspace - | ManifestWorkspaceView - | ManifestWorkspaceViewCollection; - -type LoadableManifestJSONTypes = ManifestJSONTypes & { - /** - * @title The file location of the javascript file to load - */ - js: string; - - /** - * @title The name of the exported custom element to use - * @description This is optional but useful if your module exports more than one custom element - * @example my-dashboard - */ - elementName?: string; -}; +import type { ManifestTypes } from './models'; /** * Umbraco package manifest JSON @@ -85,5 +24,5 @@ export class UmbracoPackage { /** * @title An array of Umbraco package manifest types that will be installed */ - extensions?: LoadableManifestJSONTypes[]; + extensions?: ManifestTypes[]; } From b5a14152209dcf0a9b3f13bf93d265f64224cb3c Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Wed, 12 Apr 2023 11:22:16 +0200 Subject: [PATCH 029/156] export everything from router --- src/Umbraco.Web.UI.Client/libs/router/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/libs/router/index.ts b/src/Umbraco.Web.UI.Client/libs/router/index.ts index 537b3d396d..ddd7e637cb 100644 --- a/src/Umbraco.Web.UI.Client/libs/router/index.ts +++ b/src/Umbraco.Web.UI.Client/libs/router/index.ts @@ -1,4 +1,4 @@ -export type * from 'router-slot/model'; +export * from 'router-slot/model'; export * from 'router-slot/util'; export * from './route-location.interface'; export * from './route.context'; From b7b8024a6a54f4e4bdf9fbd86e80ad72e4d55cd1 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Wed, 12 Apr 2023 11:22:27 +0200 Subject: [PATCH 030/156] use type File instead of Blob (ts error) --- .../input-upload-field/input-upload-field.element.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-upload-field/input-upload-field.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-upload-field/input-upload-field.element.ts index a5237a876d..f4727f6792 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-upload-field/input-upload-field.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-upload-field/input-upload-field.element.ts @@ -64,10 +64,10 @@ export class UmbInputUploadFieldElement extends FormControlMixin(UmbLitElement) multiple = false; @state() - _currentFiles: Blob[] = []; + _currentFiles: File[] = []; @state() - _currentFilesTemp?: Blob[]; + _currentFilesTemp?: File[]; @state() extensions?: string[]; @@ -114,12 +114,12 @@ export class UmbInputUploadFieldElement extends FormControlMixin(UmbLitElement) this.#setFiles(validated); } - #validateExtensions(): Blob[] { + #validateExtensions(): File[] { // TODO: Should property editor be able to handle allowed extensions like image/* ? - const filesValidated: Blob[] = []; + const filesValidated: File[] = []; this._currentFilesTemp?.forEach((temp) => { - const type = temp.type.slice(temp.type.lastIndexOf('/') + 1, temp.length); + const type = temp.type.slice(temp.type.lastIndexOf('/') + 1); if (this.fileExtensions?.find((x) => x === type)) filesValidated.push(temp); else this._notificationContext?.peek('danger', { @@ -129,7 +129,7 @@ export class UmbInputUploadFieldElement extends FormControlMixin(UmbLitElement) return filesValidated; } - #setFiles(files: Blob[]) { + #setFiles(files: File[]) { this._currentFiles = [...this._currentFiles, ...files]; //TODO: set keys when possible, not names From c2e977d010c34e803dd1f608d30730257232c39c Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Wed, 12 Apr 2023 11:22:39 +0200 Subject: [PATCH 031/156] add type guard --- .../workspace-layout/workspace-layout.element.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-layout/workspace-layout.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-layout/workspace-layout.element.ts index 48c6859ea2..c152611360 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-layout/workspace-layout.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-layout/workspace-layout.element.ts @@ -4,7 +4,7 @@ import { customElement, property, state } from 'lit/decorators.js'; import { map } from 'rxjs'; import { repeat } from 'lit/directives/repeat.js'; -import type { IRoute } from '@umbraco-cms/backoffice/router'; +import type { IRoute, PageComponent } from '@umbraco-cms/backoffice/router'; import type { UmbRouterSlotInitEvent, UmbRouterSlotChangeEvent } from '@umbraco-cms/internal/router'; import { createExtensionElement, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api'; import type { @@ -120,6 +120,10 @@ export class UmbWorkspaceLayoutElement extends UmbLitElement { ); } + private componentHasManifest(component: PageComponent): component is HTMLElement & { manifest: unknown } { + return component ? 'manifest' in component : false; + } + private _createRoutes() { this._routes = []; @@ -136,7 +140,7 @@ export class UmbWorkspaceLayoutElement extends UmbLitElement { return createExtensionElement(view); }, setup: (component, info) => { - if (component && 'manifest' in component) { + if (this.componentHasManifest(component)) { component.manifest = view; } else { console.group(`[UmbWorkspaceLayout] Failed to setup component for route: ${info.match.route.path}`); From 8c7a422b970a8341e056257f44ec58b6a2e9491c Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Wed, 12 Apr 2023 11:24:03 +0200 Subject: [PATCH 032/156] update command to base on tsconfig with --include param --- src/Umbraco.Web.UI.Client/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 4d2661e8a5..2a70dd2e6c 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -45,7 +45,7 @@ "format:fix": "npm run format -- --write", "generate:api": "openapi --input https://raw.githubusercontent.com/umbraco/Umbraco-CMS/v13/dev/src/Umbraco.Cms.Api.Management/OpenApi.json --output libs/backend-api/src --postfix Resource --useOptions", "generate:api-dev": "openapi --input http://localhost:11000/umbraco/swagger/v1/swagger.json --output libs/backend-api/src --postfix Resource --useOptions", - "generate:jsonschema": "typescript-json-schema --required --out types/umbraco-package-schema.json libs/extensions-registry/umbraco-package.ts UmbracoPackage", + "generate:jsonschema": "typescript-json-schema --required --include \"./libs/extensions-registry/*.ts\" --out types/umbraco-package-schema.json tsconfig.json UmbracoPackage", "storybook": "npm run wc-analyze && storybook dev -p 6006", "storybook:build": "npm run wc-analyze && storybook build", "build-storybook": "npm run wc-analyze && storybook build", From 915da8f3e583a1f3b81f353b192cd16de1388d5b Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Wed, 12 Apr 2023 11:38:25 +0200 Subject: [PATCH 033/156] correct examples --- .../libs/extensions-registry/dashboard.models.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/dashboard.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/dashboard.models.ts index 40aa2d570a..391853d187 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/dashboard.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/dashboard.models.ts @@ -10,7 +10,7 @@ export interface MetaDashboard { * This is the URL path for the dashboard which is used for navigating or deep linking directly to the dashboard * https://yoursite.com/section/settings/dashboard/my-dashboard-path * - * @example 'my-dashboard-path' + * @examples 'my-dashboard-path' */ pathname: string; @@ -21,5 +21,12 @@ export interface MetaDashboard { } export interface ConditionsDashboard { + /** + * An array of section aliases that the dashboard should be available in + * + * @examples [ + * ["Umb.Section.Content"] + * ] + */ sections: string[]; } From f9f5074662f5698a5c37aa135aff318695afed23 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Wed, 12 Apr 2023 11:38:29 +0200 Subject: [PATCH 034/156] ignore certain properties --- .../libs/extensions-registry/models.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts index 8619fdd9ba..274501d78a 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts @@ -142,9 +142,7 @@ export interface ManifestWithConditions { export interface ManifestWithLoader extends ManifestBase { /** - * Ignore this property when serializing to JSON Schema - * found at /types/umbraco-package-schema.json - * @ignore + * @TJS-ignore */ loader?: () => Promise; } @@ -162,12 +160,12 @@ export interface ManifestClass extends ManifestWithLoader { js?: string; /** - * @ignore + * @TJS-ignore */ className?: string; /** - * @ignore + * @TJS-ignore */ class?: ClassConstructor; //loader?: () => Promise; From 4bc75449588c05cab22cdf07f9bb15f8c195d052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 12 Apr 2023 11:48:42 +0200 Subject: [PATCH 035/156] move styles --- .../document-workspace-split-view.element.ts | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace-split-view.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace-split-view.element.ts index 936b5c7783..1f32d29b73 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace-split-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace-split-view.element.ts @@ -10,30 +10,6 @@ import { UMB_ENTITY_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/context-ap @customElement('umb-document-workspace-split-view') export class UmbDocumentWorkspaceSplitViewElement extends UmbLitElement { - static styles = [ - UUITextStyles, - css` - :host { - width: 100%; - height: 100%; - - display: flex; - flex: 1; - flex-direction: column; - } - - #splitViews { - display: flex; - width: 100%; - height: calc(100% - var(--umb-footer-layout-height)); - } - - #breadcrumbs { - margin: 0 var(--uui-size-layout-1); - } - `, - ]; - private _workspaceContext?: UmbDocumentWorkspaceContext; @state() @@ -82,6 +58,30 @@ export class UmbDocumentWorkspaceSplitViewElement extends UmbLitElement { ` : nothing; } + + static styles = [ + UUITextStyles, + css` + :host { + width: 100%; + height: 100%; + + display: flex; + flex: 1; + flex-direction: column; + } + + #splitViews { + display: flex; + width: 100%; + height: calc(100% - var(--umb-footer-layout-height)); + } + + #breadcrumbs { + margin: 0 var(--uui-size-layout-1); + } + `, + ]; } export default UmbDocumentWorkspaceSplitViewElement; From 9ba3c149ffae33752be97f9b0a5aefba466ea6d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 12 Apr 2023 11:49:04 +0200 Subject: [PATCH 036/156] move styles --- .../document-workspace-editor.element.ts | 22 +++++++++---------- .../workspace/document-workspace.element.ts | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace-editor.element.ts index dd2f4c5fdf..defdf43afb 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace-editor.element.ts @@ -14,17 +14,6 @@ import { UMB_ENTITY_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/context-ap @customElement('umb-document-workspace-editor') export class UmbDocumentWorkspaceEditorElement extends UmbLitElement { - static styles = [ - UUITextStyles, - css` - :host { - display: block; - width: 100%; - height: 100%; - } - `, - ]; - //private _defaultVariant?: VariantViewModelBaseModel; private splitViewElement = new UmbDocumentWorkspaceSplitViewElement(); @@ -132,6 +121,17 @@ export class UmbDocumentWorkspaceEditorElement extends UmbLitElement { >` : ''; } + + static styles = [ + UUITextStyles, + css` + :host { + display: block; + width: 100%; + height: 100%; + } + `, + ]; } export default UmbDocumentWorkspaceEditorElement; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace.element.ts index 19301cf90a..bd99def08f 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace.element.ts @@ -9,8 +9,6 @@ import './document-workspace-editor.element'; @customElement('umb-document-workspace') export class UmbDocumentWorkspaceElement extends UmbLitElement { - static styles = [UUITextStyles]; - #workspaceContext = new UmbDocumentWorkspaceContext(this); #element = document.createElement('umb-document-workspace-editor'); @@ -40,6 +38,8 @@ export class UmbDocumentWorkspaceElement extends UmbLitElement { render() { return html``; } + + static styles = [UUITextStyles]; } export default UmbDocumentWorkspaceElement; From 1154646081a8920873eeeb8fcd8cf71697eb5ac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 12 Apr 2023 12:50:04 +0200 Subject: [PATCH 037/156] save mock data --- .../sources/document-type.server.data.ts | 6 +-- .../sources/document.server.data.ts | 50 ++----------------- .../mocks/domains/document-type.handlers.ts | 14 +++++- .../core/mocks/domains/document.handlers.ts | 12 ++++- 4 files changed, 27 insertions(+), 55 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/sources/document-type.server.data.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/sources/document-type.server.data.ts index f6bff744b2..5915dc9907 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/sources/document-type.server.data.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/sources/document-type.server.data.ts @@ -66,11 +66,7 @@ export class UmbDocumentTypeServerDataSource implements UmbDataSource( - this.#host, - fetch('/umbraco/management/api/v1/document/save', { - method: 'POST', - body: body, - headers: { - 'Content-Type': 'application/json', - }, - }) as any - ); + return tryExecuteAndNotify(this.#host, DocumentResource.postDocument({ requestBody: document })); } /** @@ -118,33 +99,10 @@ export class UmbDocumentServerDataSource * @return {*} * @memberof UmbDocumentServerDataSource */ - async update(id: string, document: DocumentResponseModel) { - if (!document.id) { - const error: ProblemDetailsModel = { title: 'Document id is missing' }; - return { error }; - } - //const payload = { id: document.id, requestBody: document }; + async update(id: string, document: UpdateDocumentRequestModel) { + if (!id) throw new Error('Id is missing'); - let body: string; - - try { - body = JSON.stringify(document); - } catch (error) { - const myError: ProblemDetailsModel = { title: 'JSON could not parse' }; - return { error: myError }; - } - - // TODO: use resources when end point is ready: - return tryExecuteAndNotify( - this.#host, - fetch('/umbraco/management/api/v1/document/save', { - method: 'POST', - body: body, - headers: { - 'Content-Type': 'application/json', - }, - }) as any - ); + return tryExecuteAndNotify(this.#host, DocumentResource.putDocumentById({ id, requestBody: document })); } /** diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/document-type.handlers.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/document-type.handlers.ts index 1daea0ba0f..75f44b4a9a 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/document-type.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/document-type.handlers.ts @@ -1,11 +1,21 @@ import { rest } from 'msw'; import { umbDocumentTypeData } from '../data/document-type.data'; import type { DocumentTypeResponseModel } from '@umbraco-cms/backoffice/backend-api'; +import { umbracoPath } from '@umbraco-cms/backoffice/utils'; // TODO: add schema export const handlers = [ - rest.post('/umbraco/management/api/v1/document-type/:id', (req, res, ctx) => { - const data = req.body; + rest.post(umbracoPath(`/document-type`), async (req, res, ctx) => { + const data = await req.json(); + if (!data) return; + + umbDocumentTypeData.insert(data); + + return res(ctx.status(200)); + }), + + rest.put(umbracoPath(`/document-type/:id`), async (req, res, ctx) => { + const data = await req.json(); if (!data) return; const saved = umbDocumentTypeData.save(data); diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/document.handlers.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/document.handlers.ts index 44c3eb41da..487ccbcb0f 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/document.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/document.handlers.ts @@ -1,6 +1,5 @@ import { rest } from 'msw'; import { umbDocumentData } from '../data/document.data'; -import type { DocumentResponseModel } from '@umbraco-cms/backoffice/backend-api'; import { umbracoPath } from '@umbraco-cms/backoffice/utils'; // TODO: add schema @@ -35,7 +34,16 @@ export const handlers = [ return res(ctx.status(200), ctx.json(items)); }), - rest.post('/umbraco/management/api/v1/document/:id', async (req, res, ctx) => { + rest.post(umbracoPath(`/document`), async (req, res, ctx) => { + const data = await req.json(); + if (!data) return; + + umbDocumentData.insert(data); + + return res(ctx.status(200)); + }), + + rest.put(umbracoPath(`/document/:id`), async (req, res, ctx) => { const data = await req.json(); if (!data) return; From 5f21fdaf21cd79dd8933a6f957e2acc3eda05d20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 12 Apr 2023 12:54:57 +0200 Subject: [PATCH 038/156] move styles --- .../document-type-workspace-editor.element.ts | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/document-type-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/document-type-workspace-editor.element.ts index 21d8c3e526..37523e2d6b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/document-type-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/document-type-workspace-editor.element.ts @@ -10,39 +10,6 @@ import { UMB_ENTITY_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/context-ap @customElement('umb-document-type-workspace-editor') export class UmbDocumentTypeWorkspaceEditorElement extends UmbLitElement { - static styles = [ - UUITextStyles, - css` - :host { - display: block; - width: 100%; - height: 100%; - } - - #header { - display: flex; - flex: 1 1 auto; - margin: 0 var(--uui-size-layout-1); - } - - #name { - width: 100%; - flex: 1 1 auto; - align-items: center; - } - - #alias { - height: calc(100% - 2px); - --uui-input-border-width: 0; - --uui-button-height: calc(100% -2px); - } - - #icon { - font-size: calc(var(--uui-size-layout-3) / 2); - } - `, - ]; - // TODO: notice this format is not acceptable: @state() private _icon = { @@ -143,6 +110,39 @@ export class UmbDocumentTypeWorkspaceEditorElement extends UmbLitElement { `; } + + static styles = [ + UUITextStyles, + css` + :host { + display: block; + width: 100%; + height: 100%; + } + + #header { + display: flex; + flex: 1 1 auto; + margin: 0 var(--uui-size-layout-1); + } + + #name { + width: 100%; + flex: 1 1 auto; + align-items: center; + } + + #alias { + height: calc(100% - 2px); + --uui-input-border-width: 0; + --uui-button-height: calc(100% -2px); + } + + #icon { + font-size: calc(var(--uui-size-layout-3) / 2); + } + `, + ]; } export default UmbDocumentTypeWorkspaceEditorElement; From 8d61ff50f2a01b6cf14cf2f3cbfdabe6fb84775e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 12 Apr 2023 14:04:09 +0200 Subject: [PATCH 039/156] clean up --- .../workspace/document-type-workspace-editor.element.ts | 3 --- .../document-type-workspace-view-edit-property.element.ts | 4 ++-- .../workspace-context/workspace-structure-manager.class.ts | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/document-type-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/document-type-workspace-editor.element.ts index 37523e2d6b..2c4b917701 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/document-type-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/document-type-workspace-editor.element.ts @@ -3,7 +3,6 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { css, html } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { UmbDocumentTypeWorkspaceContext } from './document-type-workspace.context'; -import type { DocumentTypeResponseModel } from '@umbraco-cms/backoffice/backend-api'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN, UMB_ICON_PICKER_MODAL } from '@umbraco-cms/backoffice/modal'; import { UMB_ENTITY_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/context-api'; @@ -19,8 +18,6 @@ export class UmbDocumentTypeWorkspaceEditorElement extends UmbLitElement { #workspaceContext?: UmbDocumentTypeWorkspaceContext; - //@state() - //private _documentType?: DocumentTypeResponseModel; @state() private _name?: string; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts index 45fad85fcb..6b0b0d3ea8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts @@ -12,9 +12,9 @@ import { PropertyTypeResponseModelBaseModel } from '@umbraco-cms/backoffice/back export class UmbDocumentTypeWorkspacePropertyElement extends LitElement { /** * Property, the data object for the property. - * @type {string} + * @type {PropertyTypeResponseModelBaseModel} * @attr - * @default '' + * @default undefined */ @property({ type: Object }) public property?: PropertyTypeResponseModelBaseModel; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-structure-manager.class.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-structure-manager.class.ts index 8a7b24dc23..70f8c9da70 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-structure-manager.class.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-structure-manager.class.ts @@ -213,7 +213,7 @@ export class UmbWorkspacePropertyStructureManager x.id === documentTypeKey)?.properties ?? []; - const properties = partialUpdateFrozenArray(frozenProperties, partialUpdate, (x) => x.id === propertyKey!); + const properties = partialUpdateFrozenArray(frozenProperties, partialUpdate, (x) => x.id === propertyKey); this.#documentTypes.updateOne(documentTypeKey, { properties }); } From efc1e03eeaf98347f88b24533f24bba547459ac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 12 Apr 2023 14:04:34 +0200 Subject: [PATCH 040/156] await context retrieving --- .../workspace-property-structure-helper.class.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-property-structure-helper.class.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-property-structure-helper.class.ts index 6941cd3daa..8a3f2e2844 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-property-structure-helper.class.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-property-structure-helper.class.ts @@ -7,6 +7,7 @@ import { ArrayState, UmbObserverController } from '@umbraco-cms/backoffice/obser export class UmbWorkspacePropertyStructureHelper { #host: UmbControllerHostElement; + #init; #workspaceContext?: UmbDocumentWorkspaceContext; @@ -19,10 +20,10 @@ export class UmbWorkspacePropertyStructureHelper { constructor(host: UmbControllerHostElement) { this.#host = host; - new UmbContextConsumerController(host, UMB_ENTITY_WORKSPACE_CONTEXT, (context) => { + this.#init = new UmbContextConsumerController(host, UMB_ENTITY_WORKSPACE_CONTEXT, (context) => { this.#workspaceContext = context as UmbDocumentWorkspaceContext; this._observeGroupContainers(); - }); + }).asPromise(); } public setContainerType(value?: PropertyContainerTypes) { @@ -97,9 +98,11 @@ export class UmbWorkspacePropertyStructureHelper { ); } + // TODO: consider moving this to another class, to separate 'viewer' from 'manipulator': /** Manipulate methods: */ async addProperty(ownerKey?: string, sortOrder?: number) { + await this.#init; if (!this.#workspaceContext) return; return await this.#workspaceContext.structure.createProperty(null, ownerKey, sortOrder); @@ -107,6 +110,7 @@ export class UmbWorkspacePropertyStructureHelper { // Takes optional arguments as this is easier for the implementation in the view: async partialUpdateProperty(propertyKey?: string, partialUpdate?: Partial) { + await this.#init; if (!this.#workspaceContext || !propertyKey || !partialUpdate) return; return await this.#workspaceContext.structure.updateProperty(null, propertyKey, partialUpdate); From 501958e2df76ca6473b6367f76d9ad9d0e9c2a0d Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Wed, 12 Apr 2023 14:19:41 +0200 Subject: [PATCH 041/156] updated examples --- .../collection-view.models.ts | 11 ++++++---- .../extensions-registry/dashboard.models.ts | 5 ++++- .../entity-action.models.ts | 22 ++++++++++++++----- .../entity-bulk-action.models.ts | 11 ++++++++-- .../libs/extensions-registry/models.ts | 16 +++++++++----- .../libs/extensions-registry/theme.models.ts | 3 ++- .../extensions-registry/umbraco-package.ts | 2 +- 7 files changed, 50 insertions(+), 20 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/collection-view.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/collection-view.models.ts index 4f7104b913..823ca3bc21 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/collection-view.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/collection-view.models.ts @@ -13,14 +13,17 @@ export interface MetaCollectionView { /** * An icon to represent the collection view - * @example 'umb:box' - * @example 'umb:grid' + * + * @examples [ + * "umb:box", + * "umb:grid" + * ] */ icon: string; /** - * The URL pathname for this collection view that can be deep linked to by sharing the url - */ + * The URL pathname for this collection view that can be deep linked to by sharing the url + */ pathName: string; } diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/dashboard.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/dashboard.models.ts index 391853d187..d12fd07b0d 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/dashboard.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/dashboard.models.ts @@ -10,7 +10,10 @@ export interface MetaDashboard { * This is the URL path for the dashboard which is used for navigating or deep linking directly to the dashboard * https://yoursite.com/section/settings/dashboard/my-dashboard-path * - * @examples 'my-dashboard-path' + * @example my-dashboard-path + * @examples [ + * "my-dashboard-path" + * ] */ pathname: string; diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/entity-action.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/entity-action.models.ts index a9cd1b27a8..4816f084fd 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/entity-action.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/entity-action.models.ts @@ -13,25 +13,35 @@ export interface ManifestEntityAction extends ManifestElement { export interface MetaEntityAction { /** * An icon to represent the action to be performed - * @example 'umb:box' - * @example 'umb:grid' + * + * @examples [ + * "umb:box", + * "umb:grid" + * ] */ icon?: string; /** * The friendly name of the action to perform - * @example 'Create' - * @example 'Create Content Template' + * + * @examples [ + * "Create", + * "Create Content Template" + * ] */ label: string; + /** + * @TJS-ignore + */ api: any; // create interface - /** * The alias for the repsoitory of the entity type this action is for * such as 'Umb.Repository.Documents' - * @example 'Umb.Repository.Documents' + * @examples [ + * "Umb.Repository.Documents" + * ] */ repositoryAlias: string; } diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/entity-bulk-action.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/entity-bulk-action.models.ts index afe32fa3f8..5564bb5b5d 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/entity-bulk-action.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/entity-bulk-action.models.ts @@ -11,15 +11,22 @@ export interface ManifestEntityBulkAction extends ManifestElement, ManifestWithC export interface MetaEntityBulkAction { /** - * + * A friendly label for the action */ label: string; + + /** + * @TJS-ignore + */ api: any; // create interface /** * The alias for the repsoitory of the entity type this action is for * such as 'Umb.Repository.Documents' - * @example 'Umb.Repository.Documents' + * + * @examples [ + * "Umb.Repository.Documents" + * ] */ repositoryAlias: string; } diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts index 274501d78a..6de04ccfcf 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts @@ -113,9 +113,10 @@ export interface ManifestBase { /** * The kind of the extension, used to group extensions together - * @example "button" + * + * @examples ["button"] */ - kind?: any; // I had to add the optional kind property set to undefined. To make the ManifestTypes recognize the Manifest Kind types. Notice that Kinds has to Omit the kind property when extending. + kind?: unknown; // I had to add the optional kind property set to undefined. To make the ManifestTypes recognize the Manifest Kind types. Notice that Kinds has to Omit the kind property when extending. /** * The friendly name of the extension @@ -137,6 +138,9 @@ export interface ManifestKind { } export interface ManifestWithConditions { + /** + * Set the conditions for when the extension should be loaded + */ conditions: ConditionsType; } @@ -155,7 +159,7 @@ export interface ManifestClass extends ManifestWithLoader { /** * The file location of the javascript file to load - * @required + * @TJS-required */ js?: string; @@ -180,7 +184,8 @@ export interface ManifestElement extends ManifestWithLoader but just the name */ elementName?: string; + //loader?: () => Promise; /** * This contains properties specific to the type of extension */ - meta?: any; + meta?: unknown; } export interface ManifestWithView extends ManifestElement { diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/theme.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/theme.models.ts index 51704abc53..0e18a0164a 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/theme.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/theme.models.ts @@ -10,7 +10,8 @@ export interface ManifestTheme extends ManifestWithLoader { /** * File location of the CSS file of the theme - * @example 'themes/dark.theme.css' + * + * @examples ["themes/dark.theme.css"] */ css?: string; } diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts index 85e0f1572d..c594bada93 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/umbraco-package.ts @@ -11,7 +11,7 @@ export class UmbracoPackage { /** * @title The version of the Umbraco package in the style of semver - * @example 0.1.0 + * @examples ["0.1.0"] */ version?: string; From 9dec24ce5d2b2511a275999e3cd88b4ecc98820d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 12 Apr 2023 14:30:03 +0200 Subject: [PATCH 042/156] update tab name --- ...nt-type-workspace-view-edit-tab.element.ts | 2 +- ...cument-type-workspace-view-edit.element.ts | 16 +++++- ...kspace-container-structure-helper.class.ts | 16 ++++-- .../workspace-structure-manager.class.ts | 53 ++++++++++++------- 4 files changed, 61 insertions(+), 26 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-tab.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-tab.element.ts index 51782de0b7..6b3c935ea8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-tab.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-tab.element.ts @@ -78,7 +78,7 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { #onAddGroup = () => { // Idea, maybe we can gather the sortOrder from the last group rendered and add 1 to it? - this._groupStructureHelper.addGroup(this._ownerTabId); + this._groupStructureHelper.addContainer(this._ownerTabId); }; render() { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit.element.ts index b09416588d..c244382b54 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit.element.ts @@ -142,13 +142,25 @@ export class UmbDocumentTypeWorkspaceViewEditElement extends UmbLitElement { : ''} ${repeat( this._tabs, - (tab) => tab.id, + (tab) => tab.id! + tab.name, (tab) => { // TODO: make better url folder name: const path = this._routerPath + '/tab/' + encodeURI(tab.name || ''); return html` ${path === this._activePath - ? html` + ? html` { + const newName = (e.target as HTMLInputElement).value; + // Update the current URL, so we are still on this specific tab: + window.history.replaceState(null, '', this._routerPath + '/tab/' + encodeURI(newName)); + this._tabsStructureHelper.partialUpdateContainer(tab.id, { + name: newName, + }); + }}> (a.sortOrder || 0) - (b.sortOrder || 0)); - new UmbContextConsumerController(host, UMB_ENTITY_WORKSPACE_CONTEXT, (context) => { + this.#init = new UmbContextConsumerController(host, UMB_ENTITY_WORKSPACE_CONTEXT, (context) => { this.#workspaceContext = context as UmbDocumentWorkspaceContext; this._observeOwnerContainers(); - }); + }).asPromise(); } public setType(value?: PropertyContainerTypes) { @@ -152,9 +153,16 @@ export class UmbWorkspaceContainerStructureHelper { /** Manipulate methods: */ - async addGroup(ownerKey?: string, sortOrder?: number) { + async addContainer(ownerId?: string, sortOrder?: number) { if (!this.#workspaceContext) return; - await this.#workspaceContext.structure.createContainer(null, ownerKey, this._childType, sortOrder); + await this.#workspaceContext.structure.createContainer(null, ownerId, this._childType, sortOrder); + } + + async partialUpdateContainer(groupId?: string, partialUpdate?: Partial) { + await this.#init; + if (!this.#workspaceContext || !groupId || !partialUpdate) return; + + return await this.#workspaceContext.structure.updateContainer(null, groupId, partialUpdate); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-structure-manager.class.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-structure-manager.class.ts index 70f8c9da70..94bca9717d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-structure-manager.class.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-structure-manager.class.ts @@ -27,7 +27,7 @@ export class UmbWorkspacePropertyStructureManager(); #documentTypes = new ArrayState([], (x) => x.id); readonly documentTypes = this.#documentTypes.asObservable(); @@ -62,7 +62,7 @@ export class UmbWorkspacePropertyStructureManager x.find((y) => y.id === this.#rootDocumentTypeKey)); + return this.#documentTypes.getObservablePart((x) => x.find((y) => y.id === this.#rootDocumentTypeId)); } getRootDocumentType() { - return this.#documentTypes.getValue().find((y) => y.id === this.#rootDocumentTypeKey); + return this.#documentTypes.getValue().find((y) => y.id === this.#rootDocumentTypeId); } updateRootDocumentType(entry: T) { - this.#documentTypes.updateOne(this.#rootDocumentTypeKey, entry); + this.#documentTypes.updateOne(this.#rootDocumentTypeId, entry); } // We could move the actions to another class? @@ -157,7 +157,7 @@ export class UmbWorkspacePropertyStructureManager + ) { + await this.#init; + documentTypeId = documentTypeId ?? this.#rootDocumentTypeId!; + + const frozenContainers = this.#documentTypes.getValue().find((x) => x.id === documentTypeId)?.containers ?? []; + + const containers = partialUpdateFrozenArray(frozenContainers, partialUpdate, (x) => x.id === groupKey); + + this.#documentTypes.updateOne(documentTypeId, { containers }); + } + async removeContainer(documentTypeKey: string | null, containerId: string | null = null) { await this.#init; - documentTypeKey = documentTypeKey ?? this.#rootDocumentTypeKey!; + documentTypeKey = documentTypeKey ?? this.#rootDocumentTypeId!; const frozenContainers = this.#documentTypes.getValue().find((x) => x.id === documentTypeKey)?.containers ?? []; const containers = frozenContainers.filter((x) => x.id !== containerId); @@ -185,9 +200,9 @@ export class UmbWorkspacePropertyStructureManager x.id === documentTypeKey)?.properties ?? [])]; + const properties = [...(this.#documentTypes.getValue().find((x) => x.id === documentTypeId)?.properties ?? [])]; properties.push(property); - this.#documentTypes.updateOne(documentTypeKey, { properties }); + this.#documentTypes.updateOne(documentTypeId, { properties }); return property; } async updateProperty( - documentTypeKey: string | null, - propertyKey: string, + documentTypeId: string | null, + propertyId: string, partialUpdate: Partial ) { await this.#init; - documentTypeKey = documentTypeKey ?? this.#rootDocumentTypeKey!; + documentTypeId = documentTypeId ?? this.#rootDocumentTypeId!; - const frozenProperties = this.#documentTypes.getValue().find((x) => x.id === documentTypeKey)?.properties ?? []; + const frozenProperties = this.#documentTypes.getValue().find((x) => x.id === documentTypeId)?.properties ?? []; - const properties = partialUpdateFrozenArray(frozenProperties, partialUpdate, (x) => x.id === propertyKey); + const properties = partialUpdateFrozenArray(frozenProperties, partialUpdate, (x) => x.id === propertyId); - this.#documentTypes.updateOne(documentTypeKey, { properties }); + this.#documentTypes.updateOne(documentTypeId, { properties }); } /* @@ -229,7 +244,7 @@ export class UmbWorkspacePropertyStructureManager(mappingFunction: MappingFunction) { return this.#documentTypes.getObservablePart((docTypes) => { - const docType = docTypes.find((x) => x.id === this.#rootDocumentTypeKey); + const docType = docTypes.find((x) => x.id === this.#rootDocumentTypeId); return docType ? mappingFunction(docType) : undefined; }); } From 1395dd84eed9e1b16666f0c5f11a96f4e8503fa8 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Wed, 12 Apr 2023 14:35:19 +0200 Subject: [PATCH 043/156] add json schema build --- src/Umbraco.Web.UI.Client/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 2a70dd2e6c..786a79a8e7 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -30,7 +30,7 @@ "build": "tsc && vite build --mode staging", "build:libs": "npm run wc-analyze && npm run wc-analyze:vscode && rollup -c rollup-libs.config.js && node utils/move-libs.js", "build:for:static": "tsc && vite build", - "build:for:cms": "tsc && npm run build:libs && vite build -c vite.cms.config.ts", + "build:for:cms": "tsc && npm run build:libs && npm run generate:jsonschema && vite build -c vite.cms.config.ts", "build:for:cms:watch": "tsc && npm run build:libs && vite build -c vite.cms.config.ts --watch", "preview": "vite preview --open", "test": "web-test-runner --coverage", From f03a768e0bebfba7e7a16c92212160e3265846b0 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Wed, 12 Apr 2023 14:35:28 +0200 Subject: [PATCH 044/156] dashboard examples --- .../libs/extensions-registry/dashboard.models.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/dashboard.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/dashboard.models.ts index d12fd07b0d..fedb4bdff2 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/dashboard.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/dashboard.models.ts @@ -28,8 +28,10 @@ export interface ConditionsDashboard { * An array of section aliases that the dashboard should be available in * * @examples [ - * ["Umb.Section.Content"] + * ["Umb.Section.Content"], + * ["Umb.Section.Settings"] * ] + * @uniqueItems true */ sections: string[]; } From 545d46b8d357c134d72482a0231a0215ba1b4609 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Wed, 12 Apr 2023 14:43:27 +0200 Subject: [PATCH 045/156] improve dashboard json schema --- .../libs/extensions-registry/dashboard.models.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/dashboard.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/dashboard.models.ts index fedb4bdff2..033e554623 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/dashboard.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/dashboard.models.ts @@ -27,11 +27,13 @@ export interface ConditionsDashboard { /** * An array of section aliases that the dashboard should be available in * - * @examples [ - * ["Umb.Section.Content"], - * ["Umb.Section.Settings"] - * ] * @uniqueItems true + * @minItems 1 + * @items.examples [ + * "Umb.Section.Content", + * "Umb.Section.Settings" + * ] + * */ sections: string[]; } From 06744ec39b2b20142ffda8d2e2f375cbd06c31c9 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 12 Apr 2023 17:05:01 +0200 Subject: [PATCH 046/156] add picker context base class --- .../libs/picker/index.ts | 1 + .../libs/picker/picker.context.ts | 94 +++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/libs/picker/index.ts create mode 100644 src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts diff --git a/src/Umbraco.Web.UI.Client/libs/picker/index.ts b/src/Umbraco.Web.UI.Client/libs/picker/index.ts new file mode 100644 index 0000000000..49b83a7cbe --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/picker/index.ts @@ -0,0 +1 @@ +export * from './picker.context'; diff --git a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts b/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts new file mode 100644 index 0000000000..0144293104 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts @@ -0,0 +1,94 @@ +import { UmbTreeRepository } from '../repository'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; +import { ArrayState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; +import { createExtensionClass, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api'; +import { + UMB_CONFIRM_MODAL, + UMB_MODAL_CONTEXT_TOKEN, + UmbModalContext, + UmbModalToken, +} from '@umbraco-cms/backoffice/modal'; +import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; + +export class UmbPickerContext { + host: UmbControllerHostElement; + modalAlias: UmbModalToken | string; + repository?: RepositoryType; + + public modalContext?: UmbModalContext; + + #selection = new ArrayState([]); + selection = this.#selection.asObservable(); + + #items = new ArrayState([]); + items = this.#items.asObservable(); + + max = Infinity; + min = 0; + + constructor(host: UmbControllerHostElement, repositoryAlias: string, modalAlias: UmbModalToken | string) { + this.host = host; + this.modalAlias = modalAlias; + + // TODO: unsure a method can't be called before everything is initialized + new UmbObserverController( + this.host, + + // TODO: this code is reused in multiple places, so it should be extracted to a function + umbExtensionsRegistry.getByTypeAndAlias('repository', repositoryAlias), + async (repositoryManifest) => { + if (!repositoryManifest) return; + + try { + const result = await createExtensionClass(repositoryManifest, [this.host]); + this.repository = result; + } catch (error) { + throw new Error('Could not create repository with alias: ' + repositoryAlias + ''); + } + } + ); + + new UmbContextConsumerController(this.host, UMB_MODAL_CONTEXT_TOKEN, (instance) => { + this.modalContext = instance; + }); + } + + getSelection() { + return this.#selection.value; + } + + setSelection(selection: string[]) { + this.#selection.next(selection); + } + + openPicker() { + if (!this.modalContext) throw new Error('Modal context is not initialized'); + + const modalHandler = this.modalContext.open(this.modalAlias, { + multiple: this.max === 1 ? false : true, + selection: [...this.getSelection()], + }); + + modalHandler?.onSubmit().then(({ selection }: any) => { + this.setSelection(selection); + }); + } + + async removeItem(unique: string) { + if (!this.repository) throw new Error('Repository is not initialized'); + + const { data } = await this.repository.requestTreeItems([unique]); + if (!data) throw new Error('Could not find item with unique id: ' + unique); + + const modalHandler = this.modalContext?.open(UMB_CONFIRM_MODAL, { + color: 'danger', + headline: `Remove ${data[0].name}?`, + content: 'Are you sure you want to remove this item', + confirmLabel: 'Remove', + }); + + await modalHandler?.onSubmit(); + const newSelection = this.getSelection().filter((value) => value !== unique); + this.setSelection(newSelection); + } +} From 32eaf9783bbf53d4b126f5406beb7b43cf62cb22 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 12 Apr 2023 17:05:14 +0200 Subject: [PATCH 047/156] add import alias's --- src/Umbraco.Web.UI.Client/tsconfig.json | 2 ++ src/Umbraco.Web.UI.Client/web-test-runner.config.mjs | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/tsconfig.json b/src/Umbraco.Web.UI.Client/tsconfig.json index 147a4a8288..4331c9a1ae 100644 --- a/src/Umbraco.Web.UI.Client/tsconfig.json +++ b/src/Umbraco.Web.UI.Client/tsconfig.json @@ -39,10 +39,12 @@ "@umbraco-cms/backoffice/store": ["libs/store"], "@umbraco-cms/backoffice/utils": ["libs/utils"], "@umbraco-cms/backoffice/workspace": ["libs/workspace"], + "@umbraco-cms/backoffice/picker": ["libs/picker"], "@umbraco-cms/internal/lit-element": ["src/core/lit-element"], "@umbraco-cms/internal/modal": ["src/core/modal"], "@umbraco-cms/internal/router": ["src/core/router"], "@umbraco-cms/internal/test-utils": ["utils/test-utils.ts"] + } }, "include": ["src/**/*.ts", "apps/**/*.ts", "libs/**/*.ts", "e2e/**/*.ts"], diff --git a/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs b/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs index 2aa8016715..1c2161cc20 100644 --- a/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs +++ b/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs @@ -56,10 +56,11 @@ export default { '@umbraco-cms/backoffice/store': './libs/store/index.ts', '@umbraco-cms/backoffice/utils': './libs/utils/index.ts', '@umbraco-cms/backoffice/workspace': './libs/workspace/index.ts', + '@umbraco-cms/backoffice/picker': './libs/picker/index.ts', '@umbraco-cms/internal/lit-element': './src/core/lit-element/index.ts', '@umbraco-cms/internal/modal': './src/core/modal/index.ts', '@umbraco-cms/internal/router': './src/core/router/index.ts', - '@umbraco-cms/internal/test-utils': './utils/test-utils.ts' + '@umbraco-cms/internal/test-utils': './utils/test-utils.ts', }, }, }, From bef326ec6995698c2a46246c267af1327b82be7a Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 12 Apr 2023 17:05:28 +0200 Subject: [PATCH 048/156] add data type picker token --- .../modal/token/data-type-picker-modal.token.ts | 17 +++++++++++++++++ .../libs/modal/token/index.ts | 1 + 2 files changed, 18 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/libs/modal/token/data-type-picker-modal.token.ts diff --git a/src/Umbraco.Web.UI.Client/libs/modal/token/data-type-picker-modal.token.ts b/src/Umbraco.Web.UI.Client/libs/modal/token/data-type-picker-modal.token.ts new file mode 100644 index 0000000000..aa6b1ea39c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/modal/token/data-type-picker-modal.token.ts @@ -0,0 +1,17 @@ +import { UmbModalToken } from '@umbraco-cms/backoffice/modal'; + +export interface UmbDataTypePickerModalData { + selection?: Array; +} + +export interface UmbDataTypePickerModalResult { + selection: Array; +} + +export const UMB_DATA_TYPE_PICKER_MODAL = new UmbModalToken( + 'Umb.Modal.DataTypePicker', + { + type: 'sidebar', + size: 'small', + } +); diff --git a/src/Umbraco.Web.UI.Client/libs/modal/token/index.ts b/src/Umbraco.Web.UI.Client/libs/modal/token/index.ts index 7fd02d418b..284cdc1e6a 100644 --- a/src/Umbraco.Web.UI.Client/libs/modal/token/index.ts +++ b/src/Umbraco.Web.UI.Client/libs/modal/token/index.ts @@ -26,3 +26,4 @@ export * from './template-picker-modal.token'; export * from './user-group-picker-modal.token'; export * from './user-picker-modal.token'; export * from './folder-modal.token'; +export * from './data-type-picker-modal.token'; From 191bc18acb9e7d4ef1088bd1a90f6089a551ce48 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 12 Apr 2023 17:05:53 +0200 Subject: [PATCH 049/156] add correct name to document type --- .../src/core/mocks/data/document-type.data.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/data/document-type.data.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/data/document-type.data.ts index 532186dde7..5eacc9db6f 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/data/document-type.data.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/data/document-type.data.ts @@ -12,7 +12,7 @@ export const data: Array = [ defaultTemplateId: null, id: 'all-property-editors-document-type-id', alias: 'blogPost', - name: 'Blog Post', + name: 'All property editors document type', description: null, icon: 'umb:item-arrangement', allowedAsRoot: true, From 3b2fc0e6e4d2719ed0fe23b205538c47ed7df015 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 12 Apr 2023 17:08:14 +0200 Subject: [PATCH 050/156] add data type input and picker modal --- .../workspace-package-builder.element.ts | 2 +- .../data-type-input.context.ts | 10 ++ .../data-type-input.element.ts | 128 ++++++++++++++++++ .../settings/data-types/components/index.ts | 1 + .../backoffice/settings/data-types/index.ts | 1 + .../settings/data-types/manifests.ts | 2 + .../data-type-picker-modal.element.ts | 77 +++++++++++ .../settings/data-types/modal/manifests.ts | 12 ++ .../src/backoffice/settings/index.ts | 2 + 9 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.context.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/modal/data-type-picker/data-type-picker-modal.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/modal/manifests.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-builder/workspace/workspace-package-builder.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-builder/workspace/workspace-package-builder.element.ts index 9dce5a6dca..ccb98189a6 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-builder/workspace/workspace-package-builder.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-builder/workspace/workspace-package-builder.element.ts @@ -259,7 +259,7 @@ export class UmbWorkspacePackageBuilderElement extends UmbLitElement { #renderDataTypeSection() { return html`
- +
`; } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.context.ts new file mode 100644 index 0000000000..2f91e61fea --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.context.ts @@ -0,0 +1,10 @@ +import { UmbPickerContext } from '@umbraco-cms/backoffice/picker'; +import { UmbDataTypeRepository } from '../../repository/data-type.repository'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; +import { UMB_DATA_TYPE_PICKER_MODAL } from '@umbraco-cms/backoffice/modal'; + +export class UmbDataTypePickerContext extends UmbPickerContext { + constructor(host: UmbControllerHostElement) { + super(host, 'Umb.Repository.DataType', UMB_DATA_TYPE_PICKER_MODAL); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts new file mode 100644 index 0000000000..126c0d97f5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts @@ -0,0 +1,128 @@ +import { css, html } from 'lit'; +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { customElement, property, state } from 'lit/decorators.js'; +import { FormControlMixin } from '@umbraco-ui/uui-base/lib/mixins'; +import { UmbDataTypePickerContext } from './data-type-input.context'; +import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; +import type { DataTypeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; +import { UMB_DATA_TYPE_PICKER_MODAL } from '@umbraco-cms/backoffice/modal'; + +@customElement('umb-data-type-input') +export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) { + static styles = [ + UUITextStyles, + css` + #add-button { + width: 100%; + } + `, + ]; + /** + * This is a minimum amount of selected items in this input. + * @type {number} + * @attr + * @default undefined + */ + @property({ type: Number }) + min?: number; + + /** + * 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 undefined + */ + @property({ type: Number }) + max?: number; + + /** + * Max validation message. + * @type {boolean} + * @attr + * @default + */ + @property({ type: String, attribute: 'min-message' }) + maxMessage = 'This field exceeds the allowed amount of items'; + + private _selectedIds: Array = []; + public get selectedIds(): Array { + return this._selectedIds; + } + public set selectedIds(ids: Array) { + this._selectedIds = ids; + super.value = ids.join(','); + } + + @property() + public set value(idsString: string) { + if (idsString !== this._value) { + this.selectedIds = idsString.split(/[ ,]+/); + } + } + + @state() + private _items?: Array; + + #pickerContext = new UmbDataTypePickerContext(this); + + constructor() { + super(); + + this.addValidator( + 'rangeUnderflow', + () => this.minMessage, + () => !!this.min && this._selectedIds.length < this.min + ); + + this.addValidator( + 'rangeOverflow', + () => this.maxMessage, + () => !!this.max && this._selectedIds.length > this.max + ); + + this.observe(this.#pickerContext.selection, (selection) => (this.selectedIds = selection)); + //this.observe(this.#pickerContext.items, (items) => (this._items = items)); + } + + protected getFormElement() { + return undefined; + } + + render() { + return html` + ${this._items?.map((item) => this._renderItem(item))} + this.#pickerContext.openPicker()} label="open" + >Add + `; + } + + private _renderItem(item: DataTypeItemResponseModel) { + return html` + + + this.#pickerContext.removeItem(item.id)} label="Remove Data Type ${item.name}" + >Remove + + + `; + } +} + +export default UmbDataTypeInputElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-data-type-input': UmbDataTypeInputElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/index.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/index.ts new file mode 100644 index 0000000000..c076c5f9a3 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/index.ts @@ -0,0 +1 @@ +import './data-type-input/data-type-input.element'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/index.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/index.ts new file mode 100644 index 0000000000..758f322450 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/index.ts @@ -0,0 +1 @@ +import './components'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/manifests.ts index fac58d2628..28e0f18938 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/manifests.ts @@ -3,6 +3,7 @@ import { manifests as repositoryManifests } from './repository/manifests'; import { manifests as menuItemManifests } from './menu-item/manifests'; import { manifests as treeManifests } from './tree/manifests'; import { manifests as workspaceManifests } from './workspace/manifests'; +import { manifests as modalManifests } from './modal/manifests'; export const manifests = [ ...entityActions, @@ -10,4 +11,5 @@ export const manifests = [ ...menuItemManifests, ...treeManifests, ...workspaceManifests, + ...modalManifests, ]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/modal/data-type-picker/data-type-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/modal/data-type-picker/data-type-picker-modal.element.ts new file mode 100644 index 0000000000..dd4d6d3a25 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/modal/data-type-picker/data-type-picker-modal.element.ts @@ -0,0 +1,77 @@ +import { css, html } from 'lit'; +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { customElement, property, state } from 'lit/decorators.js'; +import type { UmbTreeElement } from '../../../../shared/components/tree/tree.element'; +import { + UmbDocumentTypePickerModalData, + UmbDocumentTypePickerModalResult, + UmbModalHandler, +} from '@umbraco-cms/backoffice/modal'; +import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; + +// TODO: make use of UmbPickerLayoutBase +@customElement('umb-data-type-picker-modal') +export class UmbDataTypePickerModalElement extends UmbLitElement { + static styles = [UUITextStyles, css``]; + + @property({ attribute: false }) + modalHandler?: UmbModalHandler; + + @property({ type: Object, attribute: false }) + data?: UmbDocumentTypePickerModalData; + + @state() + _selection: Array = []; + + @state() + _multiple = true; + + connectedCallback() { + super.connectedCallback(); + this._selection = this.data?.selection ?? []; + this._multiple = this.data?.multiple ?? true; + } + + private _handleSelectionChange(e: CustomEvent) { + e.stopPropagation(); + const element = e.target as UmbTreeElement; + //TODO: Should multiple property be implemented here or be passed down into umb-tree? + this._selection = this._multiple ? element.selection : [element.selection[element.selection.length - 1]]; + } + + private _submit() { + this.modalHandler?.submit({ selection: this._selection }); + } + + private _close() { + this.modalHandler?.reject(); + } + + render() { + return html` + + + +
+ +
+
+ + +
+
+ `; + } +} + +export default UmbDataTypePickerModalElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-data-type-picker-modal': UmbDataTypePickerModalElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/modal/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/modal/manifests.ts new file mode 100644 index 0000000000..838aba346b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/modal/manifests.ts @@ -0,0 +1,12 @@ +import type { ManifestModal } from '@umbraco-cms/backoffice/extensions-registry'; + +const modals: Array = [ + { + type: 'modal', + alias: 'Umb.Modal.DataTypePicker', + name: 'Data Type Picker Modal', + loader: () => import('./data-type-picker/data-type-picker-modal.element'), + }, +]; + +export const manifests = [...modals]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/index.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/index.ts index a578c12d5c..c86644f739 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/index.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/index.ts @@ -11,6 +11,8 @@ import { manifests as logviewerManifests } from './logviewer/manifests'; import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api'; import { ManifestTypes } from '@umbraco-cms/backoffice/extensions-registry'; +import './data-types/components'; + export const manifests = [ ...settingsSectionManifests, ...settingsMenuManifests, From ec0ead8102861f621f3974cae8343b9849294398 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 12 Apr 2023 21:19:03 +0200 Subject: [PATCH 051/156] support multi and single select in tree element --- .../shared/components/tree/tree.context.ts | 36 ++++++++++++++----- .../shared/components/tree/tree.element.ts | 13 +++++++ 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree.context.ts index 89020e9acd..bfa1b0680d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree.context.ts @@ -1,7 +1,7 @@ import type { Observable } from 'rxjs'; import { UmbTreeRepository } from '@umbraco-cms/backoffice/repository'; import type { ManifestTree } from '@umbraco-cms/backoffice/extensions-registry'; -import { DeepState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; +import { BooleanState, DeepState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { createExtensionClass, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api'; @@ -10,6 +10,7 @@ export interface UmbTreeContext { readonly selectable: Observable; readonly selection: Observable>; setSelectable(value: boolean): void; + setMultiple(value: boolean): void; setSelection(value: Array): void; select(id: string): void; } @@ -18,9 +19,12 @@ export class UmbTreeContextBase implements UmbTreeContext { host: UmbControllerHostElement; public tree: ManifestTree; - #selectable = new DeepState(false); + #selectable = new BooleanState(false); public readonly selectable = this.#selectable.asObservable(); + #multiple = new BooleanState(false); + public readonly multiple = this.#multiple.asObservable(); + #selection = new DeepState(>[]); public readonly selection = this.#selection.asObservable(); @@ -69,22 +73,36 @@ export class UmbTreeContextBase implements UmbTreeContext { this.#selectable.next(value); } + public getSelectable() { + return this.#selectable.getValue(); + } + + public setMultiple(value: boolean) { + this.#multiple.next(value); + } + + public getMultiple() { + return this.#multiple.getValue(); + } + public setSelection(value: Array) { if (!value) return; this.#selection.next(value); } - public select(id: string) { - const oldSelection = this.#selection.getValue(); - if (oldSelection.indexOf(id) !== -1) return; + public getSelection() { + return this.#selection.getValue(); + } - const selection = [...oldSelection, id]; - this.#selection.next(selection); + public select(id: string) { + if (!this.getSelectable()) return; + const newSelection = this.getMultiple() ? [...this.getSelection(), id] : [id]; + this.#selection.next(newSelection); } public deselect(id: string) { - const selection = this.#selection.getValue(); - this.#selection.next(selection.filter((x) => x !== id)); + const newSelection = this.getSelection().filter((x) => x !== id); + this.#selection.next(newSelection); } public async requestRootItems() { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree.element.ts index 3466abc60b..e50d1e7930 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree.element.ts @@ -51,6 +51,18 @@ export class UmbTreeElement extends UmbLitElement { this._treeContext?.setSelection(newVal); } + private _multiple = false; + @property({ type: Boolean, reflect: true }) + get multiple() { + return this._multiple; + } + set multiple(newVal) { + const oldVal = this._multiple; + this._multiple = newVal; + this.requestUpdate('multiple', oldVal); + this._treeContext?.setMultiple(newVal); + } + @state() private _tree?: ManifestTree; @@ -86,6 +98,7 @@ export class UmbTreeElement extends UmbLitElement { this._treeContext = new UmbTreeContextBase(this, this._tree); this._treeContext.setSelectable(this.selectable); this._treeContext.setSelection(this.selection); + this._treeContext.setMultiple(this.multiple); this.#observeSelection(); this.#observeTreeRoot(); From 1bd02328cc5dae471934ea0a5fefa8290bf5bc85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 13 Apr 2023 11:23:44 +0200 Subject: [PATCH 052/156] update URL as tab name changes --- .../document-type-workspace-view-edit.element.ts | 7 ++++--- .../workspace-container-structure-helper.class.ts | 10 ++++++++++ .../workspace-structure-manager.class.ts | 2 +- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit.element.ts index c244382b54..8411f6470f 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit.element.ts @@ -147,7 +147,7 @@ export class UmbDocumentTypeWorkspaceViewEditElement extends UmbLitElement { // TODO: make better url folder name: const path = this._routerPath + '/tab/' + encodeURI(tab.name || ''); return html` - ${path === this._activePath + ${path === this._activePath && this._tabsStructureHelper.isOwnerContainer(tab.id!) ? html` { const newName = (e.target as HTMLInputElement).value; - // Update the current URL, so we are still on this specific tab: - window.history.replaceState(null, '', this._routerPath + '/tab/' + encodeURI(newName)); this._tabsStructureHelper.partialUpdateContainer(tab.id, { name: newName, }); + + // Update the current URL, so we are still on this specific tab: + window.history.replaceState(null, '', this._routerPath + '/tab/' + encodeURI(newName)); }}> x.id === groupId) !== undefined; + } + /** Manipulate methods: */ async addContainer(ownerId?: string, sortOrder?: number) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-structure-manager.class.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-structure-manager.class.ts index 94bca9717d..fd6d6ad19b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-structure-manager.class.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-structure-manager.class.ts @@ -221,7 +221,7 @@ export class UmbWorkspacePropertyStructureManager + partialUpdate: Partial ) { await this.#init; documentTypeId = documentTypeId ?? this.#rootDocumentTypeId!; From 6a6d097ef6a3f8eaaa90b5037daebf29a86d1621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 13 Apr 2023 11:25:53 +0200 Subject: [PATCH 053/156] request delete of tab comment --- .../design/document-type-workspace-view-edit.element.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit.element.ts index 8411f6470f..f6fe6e032d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit.element.ts @@ -120,6 +120,11 @@ export class UmbDocumentTypeWorkspaceViewEditElement extends UmbLitElement { this._routes = routes; } + #requestRemoveTab(tabId: string | undefined) { + // TODO: If this tab is composed of other tabs, then notify that it will only delete the local tab. + // TODO: Update URL when removing tab. + this.#remove(tabId); + } #remove(tabId: string | undefined) { if (!tabId) return; this._workspaceContext?.structure.removeContainer(null, tabId); @@ -162,12 +167,11 @@ export class UmbDocumentTypeWorkspaceViewEditElement extends UmbLitElement { // Update the current URL, so we are still on this specific tab: window.history.replaceState(null, '', this._routerPath + '/tab/' + encodeURI(newName)); }}> - this.#remove(tab.id)} + @click=${() => this.#requestRemoveTab(tab.id)} compact> From 6f9edf21d9351bcbc679be451f11274f1a1a9b26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 14 Apr 2023 08:58:50 +0200 Subject: [PATCH 054/156] commit original code --- .../libs/sorter/sorter.angular.ts | 685 ++++++++++++++++++ 1 file changed, 685 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/libs/sorter/sorter.angular.ts diff --git a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.angular.ts b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.angular.ts new file mode 100644 index 0000000000..a46a4a6c01 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.angular.ts @@ -0,0 +1,685 @@ +(function () { + 'use strict'; + + function isWithinRect(x, y, rect, modifier) { + return ( + x > rect.left - modifier && x < rect.right + modifier && y > rect.top - modifier && y < rect.bottom + modifier + ); + } + + function getParentScrollElement(el, includeSelf) { + // skip to window + if (!el || !el.getBoundingClientRect) return null; + var elem = el; + var gotSelf = false; + + while (elem) { + // we don't need to get elem css if it isn't even overflowing in the first place (performance) + if (elem.clientWidth < elem.scrollWidth || elem.clientHeight < elem.scrollHeight) { + var elemCSS = getComputedStyle(elem); + + if ( + (elem.clientHeight < elem.scrollHeight && (elemCSS.overflowY == 'auto' || elemCSS.overflowY == 'scroll')) || + (elem.clientWidth < elem.scrollWidth && (elemCSS.overflowX == 'auto' || elemCSS.overflowX == 'scroll')) + ) { + if (!elem.getBoundingClientRect || elem === document.body) return null; + if (gotSelf || includeSelf) return elem; + gotSelf = true; + } + } + + if (elem.parentNode === document) { + return null; + } else if (elem.parentNode instanceof DocumentFragment) { + elem = elem.parentNode.host; + } else { + elem = elem.parentNode; + } + } + + return null; + } + + const DefaultConfig = { + compareElementToModel: (el, modelEntry) => modelEntry.contentUdi === el.dataset.elementUdi, + querySelectModelToElement: (container, modelEntry) => + container.querySelector(`[data-element-udi='${modelEntry.contentUdi}']`), + identifier: 'UmbBlockGridSorter', + containerSelector: 'ol', // To find container and to connect with others. + ignorerSelector: 'a, img, iframe', + itemSelector: 'li', + placeholderClass: 'umb-drag-placeholder', + }; + + function UmbBlockGridSorter() { + function link(scope, element) { + let observer = new MutationObserver(function (mutations) { + mutations.forEach(function (mutation) { + mutation.addedNodes.forEach(function (addedNode) { + if (addedNode.matches && addedNode.matches(scope.config.itemSelector)) { + setupItem(addedNode); + } + }); + mutation.removedNodes.forEach(function (removedNode) { + if (removedNode.matches && removedNode.matches(scope.config.itemSelector)) { + destroyItem(removedNode); + } + }); + }); + }); + + let vm = {}; + + const config = { ...DefaultConfig, ...scope.config }; + + vm.identifier = config.identifier; + vm.ownerVM = config.ownerVM || null; + + let scrollElement = null; + + let containerEl = config.containerSelector ? element[0].closest(config.containerSelector) : element[0]; + if (!containerEl) { + console.error('Could not initialize umb block grid sorter.', element[0]); + return; + } + + function init() { + containerEl['umbBlockGridSorter:vm'] = () => { + return vm; + }; + containerEl.addEventListener('dragover', preventDragOver); + + observer.observe(containerEl, { childList: true, subtree: false }); + } + init(); + + function preventDragOver(e) { + e.preventDefault(); + } + + function setupItem(element) { + setupIgnorerElements(element); + + element.draggable = true; + element.addEventListener('dragstart', handleDragStart); + } + + function destroyItem(element) { + destroyIgnorerElements(element); + + element.removeEventListener('dragstart', handleDragStart); + } + + function setupIgnorerElements(element) { + config.ignorerSelector.split(',').forEach(function (criteria) { + element.querySelectorAll(criteria.trim()).forEach(setupPreventEvent); + }); + } + function destroyIgnorerElements(element) { + config.ignorerSelector.split(',').forEach(function (criteria) { + element.querySelectorAll(criteria.trim()).forEach(destroyPreventEvent); + }); + } + function setupPreventEvent(element) { + element.draggable = false; + } + function destroyPreventEvent(element) { + element.removeAttribute('draggable'); + } + + let currentContainerElement = containerEl; + let currentContainerVM = vm; + + let rqaId = null; + let currentItem = null; + let currentElement = null; + let currentDragElement = null; + let currentDragRect = null; + let dragX = 0; + let dragY = 0; + + function handleDragStart(event) { + if (currentElement) { + handleDragEnd(); + } + + event.stopPropagation(); + event.dataTransfer.effectAllowed = 'move'; // copyMove when we enhance the drag with clipboard data. + event.dataTransfer.dropEffect = 'none'; // visual feedback when dropped. + + if (!scrollElement) { + scrollElement = getParentScrollElement(containerEl, true); + } + + const element = event.target.closest(config.itemSelector); + + currentElement = element; + currentDragElement = config.draggableSelector + ? currentElement.querySelector(config.draggableSelector) + : currentElement; + currentDragRect = currentDragElement.getBoundingClientRect(); + currentItem = vm.getItemOfElement(currentElement); + if (!currentItem) { + console.error('Could not find item related to this element.'); + return; + } + + currentElement.style.transform = 'translateZ(0)'; // Solves problem with FireFox and ShadowDom in the drag-image. + + if (config.dataTransferResolver) { + config.dataTransferResolver(event.dataTransfer, currentItem); + } + + if (config.onStart) { + config.onStart({ item: currentItem, element: currentElement }); + } + + window.addEventListener('dragover', handleDragMove); + window.addEventListener('dragend', handleDragEnd); + + // We must wait one frame before changing the look of the block. + rqaId = requestAnimationFrame(() => { + // It should be okay to use the same refId, as the move does not or is okay not to happen on first frame/drag-move. + rqaId = null; + currentElement.style.transform = ''; + currentElement.classList.add(config.placeholderClass); + }); + } + + function handleDragEnd() { + if (!currentElement) { + return; + } + + window.removeEventListener('dragover', handleDragMove); + window.removeEventListener('dragend', handleDragEnd); + currentElement.style.transform = ''; + currentElement.classList.remove(config.placeholderClass); + + stopAutoScroll(); + removeAllowIndication(); + + if (currentContainerVM.sync(currentElement, vm) === false) { + // Sync could not succeed, might be because item is not allowed here. + + currentContainerVM = vm; + if (config.onContainerChange) { + config.onContainerChange({ + item: currentItem, + element: currentElement, + ownerVM: currentContainerVM.ownerVM, + }); + } + + // Lets move the Element back to where it came from: + const movingItemIndex = scope.model.indexOf(currentItem); + if (movingItemIndex < scope.model.length - 1) { + const afterItem = scope.model[movingItemIndex + 1]; + const afterEl = config.querySelectModelToElement(containerEl, afterItem); + containerEl.insertBefore(currentElement, afterEl); + } else { + containerEl.appendChild(currentElement); + } + } + + if (config.onEnd) { + config.onEnd({ item: currentItem, element: currentElement }); + } + + if (rqaId) { + cancelAnimationFrame(rqaId); + } + + currentContainerElement = containerEl; + currentContainerVM = vm; + + rqaId = null; + currentItem = null; + currentElement = null; + currentDragElement = null; + currentDragRect = null; + dragX = 0; + dragY = 0; + } + + function handleDragMove(event) { + if (!currentElement) { + return; + } + + const clientX = (event.touches ? event.touches[0] : event).clientX; + const clientY = (event.touches ? event.touches[1] : event).clientY; + if (clientX !== 0 && clientY !== 0) { + if (dragX === clientX && dragY === clientY) { + return; + } + dragX = clientX; + dragY = clientY; + + handleAutoScroll(dragX, dragY); + + currentDragRect = currentDragElement.getBoundingClientRect(); + const insideCurrentRect = isWithinRect(dragX, dragY, currentDragRect, 0); + if (!insideCurrentRect) { + if (rqaId === null) { + rqaId = requestAnimationFrame(moveCurrentElement); + } + } + } + } + + function moveCurrentElement() { + rqaId = null; + if (!currentElement) { + return; + } + + const currentElementRect = currentElement.getBoundingClientRect(); + const insideCurrentRect = isWithinRect(dragX, dragY, currentElementRect); + if (insideCurrentRect) { + return; + } + + // If we have a boundarySelector, try it, if we didn't get anything fall back to currentContainerElement. + var currentBoundaryElement = + (config.boundarySelector + ? currentContainerElement.closest(config.boundarySelector) + : currentContainerElement) || currentContainerElement; + + var currentBoundaryRect = currentBoundaryElement.getBoundingClientRect(); + + const currentContainerHasItems = currentContainerVM.hasOtherItemsThan(currentItem); + + // if empty we will be move likely to accept an item (add 20px to the bounding box) + // If we have items we must be 10 within the container to accept the move. + const offsetEdge = currentContainerHasItems ? -10 : 20; + if (!isWithinRect(dragX, dragY, currentBoundaryRect, offsetEdge)) { + // we are outside the current container boundary, so lets see if there is a parent we can move. + var parentContainer = currentContainerElement.parentNode.closest(config.containerSelector); + if (parentContainer) { + const parentContainerVM = parentContainer['umbBlockGridSorter:vm'](); + if (parentContainerVM.identifier === vm.identifier) { + currentContainerElement = parentContainer; + currentContainerVM = parentContainerVM; + if (config.onContainerChange) { + config.onContainerChange({ + item: currentItem, + element: currentElement, + ownerVM: currentContainerVM.ownerVM, + }); + } + } + } + } + + // We want to retrieve the children of the container, every time to ensure we got the right order and index + const orderedContainerElements = Array.from(currentContainerElement.children); + + var currentContainerRect = currentContainerElement.getBoundingClientRect(); + + // gather elements on the same row. + let elementsInSameRow = []; + let placeholderIsInThisRow = false; + for (const el of orderedContainerElements) { + const elRect = el.getBoundingClientRect(); + // gather elements on the same row. + if (dragY >= elRect.top && dragY <= elRect.bottom) { + const dragElement = config.draggableSelector ? el.querySelector(config.draggableSelector) : el; + const dragElementRect = dragElement.getBoundingClientRect(); + if (el !== currentElement) { + elementsInSameRow.push({ el: el, dragRect: dragElementRect }); + } else { + placeholderIsInThisRow = true; + } + } + } + + let lastDistance = 99999; + let foundEl = null; + let foundElDragRect = null; + let placeAfter = false; + elementsInSameRow.forEach((sameRow) => { + const centerX = sameRow.dragRect.left + sameRow.dragRect.width * 0.5; + let distance = Math.abs(dragX - centerX); + if (distance < lastDistance) { + foundEl = sameRow.el; + foundElDragRect = sameRow.dragRect; + lastDistance = Math.abs(distance); + placeAfter = dragX > centerX; + } + }); + + // If we are on top or closest to our self, we should not do anything. + if (foundEl === currentElement) { + return; + } + + if (foundEl) { + const isInsideFound = isWithinRect(dragX, dragY, foundElDragRect, 0); + + // If we are inside the found element, lets look for sub containers. + // use the itemHasNestedContainersResolver, if not configured fallback to looking for the existence of a container via DOM. + if ( + isInsideFound && config.itemHasNestedContainersResolver + ? config.itemHasNestedContainersResolver(foundEl) + : foundEl.querySelector(config.containerSelector) + ) { + // Find all sub containers: + const subLayouts = foundEl.querySelectorAll(config.containerSelector); + for (const subLayoutEl of subLayouts) { + // Use boundary element or fallback to container element. + var subBoundaryElement = + (config.boundarySelector ? subLayoutEl.closest(config.boundarySelector) : subLayoutEl) || subLayoutEl; + var subBoundaryRect = subBoundaryElement.getBoundingClientRect(); + + const subContainerHasItems = subLayoutEl.querySelector( + config.itemSelector + ':not(.' + config.placeholderClass + ')' + ); + // gather elements on the same row. + const subOffsetEdge = subContainerHasItems ? -10 : 20; + if (isWithinRect(dragX, dragY, subBoundaryRect, subOffsetEdge)) { + var subVm = subLayoutEl['umbBlockGridSorter:vm'](); + if (subVm.identifier === vm.identifier) { + currentContainerElement = subLayoutEl; + currentContainerVM = subVm; + if (config.onContainerChange) { + config.onContainerChange({ + item: currentItem, + element: currentElement, + ownerVM: currentContainerVM.ownerVM, + }); + } + moveCurrentElement(); + return; + } + } + } + } + + // Indication if drop is good: + if (updateAllowIndication(currentContainerVM, currentItem) === false) { + return; + } + + let verticalDirection = scope.config.resolveVerticalDirection + ? scope.config.resolveVerticalDirection({ + containerElement: currentContainerElement, + containerRect: currentContainerRect, + item: currentItem, + element: currentElement, + elementRect: currentElementRect, + relatedElement: foundEl, + relatedRect: foundElDragRect, + placeholderIsInThisRow: placeholderIsInThisRow, + horizontalPlaceAfter: placeAfter, + }) + : true; + + if (verticalDirection) { + placeAfter = dragY > foundElDragRect.top + foundElDragRect.height * 0.5; + } + + if (verticalDirection) { + let el; + if (placeAfter === false) { + let lastLeft = foundElDragRect.left; + elementsInSameRow.findIndex((x) => { + if (x.dragRect.left < lastLeft) { + lastLeft = x.dragRect.left; + el = x.el; + } + }); + } else { + let lastRight = foundElDragRect.right; + elementsInSameRow.findIndex((x) => { + if (x.dragRect.right > lastRight) { + lastRight = x.dragRect.right; + el = x.el; + } + }); + } + if (el) { + foundEl = el; + } + } + + const foundElIndex = orderedContainerElements.indexOf(foundEl); + const placeAt = placeAfter ? foundElIndex + 1 : foundElIndex; + + move(orderedContainerElements, placeAt); + + return; + } + // We skipped the above part cause we are above or below container: + + // Indication if drop is good: + if (updateAllowIndication(currentContainerVM, currentItem) === false) { + return; + } + + if (dragY < currentContainerRect.top) { + move(orderedContainerElements, 0); + } else if (dragY > currentContainerRect.bottom) { + move(orderedContainerElements, -1); + } + } + + function move(orderedContainerElements, newElIndex) { + newElIndex = newElIndex === -1 ? orderedContainerElements.length : newElIndex; + + const placeBeforeElement = orderedContainerElements[newElIndex]; + if (placeBeforeElement) { + // We do not need to move this, if the element to be placed before is it self. + if (placeBeforeElement !== currentElement) { + currentContainerElement.insertBefore(currentElement, placeBeforeElement); + } + } else { + currentContainerElement.appendChild(currentElement); + } + + if (config.onChange) { + config.onChange({ element: currentElement, item: currentItem, ownerVM: currentContainerVM.ownerVM }); + } + } + + /** Removes an element from container and returns its items-data entry */ + vm.getItemOfElement = function (element) { + if (!element) { + return null; + } + return scope.model.find((entry) => config.compareElementToModel(element, entry)); + }; + vm.removeItem = function (item) { + if (!item) { + return null; + } + const oldIndex = scope.model.indexOf(item); + if (oldIndex !== -1) { + return scope.model.splice(oldIndex, 1)[0]; + } + return null; + }; + + vm.hasOtherItemsThan = function (item) { + return scope.model.filter((x) => x !== item).length > 0; + }; + + vm.sync = function (element, fromVm) { + const movingItem = fromVm.getItemOfElement(element); + if (!movingItem) { + console.error('Could not find item of sync item'); + return false; + } + if (vm.notifyRequestDrop({ item: movingItem }) === false) { + return false; + } + if (fromVm.removeItem(movingItem) === null) { + console.error('Sync could not remove item'); + return false; + } + + /** Find next element, to then find the index of that element in items-data, to use as a safe reference to where the item will go in our items-data. + * This enables the container to contain various other elements and as well having these elements change while sorting is occurring. + */ + + // find next valid element (This assumes the next element in DOM is presented in items-data, aka. only moving one item between each sync) + let nextEl; + let loopEl = element; + while ((loopEl = loopEl.nextElementSibling)) { + if (loopEl.matches && loopEl.matches(config.itemSelector)) { + nextEl = loopEl; + break; + } + } + + let newIndex = scope.model.length; + if (nextEl) { + // We had a reference element, we want to get the index of it. + // This is problem if a item is being moved forward? + newIndex = scope.model.findIndex((entry) => config.compareElementToModel(nextEl, entry)); + } + + scope.model.splice(newIndex, 0, movingItem); + + const eventData = { item: movingItem, fromController: fromVm, toController: vm }; + if (fromVm !== vm) { + fromVm.notifySync(eventData); + } + vm.notifySync(eventData); + + return true; + }; + + var _lastIndicationContainerVM = null; + function updateAllowIndication(contextVM, item) { + // Remove old indication: + if (_lastIndicationContainerVM !== null && _lastIndicationContainerVM !== contextVM) { + _lastIndicationContainerVM.notifyAllowed(); + } + _lastIndicationContainerVM = contextVM; + + if (contextVM.notifyRequestDrop({ item: item }) === true) { + contextVM.notifyAllowed(); + return true; + } + + contextVM.notifyDisallowed(); // This block is not accepted to we will indicate that its not allowed. + return false; + } + function removeAllowIndication() { + // Remove old indication: + if (_lastIndicationContainerVM !== null) { + _lastIndicationContainerVM.notifyAllowed(); + } + _lastIndicationContainerVM = null; + } + + let autoScrollRAF; + let autoScrollEl; + const autoScrollSensitivity = 50; + const autoScrollSpeed = 16; + let autoScrollX = 0; + let autoScrollY = 0; + + function handleAutoScroll(clientX, clientY) { + let scrollRect = null; + if (scrollElement) { + autoScrollEl = scrollElement; + scrollRect = scrollElement.getBoundingClientRect(); + } else { + autoScrollEl = document.scrollingElement || document.documentElement; + scrollRect = { + top: 0, + left: 0, + bottom: window.innerHeight, + right: window.innerWidth, + height: window.innerHeight, + width: window.innerWidth, + }; + } + + const scrollWidth = autoScrollEl.scrollWidth; + const scrollHeight = autoScrollEl.scrollHeight; + const canScrollX = scrollRect.width < scrollWidth; + const canScrollY = scrollRect.height < scrollHeight; + const scrollPosX = autoScrollEl.scrollLeft; + const scrollPosY = autoScrollEl.scrollTop; + + cancelAnimationFrame(autoScrollRAF); + + if (canScrollX || canScrollY) { + autoScrollX = + (Math.abs(scrollRect.right - clientX) <= autoScrollSensitivity && + scrollPosX + scrollRect.width < scrollWidth) - + (Math.abs(scrollRect.left - clientX) <= autoScrollSensitivity && !!scrollPosX); + autoScrollY = + (Math.abs(scrollRect.bottom - clientY) <= autoScrollSensitivity && + scrollPosY + scrollRect.height < scrollHeight) - + (Math.abs(scrollRect.top - clientY) <= autoScrollSensitivity && !!scrollPosY); + autoScrollRAF = requestAnimationFrame(performAutoScroll); + } + } + function performAutoScroll() { + autoScrollEl.scrollLeft += autoScrollX * autoScrollSpeed; + autoScrollEl.scrollTop += autoScrollY * autoScrollSpeed; + autoScrollRAF = requestAnimationFrame(performAutoScroll); + } + function stopAutoScroll() { + cancelAnimationFrame(autoScrollRAF); + autoScrollRAF = null; + } + + vm.notifySync = function (data) { + if (config.onSync) { + config.onSync(data); + } + }; + vm.notifyDisallowed = function () { + if (config.onDisallowed) { + config.onDisallowed(); + } + }; + vm.notifyAllowed = function () { + if (config.onAllowed) { + config.onAllowed(); + } + }; + vm.notifyRequestDrop = function (data) { + if (config.onRequestDrop) { + return config.onRequestDrop(data); + } + return true; + }; + + scope.$on('$destroy', () => { + if (currentElement) { + handleDragEnd(); + } + + _lastIndicationContainerVM = null; + + containerEl['umbBlockGridSorter:vm'] = null; + containerEl.removeEventListener('dragover', preventDragOver); + + observer.disconnect(); + observer = null; + containerEl = null; + scrollElement = null; + vm = null; + }); + } + + var directive = { + restrict: 'A', + scope: { + config: '=umbBlockGridSorter', + model: '=umbBlockGridSorterModel', + }, + link: link, + }; + + return directive; + } + + angular.module('umbraco.directives').directive('umbBlockGridSorter', UmbBlockGridSorter); +})(); From 24a371d3b986cf25a01428539ded51c7f26836b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 14 Apr 2023 08:59:09 +0200 Subject: [PATCH 055/156] switch format --- .../libs/sorter/{sorter.angular.ts => sorter.angular.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Umbraco.Web.UI.Client/libs/sorter/{sorter.angular.ts => sorter.angular.js} (100%) diff --git a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.angular.ts b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.angular.js similarity index 100% rename from src/Umbraco.Web.UI.Client/libs/sorter/sorter.angular.ts rename to src/Umbraco.Web.UI.Client/libs/sorter/sorter.angular.js From ff94a986c8644bf16bf360e015597c4f36a90e58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 14 Apr 2023 16:32:53 +0200 Subject: [PATCH 056/156] initial convert --- .../libs/sorter/sorter.controller.ts | 745 ++++++++++++++++++ 1 file changed, 745 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts diff --git a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts new file mode 100644 index 0000000000..d3cc5c6683 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts @@ -0,0 +1,745 @@ +import { UmbControllerInterface, UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; + +const autoScrollSensitivity = 50; +const autoScrollSpeed = 16; + +function isWithinRect(x: number, y: number, rect: DOMRect, modifier: number = 0) { + return x > rect.left - modifier && x < rect.right + modifier && y > rect.top - modifier && y < rect.bottom + modifier; +} + +function getParentScrollElement(el: Element, includeSelf: boolean) { + if (!el || !el.getBoundingClientRect) return null; + + let elem = el; + let gotSelf = false; + + while (elem) { + // we don't need to get elem css if it isn't even overflowing in the first place (performance) + if (elem.clientWidth < elem.scrollWidth || elem.clientHeight < elem.scrollHeight) { + const elemCSS = getComputedStyle(elem); + + if ( + (elem.clientHeight < elem.scrollHeight && (elemCSS.overflowY == 'auto' || elemCSS.overflowY == 'scroll')) || + (elem.clientWidth < elem.scrollWidth && (elemCSS.overflowX == 'auto' || elemCSS.overflowX == 'scroll')) + ) { + if (!elem.getBoundingClientRect || elem === document.body) return null; + if (gotSelf || includeSelf) return elem; + gotSelf = true; + } + } + + if (elem.parentNode === document) { + return null; + } else if (elem.parentNode instanceof ShadowRoot) { + elem = elem.parentNode.host; + } else { + elem = elem.parentNode as Element; + } + } + + return null; +} + +function preventDragOver(e: Event) { + e.preventDefault(); +} + +function setupIgnorerElements(element: HTMLElement, ignorerSelectors: string) { + ignorerSelectors.split(',').forEach(function (criteria) { + element.querySelectorAll(criteria.trim()).forEach(setupPreventEvent); + }); +} +function destroyIgnorerElements(element: HTMLElement, ignorerSelectors: string) { + ignorerSelectors.split(',').forEach(function (criteria: string) { + element.querySelectorAll(criteria.trim()).forEach(destroyPreventEvent); + }); +} +function setupPreventEvent(element: Element) { + (element as HTMLElement).draggable = false; +} +function destroyPreventEvent(element: Element) { + element.removeAttribute('draggable'); +} + +export type UmbSorterConfig = { + compareElementToModel: (el: HTMLElement, modelEntry: T) => boolean; + querySelectModelToElement: (container: HTMLElement, modelEntry: T) => HTMLElement; + identifier: string; + ignorerSelector: string; + itemSelector: string; + placeholderClass: string; + containerSelector: string; + draggableSelector?: string; + boundarySelector?: string; + dataTransferResolver?: (dataTransfer: DataTransfer | null, currentItem: T) => void; + onStart?: (argument: { item: T; element: HTMLElement }) => void; + onChange?: (argument: { item: T; element: HTMLElement }) => void; + onContainerChange?: (argument: { item: T; element: HTMLElement }) => void; + onEnd?: (argument: { item: T; element: HTMLElement }) => void; + onSync?: (argument: { + item: T; + fromController: UmbSorterController; + toController: UmbSorterController; + }) => void; + itemHasNestedContainersResolver?: (element: HTMLElement) => boolean; + onDisallowed?: () => void; + onAllowed?: () => void; + onRequestDrop?: (argument: { item: T }) => boolean | void; + resolveVerticalDirection?: (argument: { + containerElement: Element; + containerRect: DOMRect; + item: T; + element: HTMLElement; + elementRect: DOMRect; + relatedElement: HTMLElement; + relatedRect: DOMRect; + placeholderIsInThisRow: boolean; + horizontalPlaceAfter: boolean; + }) => void; +}; + +export class UmbSorterController implements UmbControllerInterface { + #host; + #config; + #observer; + + #model: Array = []; + #rqaId?: number; + + #currentContainerVM = this; + #currentContainerElement: Element; + + #scrollElement?: Element | null; + #currentElement?: HTMLElement; + #currentDragElement?: Element; + #currentDragRect?: DOMRect; + #currentItem?: T | null; + + #dragX = 0; + #dragY = 0; + + private _lastIndicationContainerVM: UmbSorterController | null = null; + + public get unique() { + return this.#config.identifier; + } + + constructor(host: UmbControllerHostElement, config: UmbSorterConfig) { + this.#host = host; + this.#config = config; + host.addController(this); + + this.#currentContainerElement = host; + + this.#observer = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + mutation.addedNodes.forEach((addedNode) => { + if ((addedNode as HTMLElement).matches && (addedNode as HTMLElement).matches(this.#config.itemSelector)) { + this.setupItem(addedNode as HTMLElement); + } + }); + mutation.removedNodes.forEach((removedNode) => { + if ((removedNode as HTMLElement).matches && (removedNode as HTMLElement).matches(this.#config.itemSelector)) { + this.destroyItem(removedNode as HTMLElement); + } + }); + }); + }); + + (host as any)['__umbBlockGridSorterController'] = () => { + return this; + }; + host.addEventListener('dragover', preventDragOver); + } + + setModel(model: Array) { + this.#model = model; + // TODO: Some update? + } + + hostConnected() { + this.#observer.observe(this.#host, { childList: true, subtree: false }); + } + hostDisconnected() { + this.#observer.disconnect(); + } + + setupItem(element: HTMLElement) { + setupIgnorerElements(element, this.#config.ignorerSelector); + + element.draggable = true; + element.addEventListener('dragstart', this.handleDragStart); + } + + destroyItem(element: HTMLElement) { + destroyIgnorerElements(element, this.#config.ignorerSelector); + + element.removeEventListener('dragstart', this.handleDragStart); + } + + handleDragStart = (event: DragEvent) => { + if (this.#currentElement) { + this.handleDragEnd(); + } + + event.stopPropagation(); + if (event.dataTransfer) { + event.dataTransfer.effectAllowed = 'move'; // copyMove when we enhance the drag with clipboard data. + event.dataTransfer.dropEffect = 'none'; // visual feedback when dropped. + } + + if (!this.#scrollElement) { + this.#scrollElement = getParentScrollElement(this.#host, true); + } + + const element = (event.target as HTMLElement).closest(this.#config.itemSelector); + + if (!element) return; + + this.#currentDragElement = this.#config.draggableSelector + ? element.querySelector(this.#config.draggableSelector) ?? undefined + : element; + + if (!this.#currentDragElement) { + throw new Error( + 'Could not find drag element, query was made with the `draggableSelector` of "' + + this.#config.draggableSelector + + '"' + ); + return; + } + + this.#currentElement = element as HTMLElement; + this.#currentDragRect = this.#currentDragElement.getBoundingClientRect(); + this.#currentItem = this.getItemOfElement(this.#currentElement); + if (!this.#currentItem) { + console.error('Could not find item related to this element.'); + return; + } + + this.#currentElement.style.transform = 'translateZ(0)'; // Solves problem with FireFox and ShadowDom in the drag-image. + + if (this.#config.dataTransferResolver) { + this.#config.dataTransferResolver(event.dataTransfer, this.#currentItem); + } + + if (this.#config.onStart) { + this.#config.onStart({ item: this.#currentItem!, element: this.#currentElement }); + } + + window.addEventListener('dragover', this.handleDragMove); + window.addEventListener('dragend', this.handleDragEnd); + + // We must wait one frame before changing the look of the block. + this.#rqaId = requestAnimationFrame(() => { + // It should be okay to use the same rqafId, as the move does not or is okay not to happen on first frame/drag-move. + this.#rqaId = undefined; + if (this.#currentElement) { + this.#currentElement.style.transform = ''; + this.#currentElement.classList.add(this.#config.placeholderClass); + } + }); + }; + + handleDragEnd = () => { + if (!this.#currentElement || !this.#currentItem) { + return; + } + + window.removeEventListener('dragover', this.handleDragMove); + window.removeEventListener('dragend', this.handleDragEnd); + this.#currentElement.style.transform = ''; + this.#currentElement.classList.remove(this.#config.placeholderClass); + + this.stopAutoScroll(); + this.removeAllowIndication(); + + if (this.#currentContainerVM.sync(this.#currentElement, this) === false) { + // Sync could not succeed, might be because item is not allowed here. + + this.#currentContainerVM = this; + if (this.#config.onContainerChange) { + this.#config.onContainerChange({ + item: this.#currentItem, + element: this.#currentElement, + //ownerVM: this.#currentContainerVM.ownerVM, + }); + } + + // Lets move the Element back to where it came from: + const movingItemIndex = this.#model.indexOf(this.#currentItem); + if (movingItemIndex < this.#model.length - 1) { + const afterItem = this.#model[movingItemIndex + 1]; + const afterEl = this.#config.querySelectModelToElement(this.#host, afterItem); + this.#host.insertBefore(this.#currentElement, afterEl); + } else { + this.#host.appendChild(this.#currentElement); + } + } + + if (this.#config.onEnd) { + this.#config.onEnd({ item: this.#currentItem, element: this.#currentElement }); + } + + if (this.#rqaId) { + cancelAnimationFrame(this.#rqaId); + } + + this.#currentContainerElement = this.#host; + this.#currentContainerVM = this; + + this.#rqaId = undefined; + this.#currentItem = undefined; + this.#currentElement = undefined; + this.#currentDragElement = undefined; + this.#currentDragRect = undefined; + this.#dragX = 0; + this.#dragY = 0; + }; + + handleDragMove = (event: DragEvent) => { + if (!this.#currentElement) { + return; + } + + const clientX = (event as unknown as TouchEvent).touches + ? (event as unknown as TouchEvent).touches[0].clientX + : event.clientX; + const clientY = (event as unknown as TouchEvent).touches + ? (event as unknown as TouchEvent).touches[0].clientY + : event.clientY; + if (clientX !== 0 && clientY !== 0) { + if (this.#dragX === clientX && this.#dragY === clientY) { + return; + } + this.#dragX = clientX; + this.#dragY = clientY; + + handleAutoScroll(this.#dragX, this.#dragY); + + this.#currentDragRect = this.#currentDragElement!.getBoundingClientRect(); + const insideCurrentRect = isWithinRect(this.#dragX, this.#dragY, this.#currentDragRect); + if (!insideCurrentRect) { + if (this.#rqaId === null) { + this.#rqaId = requestAnimationFrame(this.moveCurrentElement); + } + } + } + }; + + moveCurrentElement = () => { + this.#rqaId = undefined; + if (!this.#currentElement || !this.#currentContainerElement || !this.#currentItem) { + return; + } + + const currentElementRect = this.#currentElement.getBoundingClientRect(); + const insideCurrentRect = isWithinRect(this.#dragX, this.#dragY, currentElementRect); + if (insideCurrentRect) { + return; + } + + // If we have a boundarySelector, try it, if we didn't get anything fall back to currentContainerElement. + const currentBoundaryElement = + (this.#config.boundarySelector + ? this.#currentContainerElement.closest(this.#config.boundarySelector) + : this.#currentContainerElement) || this.#currentContainerElement; + + const currentBoundaryRect = currentBoundaryElement.getBoundingClientRect(); + + const currentContainerHasItems = this.#currentContainerVM.hasOtherItemsThan(this.#currentItem!); + + // if empty we will be move likely to accept an item (add 20px to the bounding box) + // If we have items we must be 10 within the container to accept the move. + const offsetEdge = currentContainerHasItems ? -10 : 20; + if (!isWithinRect(this.#dragX, this.#dragY, currentBoundaryRect, offsetEdge)) { + // we are outside the current container boundary, so lets see if there is a parent we can move. + const parentNode = this.#currentContainerElement.parentNode; + const parentContainer = parentNode ? (parentNode as HTMLElement).closest(this.#config.containerSelector) : null; + if (parentContainer) { + const parentContainerVM = (parentContainer as any)['__umbBlockGridSorterController'](); + if (parentContainerVM.unique === this.unique) { + this.#currentContainerElement = parentContainer; + this.#currentContainerVM = parentContainerVM; + if (this.#config.onContainerChange) { + this.#config.onContainerChange({ + item: this.#currentItem, + element: this.#currentElement, + //ownerVM: this.#currentContainerVM.ownerVM, + }); + } + } + } + } + + // We want to retrieve the children of the container, every time to ensure we got the right order and index + const orderedContainerElements = Array.from(this.#currentContainerElement.children); + + const currentContainerRect = this.#currentContainerElement.getBoundingClientRect(); + + // gather elements on the same row. + const elementsInSameRow = []; + let placeholderIsInThisRow = false; + for (const el of orderedContainerElements) { + const elRect = el.getBoundingClientRect(); + // gather elements on the same row. + if (this.#dragY >= elRect.top && this.#dragY <= elRect.bottom) { + const dragElement = this.#config.draggableSelector ? el.querySelector(this.#config.draggableSelector) : el; + if (dragElement) { + const dragElementRect = dragElement.getBoundingClientRect(); + if (el !== this.#currentElement) { + elementsInSameRow.push({ el: el, dragRect: dragElementRect }); + } else { + placeholderIsInThisRow = true; + } + } + } + } + + let lastDistance = 99999; + let foundEl: Element | null = null; + let foundElDragRect!: DOMRect; + let placeAfter = false; + elementsInSameRow.forEach((sameRow) => { + const centerX = sameRow.dragRect.left + sameRow.dragRect.width * 0.5; + const distance = Math.abs(this.#dragX - centerX); + if (distance < lastDistance) { + foundEl = sameRow.el; + foundElDragRect = sameRow.dragRect; + lastDistance = distance; + placeAfter = this.#dragX > centerX; + } + }); + + if (foundEl) { + // If we are on top or closest to our self, we should not do anything. + if (foundEl === this.#currentElement) { + return; + } + const isInsideFound = isWithinRect(this.#dragX, this.#dragY, foundElDragRect, 0); + + // If we are inside the found element, lets look for sub containers. + // use the itemHasNestedContainersResolver, if not configured fallback to looking for the existence of a container via DOM. + if ( + isInsideFound && this.#config.itemHasNestedContainersResolver + ? this.#config.itemHasNestedContainersResolver(foundEl) + : (foundEl as HTMLElement).querySelector(this.#config.containerSelector) + ) { + // Find all sub containers: + const subLayouts = (foundEl as HTMLElement).querySelectorAll(this.#config.containerSelector); + for (const subLayoutEl of subLayouts) { + // Use boundary element or fallback to container element. + const subBoundaryElement = + (this.#config.boundarySelector ? subLayoutEl.closest(this.#config.boundarySelector) : subLayoutEl) || + subLayoutEl; + const subBoundaryRect = subBoundaryElement.getBoundingClientRect(); + + const subContainerHasItems = subLayoutEl.querySelector( + this.#config.itemSelector + ':not(.' + this.#config.placeholderClass + ')' + ); + // gather elements on the same row. + const subOffsetEdge = subContainerHasItems ? -10 : 20; + if (isWithinRect(this.#dragX, this.#dragY, subBoundaryRect, subOffsetEdge)) { + const subVm = (subLayoutEl as any)['__umbBlockGridSorterController'](); + if (subVm.unique === this.unique) { + this.#currentContainerElement = subLayoutEl as HTMLElement; + this.#currentContainerVM = subVm; + if (this.#config.onContainerChange) { + this.#config.onContainerChange({ + item: this.#currentItem, + element: this.#currentElement, + //ownerVM: this.#currentContainerVM.ownerVM, + }); + } + this.moveCurrentElement(); + return; + } + } + } + } + + // Indication if drop is good: + if (this.updateAllowIndication(this.#currentContainerVM, this.#currentItem) === false) { + return; + } + + const verticalDirection = this.#config.resolveVerticalDirection + ? this.#config.resolveVerticalDirection({ + containerElement: this.#currentContainerElement, + containerRect: currentContainerRect, + item: this.#currentItem, + element: this.#currentElement, + elementRect: currentElementRect, + relatedElement: foundEl, + relatedRect: foundElDragRect, + placeholderIsInThisRow: placeholderIsInThisRow, + horizontalPlaceAfter: placeAfter, + }) + : true; + + if (verticalDirection) { + placeAfter = this.#dragY > foundElDragRect.top + foundElDragRect.height * 0.5; + } + + if (verticalDirection) { + let el; + if (placeAfter === false) { + let lastLeft = foundElDragRect.left; + elementsInSameRow.findIndex((x) => { + if (x.dragRect.left < lastLeft) { + lastLeft = x.dragRect.left; + el = x.el; + } + }); + } else { + let lastRight = foundElDragRect.right; + elementsInSameRow.findIndex((x) => { + if (x.dragRect.right > lastRight) { + lastRight = x.dragRect.right; + el = x.el; + } + }); + } + if (el) { + foundEl = el; + } + } + + const foundElIndex = orderedContainerElements.indexOf(foundEl); + const placeAt = placeAfter ? foundElIndex + 1 : foundElIndex; + + this.move(orderedContainerElements, placeAt); + + return; + } + // We skipped the above part cause we are above or below container: + + // Indication if drop is good: + if (this.updateAllowIndication(this.#currentContainerVM, this.#currentItem) === false) { + return; + } + + if (this.#dragY < currentContainerRect.top) { + this.move(orderedContainerElements, 0); + } else if (this.#dragY > currentContainerRect.bottom) { + this.move(orderedContainerElements, -1); + } + }; + + move(orderedContainerElements: Array, newElIndex: number) { + if (!this.#currentElement || !this.#currentItem) return; + + newElIndex = newElIndex === -1 ? orderedContainerElements.length : newElIndex; + + const placeBeforeElement = orderedContainerElements[newElIndex]; + if (placeBeforeElement) { + // We do not need to move this, if the element to be placed before is it self. + if (placeBeforeElement !== this.#currentElement) { + this.#currentContainerElement.insertBefore(this.#currentElement, placeBeforeElement); + } + } else { + this.#currentContainerElement.appendChild(this.#currentElement); + } + + if (this.#config.onChange) { + this.#config.onChange({ + element: this.#currentElement, + item: this.#currentItem, + //ownerVM: this.#currentContainerVM.ownerVM + }); + } + } + + /** Management methods: */ + + public getItemOfElement(element: HTMLElement) { + if (!element) { + return null; + } + return this.#model.find((entry: T) => this.#config.compareElementToModel(element, entry)); + } + + public removeItem(item: T) { + if (!item) { + return null; + } + const oldIndex = this.#model.indexOf(item); + if (oldIndex !== -1) { + return this.#model.splice(oldIndex, 1)[0]; + } + return null; + } + + hasOtherItemsThan(item: T) { + return this.#model.filter((x) => x !== item).length > 0; + } + + public sync(element: HTMLElement, fromVm: UmbSorterController) { + const movingItem = fromVm.getItemOfElement(element); + if (!movingItem) { + console.error('Could not find item of sync item'); + return false; + } + if (this.notifyRequestDrop({ item: movingItem }) === false) { + return false; + } + if (fromVm.removeItem(movingItem) === null) { + console.error('Sync could not remove item'); + return false; + } + + /** Find next element, to then find the index of that element in items-data, to use as a safe reference to where the item will go in our items-data. + * This enables the container to contain various other elements and as well having these elements change while sorting is occurring. + */ + + // find next valid element (This assumes the next element in DOM is presented in items-data, aka. only moving one item between each sync) + let nextEl: Element | null = null; + let loopEl: Element | null = element; + while ((loopEl = loopEl?.nextElementSibling)) { + if (loopEl.matches && loopEl.matches(this.#config.itemSelector)) { + nextEl = loopEl; + break; + } + } + + let newIndex = this.#model.length; + if (nextEl) { + // We had a reference element, we want to get the index of it. + // This is problem if a item is being moved forward? + newIndex = this.#model.findIndex((entry) => this.#config.compareElementToModel(nextEl! as HTMLElement, entry)); + } + + this.#model.splice(newIndex, 0, movingItem); + + const eventData = { item: movingItem, fromController: fromVm, toController: this }; + if (fromVm !== this) { + fromVm.notifySync(eventData); + } + this.notifySync(eventData); + + return true; + } + + updateAllowIndication(contextVM: UmbSorterController, item: T) { + // Remove old indication: + if (this._lastIndicationContainerVM !== null && this._lastIndicationContainerVM !== contextVM) { + this._lastIndicationContainerVM.notifyAllowed(); + } + this._lastIndicationContainerVM = contextVM; + + if (contextVM.notifyRequestDrop({ item: item }) === true) { + contextVM.notifyAllowed(); + return true; + } + + contextVM.notifyDisallowed(); // This block is not accepted to we will indicate that its not allowed. + return false; + } + removeAllowIndication() { + // Remove old indication: + if (this._lastIndicationContainerVM !== null) { + this._lastIndicationContainerVM.notifyAllowed(); + } + this._lastIndicationContainerVM = null; + } + + // TODO: Move auto scroll into its own class? + #autoScrollRAF: number | null = null; + #autoScrollEl?: Element; + private autoScrollX = 0; + private autoScrollY = 0; + + private handleAutoScroll(clientX: number, clientY: number) { + let scrollRect = null; + if (this.#scrollElement) { + this.#autoScrollEl = this.#scrollElement; + scrollRect = this.#autoScrollEl.getBoundingClientRect(); + } else { + this.#autoScrollEl = document.scrollingElement || document.documentElement; + scrollRect = { + top: 0, + left: 0, + bottom: window.innerHeight, + right: window.innerWidth, + height: window.innerHeight, + width: window.innerWidth, + }; + } + + const scrollWidth = this.#autoScrollEl.scrollWidth; + const scrollHeight = this.#autoScrollEl.scrollHeight; + const canScrollX = scrollRect.width < scrollWidth; + const canScrollY = scrollRect.height < scrollHeight; + const scrollPosX = this.#autoScrollEl.scrollLeft; + const scrollPosY = this.#autoScrollEl.scrollTop; + + cancelAnimationFrame(this.#autoScrollRAF!); + + if (canScrollX || canScrollY) { + this.autoScrollX = + Math.abs(scrollRect.right - clientX) <= autoScrollSensitivity && scrollPosX + scrollRect.width < scrollWidth + ? 1 + : Math.abs(scrollRect.left - clientX) <= autoScrollSensitivity && !!scrollPosX + ? -1 + : 0; + + this.autoScrollY = + Math.abs(scrollRect.bottom - clientY) <= autoScrollSensitivity && scrollPosY + scrollRect.height < scrollHeight + ? 1 + : Math.abs(scrollRect.top - clientY) <= autoScrollSensitivity && !!scrollPosY + ? -1 + : 0; + + this.#autoScrollRAF = requestAnimationFrame(this._performAutoScroll); + } + } + private _performAutoScroll() { + this.#autoScrollEl!.scrollLeft += this.autoScrollX * autoScrollSpeed; + this.#autoScrollEl!.scrollTop += this.autoScrollY * autoScrollSpeed; + this.#autoScrollRAF = requestAnimationFrame(this._performAutoScroll); + } + private stopAutoScroll() { + cancelAnimationFrame(this.#autoScrollRAF!); + this.#autoScrollRAF = null; + } + + public notifySync(data: any) { + if (this.#config.onSync) { + this.#config.onSync(data); + } + } + public notifyDisallowed() { + if (this.#config.onDisallowed) { + this.#config.onDisallowed(); + } + } + public notifyAllowed() { + if (this.#config.onAllowed) { + this.#config.onAllowed(); + } + } + public notifyRequestDrop(data: any) { + if (this.#config.onRequestDrop) { + return this.#config.onRequestDrop(data) || false; + } + return true; + } + + destroy() { + // Do something when host element is destroyed. + if (this.#currentElement) { + this.handleDragEnd(); + } + + this._lastIndicationContainerVM = null; + + (this.#host as any)['__umbBlockGridSorterController'] = null; + this.#host.removeEventListener('dragover', preventDragOver); + + this.#observer.disconnect(); + + // For auto scroller: + this.#scrollElement = null; + this.#autoScrollEl = undefined; + } +} From 8d27725d967744ae50304edfb76776ca73a590d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 14 Apr 2023 16:32:57 +0200 Subject: [PATCH 057/156] index --- src/Umbraco.Web.UI.Client/libs/sorter/index.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/Umbraco.Web.UI.Client/libs/sorter/index.ts diff --git a/src/Umbraco.Web.UI.Client/libs/sorter/index.ts b/src/Umbraco.Web.UI.Client/libs/sorter/index.ts new file mode 100644 index 0000000000..c3024038f4 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/sorter/index.ts @@ -0,0 +1 @@ +export * from './sorter.controller'; From cd9a3a3275345281ef1178b3a2adf4ecd62e6c78 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Sun, 16 Apr 2023 20:27:07 +0200 Subject: [PATCH 058/156] add eslint to to ensure umb prefix on classes --- src/Umbraco.Web.UI.Client/.eslintrc.json | 1 + .../eslint-local-rules.cjs | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/.eslintrc.json b/src/Umbraco.Web.UI.Client/.eslintrc.json index 88caa66773..5d886c4d8f 100644 --- a/src/Umbraco.Web.UI.Client/.eslintrc.json +++ b/src/Umbraco.Web.UI.Client/.eslintrc.json @@ -44,6 +44,7 @@ "local-rules/enforce-element-suffix-on-element-class-name": "error", "local-rules/prefer-umbraco-cms-imports": "error", "local-rules/no-external-imports": "error", + "local-rules/umb-class-prefix": "error", "@typescript-eslint/no-non-null-assertion": "off" }, "settings": { diff --git a/src/Umbraco.Web.UI.Client/eslint-local-rules.cjs b/src/Umbraco.Web.UI.Client/eslint-local-rules.cjs index ed1c5036cd..5d121e8cfb 100644 --- a/src/Umbraco.Web.UI.Client/eslint-local-rules.cjs +++ b/src/Umbraco.Web.UI.Client/eslint-local-rules.cjs @@ -205,4 +205,31 @@ module.exports = { }; }, }, + + /** @type {import('eslint').Rule.RuleModule} */ + 'umb-class-prefix': { + meta: { + type: 'problem', + docs: { + description: 'Ensure that all class declarations are prefixed with "Umb"', + category: 'Best Practices', + recommended: true, + }, + schema: [], + }, + create: function (context) { + function checkClassName(node) { + if (node.id && node.id.name && !node.id.name.startsWith('Umb')) { + context.report({ + node: node.id, + message: 'Class declaration should be prefixed with "Umb"', + }); + } + } + + return { + ClassDeclaration: checkClassName, + }; + }, + }, }; From cc7b07c61c3ce941dc9f20960799b87954f8a6b2 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Sun, 16 Apr 2023 20:30:39 +0200 Subject: [PATCH 059/156] prefix with umb --- .../dictionary/repository/dictionary.repository.ts | 4 ++-- .../repository/sources/dictionary.tree.server.data.ts | 10 +++++----- .../context-provider/context-provider.element.test.ts | 6 +++--- .../core/controller-host/controller-host-test.test.ts | 6 +++--- .../src/core/modal/stories/modal.stories.ts | 2 +- .../stories/story-modal-service-example.element.ts | 4 ++-- .../core/notification/stories/notification.stories.ts | 2 +- .../story-notification-default-example.element.ts | 6 +++--- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/repository/dictionary.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/repository/dictionary.repository.ts index 0ce6e7db0f..d805833fe8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/repository/dictionary.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/repository/dictionary.repository.ts @@ -1,7 +1,7 @@ import { UmbDictionaryStore, UMB_DICTIONARY_STORE_CONTEXT_TOKEN } from './dictionary.store'; import { UmbDictionaryDetailServerDataSource } from './sources/dictionary.detail.server.data'; import { UmbDictionaryTreeStore, UMB_DICTIONARY_TREE_STORE_CONTEXT_TOKEN } from './dictionary.tree.store'; -import { DictionaryTreeServerDataSource } from './sources/dictionary.tree.server.data'; +import { UmbDictionaryTreeServerDataSource } from './sources/dictionary.tree.server.data'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; import { UmbTreeDataSource, UmbDetailRepository, UmbTreeRepository } from '@umbraco-cms/backoffice/repository'; @@ -39,7 +39,7 @@ export class UmbDictionaryRepository this.#host = host; // TODO: figure out how spin up get the correct data source - this.#treeSource = new DictionaryTreeServerDataSource(this.#host); + this.#treeSource = new UmbDictionaryTreeServerDataSource(this.#host); this.#detailSource = new UmbDictionaryDetailServerDataSource(this.#host); this.#init = Promise.all([ diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/repository/sources/dictionary.tree.server.data.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/repository/sources/dictionary.tree.server.data.ts index a24572eb9f..e9d5ab9a40 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/repository/sources/dictionary.tree.server.data.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/repository/sources/dictionary.tree.server.data.ts @@ -6,10 +6,10 @@ import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; /** * A data source for the Dictionary tree that fetches data from the server * @export - * @class DictionaryTreeServerDataSource + * @class UmbDictionaryTreeServerDataSource * @implements {DictionaryTreeDataSource} */ -export class DictionaryTreeServerDataSource implements UmbTreeDataSource { +export class UmbDictionaryTreeServerDataSource implements UmbTreeDataSource { #host: UmbControllerHostElement; /** @@ -24,7 +24,7 @@ export class DictionaryTreeServerDataSource implements UmbTreeDataSource { /** * Fetches the root items for the tree from the server * @return {*} - * @memberof DictionaryTreeServerDataSource + * @memberof UmbDictionaryTreeServerDataSource */ async getRootItems() { return tryExecuteAndNotify(this.#host, DictionaryResource.getTreeDictionaryRoot({})); @@ -34,7 +34,7 @@ export class DictionaryTreeServerDataSource implements UmbTreeDataSource { * Fetches the children of a given parent id from the server * @param {(string | null)} parentId * @return {*} - * @memberof DictionaryTreeServerDataSource + * @memberof UmbDictionaryTreeServerDataSource */ async getChildrenOf(parentId: string | null) { if (!parentId) { @@ -54,7 +54,7 @@ export class DictionaryTreeServerDataSource implements UmbTreeDataSource { * Fetches the items for the given ids from the server * @param {Array} ids * @return {*} - * @memberof DictionaryTreeServerDataSource + * @memberof UmbDictionaryTreeServerDataSource */ async getItems(ids: Array) { if (!ids || ids.length === 0) { diff --git a/src/Umbraco.Web.UI.Client/src/core/context-provider/context-provider.element.test.ts b/src/Umbraco.Web.UI.Client/src/core/context-provider/context-provider.element.test.ts index d64bd405c4..6ea4d15838 100644 --- a/src/Umbraco.Web.UI.Client/src/core/context-provider/context-provider.element.test.ts +++ b/src/Umbraco.Web.UI.Client/src/core/context-provider/context-provider.element.test.ts @@ -4,7 +4,7 @@ import { UmbContextProviderElement } from './context-provider.element'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; @customElement('umb-context-test') -export class ContextTestElement extends UmbLitElement { +export class UmbContextTestElement extends UmbLitElement { public value: string | null = null; constructor() { super(); @@ -16,7 +16,7 @@ export class ContextTestElement extends UmbLitElement { describe('UmbContextProvider', () => { let element: UmbContextProviderElement; - let consumer: ContextTestElement; + let consumer: UmbContextTestElement; const contextValue = 'test-value'; beforeEach(async () => { @@ -25,7 +25,7 @@ describe('UmbContextProvider', () => { ` ); - consumer = element.getElementsByTagName('umb-context-test')[0] as ContextTestElement; + consumer = element.getElementsByTagName('umb-context-test')[0] as UmbContextTestElement; }); it('is defined with its own instance', () => { diff --git a/src/Umbraco.Web.UI.Client/src/core/controller-host/controller-host-test.test.ts b/src/Umbraco.Web.UI.Client/src/core/controller-host/controller-host-test.test.ts index df0e1f3c42..322bb7246c 100644 --- a/src/Umbraco.Web.UI.Client/src/core/controller-host/controller-host-test.test.ts +++ b/src/Umbraco.Web.UI.Client/src/core/controller-host/controller-host-test.test.ts @@ -6,7 +6,7 @@ import { UmbContextProviderController } from '@umbraco-cms/backoffice/context-ap import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; @customElement('umb-controller-host-test-consumer') -export class ControllerHostTestConsumerElement extends UmbLitElement { +export class UmbControllerHostTestConsumerElement extends UmbLitElement { public value: string | null = null; constructor() { super(); @@ -18,7 +18,7 @@ export class ControllerHostTestConsumerElement extends UmbLitElement { describe('UmbControllerHostTestElement', () => { let element: UmbControllerHostTestElement; - let consumer: ControllerHostTestConsumerElement; + let consumer: UmbControllerHostTestConsumerElement; const contextValue = 'test-value'; beforeEach(async () => { @@ -31,7 +31,7 @@ describe('UmbControllerHostTestElement', () => { ); consumer = element.getElementsByTagName( 'umb-controller-host-test-consumer' - )[0] as ControllerHostTestConsumerElement; + )[0] as UmbControllerHostTestConsumerElement; }); it('element is defined with its own instance', () => { diff --git a/src/Umbraco.Web.UI.Client/src/core/modal/stories/modal.stories.ts b/src/Umbraco.Web.UI.Client/src/core/modal/stories/modal.stories.ts index e1c4bb2daa..b80cd203b5 100644 --- a/src/Umbraco.Web.UI.Client/src/core/modal/stories/modal.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/core/modal/stories/modal.stories.ts @@ -15,7 +15,7 @@ export default { const Template: Story = (props) => { return html` Under construction - + `; }; diff --git a/src/Umbraco.Web.UI.Client/src/core/modal/stories/story-modal-service-example.element.ts b/src/Umbraco.Web.UI.Client/src/core/modal/stories/story-modal-service-example.element.ts index 42f97388b3..4e0580a122 100644 --- a/src/Umbraco.Web.UI.Client/src/core/modal/stories/story-modal-service-example.element.ts +++ b/src/Umbraco.Web.UI.Client/src/core/modal/stories/story-modal-service-example.element.ts @@ -3,8 +3,8 @@ import { customElement, property, state } from 'lit/decorators.js'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import { UMB_MODAL_CONTEXT_TOKEN, UmbModalContext } from '@umbraco-cms/backoffice/modal'; -@customElement('story-modal-context-example') -export class StoryModalContextExampleElement extends UmbLitElement { +@customElement('umb-story-modal-context-example') +export class UmbStoryModalContextExampleElement extends UmbLitElement { @property() modalLayout = 'confirm'; diff --git a/src/Umbraco.Web.UI.Client/src/core/notification/stories/notification.stories.ts b/src/Umbraco.Web.UI.Client/src/core/notification/stories/notification.stories.ts index 3c8e401107..6928ff210a 100644 --- a/src/Umbraco.Web.UI.Client/src/core/notification/stories/notification.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/core/notification/stories/notification.stories.ts @@ -15,7 +15,7 @@ export default { ], } as Meta; -const Template: Story = () => html``; +const Template: Story = () => html``; export const Default = Template.bind({}); Default.parameters = { diff --git a/src/Umbraco.Web.UI.Client/src/core/notification/stories/story-notification-default-example.element.ts b/src/Umbraco.Web.UI.Client/src/core/notification/stories/story-notification-default-example.element.ts index de78281ffb..fc29c90356 100644 --- a/src/Umbraco.Web.UI.Client/src/core/notification/stories/story-notification-default-example.element.ts +++ b/src/Umbraco.Web.UI.Client/src/core/notification/stories/story-notification-default-example.element.ts @@ -8,8 +8,8 @@ import { } from '@umbraco-cms/backoffice/notification'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; -@customElement('story-notification-default-example') -export class StoryNotificationDefaultExampleElement extends UmbLitElement { +@customElement('umb-story-notification-default-example') +export class UmbStoryNotificationDefaultExampleElement extends UmbLitElement { private _notificationContext?: UmbNotificationContext; connectedCallback(): void { @@ -56,6 +56,6 @@ export class StoryNotificationDefaultExampleElement extends UmbLitElement { declare global { interface HTMLElementTagNameMap { - 'story-notification-default-example': StoryNotificationDefaultExampleElement; + 'umb-story-notification-default-example': UmbStoryNotificationDefaultExampleElement; } } From b37a2382f92c201f0c6c3362b0ae4e327b2b00dc Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Sun, 16 Apr 2023 20:35:53 +0200 Subject: [PATCH 060/156] add umb prefix --- .../dashboard-models-builder.element.ts | 2 +- .../repository/relation-type.repository.ts | 8 ++++---- .../relation-types/repository/sources/index.ts | 2 +- .../sources/relation-type.tree.server.data.ts | 16 ++++++++-------- .../components/code-block/code-block.element.ts | 6 +++--- .../components/code-block/code-block.stories.ts | 10 +++++----- .../sources/template.tree.server.data.ts | 14 +++++++------- .../templates/repository/template.repository.ts | 6 +++--- 8 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/dashboards/models-builder/dashboard-models-builder.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/dashboards/models-builder/dashboard-models-builder.element.ts index 249718f61e..34bc597c23 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/dashboards/models-builder/dashboard-models-builder.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/dashboards/models-builder/dashboard-models-builder.element.ts @@ -135,7 +135,7 @@ export class UmbDashboardModelsBuilderElement extends UmbLitElement {

${this._modelsBuilder?.lastError ? html`

Last generation failed with the following error:

- ${this._modelsBuilder.lastError}` + ${this._modelsBuilder.lastError}` : nothing} `; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/relation-type.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/relation-type.repository.ts index 52249a2896..db6bfe9bcf 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/relation-type.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/relation-type.repository.ts @@ -1,8 +1,8 @@ import { UmbRelationTypeTreeStore, UMB_RELATION_TYPE_TREE_STORE_CONTEXT_TOKEN } from './relation-type.tree.store'; import { UmbRelationTypeServerDataSource } from './sources/relation-type.server.data'; import { UmbRelationTypeStore, UMB_RELATION_TYPE_STORE_CONTEXT_TOKEN } from './relation-type.store'; -import { RelationTypeTreeServerDataSource } from './sources/relation-type.tree.server.data'; -import { RelationTypeTreeDataSource } from './sources'; +import { UmbRelationTypeTreeServerDataSource } from './sources/relation-type.tree.server.data'; +import { UmbRelationTypeTreeDataSource } from './sources'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; import { @@ -23,7 +23,7 @@ export class UmbRelationTypeRepository #host: UmbControllerHostElement; - #treeSource: RelationTypeTreeDataSource; + #treeSource: UmbRelationTypeTreeDataSource; #treeStore?: UmbRelationTypeTreeStore; #detailDataSource: UmbRelationTypeServerDataSource; @@ -35,7 +35,7 @@ export class UmbRelationTypeRepository this.#host = host; // TODO: figure out how spin up get the correct data source - this.#treeSource = new RelationTypeTreeServerDataSource(this.#host); + this.#treeSource = new UmbRelationTypeTreeServerDataSource(this.#host); this.#detailDataSource = new UmbRelationTypeServerDataSource(this.#host); this.#init = Promise.all([ diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/sources/index.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/sources/index.ts index f8ff932071..7acf297b3e 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/sources/index.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/sources/index.ts @@ -1,7 +1,7 @@ import type { DataSourceResponse } from '@umbraco-cms/backoffice/repository'; import { ItemResponseModelBaseModel, PagedEntityTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; -export interface RelationTypeTreeDataSource { +export interface UmbRelationTypeTreeDataSource { getRootItems(): Promise>; getItems(ids: Array): Promise>; } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/sources/relation-type.tree.server.data.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/sources/relation-type.tree.server.data.ts index 1dc64b51b5..4529c77390 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/sources/relation-type.tree.server.data.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/sources/relation-type.tree.server.data.ts @@ -1,4 +1,4 @@ -import { RelationTypeTreeDataSource } from '.'; +import { UmbRelationTypeTreeDataSource } from '.'; import { ProblemDetailsModel, RelationTypeResource } from '@umbraco-cms/backoffice/backend-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; @@ -7,10 +7,10 @@ import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; /** * A data source for the RelationType tree that fetches data from the server * @export - * @class RelationTypeTreeServerDataSource - * @implements {RelationTypeTreeDataSource} + * @class UmbRelationTypeTreeServerDataSource + * @implements {UmbRelationTypeTreeDataSource} */ -export class RelationTypeTreeServerDataSource implements RelationTypeTreeDataSource { +export class UmbRelationTypeTreeServerDataSource implements UmbRelationTypeTreeDataSource { #host: UmbControllerHostElement; // TODO: how do we handle trashed items? @@ -47,9 +47,9 @@ export class RelationTypeTreeServerDataSource implements RelationTypeTreeDataSou } /** - * Creates an instance of RelationTypeTreeServerDataSource. + * Creates an instance of UmbRelationTypeTreeServerDataSource. * @param {UmbControllerHostElement} host - * @memberof RelationTypeTreeServerDataSource + * @memberof UmbRelationTypeTreeServerDataSource */ constructor(host: UmbControllerHostElement) { this.#host = host; @@ -58,7 +58,7 @@ export class RelationTypeTreeServerDataSource implements RelationTypeTreeDataSou /** * Fetches the root items for the tree from the server * @return {*} - * @memberof RelationTypeTreeServerDataSource + * @memberof UmbRelationTypeTreeServerDataSource */ async getRootItems() { return tryExecuteAndNotify(this.#host, RelationTypeResource.getTreeRelationTypeRoot({})); @@ -68,7 +68,7 @@ export class RelationTypeTreeServerDataSource implements RelationTypeTreeDataSou * Fetches the items for the given ids from the server * @param {Array} ids * @return {*} - * @memberof RelationTypeTreeServerDataSource + * @memberof UmbRelationTypeTreeServerDataSource */ async getItems(ids: Array) { if (ids) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/code-block/code-block.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/code-block/code-block.element.ts index 99833cbcce..11a4372905 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/code-block/code-block.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/code-block/code-block.element.ts @@ -7,8 +7,8 @@ import { customElement } from 'lit/decorators.js'; * @slot the full message * */ -@customElement('uui-code-block') -export class UUICodeBlockElement extends LitElement { +@customElement('umb-code-block') +export class UmbCodeBlockElement extends LitElement { static styles = [ UUITextStyles, css` @@ -54,6 +54,6 @@ export class UUICodeBlockElement extends LitElement { declare global { interface HTMLElementTagNameMap { - 'uui-code-block': UUICodeBlockElement; + 'umb-code-block': UmbCodeBlockElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/code-block/code-block.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/code-block/code-block.stories.ts index f3f2d6ca24..46edd57d43 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/code-block/code-block.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/code-block/code-block.stories.ts @@ -1,15 +1,15 @@ import { Meta, StoryObj } from '@storybook/web-components'; import { html } from 'lit'; import './code-block.element'; -import type { UUICodeBlockElement } from './code-block.element'; +import type { UmbCodeBlockElement } from './code-block.element'; -const meta: Meta = { +const meta: Meta = { title: 'Components/Code Block', - component: 'uui-code-block', + component: 'umb-code-block', }; export default meta; -type Story = StoryObj; +type Story = StoryObj; export const Overview: Story = { args: {}, @@ -17,5 +17,5 @@ export const Overview: Story = { export const WithCode: Story = { decorators: [], - render: () => html` // Lets write some javascript alert("Hello World"); `, + render: () => html` // Lets write some javascript alert("Hello World"); `, }; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/repository/sources/template.tree.server.data.ts b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/repository/sources/template.tree.server.data.ts index ed7be4b8d9..ee94417b50 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/repository/sources/template.tree.server.data.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/repository/sources/template.tree.server.data.ts @@ -6,16 +6,16 @@ import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; /** * A data source for the Template tree that fetches data from the server * @export - * @class TemplateTreeServerDataSource + * @class UmbTemplateTreeServerDataSource * @implements {TemplateTreeDataSource} */ -export class TemplateTreeServerDataSource implements TemplateTreeDataSource { +export class UmbTemplateTreeServerDataSource implements TemplateTreeDataSource { #host: UmbControllerHostElement; /** - * Creates an instance of TemplateTreeServerDataSource. + * Creates an instance of UmbTemplateTreeServerDataSource. * @param {UmbControllerHostElement} host - * @memberof TemplateTreeServerDataSource + * @memberof UmbTemplateTreeServerDataSource */ constructor(host: UmbControllerHostElement) { this.#host = host; @@ -24,7 +24,7 @@ export class TemplateTreeServerDataSource implements TemplateTreeDataSource { /** * Fetches the root items for the tree from the server * @return {*} - * @memberof TemplateTreeServerDataSource + * @memberof UmbTemplateTreeServerDataSource */ async getRootItems() { return tryExecuteAndNotify(this.#host, TemplateResource.getTreeTemplateRoot({})); @@ -34,7 +34,7 @@ export class TemplateTreeServerDataSource implements TemplateTreeDataSource { * Fetches the children of a given parent id from the server * @param {(string | null)} parentId * @return {*} - * @memberof TemplateTreeServerDataSource + * @memberof UmbTemplateTreeServerDataSource */ async getChildrenOf(parentId: string | null) { if (!parentId) { @@ -54,7 +54,7 @@ export class TemplateTreeServerDataSource implements TemplateTreeDataSource { * Fetches the items for the given ids from the server * @param {Array} id * @return {*} - * @memberof TemplateTreeServerDataSource + * @memberof UmbTemplateTreeServerDataSource */ async getItems(ids: Array) { if (!ids) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/repository/template.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/repository/template.repository.ts index 0ec0c4baa7..2903994109 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/repository/template.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/repository/template.repository.ts @@ -1,5 +1,5 @@ import { UmbTemplateDetailServerDataSource } from './sources/template.detail.server.data'; -import { TemplateTreeServerDataSource } from './sources/template.tree.server.data'; +import { UmbTemplateTreeServerDataSource } from './sources/template.tree.server.data'; import { UmbTemplateStore, UMB_TEMPLATE_STORE_CONTEXT_TOKEN } from './template.store'; import { UmbTemplateTreeStore, UMB_TEMPLATE_TREE_STORE_CONTEXT_TOKEN } from './template.tree.store'; import type { UmbDetailRepository, UmbTreeRepository } from '@umbraco-cms/backoffice/repository'; @@ -21,7 +21,7 @@ export class UmbTemplateRepository #init; #host: UmbControllerHostElement; - #treeDataSource: TemplateTreeServerDataSource; + #treeDataSource: UmbTemplateTreeServerDataSource; #detailDataSource: UmbTemplateDetailServerDataSource; #treeStore?: UmbTemplateTreeStore; @@ -33,7 +33,7 @@ export class UmbTemplateRepository this.#host = host; // TODO: figure out how spin up get the correct data source - this.#treeDataSource = new TemplateTreeServerDataSource(this.#host); + this.#treeDataSource = new UmbTemplateTreeServerDataSource(this.#host); this.#detailDataSource = new UmbTemplateDetailServerDataSource(this.#host); this.#init = Promise.all([ From 26fed3638d444fbdf63a85249685237b980cd39e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Sun, 16 Apr 2023 20:40:13 +0200 Subject: [PATCH 061/156] prefix with umb --- .../consume/context-consumer.test.ts | 16 ++++++---- .../context-provider.controller.test.ts | 20 +++++++----- .../provide/context-provider.test.ts | 31 ++++++++++++------- .../context-api/token/context-token.test.ts | 12 +++---- 4 files changed, 47 insertions(+), 32 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/context-api/consume/context-consumer.test.ts b/src/Umbraco.Web.UI.Client/libs/context-api/consume/context-consumer.test.ts index bc0c5f2e1e..09a575938f 100644 --- a/src/Umbraco.Web.UI.Client/libs/context-api/consume/context-consumer.test.ts +++ b/src/Umbraco.Web.UI.Client/libs/context-api/consume/context-consumer.test.ts @@ -5,7 +5,7 @@ import { UmbContextRequestEventImplementation, umbContextRequestEventType } from const testContextAlias = 'my-test-context'; -class MyClass { +class UmbTestContextConsumerClass { prop = 'value from provider'; } @@ -39,16 +39,20 @@ describe('UmbContextConsumer', () => { }); it('works with UmbContextProvider', (done) => { - const provider = new UmbContextProvider(document.body, testContextAlias, new MyClass()); + const provider = new UmbContextProvider(document.body, testContextAlias, new UmbTestContextConsumerClass()); provider.hostConnected(); const element = document.createElement('div'); document.body.appendChild(element); - const localConsumer = new UmbContextConsumer(element, testContextAlias, (_instance: MyClass) => { - expect(_instance.prop).to.eq('value from provider'); - done(); - }); + const localConsumer = new UmbContextConsumer( + element, + testContextAlias, + (_instance: UmbTestContextConsumerClass) => { + expect(_instance.prop).to.eq('value from provider'); + done(); + } + ); localConsumer.hostConnected(); provider.hostDisconnected(); diff --git a/src/Umbraco.Web.UI.Client/libs/context-api/provide/context-provider.controller.test.ts b/src/Umbraco.Web.UI.Client/libs/context-api/provide/context-provider.controller.test.ts index 7946d8b30b..83bd2a2621 100644 --- a/src/Umbraco.Web.UI.Client/libs/context-api/provide/context-provider.controller.test.ts +++ b/src/Umbraco.Web.UI.Client/libs/context-api/provide/context-provider.controller.test.ts @@ -3,7 +3,7 @@ import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import { UmbContextConsumer } from '../consume/context-consumer'; import { UmbContextProviderController } from './context-provider.controller'; -class MyClass { +class UmbTestContextProviderControllerClass { prop = 'value from provider'; } @@ -11,13 +11,13 @@ class ControllerHostElement extends UmbLitElement {} const controllerHostElement = defineCE(ControllerHostElement); describe('UmbContextProviderController', () => { - let instance: MyClass; + let instance: UmbTestContextProviderControllerClass; let provider: UmbContextProviderController; let element: UmbLitElement; beforeEach(async () => { element = await fixture(`<${controllerHostElement}>`); - instance = new MyClass(); + instance = new UmbTestContextProviderControllerClass(); provider = new UmbContextProviderController(element, 'my-test-context', instance); }); @@ -39,11 +39,15 @@ describe('UmbContextProviderController', () => { }); it('works with UmbContextConsumer', (done) => { - const localConsumer = new UmbContextConsumer(element, 'my-test-context', (_instance: MyClass) => { - expect(_instance.prop).to.eq('value from provider'); - done(); - localConsumer.hostDisconnected(); - }); + const localConsumer = new UmbContextConsumer( + element, + 'my-test-context', + (_instance: UmbTestContextProviderControllerClass) => { + expect(_instance.prop).to.eq('value from provider'); + done(); + localConsumer.hostDisconnected(); + } + ); localConsumer.hostConnected(); }); diff --git a/src/Umbraco.Web.UI.Client/libs/context-api/provide/context-provider.test.ts b/src/Umbraco.Web.UI.Client/libs/context-api/provide/context-provider.test.ts index d39e026a2f..ce82bcb9b5 100644 --- a/src/Umbraco.Web.UI.Client/libs/context-api/provide/context-provider.test.ts +++ b/src/Umbraco.Web.UI.Client/libs/context-api/provide/context-provider.test.ts @@ -3,16 +3,16 @@ import { UmbContextConsumer } from '../consume/context-consumer'; import { UmbContextRequestEventImplementation } from '../consume/context-request.event'; import { UmbContextProvider } from './context-provider'; -class MyClass { +class UmbTestContextProviderClass { prop = 'value from provider'; } describe('UmbContextProvider', () => { - let instance: MyClass; + let instance: UmbTestContextProviderClass; let provider: UmbContextProvider; beforeEach(() => { - instance = new MyClass(); + instance = new UmbTestContextProviderClass(); provider = new UmbContextProvider(document.body, 'my-test-context', instance); provider.hostConnected(); }); @@ -40,10 +40,13 @@ describe('UmbContextProvider', () => { }); it('handles context request events', (done) => { - const event = new UmbContextRequestEventImplementation('my-test-context', (_instance: MyClass) => { - expect(_instance.prop).to.eq('value from provider'); - done(); - }); + const event = new UmbContextRequestEventImplementation( + 'my-test-context', + (_instance: UmbTestContextProviderClass) => { + expect(_instance.prop).to.eq('value from provider'); + done(); + } + ); document.body.dispatchEvent(event); }); @@ -52,11 +55,15 @@ describe('UmbContextProvider', () => { const element = document.createElement('div'); document.body.appendChild(element); - const localConsumer = new UmbContextConsumer(element, 'my-test-context', (_instance: MyClass) => { - expect(_instance.prop).to.eq('value from provider'); - done(); - localConsumer.hostDisconnected(); - }); + const localConsumer = new UmbContextConsumer( + element, + 'my-test-context', + (_instance: UmbTestContextProviderClass) => { + expect(_instance.prop).to.eq('value from provider'); + done(); + localConsumer.hostDisconnected(); + } + ); localConsumer.hostConnected(); }); }); diff --git a/src/Umbraco.Web.UI.Client/libs/context-api/token/context-token.test.ts b/src/Umbraco.Web.UI.Client/libs/context-api/token/context-token.test.ts index f8b0a2046d..01cdf69427 100644 --- a/src/Umbraco.Web.UI.Client/libs/context-api/token/context-token.test.ts +++ b/src/Umbraco.Web.UI.Client/libs/context-api/token/context-token.test.ts @@ -5,13 +5,13 @@ import { UmbContextToken } from './context-token'; const testContextAlias = 'my-test-context'; -class MyClass { +class UmbTestContextTokenClass { prop = 'value from provider'; } describe('ContextAlias', () => { - const contextAlias = new UmbContextToken(testContextAlias); - const typedProvider = new UmbContextProvider(document.body, contextAlias, new MyClass()); + const contextAlias = new UmbContextToken(testContextAlias); + const typedProvider = new UmbContextProvider(document.body, contextAlias, new UmbTestContextTokenClass()); typedProvider.hostConnected(); after(() => { @@ -27,7 +27,7 @@ describe('ContextAlias', () => { document.body.appendChild(element); const localConsumer = new UmbContextConsumer(element, contextAlias, (_instance) => { - expect(_instance).to.be.instanceOf(MyClass); + expect(_instance).to.be.instanceOf(UmbTestContextTokenClass); expect(_instance.prop).to.eq('value from provider'); done(); }); @@ -39,8 +39,8 @@ describe('ContextAlias', () => { const element = document.createElement('div'); document.body.appendChild(element); - const localConsumer = new UmbContextConsumer(element, testContextAlias, (_instance: MyClass) => { - expect(_instance).to.be.instanceOf(MyClass); + const localConsumer = new UmbContextConsumer(element, testContextAlias, (_instance: UmbTestContextTokenClass) => { + expect(_instance).to.be.instanceOf(UmbTestContextTokenClass); expect(_instance.prop).to.eq('value from provider'); done(); }); From cce5477195d7390ced363436fcbd9528ced241b7 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Sun, 16 Apr 2023 20:48:38 +0200 Subject: [PATCH 062/156] add umb prefix --- .../libs/observable-api/array-state.test.ts | 6 ++-- .../libs/observable-api/array-state.ts | 30 +++++++++---------- .../libs/observable-api/basic-state.ts | 4 +-- .../libs/observable-api/boolean-state.ts | 6 ++-- .../libs/observable-api/class-state.ts | 8 ++--- .../libs/observable-api/number-state.ts | 4 +-- .../libs/observable-api/object-state.test.ts | 29 +++++++----------- .../libs/observable-api/object-state.ts | 10 +++---- .../partial-update-frozen-array.function.ts | 2 +- .../libs/observable-api/string-state.ts | 6 ++-- .../libs/store/entity-tree-store.ts | 4 +-- .../libs/store/file-system-tree.store.ts | 4 +-- .../document-blueprint.detail.store.ts | 4 +-- .../repository/document-type.store.ts | 4 +-- .../documents/repository/document.store.ts | 4 +-- .../workspace/document-workspace.context.ts | 10 +++++-- .../repository/media-type.detail.store.ts | 4 +-- .../workspace/media-type-workspace.context.ts | 4 +-- .../media/media/repository/media.store.ts | 4 +-- .../media/repository/media.tree.store.ts | 4 +-- .../workspace/media-workspace.context.ts | 4 +-- .../repository/member-group.store.ts | 4 +-- .../member-group-workspace.context.ts | 4 +-- .../repository/member-type.store.ts | 4 +-- .../member-type-workspace.context.ts | 4 +-- .../members/members/member.detail.store.ts | 4 +-- .../members/repository/member.store.ts | 4 +-- .../packages/repository/package.store.ts | 6 ++-- .../data-types/repository/data-type.store.ts | 4 +-- .../workspace/data-type-workspace.context.ts | 4 +-- .../app-language.context.ts | 4 +-- .../languages/repository/language.store.ts | 4 +-- .../language/language-workspace.context.ts | 6 ++-- .../logviewer/workspace/logviewer.context.ts | 16 +++++----- .../repository/relation-type.store.ts | 4 +-- .../relation-type-workspace.context.ts | 4 +-- .../shared/collection/collection.context.ts | 6 ++-- .../section-sidebar.context.ts | 4 +-- .../components/section/section.context.ts | 2 +- .../tree-item-base/tree-item-base.context.ts | 14 ++++----- .../workspace-property.context.ts | 13 +++++--- .../entity-manager-controller.ts | 4 +-- ...kspace-container-structure-helper.class.ts | 6 ++-- .../workspace-context/workspace-context.ts | 4 +-- ...rkspace-property-structure-helper.class.ts | 4 +-- .../workspace-split-view-manager.class.ts | 4 +-- .../workspace-structure-manager.class.ts | 6 ++-- .../workspace-variant.context.ts | 11 +++++-- .../workspace/stylesheet-workspace.context.ts | 4 +-- .../templates/repository/template.store.ts | 4 +-- .../dictionary/repository/dictionary.store.ts | 4 +-- .../workspace/dictionary-workspace.context.ts | 4 +-- .../users/current-user/current-user.store.ts | 4 +-- .../repository/user-group.store.ts | 4 +-- .../users/users/repository/user.store.ts | 4 +-- .../src/installer/installer.context.ts | 8 ++--- .../src/stories/store.mdx | 6 ++-- 57 files changed, 179 insertions(+), 172 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/array-state.test.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/array-state.test.ts index 854ec3ee92..1a22dae157 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/array-state.test.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/array-state.test.ts @@ -1,11 +1,11 @@ import { expect } from '@open-wc/testing'; -import { ArrayState } from './array-state'; +import { UmbArrayState } from './array-state'; describe('ArrayState', () => { type ObjectType = { key: string; another: string }; type ArrayType = ObjectType[]; - let subject: ArrayState; + let subject: UmbArrayState; let initialData: ArrayType; beforeEach(() => { @@ -14,7 +14,7 @@ describe('ArrayState', () => { { key: '2', another: 'myValue2' }, { key: '3', another: 'myValue3' }, ]; - subject = new ArrayState(initialData, (x) => x.key); + subject = new UmbArrayState(initialData, (x) => x.key); }); it('replays latests, no matter the amount of subscriptions.', (done) => { diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/array-state.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/array-state.ts index 7572f89d8b..df29f02b1c 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/array-state.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/array-state.ts @@ -4,14 +4,14 @@ import { pushToUniqueArray } from './push-to-unique-array.function'; /** * @export - * @class ArrayState + * @class UmbArrayState * @extends {DeepState} * @description - A RxJS BehaviorSubject which deepFreezes the object-data to ensure its not manipulated from any implementations. * Additionally the Subject ensures the data is unique, not updating any Observes unless there is an actual change of the content. * * The ArrayState provides methods to append data when the data is an Object. */ -export class ArrayState extends DeepState { +export class UmbArrayState extends DeepState { #getUnique?: (entry: T) => unknown; #sortMethod?: (a: T, b: T) => number; @@ -29,7 +29,7 @@ export class ArrayState extends DeepState { * { key: 1, value: 'foo'}, * { key: 2, value: 'bar'} * ]; - * const myState = new ArrayState(data, (x) => x.key); + * const myState = new UmbArrayState(data, (x) => x.key); * myState.sortBy((a, b) => (a.sortOrder || 0) - (b.sortOrder || 0)); */ sortBy(sortMethod?: (a: T, b: T) => number) { @@ -48,14 +48,14 @@ export class ArrayState extends DeepState { /** * @method remove * @param {unknown[]} uniques - The unique values to remove. - * @return {ArrayState} Reference to it self. + * @return {UmbArrayState} Reference to it self. * @description - Remove some new data of this Subject. * @example Example remove entry with id '1' and '2' * const data = [ * { id: 1, value: 'foo'}, * { id: 2, value: 'bar'} * ]; - * const myState = new ArrayState(data, (x) => x.id); + * const myState = new UmbArrayState(data, (x) => x.id); * myState.remove([1, 2]); */ remove(uniques: unknown[]) { @@ -77,14 +77,14 @@ export class ArrayState extends DeepState { /** * @method removeOne * @param {unknown} unique - The unique value to remove. - * @return {ArrayState} Reference to it self. + * @return {UmbArrayState} Reference to it self. * @description - Remove some new data of this Subject. * @example Example remove entry with id '1' * const data = [ * { id: 1, value: 'foo'}, * { id: 2, value: 'bar'} * ]; - * const myState = new ArrayState(data, (x) => x.id); + * const myState = new UmbArrayState(data, (x) => x.id); * myState.removeOne(1); */ removeOne(unique: unknown) { @@ -104,7 +104,7 @@ export class ArrayState extends DeepState { /** * @method filter * @param {unknown} filterMethod - The unique value to remove. - * @return {ArrayState} Reference to it self. + * @return {UmbArrayState} Reference to it self. * @description - Remove some new data of this Subject. * @example Example remove entry with key '1' * const data = [ @@ -112,7 +112,7 @@ export class ArrayState extends DeepState { * { key: 2, value: 'bar'}, * { key: 3, value: 'poo'} * ]; - * const myState = new ArrayState(data, (x) => x.key); + * const myState = new UmbArrayState(data, (x) => x.key); * myState.filter((entry) => entry.key !== 1); * * Result: @@ -130,14 +130,14 @@ export class ArrayState extends DeepState { /** * @method appendOne * @param {T} entry - new data to be added in this Subject. - * @return {ArrayState} Reference to it self. + * @return {UmbArrayState} Reference to it self. * @description - Append some new data to this Subject. * @example Example append some data. * const data = [ * { key: 1, value: 'foo'}, * { key: 2, value: 'bar'} * ]; - * const myState = new ArrayState(data); + * const myState = new UmbArrayState(data); * myState.append({ key: 1, value: 'replaced-foo'}); */ appendOne(entry: T) { @@ -154,14 +154,14 @@ export class ArrayState extends DeepState { /** * @method append * @param {T[]} entries - A array of new data to be added in this Subject. - * @return {ArrayState} Reference to it self. + * @return {UmbArrayState} Reference to it self. * @description - Append some new data to this Subject, if it compares to existing data it will replace it. * @example Example append some data. * const data = [ * { key: 1, value: 'foo'}, * { key: 2, value: 'bar'} * ]; - * const myState = new ArrayState(data); + * const myState = new UmbArrayState(data); * myState.append([ * { key: 1, value: 'replaced-foo'}, * { key: 3, value: 'another-bla'} @@ -184,14 +184,14 @@ export class ArrayState extends DeepState { * @method updateOne * @param {unknown} unique - Unique value to find entry to update. * @param {Partial} entry - new data to be added in this Subject. - * @return {ArrayState} Reference to it self. + * @return {UmbArrayState} Reference to it self. * @description - Update a item with some new data, requires the ArrayState to be constructed with a getUnique method. * @example Example append some data. * const data = [ * { key: 1, value: 'foo'}, * { key: 2, value: 'bar'} * ]; - * const myState = new ArrayState(data, (x) => x.key); + * const myState = new UmbArrayState(data, (x) => x.key); * myState.updateOne(2, {value: 'updated-bar'}); */ updateOne(unique: unknown, entry: Partial) { diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/basic-state.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/basic-state.ts index 57d7f8581b..30972d0ef4 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/basic-state.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/basic-state.ts @@ -2,11 +2,11 @@ import { BehaviorSubject } from 'rxjs'; /** * @export - * @class BasicState + * @class UmbBasicState * @extends {BehaviorSubject} * @description - A RxJS BehaviorSubject this Subject ensures the data is unique, not updating any Observes unless there is an actual change of the value. */ -export class BasicState extends BehaviorSubject { +export class UmbBasicState extends BehaviorSubject { constructor(initialData: T) { super(initialData); } diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/boolean-state.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/boolean-state.ts index 5404d43651..85a91d895d 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/boolean-state.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/boolean-state.ts @@ -1,12 +1,12 @@ -import { BasicState } from './basic-state'; +import { UmbBasicState } from './basic-state'; /** * @export - * @class BooleanState + * @class UmbBooleanState * @extends {BehaviorSubject} * @description - A RxJS BehaviorSubject this Subject ensures the data is unique, not updating any Observes unless there is an actual change of the value. */ -export class BooleanState extends BasicState { +export class UmbBooleanState extends UmbBasicState { constructor(initialData: T | boolean) { super(initialData); } diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/class-state.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/class-state.ts index 11c38dc6b9..586710e38b 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/class-state.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/class-state.ts @@ -1,16 +1,16 @@ import { BehaviorSubject } from 'rxjs'; -interface ClassStateData { - equal(otherClass: ClassStateData): boolean; +interface UmbClassStateData { + equal(otherClass: UmbClassStateData): boolean; } /** * @export - * @class ClassState + * @class UmbClassState * @extends {BehaviorSubject} * @description - A RxJS BehaviorSubject which can hold class instance which has a equal method to compare in coming instances for changes. */ -export class ClassState extends BehaviorSubject { +export class UmbClassState extends BehaviorSubject { constructor(initialData: T) { super(initialData); } diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/number-state.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/number-state.ts index ded3defeb9..82387e9580 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/number-state.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/number-state.ts @@ -1,4 +1,4 @@ -import { BasicState } from './basic-state'; +import { UmbBasicState } from './basic-state'; /** * @export @@ -6,7 +6,7 @@ import { BasicState } from './basic-state'; * @extends {BehaviorSubject} * @description - A RxJS BehaviorSubject this Subject ensures the data is unique, not updating any Observes unless there is an actual change of the value. */ -export class NumberState extends BasicState { +export class NumberState extends UmbBasicState { constructor(initialData: T | number) { super(initialData); } diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/object-state.test.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/object-state.test.ts index 66b1e0deef..75b4d3bbe2 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/object-state.test.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/object-state.test.ts @@ -1,21 +1,18 @@ import { expect } from '@open-wc/testing'; -import { ObjectState } from './object-state'; +import { UmbObjectState } from './object-state'; -describe('ObjectState', () => { +describe('UmbObjectState', () => { + type ObjectType = { key: string; another: string }; - type ObjectType = {key: string, another: string}; - - let subject: ObjectState; + let subject: UmbObjectState; let initialData: ObjectType; beforeEach(() => { - initialData = {key: 'some', another: 'myValue'}; - subject = new ObjectState(initialData); + initialData = { key: 'some', another: 'myValue' }; + subject = new UmbObjectState(initialData); }); - it('replays latests, no matter the amount of subscriptions.', (done) => { - const observer = subject.asObservable(); observer.subscribe((value) => { expect(value).to.be.equal(initialData); @@ -24,28 +21,24 @@ describe('ObjectState', () => { expect(value).to.be.equal(initialData); done(); }); - }); it('use getObservablePart, updates on its specific change.', (done) => { - let amountOfCallbacks = 0; - const subObserver = subject.getObservablePart(data => data.another); + const subObserver = subject.getObservablePart((data) => data.another); subObserver.subscribe((value) => { amountOfCallbacks++; - if(amountOfCallbacks === 1) { + if (amountOfCallbacks === 1) { expect(value).to.be.equal('myValue'); } - if(amountOfCallbacks === 2) { + if (amountOfCallbacks === 2) { expect(value).to.be.equal('myNewValue'); done(); } }); - subject.update({key: 'change_this_first_should_not_trigger_update'}); - subject.update({another: 'myNewValue'}); - + subject.update({ key: 'change_this_first_should_not_trigger_update' }); + subject.update({ another: 'myNewValue' }); }); - }); diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/object-state.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/object-state.ts index 04c72dd9b3..fdb85a43b9 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/object-state.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/object-state.ts @@ -2,22 +2,22 @@ import { DeepState } from './deep-state'; /** * @export - * @class ObjectState + * @class UmbObjectState * @extends {DeepState} * @description - A RxJS BehaviorSubject which deepFreezes the object-data to ensure its not manipulated from any implementations. * Additionally the Subject ensures the data is unique, not updating any Observes unless there is an actual change of the content. * - * The ObjectState provides methods to append data when the data is an Object. + * The UmbObjectState provides methods to append data when the data is an Object. */ -export class ObjectState extends DeepState { +export class UmbObjectState extends DeepState { /** * @method update * @param {Partial} partialData - A object containing some of the data to update in this Subject. * @description - Append some new data to this Object. - * @return {ObjectState} Reference to it self. + * @return {UmbObjectState} Reference to it self. * @example Example append some data. * const data = {key: 'myKey', value: 'myInitialValue'}; - * const myState = new ObjectState(data); + * const myState = new UmbObjectState(data); * myState.update({value: 'myNewValue'}); */ update(partialData: Partial) { diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/partial-update-frozen-array.function.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/partial-update-frozen-array.function.ts index 14a2e4c5b6..9064fb0384 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/partial-update-frozen-array.function.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/partial-update-frozen-array.function.ts @@ -5,7 +5,7 @@ * @param {(mappable: T) => R} mappingFunction - Method to return the part for this Observable to return. * @param {(previousResult: R, currentResult: R) => boolean} [memoizationFunction] - Method to Compare if the data has changed. Should return true when data is different. * @description - Creates a RxJS Observable from RxJS Subject. - * @example Example append new entry for a ArrayState or a part of DeepState/ObjectState it which is an array. Where the key is unique and the item will be updated if matched with existing. + * @example Example append new entry for a ArrayState or a part of DeepState/UmbObjectState it which is an array. Where the key is unique and the item will be updated if matched with existing. * const partialEntry = {value: 'myValue'}; * const newDataSet = partialUpdateFrozenArray(mySubject.getValue(), partialEntry, x => x.key === 'myKey'); * mySubject.next(newDataSet); diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/string-state.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/string-state.ts index d3e9689a7b..d78d91127e 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/string-state.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/string-state.ts @@ -1,12 +1,12 @@ -import { BasicState } from './basic-state'; +import { UmbBasicState } from './basic-state'; /** * @export * @class StringState - * @extends {BasicState} + * @extends {UmbBasicState} * @description - A RxJS BehaviorSubject this Subject ensures the data is unique, not updating any Observes unless there is an actual change of the value. */ -export class StringState extends BasicState { +export class StringState extends UmbBasicState { constructor(initialData: T | string) { super(initialData); } diff --git a/src/Umbraco.Web.UI.Client/libs/store/entity-tree-store.ts b/src/Umbraco.Web.UI.Client/libs/store/entity-tree-store.ts index ea94db043a..dfa6815a04 100644 --- a/src/Umbraco.Web.UI.Client/libs/store/entity-tree-store.ts +++ b/src/Umbraco.Web.UI.Client/libs/store/entity-tree-store.ts @@ -1,5 +1,5 @@ import { EntityTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; -import { ArrayState, partialUpdateFrozenArray } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState, partialUpdateFrozenArray } from '@umbraco-cms/backoffice/observable-api'; import { UmbStoreBase, UmbTreeStore } from '@umbraco-cms/backoffice/store'; /** @@ -9,7 +9,7 @@ import { UmbStoreBase, UmbTreeStore } from '@umbraco-cms/backoffice/store'; * @description - General Tree Data Store */ export class UmbEntityTreeStore extends UmbStoreBase implements UmbTreeStore { - #data = new ArrayState([], (x) => x.id); + #data = new UmbArrayState([], (x) => x.id); /** * Appends items to the store diff --git a/src/Umbraco.Web.UI.Client/libs/store/file-system-tree.store.ts b/src/Umbraco.Web.UI.Client/libs/store/file-system-tree.store.ts index 8afa8ca62e..3bb024511a 100644 --- a/src/Umbraco.Web.UI.Client/libs/store/file-system-tree.store.ts +++ b/src/Umbraco.Web.UI.Client/libs/store/file-system-tree.store.ts @@ -1,5 +1,5 @@ import { FileSystemTreeItemPresentationModel } from '@umbraco-cms/backoffice/backend-api'; -import { ArrayState, partialUpdateFrozenArray } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState, partialUpdateFrozenArray } from '@umbraco-cms/backoffice/observable-api'; import { UmbStoreBase, UmbTreeStore } from '@umbraco-cms/backoffice/store'; /** @@ -9,7 +9,7 @@ import { UmbStoreBase, UmbTreeStore } from '@umbraco-cms/backoffice/store'; * @description - General Tree Data Store */ export class UmbFileSystemTreeStore extends UmbStoreBase implements UmbTreeStore { - #data = new ArrayState([], (x) => x.path); + #data = new UmbArrayState([], (x) => x.path); /** * Appends items to the store diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-blueprints/document-blueprint.detail.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-blueprints/document-blueprint.detail.store.ts index f60b478a36..054c05d1ec 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-blueprints/document-blueprint.detail.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-blueprints/document-blueprint.detail.store.ts @@ -1,6 +1,6 @@ import type { DocumentBlueprintDetails } from '@umbraco-cms/backoffice/models'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; -import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; import { UmbStoreBase } from '@umbraco-cms/backoffice/store'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; @@ -12,7 +12,7 @@ import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; */ export class UmbDocumentBlueprintStore extends UmbStoreBase { // TODO: use the right type: - #data = new ArrayState([], (x) => x.id); + #data = new UmbArrayState([], (x) => x.id); constructor(host: UmbControllerHostElement) { super(host, UMB_DOCUMENT_BLUEPRINT_STORE_CONTEXT_TOKEN.toString()); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/document-type.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/document-type.store.ts index 23b64c0942..3ad9e8e4e2 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/document-type.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/document-type.store.ts @@ -1,6 +1,6 @@ import { DocumentTypeResponseModel } from '@umbraco-cms/backoffice/backend-api'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; -import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; import { UmbStoreBase } from '@umbraco-cms/backoffice/store'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; @@ -11,7 +11,7 @@ import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; * @description - Data Store for Document Types */ export class UmbDocumentTypeStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.id); + #data = new UmbArrayState([], (x) => x.id); /** * Creates an instance of UmbDocumentTypeStore. diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/document.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/document.store.ts index d53818f95e..5af98a68b8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/document.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/document.store.ts @@ -1,6 +1,6 @@ import { DocumentResponseModel } from '@umbraco-cms/backoffice/backend-api'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; -import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; import { UmbStoreBase } from '@umbraco-cms/backoffice/store'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; @@ -11,7 +11,7 @@ import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; * @description - Data Store for Template Details */ export class UmbDocumentStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.id); + #data = new UmbArrayState([], (x) => x.id); /** * Creates an instance of UmbDocumentDetailStore. diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace.context.ts index e4d3f0b984..3b38145096 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace.context.ts @@ -6,7 +6,11 @@ import { UmbVariantId } from '../../../shared/variants/variant-id.class'; import { UmbWorkspacePropertyStructureManager } from '../../../shared/components/workspace/workspace-context/workspace-structure-manager.class'; import { UmbWorkspaceSplitViewManager } from '../../../shared/components/workspace/workspace-context/workspace-split-view-manager.class'; import type { CreateDocumentRequestModel, DocumentResponseModel } from '@umbraco-cms/backoffice/backend-api'; -import { partialUpdateFrozenArray, ObjectState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; +import { + partialUpdateFrozenArray, + UmbObjectState, + UmbObserverController, +} from '@umbraco-cms/backoffice/observable-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; // TODO: should this context be called DocumentDraft instead of workspace? or should the draft be part of this? @@ -22,12 +26,12 @@ export class UmbDocumentWorkspaceContext * For now lets not share this publicly as it can become confusing. * TODO: Use this to compare, for variants with changes. */ - #document = new ObjectState(undefined); + #document = new UmbObjectState(undefined); /** * The document is the current state/draft version of the document. */ - #draft = new ObjectState(undefined); + #draft = new UmbObjectState(undefined); readonly unique = this.#draft.getObservablePart((data) => data?.id); readonly documentTypeKey = this.#draft.getObservablePart((data) => data?.contentTypeId); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/repository/media-type.detail.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/repository/media-type.detail.store.ts index d6ef9c0fa9..844b1f5a1e 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/repository/media-type.detail.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/repository/media-type.detail.store.ts @@ -1,7 +1,7 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import { UmbStoreBase } from '@umbraco-cms/backoffice/store'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; import type { MediaTypeDetails } from '@umbraco-cms/backoffice/models'; /** @@ -11,7 +11,7 @@ import type { MediaTypeDetails } from '@umbraco-cms/backoffice/models'; * @description - Details Data Store for Media Types */ export class UmbMediaTypeStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.id); + #data = new UmbArrayState([], (x) => x.id); constructor(host: UmbControllerHostElement) { super(host, UMB_MEDIA_TYPE_STORE_CONTEXT_TOKEN.toString()); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/workspace/media-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/workspace/media-type-workspace.context.ts index 648c880015..921a41b6b1 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/workspace/media-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/workspace/media-type-workspace.context.ts @@ -2,7 +2,7 @@ import { UmbWorkspaceContext } from '../../../shared/components/workspace/worksp import { UmbMediaTypeRepository } from '../repository/media-type.repository'; import { UmbEntityWorkspaceContextInterface } from '@umbraco-cms/backoffice/workspace'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { ObjectState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; import type { MediaTypeDetails } from '@umbraco-cms/backoffice/models'; type EntityType = MediaTypeDetails; @@ -10,7 +10,7 @@ export class UmbWorkspaceMediaTypeContext extends UmbWorkspaceContext implements UmbEntityWorkspaceContextInterface { - #data = new ObjectState(undefined); + #data = new UmbObjectState(undefined); data = this.#data.asObservable(); name = this.#data.getObservablePart((data) => data?.name); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/repository/media.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/repository/media.store.ts index ddc1a8b5fc..c6eb6e22f7 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/repository/media.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/repository/media.store.ts @@ -1,6 +1,6 @@ import type { MediaDetails } from '../'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; -import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; import { UmbStoreBase } from '@umbraco-cms/backoffice/store'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; @@ -11,7 +11,7 @@ import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; * @description - Data Store for Template Details */ export class UmbMediaStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.id); + #data = new UmbArrayState([], (x) => x.id); /** * Creates an instance of UmbMediaStore. diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/repository/media.tree.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/repository/media.tree.store.ts index 9c63d9c946..babdf21049 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/repository/media.tree.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/repository/media.tree.store.ts @@ -1,6 +1,6 @@ import { EntityTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; -import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; import { UmbEntityTreeStore } from '@umbraco-cms/backoffice/store'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; @@ -13,7 +13,7 @@ export const UMB_MEDIA_TREE_STORE_CONTEXT_TOKEN = new UmbContextToken([], (x) => x.id); + #data = new UmbArrayState([], (x) => x.id); /** * Creates an instance of UmbMediaTreeStore. diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/workspace/media-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/workspace/media-workspace.context.ts index 751b587560..9e50b63768 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/workspace/media-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/workspace/media-workspace.context.ts @@ -2,7 +2,7 @@ import { UmbWorkspaceContext } from '../../../shared/components/workspace/worksp import { UmbMediaRepository } from '../repository/media.repository'; import type { MediaDetails } from '../'; import type { UmbEntityWorkspaceContextInterface } from '@umbraco-cms/backoffice/workspace'; -import { appendToFrozenArray, ObjectState } from '@umbraco-cms/backoffice/observable-api'; +import { appendToFrozenArray, UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; type EntityType = MediaDetails; @@ -10,7 +10,7 @@ export class UmbMediaWorkspaceContext extends UmbWorkspaceContext implements UmbEntityWorkspaceContextInterface { - #data = new ObjectState(undefined); + #data = new UmbObjectState(undefined); data = this.#data.asObservable(); name = this.#data.getObservablePart((data) => data?.name); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/repository/member-group.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/repository/member-group.store.ts index 38fd8ede11..44eff1edff 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/repository/member-group.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/repository/member-group.store.ts @@ -1,6 +1,6 @@ import type { MemberGroupDetails } from '@umbraco-cms/backoffice/models'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; -import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbStoreBase } from '@umbraco-cms/backoffice/store'; @@ -11,7 +11,7 @@ import { UmbStoreBase } from '@umbraco-cms/backoffice/store'; * @description - Data Store for Member Groups */ export class UmbMemberGroupStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.id); + #data = new UmbArrayState([], (x) => x.id); constructor(host: UmbControllerHostElement) { super(host, UMB_MEMBER_GROUP_STORE_CONTEXT_TOKEN.toString()); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/workspace/member-group-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/workspace/member-group-workspace.context.ts index ecf64222eb..bf8f38eb1e 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/workspace/member-group-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/workspace/member-group-workspace.context.ts @@ -3,14 +3,14 @@ import { UmbMemberGroupRepository } from '../repository/member-group.repository' import { UmbEntityWorkspaceContextInterface } from '@umbraco-cms/backoffice/workspace'; import type { MemberGroupDetails } from '@umbraco-cms/backoffice/models'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { ObjectState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; type EntityType = MemberGroupDetails; export class UmbWorkspaceMemberGroupContext extends UmbWorkspaceContext implements UmbEntityWorkspaceContextInterface { - #data = new ObjectState(undefined); + #data = new UmbObjectState(undefined); data = this.#data.asObservable(); name = this.#data.getObservablePart((data) => data?.name); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/repository/member-type.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/repository/member-type.store.ts index b9afd506a2..c379a95620 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/repository/member-type.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/repository/member-type.store.ts @@ -1,7 +1,7 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import { UmbStoreBase } from '@umbraco-cms/backoffice/store'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; import type { MemberTypeDetails } from '@umbraco-cms/backoffice/models'; /** @@ -11,7 +11,7 @@ import type { MemberTypeDetails } from '@umbraco-cms/backoffice/models'; * @description - Data Store for Member Types */ export class UmbMemberTypeStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.id); + #data = new UmbArrayState([], (x) => x.id); constructor(host: UmbControllerHostElement) { super(host, UMB_MEMBER_TYPE_STORE_CONTEXT_TOKEN.toString()); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/workspace/member-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/workspace/member-type-workspace.context.ts index 8274bec279..9acaa2b9f7 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/workspace/member-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/workspace/member-type-workspace.context.ts @@ -1,7 +1,7 @@ import { UmbWorkspaceContext } from '../../../shared/components/workspace/workspace-context/workspace-context'; import { UmbMemberTypeRepository } from '../repository/member-type.repository'; import { UmbEntityWorkspaceContextInterface } from '@umbraco-cms/backoffice/workspace'; -import { ObjectState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; // TODO => use correct tpye @@ -11,7 +11,7 @@ export class UmbMemberTypeWorkspaceContext extends UmbWorkspaceContext implements UmbEntityWorkspaceContextInterface { - #data = new ObjectState(undefined); + #data = new UmbObjectState(undefined); name = this.#data.getObservablePart((data) => data?.name); constructor(host: UmbControllerHostElement) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/member.detail.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/member.detail.store.ts index 973f79f5c4..a5b8248990 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/member.detail.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/member.detail.store.ts @@ -2,7 +2,7 @@ import { Observable } from 'rxjs'; import { umbMemberData } from '../../../core/mocks/data/member.data'; import type { MemberDetails, MemberGroupDetails } from '@umbraco-cms/backoffice/models'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; -import { ArrayState, createObservablePart } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState, createObservablePart } from '@umbraco-cms/backoffice/observable-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbEntityDetailStore, UmbStoreBase } from '@umbraco-cms/backoffice/store'; @@ -13,7 +13,7 @@ import { UmbEntityDetailStore, UmbStoreBase } from '@umbraco-cms/backoffice/stor * @description - Data Store for Members */ export class UmbMemberStore extends UmbStoreBase implements UmbEntityDetailStore { - #data = new ArrayState([], (x) => x.id); + #data = new UmbArrayState([], (x) => x.id); public groups = this.#data.asObservable(); constructor(private host: UmbControllerHostElement) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/repository/member.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/repository/member.store.ts index 4b01b1a8d8..958cb319ab 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/repository/member.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/repository/member.store.ts @@ -1,7 +1,7 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import { UmbStoreBase } from '@umbraco-cms/backoffice/store'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; import type { MemberDetails } from '@umbraco-cms/backoffice/models'; /** @@ -11,7 +11,7 @@ import type { MemberDetails } from '@umbraco-cms/backoffice/models'; * @description - Data Store for Members */ export class UmbMemberStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.id); + #data = new UmbArrayState([], (x) => x.id); constructor(host: UmbControllerHostElement) { super(host, UMB_MEMBER_STORE_CONTEXT_TOKEN.toString()); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/package.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/package.store.ts index 8ed4792471..0d0a8440a0 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/package.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/package.store.ts @@ -5,7 +5,7 @@ import { UmbStoreBase } from '@umbraco-cms/backoffice/store'; import type { UmbPackage } from '@umbraco-cms/backoffice/models'; import type { PackageMigrationStatusResponseModel } from '@umbraco-cms/backoffice/backend-api'; import type { ManifestBase } from '@umbraco-cms/backoffice/extensions-registry'; -import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; export const UMB_PACKAGE_STORE_TOKEN = new UmbContextToken('UmbPackageStore'); @@ -21,9 +21,9 @@ export class UmbPackageStore extends UmbStoreBase { */ #packages = new ReplaySubject>(1); - #extensions = new ArrayState([], (e) => e.alias); + #extensions = new UmbArrayState([], (e) => e.alias); - #migrations = new ArrayState([], (e) => e.packageName); + #migrations = new UmbArrayState([], (e) => e.packageName); /** * Observable of packages with extensions diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.store.ts index 71db9b0013..b3aea6ee17 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.store.ts @@ -1,6 +1,6 @@ import type { DataTypeResponseModel } from '@umbraco-cms/backoffice/backend-api'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; -import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; import { UmbStoreBase } from '@umbraco-cms/backoffice/store'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; @@ -13,7 +13,7 @@ export const UMB_DATA_TYPE_STORE_CONTEXT_TOKEN = new UmbContextToken([], (x) => x.id); + #data = new UmbArrayState([], (x) => x.id); /** * Creates an instance of UmbDataTypeStore. diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/workspace/data-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/workspace/data-type-workspace.context.ts index 127850dc1f..15a5714fc1 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/workspace/data-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/workspace/data-type-workspace.context.ts @@ -2,7 +2,7 @@ import { UmbWorkspaceContext } from '../../../shared/components/workspace/worksp import { UmbDataTypeRepository } from '../repository/data-type.repository'; import { UmbEntityWorkspaceContextInterface } from '@umbraco-cms/backoffice/workspace'; import type { CreateDataTypeRequestModel, DataTypeResponseModel } from '@umbraco-cms/backoffice/backend-api'; -import { appendToFrozenArray, ObjectState } from '@umbraco-cms/backoffice/observable-api'; +import { appendToFrozenArray, UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; export class UmbDataTypeWorkspaceContext @@ -10,7 +10,7 @@ export class UmbDataTypeWorkspaceContext implements UmbEntityWorkspaceContextInterface { // TODO: revisit. temp solution because the create and response models are different. - #data = new ObjectState(undefined); + #data = new UmbObjectState(undefined); data = this.#data.asObservable(); name = this.#data.getObservablePart((data) => data?.name); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/app-language-select/app-language.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/app-language-select/app-language.context.ts index 6f85f5c271..4ed5119e48 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/app-language-select/app-language.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/app-language-select/app-language.context.ts @@ -1,5 +1,5 @@ import { UmbLanguageRepository } from '../repository/language.repository'; -import { ObjectState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; +import { UmbObjectState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import { LanguageResponseModel } from '@umbraco-cms/backoffice/backend-api'; @@ -10,7 +10,7 @@ export class UmbAppLanguageContext { #languages: Array = []; - #appLanguage = new ObjectState(undefined); + #appLanguage = new UmbObjectState(undefined); appLanguage = this.#appLanguage.asObservable(); constructor(host: UmbControllerHostElement) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language.store.ts index 820b66fc50..4844685cd7 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language.store.ts @@ -1,7 +1,7 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import { UmbStoreBase } from '@umbraco-cms/backoffice/store'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; import { LanguageResponseModel } from '@umbraco-cms/backoffice/backend-api'; export const UMB_LANGUAGE_STORE_CONTEXT_TOKEN = new UmbContextToken('UmbLanguageStore'); @@ -13,7 +13,7 @@ export const UMB_LANGUAGE_STORE_CONTEXT_TOKEN = new UmbContextToken([], (x) => x.isoCode); + #data = new UmbArrayState([], (x) => x.isoCode); data = this.#data.asObservable(); constructor(host: UmbControllerHostElement) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/language-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/language-workspace.context.ts index f51bfe3075..782f623ff0 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/language-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/language-workspace.context.ts @@ -2,18 +2,18 @@ import { UmbLanguageRepository } from '../../repository/language.repository'; import { UmbWorkspaceContext } from '../../../../shared/components/workspace/workspace-context/workspace-context'; import { UmbEntityWorkspaceContextInterface } from '@umbraco-cms/backoffice/workspace'; import type { LanguageResponseModel } from '@umbraco-cms/backoffice/backend-api'; -import { ObjectState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; export class UmbLanguageWorkspaceContext extends UmbWorkspaceContext implements UmbEntityWorkspaceContextInterface { - #data = new ObjectState(undefined); + #data = new UmbObjectState(undefined); data = this.#data.asObservable(); // TODO: this is a temp solution to bubble validation errors to the UI - #validationErrors = new ObjectState(undefined); + #validationErrors = new UmbObjectState(undefined); validationErrors = this.#validationErrors.asObservable(); constructor(host: UmbControllerHostElement) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/workspace/logviewer.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/workspace/logviewer.context.ts index 6bec1b10e9..95bf69be44 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/workspace/logviewer.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/workspace/logviewer.context.ts @@ -1,10 +1,10 @@ import { UmbLogViewerRepository } from '../repository/log-viewer.repository'; import { - BasicState, - ArrayState, + UmbBasicState, + UmbArrayState, createObservablePart, DeepState, - ObjectState, + UmbObjectState, StringState, } from '@umbraco-cms/backoffice/observable-api'; import { @@ -58,7 +58,7 @@ export class UmbLogViewerWorkspaceContext { endDate: this.today, }; - #savedSearches = new ObjectState(undefined); + #savedSearches = new UmbObjectState(undefined); savedSearches = createObservablePart(this.#savedSearches, (data) => data?.items); #logCount = new DeepState(null); @@ -70,7 +70,7 @@ export class UmbLogViewerWorkspaceContext { #loggers = new DeepState(null); loggers = createObservablePart(this.#loggers, (data) => data?.items); - #canShowLogs = new BasicState(null); + #canShowLogs = new UmbBasicState(null); canShowLogs = createObservablePart(this.#canShowLogs, (data) => data); #filterExpression = new StringState(''); @@ -79,17 +79,17 @@ export class UmbLogViewerWorkspaceContext { #messageTemplates = new DeepState(null); messageTemplates = createObservablePart(this.#messageTemplates, (data) => data); - #logLevelsFilter = new ArrayState([]); + #logLevelsFilter = new UmbArrayState([]); logLevelsFilter = createObservablePart(this.#logLevelsFilter, (data) => data); #logs = new DeepState(null); logs = createObservablePart(this.#logs, (data) => data?.items); logsTotal = createObservablePart(this.#logs, (data) => data?.total); - #polling = new ObjectState({ enabled: false, interval: 2000 }); + #polling = new UmbObjectState({ enabled: false, interval: 2000 }); polling = createObservablePart(this.#polling, (data) => data); - #sortingDirection = new BasicState(DirectionModel.ASCENDING); + #sortingDirection = new UmbBasicState(DirectionModel.ASCENDING); sortingDirection = createObservablePart(this.#sortingDirection, (data) => data); #intervalID: number | null = null; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/relation-type.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/relation-type.store.ts index f8ac1dd072..71dac38ee3 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/relation-type.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/relation-type.store.ts @@ -1,6 +1,6 @@ import type { RelationTypeResponseModel } from '@umbraco-cms/backoffice/backend-api'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; -import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; import { UmbStoreBase } from '@umbraco-cms/backoffice/store'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; @@ -13,7 +13,7 @@ export const UMB_RELATION_TYPE_STORE_CONTEXT_TOKEN = new UmbContextToken([], (x) => x.id); + #data = new UmbArrayState([], (x) => x.id); /** * Creates an instance of UmbRelationTypeStore. diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/workspace/relation-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/workspace/relation-type-workspace.context.ts index 81abf8f66f..3c87efd4c2 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/workspace/relation-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/workspace/relation-type-workspace.context.ts @@ -3,14 +3,14 @@ import { UmbRelationTypeRepository } from '../repository/relation-type.repositor import { UmbEntityWorkspaceContextInterface } from '@umbraco-cms/backoffice/workspace'; import type { RelationTypeBaseModel, RelationTypeResponseModel } from '@umbraco-cms/backoffice/backend-api'; -import { ObjectState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; export class UmbRelationTypeWorkspaceContext extends UmbWorkspaceContext implements UmbEntityWorkspaceContextInterface { - #data = new ObjectState(undefined); + #data = new UmbObjectState(undefined); data = this.#data.asObservable(); name = this.#data.getObservablePart((data) => data?.name); id = this.#data.getObservablePart((data) => data?.id); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/collection/collection.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/collection/collection.context.ts index 9668a51d68..3d417cdf4a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/collection/collection.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/collection/collection.context.ts @@ -2,7 +2,7 @@ import { Observable } from 'rxjs'; import type { EntityTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbContextToken, UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; -import { ArrayState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; import { umbExtensionsRegistry, createExtensionClass } from '@umbraco-cms/backoffice/extensions-api'; import { UmbTreeRepository } from '@umbraco-cms/backoffice/repository'; @@ -17,10 +17,10 @@ export class UmbCollectionContext; - #data = new ArrayState(>[]); + #data = new UmbArrayState(>[]); public readonly data = this.#data.asObservable(); - #selection = new ArrayState(>[]); + #selection = new UmbArrayState(>[]); public readonly selection = this.#selection.asObservable(); /* diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar/section-sidebar.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar/section-sidebar.context.ts index c3a4264b2a..799d6f015b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar/section-sidebar.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar/section-sidebar.context.ts @@ -1,10 +1,10 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { StringState, BooleanState } from '@umbraco-cms/backoffice/observable-api'; +import { StringState, UmbBooleanState } from '@umbraco-cms/backoffice/observable-api'; export class UmbSectionSidebarContext { #host: UmbControllerHostElement; - #contextMenuIsOpen = new BooleanState(false); + #contextMenuIsOpen = new UmbBooleanState(false); contextMenuIsOpen = this.#contextMenuIsOpen.asObservable(); #entityType = new StringState(undefined); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section.context.ts index 2f90f58eca..41622825a7 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section.context.ts @@ -1,6 +1,6 @@ import type { ManifestSection } from '@umbraco-cms/backoffice/extensions-registry'; import type { Entity } from '@umbraco-cms/backoffice/models'; -import { ObjectState, StringState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbObjectState, StringState } from '@umbraco-cms/backoffice/observable-api'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; export type ActiveTreeItemType = Entity | undefined; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree-item-base/tree-item-base.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree-item-base/tree-item-base.context.ts index 0465630182..9f85452b99 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree-item-base/tree-item-base.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree-item-base/tree-item-base.context.ts @@ -7,7 +7,7 @@ import { UmbSectionContext, UMB_SECTION_CONTEXT_TOKEN } from '../../section/sect import { UmbTreeContextBase } from '../tree.context'; import { UmbTreeItemContext } from '../tree-item.context.interface'; import { ManifestEntityAction } from '@umbraco-cms/backoffice/extensions-registry'; -import { BooleanState, DeepState, StringState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; +import { UmbBooleanState, DeepState, StringState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbContextConsumerController, @@ -30,22 +30,22 @@ export class UmbTreeItemContextBase(undefined); treeItem = this.#treeItem.asObservable(); - #hasChildren = new BooleanState(false); + #hasChildren = new UmbBooleanState(false); hasChildren = this.#hasChildren.asObservable(); - #isLoading = new BooleanState(false); + #isLoading = new UmbBooleanState(false); isLoading = this.#isLoading.asObservable(); - #isSelectable = new BooleanState(false); + #isSelectable = new UmbBooleanState(false); isSelectable = this.#isSelectable.asObservable(); - #isSelected = new BooleanState(false); + #isSelected = new UmbBooleanState(false); isSelected = this.#isSelected.asObservable(); - #isActive = new BooleanState(false); + #isActive = new UmbBooleanState(false); isActive = this.#isActive.asObservable(); - #hasActions = new BooleanState(false); + #hasActions = new UmbBooleanState(false); hasActions = this.#hasActions.asObservable(); #path = new StringState(''); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace-property/workspace-property.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace-property/workspace-property.context.ts index e069c2a5b5..9cbb1616de 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace-property/workspace-property.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace-property/workspace-property.context.ts @@ -3,7 +3,12 @@ import { UmbWorkspaceVariableEntityContextInterface } from '../workspace/workspa import { UMB_WORKSPACE_VARIANT_CONTEXT_TOKEN } from '../workspace/workspace-variant/workspace-variant.context'; import type { DataTypeResponseModel } from '@umbraco-cms/backoffice/backend-api'; import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { ClassState, ObjectState, StringState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; +import { + UmbClassState, + UmbObjectState, + StringState, + UmbObserverController, +} from '@umbraco-cms/backoffice/observable-api'; import { UmbContextConsumerController, UmbContextProviderController, @@ -25,7 +30,7 @@ export class UmbWorkspacePropertyContext { private _providerController: UmbContextProviderController; - private _data = new ObjectState>({}); + private _data = new UmbObjectState>({}); public readonly alias = this._data.getObservablePart((data) => data.alias); public readonly label = this._data.getObservablePart((data) => data.label); @@ -35,7 +40,7 @@ export class UmbWorkspacePropertyContext { #workspaceVariantId?: UmbVariantId; - #variantId = new ClassState(undefined); + #variantId = new UmbClassState(undefined); public readonly variantId = this.#variantId.asObservable(); private _variantDifference = new StringState(undefined); @@ -88,7 +93,7 @@ export class UmbWorkspacePropertyContext { this._data.update({ description }); } public setValue(value: WorkspacePropertyData['value']) { - // Note: Do not try to compare new / old value, as it can of any type. We trust the ObjectState in doing such. + // Note: Do not try to compare new / old value, as it can of any type. We trust the UmbObjectState in doing such. this._data.update({ value }); } public changeValue(value: WorkspacePropertyData['value']) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/entity-manager-controller.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/entity-manager-controller.ts index 9704ce80c2..9eb0f5400c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/entity-manager-controller.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/entity-manager-controller.ts @@ -6,7 +6,7 @@ import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN, } from '@umbraco-cms/backoffice/notification'; -import { ObjectState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; +import { UmbObjectState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; import type { EntityTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; import { UmbEntityDetailStore } from '@umbraco-cms/backoffice/store'; @@ -18,7 +18,7 @@ export class UmbEntityWorkspaceManager< > { private _host; - state = new ObjectState(undefined); + state = new UmbObjectState(undefined); protected _storeSubscription?: UmbObserverController; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-container-structure-helper.class.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-container-structure-helper.class.ts index 25b756dfbf..ffaf4f118e 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-container-structure-helper.class.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-container-structure-helper.class.ts @@ -3,7 +3,7 @@ import { PropertyContainerTypes } from './workspace-structure-manager.class'; import { PropertyTypeContainerResponseModelBaseModel } from '@umbraco-cms/backoffice/backend-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbContextConsumerController, UMB_ENTITY_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/context-api'; -import { ArrayState, BooleanState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState, UmbBooleanState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; export class UmbWorkspaceContainerStructureHelper { #host: UmbControllerHostElement; @@ -20,10 +20,10 @@ export class UmbWorkspaceContainerStructureHelper { private _ownerContainers: PropertyTypeContainerResponseModelBaseModel[] = []; // State containing the merged containers (only one pr. name): - #containers = new ArrayState([], (x) => x.id); + #containers = new UmbArrayState([], (x) => x.id); readonly containers = this.#containers.asObservable(); - #hasProperties = new BooleanState(false); + #hasProperties = new UmbBooleanState(false); readonly hasProperties = this.#hasProperties.asObservable(); constructor(host: UmbControllerHostElement) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-context.ts index 796b258bd3..05d6a77a39 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-context.ts @@ -1,7 +1,7 @@ import { UmbEntityWorkspaceContextInterface } from '@umbraco-cms/backoffice/workspace'; import { UmbContextProviderController, UMB_ENTITY_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/context-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { BooleanState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbBooleanState } from '@umbraco-cms/backoffice/observable-api'; import type { BaseEntity } from '@umbraco-cms/backoffice/models'; /* @@ -15,7 +15,7 @@ export abstract class UmbWorkspaceContext public host: UmbControllerHostElement; public repository: T; - #isNew = new BooleanState(undefined); + #isNew = new UmbBooleanState(undefined); isNew = this.#isNew.asObservable(); constructor(host: UmbControllerHostElement, repository: T) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-property-structure-helper.class.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-property-structure-helper.class.ts index 6941cd3daa..00bd8fb9db 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-property-structure-helper.class.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-property-structure-helper.class.ts @@ -3,7 +3,7 @@ import { PropertyContainerTypes } from './workspace-structure-manager.class'; import { DocumentTypePropertyTypeResponseModel } from '@umbraco-cms/backoffice/backend-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbContextConsumerController, UMB_ENTITY_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/context-api'; -import { ArrayState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; export class UmbWorkspacePropertyStructureHelper { #host: UmbControllerHostElement; @@ -14,7 +14,7 @@ export class UmbWorkspacePropertyStructureHelper { private _isRoot?: boolean; private _containerName?: string; - #propertyStructure = new ArrayState([], (x) => x.id); + #propertyStructure = new UmbArrayState([], (x) => x.id); readonly propertyStructure = this.#propertyStructure.asObservable(); constructor(host: UmbControllerHostElement) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-split-view-manager.class.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-split-view-manager.class.ts index 3c238c96b0..b300be5ebf 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-split-view-manager.class.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-split-view-manager.class.ts @@ -1,6 +1,6 @@ import { UmbVariantId } from '../../../variants/variant-id.class'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; export type ActiveVariant = { index: number; @@ -16,7 +16,7 @@ export type ActiveVariant = { export class UmbWorkspaceSplitViewManager { #host: UmbControllerHostElement; - #activeVariantsInfo = new ArrayState([], (x) => x.index); + #activeVariantsInfo = new UmbArrayState([], (x) => x.index); public readonly activeVariantsInfo = this.#activeVariantsInfo.asObservable(); constructor(host: UmbControllerHostElement) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-structure-manager.class.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-structure-manager.class.ts index 8a7b24dc23..a5b15b4b1d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-structure-manager.class.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-structure-manager.class.ts @@ -9,7 +9,7 @@ import { } from '@umbraco-cms/backoffice/backend-api'; import { UmbControllerHostElement, UmbControllerInterface } from '@umbraco-cms/backoffice/controller'; import { - ArrayState, + UmbArrayState, UmbObserverController, MappingFunction, partialUpdateFrozenArray, @@ -29,13 +29,13 @@ export class UmbWorkspacePropertyStructureManager(); - #documentTypes = new ArrayState([], (x) => x.id); + #documentTypes = new UmbArrayState([], (x) => x.id); readonly documentTypes = this.#documentTypes.asObservable(); private readonly _documentTypeContainers = this.#documentTypes.getObservablePart((x) => x.flatMap((x) => x.containers ?? []) ); - #containers = new ArrayState([], (x) => x.id); + #containers = new UmbArrayState([], (x) => x.id); constructor(host: UmbControllerHostElement, typeRepository: R) { this.#host = host; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-variant/workspace-variant.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-variant/workspace-variant.context.ts index 0f621391b5..2393a6c6e3 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-variant/workspace-variant.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-variant/workspace-variant.context.ts @@ -9,7 +9,12 @@ import { UMB_ENTITY_WORKSPACE_CONTEXT, } from '@umbraco-cms/backoffice/context-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { ClassState, NumberState, ObjectState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; +import { + UmbClassState, + NumberState, + UmbObjectState, + UmbObserverController, +} from '@umbraco-cms/backoffice/observable-api'; import { DocumentVariantResponseModel } from '@umbraco-cms/backoffice/backend-api'; //type EntityType = DocumentModel; @@ -25,14 +30,14 @@ export class UmbWorkspaceVariantContext { #index = new NumberState(undefined); index = this.#index.asObservable(); - #currentVariant = new ObjectState(undefined); + #currentVariant = new UmbObjectState(undefined); currentVariant = this.#currentVariant.asObservable(); name = this.#currentVariant.getObservablePart((x) => x?.name); culture = this.#currentVariant.getObservablePart((x) => x?.culture); segment = this.#currentVariant.getObservablePart((x) => x?.segment); - #variantId = new ClassState(undefined); + #variantId = new UmbClassState(undefined); variantId = this.#variantId.asObservable(); private _currentVariantObserver?: UmbObserverController; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/templating/stylesheets/workspace/stylesheet-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/templating/stylesheets/workspace/stylesheet-workspace.context.ts index a973a00a4b..e92b3f643f 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/templating/stylesheets/workspace/stylesheet-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/templating/stylesheets/workspace/stylesheet-workspace.context.ts @@ -2,10 +2,10 @@ import { UmbWorkspaceContext } from '../../../shared/components/workspace/worksp import { UmbStylesheetRepository } from '../repository/stylesheet.repository'; import { StylesheetDetails } from '..'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { ObjectState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; export class UmbStylesheetWorkspaceContext extends UmbWorkspaceContext { - #data = new ObjectState(undefined); + #data = new UmbObjectState(undefined); data = this.#data.asObservable(); constructor(host: UmbControllerHostElement) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/repository/template.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/repository/template.store.ts index edebf64d61..4ef41040e2 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/repository/template.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/repository/template.store.ts @@ -1,5 +1,5 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; -import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; import { UmbStoreBase } from '@umbraco-cms/backoffice/store'; import type { TemplateResponseModel } from '@umbraco-cms/backoffice/backend-api'; import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; @@ -11,7 +11,7 @@ import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controlle * @description - Data Store for Templates */ export class UmbTemplateStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.id); + #data = new UmbArrayState([], (x) => x.id); /** * Creates an instance of UmbTemplateStore. diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/repository/dictionary.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/repository/dictionary.store.ts index c4b62e7c82..8090202a0d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/repository/dictionary.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/repository/dictionary.store.ts @@ -1,7 +1,7 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import { UmbStoreBase } from '@umbraco-cms/backoffice/store'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; import { DictionaryItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; /** @@ -11,7 +11,7 @@ import { DictionaryItemResponseModel } from '@umbraco-cms/backoffice/backend-api * @description - Data Store for Dictionary */ export class UmbDictionaryStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.id); + #data = new UmbArrayState([], (x) => x.id); constructor(host: UmbControllerHostElement) { super(host, UMB_DICTIONARY_STORE_CONTEXT_TOKEN.toString()); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/workspace/dictionary-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/workspace/dictionary-workspace.context.ts index 2d2eb3039d..3a1115d880 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/workspace/dictionary-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/workspace/dictionary-workspace.context.ts @@ -2,14 +2,14 @@ import { UmbDictionaryRepository } from '../repository/dictionary.repository'; import { UmbWorkspaceContext } from '../../../../backoffice/shared/components/workspace/workspace-context/workspace-context'; import { UmbEntityWorkspaceContextInterface } from '@umbraco-cms/backoffice/workspace'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { ObjectState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; import { DictionaryItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; export class UmbDictionaryWorkspaceContext extends UmbWorkspaceContext implements UmbEntityWorkspaceContextInterface { - #data = new ObjectState(undefined); + #data = new UmbObjectState(undefined); data = this.#data.asObservable(); name = this.#data.getObservablePart((data) => data?.name); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/users/current-user/current-user.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/users/current-user/current-user.store.ts index 70556528f1..cf4823147e 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/users/current-user/current-user.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/users/current-user/current-user.store.ts @@ -2,13 +2,13 @@ import { umbUsersData } from '../../../core/mocks/data/users.data'; import { umbracoPath } from '@umbraco-cms/backoffice/utils'; import type { UserDetails } from '@umbraco-cms/backoffice/models'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; -import { ObjectState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; export const UMB_CURRENT_USER_STORE_CONTEXT_TOKEN = new UmbContextToken('UmbCurrentUserStore'); export class UmbCurrentUserStore { //TODO: Temp solution to get a current user. Replace when we have a real user service - private _currentUser = new ObjectState(umbUsersData.getAll()[0]); + private _currentUser = new UmbObjectState(umbUsersData.getAll()[0]); public readonly currentUser = this._currentUser.asObservable(); /** diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/repository/user-group.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/repository/user-group.store.ts index 64197bb05b..87961ea266 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/repository/user-group.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/repository/user-group.store.ts @@ -1,7 +1,7 @@ import type { UserGroupDetails } from '@umbraco-cms/backoffice/models'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; import { UmbEntityDetailStore, UmbStoreBase } from '@umbraco-cms/backoffice/store'; // TODO: get rid of this type addition & { ... }: @@ -16,7 +16,7 @@ export const UMB_USER_GROUP_STORE_CONTEXT_TOKEN = new UmbContextToken { - #groups = new ArrayState([], (x) => x.id); + #groups = new UmbArrayState([], (x) => x.id); public groups = this.#groups.asObservable(); constructor(host: UmbControllerHostElement) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/users/users/repository/user.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/users/users/repository/user.store.ts index a52581484d..bdf016f8eb 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/users/users/repository/user.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/users/users/repository/user.store.ts @@ -1,5 +1,5 @@ import type { UserDetails } from '@umbraco-cms/backoffice/models'; -import { ArrayState, NumberState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState, NumberState } from '@umbraco-cms/backoffice/observable-api'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import { UmbEntityDetailStore, UmbStoreBase } from '@umbraco-cms/backoffice/store'; import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; @@ -15,7 +15,7 @@ export const UMB_USER_STORE_CONTEXT_TOKEN = new UmbContextToken('U * @description - Data Store for Users */ export class UmbUserStore extends UmbStoreBase implements UmbEntityDetailStore { - #users = new ArrayState([], (x) => x.id); + #users = new UmbArrayState([], (x) => x.id); public users = this.#users.asObservable(); #totalUsers = new NumberState(0); diff --git a/src/Umbraco.Web.UI.Client/src/installer/installer.context.ts b/src/Umbraco.Web.UI.Client/src/installer/installer.context.ts index 9e6b26b8cf..3c19c9f491 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/installer.context.ts +++ b/src/Umbraco.Web.UI.Client/src/installer/installer.context.ts @@ -8,7 +8,7 @@ import { } from '@umbraco-cms/backoffice/backend-api'; import { tryExecute } from '@umbraco-cms/backoffice/resources'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; -import { ObjectState, NumberState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbObjectState, NumberState } from '@umbraco-cms/backoffice/observable-api'; /** * Context API for the installer @@ -16,7 +16,7 @@ import { ObjectState, NumberState } from '@umbraco-cms/backoffice/observable-api * @class UmbInstallerContext */ export class UmbInstallerContext { - private _data = new ObjectState({ + private _data = new UmbObjectState({ user: { name: '', email: '', password: '', subscribeToNewsletter: false }, database: { id: '', providerName: '' }, telemetryLevel: TelemetryLevelModel.BASIC, @@ -26,10 +26,10 @@ export class UmbInstallerContext { private _currentStep = new NumberState(1); public readonly currentStep = this._currentStep.asObservable(); - private _settings = new ObjectState(undefined); + private _settings = new UmbObjectState(undefined); public readonly settings = this._settings.asObservable(); - private _installStatus = new ObjectState(null); + private _installStatus = new UmbObjectState(null); public readonly installStatus = this._installStatus.asObservable(); constructor() { diff --git a/src/Umbraco.Web.UI.Client/src/stories/store.mdx b/src/Umbraco.Web.UI.Client/src/stories/store.mdx index 1140ee8e40..9622967a0c 100644 --- a/src/Umbraco.Web.UI.Client/src/stories/store.mdx +++ b/src/Umbraco.Web.UI.Client/src/stories/store.mdx @@ -11,7 +11,7 @@ Generally a Store will be holding one or more RxJS Subjects, each Subject is mad ```typescript class MyProductStore { - #products = new ArrayState(>[], (product) => product.id); + #products = new UmbArrayState(>[], (product) => product.id); public readonly products = this.#products.asObservable(); @@ -118,7 +118,7 @@ This example give some inspiration to how fine grained this can become: ```typescript class MyProductStore { - #products = new ArrayState(>[]); + #products = new UmbArrayState(>[]); public readonly products = this.#products.asObservable(); public readonly amountOfProducts = this.#products.getObservablePart((products) => products.length); @@ -138,7 +138,7 @@ In the examples of this guide each product has a id, and we have clarified this ```typescript class MyProductStore { - #products = new ArrayState(>[], (product) => product.id); + #products = new UmbArrayState(>[], (product) => product.id); ... } ``` From 14247b04a5db1b84ae6f0ca1f98aa2496d0ac90b Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Sun, 16 Apr 2023 20:59:15 +0200 Subject: [PATCH 063/156] add umb prefix --- .../append-to-frozen-array.function.ts | 2 +- .../libs/observable-api/array-state.ts | 6 ++-- .../libs/observable-api/deep-state.test.ts | 31 +++++++------------ .../libs/observable-api/deep-state.ts | 4 +-- .../libs/observable-api/number-state.ts | 4 +-- .../libs/observable-api/object-state.ts | 6 ++-- .../partial-update-frozen-array.function.ts | 2 +- .../libs/observable-api/string-state.ts | 4 +-- .../repository/document-type.repository.ts | 4 +-- .../sources/document-type.tree.server.data.ts | 16 +++++----- .../repository/document.repository.ts | 4 +-- .../sources/document.tree.server.data.ts | 16 +++++----- .../logviewer/workspace/logviewer.context.ts | 16 +++++----- .../shared/collection/collection.context.ts | 2 +- .../backoffice-frame/backoffice.context.ts | 4 +-- .../code-editor/code-editor.stories.ts | 4 +-- .../section-sidebar.context.ts | 8 ++--- .../components/section/section.context.ts | 8 ++--- .../tree-context-menu-page.service.ts | 4 +-- .../tree-item-base/tree-item-base.context.ts | 11 +++++-- .../shared/components/tree/tree.context.ts | 6 ++-- .../workspace-property.context.ts | 4 +-- .../workspace-variant.context.ts | 4 +-- .../property-action-menu.context.ts | 4 +-- .../workspace/template-workspace.context.ts | 4 +-- .../src/backoffice/themes/theme.context.ts | 4 +-- .../current-user-history.store.ts | 4 +-- .../views/users/section-view-users.element.ts | 8 ++--- .../users/users/repository/user.store.ts | 4 +-- .../src/installer/installer.context.ts | 4 +-- 30 files changed, 100 insertions(+), 102 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/append-to-frozen-array.function.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/append-to-frozen-array.function.ts index 97ff56848c..23510e754c 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/append-to-frozen-array.function.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/append-to-frozen-array.function.ts @@ -5,7 +5,7 @@ * @param {(mappable: T) => R} mappingFunction - Method to return the part for this Observable to return. * @param {(previousResult: R, currentResult: R) => boolean} [memoizationFunction] - Method to Compare if the data has changed. Should return true when data is different. * @description - Creates a RxJS Observable from RxJS Subject. - * @example Example append new entry for a ArrayState or a part of DeepState/ObjectState it which is an array. Where the key is unique and the item will be updated if matched with existing. + * @example Example append new entry for a ArrayState or a part of UmbDeepState/UmbObjectState it which is an array. Where the key is unique and the item will be updated if matched with existing. * const entry = {id: 'myKey', value: 'myValue'}; * const newDataSet = appendToFrozenArray(mySubject.getValue(), entry, x => x.id === id); * mySubject.next(newDataSet); diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/array-state.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/array-state.ts index df29f02b1c..a4f67b2708 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/array-state.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/array-state.ts @@ -1,17 +1,17 @@ -import { DeepState } from './deep-state'; +import { UmbDeepState } from './deep-state'; import { partialUpdateFrozenArray } from './partial-update-frozen-array.function'; import { pushToUniqueArray } from './push-to-unique-array.function'; /** * @export * @class UmbArrayState - * @extends {DeepState} + * @extends {UmbDeepState} * @description - A RxJS BehaviorSubject which deepFreezes the object-data to ensure its not manipulated from any implementations. * Additionally the Subject ensures the data is unique, not updating any Observes unless there is an actual change of the content. * * The ArrayState provides methods to append data when the data is an Object. */ -export class UmbArrayState extends DeepState { +export class UmbArrayState extends UmbDeepState { #getUnique?: (entry: T) => unknown; #sortMethod?: (a: T, b: T) => number; diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/deep-state.test.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/deep-state.test.ts index f605564749..f1971dfa40 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/deep-state.test.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/deep-state.test.ts @@ -1,30 +1,27 @@ import { expect } from '@open-wc/testing'; -import { DeepState } from './deep-state'; +import { UmbDeepState } from './deep-state'; -describe('DeepState', () => { +describe('UmbDeepState', () => { + type ObjectType = { key: string; another: string }; - type ObjectType = {key: string, another: string}; - - let subject: DeepState; + let subject: UmbDeepState; let initialData: ObjectType; beforeEach(() => { - initialData = {key: 'some', another: 'myValue'}; - subject = new DeepState(initialData); + initialData = { key: 'some', another: 'myValue' }; + subject = new UmbDeepState(initialData); }); - it('getValue gives the initial data', () => { expect(subject.value.another).to.be.equal(initialData.another); }); it('update via next', () => { - subject.next({key: 'some', another: 'myNewValue'}); + subject.next({ key: 'some', another: 'myNewValue' }); expect(subject.value.another).to.be.equal('myNewValue'); }); it('replays latests, no matter the amount of subscriptions.', (done) => { - const observer = subject.asObservable(); observer.subscribe((value) => { expect(value).to.be.equal(initialData); @@ -33,28 +30,24 @@ describe('DeepState', () => { expect(value).to.be.equal(initialData); done(); }); - }); it('use gObservablePart, updates on its specific change.', (done) => { - let amountOfCallbacks = 0; - const subObserver = subject.getObservablePart(data => data.another); + const subObserver = subject.getObservablePart((data) => data.another); subObserver.subscribe((value) => { amountOfCallbacks++; - if(amountOfCallbacks === 1) { + if (amountOfCallbacks === 1) { expect(value).to.be.equal('myValue'); } - if(amountOfCallbacks === 2) { + if (amountOfCallbacks === 2) { expect(value).to.be.equal('myNewValue'); done(); } }); - subject.next({key: 'change_this_first_should_not_trigger_update', another: 'myValue'}); - subject.next({key: 'some', another: 'myNewValue'}); - + subject.next({ key: 'change_this_first_should_not_trigger_update', another: 'myValue' }); + subject.next({ key: 'some', another: 'myNewValue' }); }); - }); diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/deep-state.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/deep-state.ts index 201ab479c8..c67daa927c 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/deep-state.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/deep-state.ts @@ -7,12 +7,12 @@ import { naiveObjectComparison } from './naive-object-comparison'; /** * @export - * @class DeepState + * @class UmbDeepState * @extends {BehaviorSubject} * @description - A RxJS BehaviorSubject which deepFreezes the data to ensure its not manipulated from any implementations. * Additionally the Subject ensures the data is unique, not updating any Observes unless there is an actual change of the content. */ -export class DeepState extends BehaviorSubject { +export class UmbDeepState extends BehaviorSubject { constructor(initialData: T) { super(deepFreeze(initialData)); } diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/number-state.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/number-state.ts index 82387e9580..5556d8956c 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/number-state.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/number-state.ts @@ -2,11 +2,11 @@ import { UmbBasicState } from './basic-state'; /** * @export - * @class NumberState + * @class UmbNumberState * @extends {BehaviorSubject} * @description - A RxJS BehaviorSubject this Subject ensures the data is unique, not updating any Observes unless there is an actual change of the value. */ -export class NumberState extends UmbBasicState { +export class UmbNumberState extends UmbBasicState { constructor(initialData: T | number) { super(initialData); } diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/object-state.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/object-state.ts index fdb85a43b9..6c4b32a115 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/object-state.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/object-state.ts @@ -1,15 +1,15 @@ -import { DeepState } from './deep-state'; +import { UmbDeepState } from './deep-state'; /** * @export * @class UmbObjectState - * @extends {DeepState} + * @extends {UmbDeepState} * @description - A RxJS BehaviorSubject which deepFreezes the object-data to ensure its not manipulated from any implementations. * Additionally the Subject ensures the data is unique, not updating any Observes unless there is an actual change of the content. * * The UmbObjectState provides methods to append data when the data is an Object. */ -export class UmbObjectState extends DeepState { +export class UmbObjectState extends UmbDeepState { /** * @method update * @param {Partial} partialData - A object containing some of the data to update in this Subject. diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/partial-update-frozen-array.function.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/partial-update-frozen-array.function.ts index 9064fb0384..b19c322594 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/partial-update-frozen-array.function.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/partial-update-frozen-array.function.ts @@ -5,7 +5,7 @@ * @param {(mappable: T) => R} mappingFunction - Method to return the part for this Observable to return. * @param {(previousResult: R, currentResult: R) => boolean} [memoizationFunction] - Method to Compare if the data has changed. Should return true when data is different. * @description - Creates a RxJS Observable from RxJS Subject. - * @example Example append new entry for a ArrayState or a part of DeepState/UmbObjectState it which is an array. Where the key is unique and the item will be updated if matched with existing. + * @example Example append new entry for a ArrayState or a part of UmbDeepState/UmbObjectState it which is an array. Where the key is unique and the item will be updated if matched with existing. * const partialEntry = {value: 'myValue'}; * const newDataSet = partialUpdateFrozenArray(mySubject.getValue(), partialEntry, x => x.key === 'myKey'); * mySubject.next(newDataSet); diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/string-state.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/string-state.ts index d78d91127e..632c28e1b1 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/string-state.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/string-state.ts @@ -2,11 +2,11 @@ import { UmbBasicState } from './basic-state'; /** * @export - * @class StringState + * @class UmbStringState * @extends {UmbBasicState} * @description - A RxJS BehaviorSubject this Subject ensures the data is unique, not updating any Observes unless there is an actual change of the value. */ -export class StringState extends UmbBasicState { +export class UmbStringState extends UmbBasicState { constructor(initialData: T | string) { super(initialData); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/document-type.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/document-type.repository.ts index 78c9ac203c..3ab4e56fd9 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/document-type.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/document-type.repository.ts @@ -1,4 +1,4 @@ -import { DocumentTypeTreeServerDataSource } from './sources/document-type.tree.server.data'; +import { UmbDocumentTypeTreeServerDataSource } from './sources/document-type.tree.server.data'; import { UmbDocumentTypeServerDataSource } from './sources/document-type.server.data'; import { UmbDocumentTypeTreeStore, UMB_DOCUMENT_TYPE_TREE_STORE_CONTEXT_TOKEN } from './document-type.tree.store'; import { UmbDocumentTypeStore, UMB_DOCUMENT_TYPE_STORE_CONTEXT_TOKEN } from './document-type.store'; @@ -27,7 +27,7 @@ export class UmbDocumentTypeRepository implements UmbTreeRepository, U this.#host = host; // TODO: figure out how spin up get the correct data source - this.#treeSource = new DocumentTypeTreeServerDataSource(this.#host); + this.#treeSource = new UmbDocumentTypeTreeServerDataSource(this.#host); this.#detailDataSource = new UmbDocumentTypeServerDataSource(this.#host); this.#init = Promise.all([ diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/sources/document-type.tree.server.data.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/sources/document-type.tree.server.data.ts index fd3cee9ccb..33869d807f 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/sources/document-type.tree.server.data.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/sources/document-type.tree.server.data.ts @@ -6,10 +6,10 @@ import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; /** * A data source for the Document tree that fetches data from the server * @export - * @class DocumentTreeServerDataSource - * @implements {DocumentTreeDataSource} + * @class UmbDocumentTypeTreeServerDataSource + * @implements {UmbTreeDataSource} */ -export class DocumentTypeTreeServerDataSource implements UmbTreeDataSource { +export class UmbDocumentTypeTreeServerDataSource implements UmbTreeDataSource { #host: UmbControllerHostElement; // TODO: how do we handle trashed items? @@ -42,9 +42,9 @@ export class DocumentTypeTreeServerDataSource implements UmbTreeDataSource { } /** - * Creates an instance of DocumentTreeServerDataSource. + * Creates an instance of UmbDocumentTypeTreeServerDataSource. * @param {UmbControllerHostElement} host - * @memberof DocumentTreeServerDataSource + * @memberof UmbDocumentTypeTreeServerDataSource */ constructor(host: UmbControllerHostElement) { this.#host = host; @@ -53,7 +53,7 @@ export class DocumentTypeTreeServerDataSource implements UmbTreeDataSource { /** * Fetches the root items for the tree from the server * @return {*} - * @memberof DocumentTreeServerDataSource + * @memberof UmbDocumentTypeTreeServerDataSource */ async getRootItems() { return tryExecuteAndNotify(this.#host, DocumentTypeResource.getTreeDocumentTypeRoot({})); @@ -63,7 +63,7 @@ export class DocumentTypeTreeServerDataSource implements UmbTreeDataSource { * Fetches the children of a given parent id from the server * @param {(string | null)} parentId * @return {*} - * @memberof DocumentTreeServerDataSource + * @memberof UmbDocumentTypeTreeServerDataSource */ async getChildrenOf(parentId: string | null) { if (!parentId) { @@ -83,7 +83,7 @@ export class DocumentTypeTreeServerDataSource implements UmbTreeDataSource { * Fetches the items for the given ids from the server * @param {Array} ids * @return {*} - * @memberof DocumentTreeServerDataSource + * @memberof UmbDocumentTypeTreeServerDataSource */ async getItems(ids: Array) { if (ids) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/document.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/document.repository.ts index 91d485f05c..b6ad80faaa 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/document.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/document.repository.ts @@ -1,7 +1,7 @@ import { UmbDocumentServerDataSource } from './sources/document.server.data'; import { UmbDocumentStore, UMB_DOCUMENT_STORE_CONTEXT_TOKEN } from './document.store'; import { UmbDocumentTreeStore, UMB_DOCUMENT_TREE_STORE_CONTEXT_TOKEN } from './document.tree.store'; -import { DocumentTreeServerDataSource } from './sources/document.tree.server.data'; +import { UmbDocumentTreeServerDataSource } from './sources/document.tree.server.data'; import type { UmbTreeDataSource, UmbTreeRepository, UmbDetailRepository } from '@umbraco-cms/backoffice/repository'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; @@ -32,7 +32,7 @@ export class UmbDocumentRepository implements UmbTreeRepository, UmbDe this.#host = host; // TODO: figure out how spin up get the correct data source - this.#treeSource = new DocumentTreeServerDataSource(this.#host); + this.#treeSource = new UmbDocumentTreeServerDataSource(this.#host); this.#detailDataSource = new UmbDocumentServerDataSource(this.#host); this.#init = Promise.all([ diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/sources/document.tree.server.data.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/sources/document.tree.server.data.ts index 076b707b0b..9d09c3bcc3 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/sources/document.tree.server.data.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/sources/document.tree.server.data.ts @@ -6,10 +6,10 @@ import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; /** * A data source for the Document tree that fetches data from the server * @export - * @class DocumentTreeServerDataSource - * @implements {DocumentTreeDataSource} + * @class UmbDocumentTreeServerDataSource + * @implements {UmbTreeDataSource} */ -export class DocumentTreeServerDataSource implements UmbTreeDataSource { +export class UmbDocumentTreeServerDataSource implements UmbTreeDataSource { #host: UmbControllerHostElement; // TODO: how do we handle trashed items? @@ -42,9 +42,9 @@ export class DocumentTreeServerDataSource implements UmbTreeDataSource { } /** - * Creates an instance of DocumentTreeServerDataSource. + * Creates an instance of UmbDocumentTreeServerDataSource. * @param {UmbControllerHostElement} host - * @memberof DocumentTreeServerDataSource + * @memberof UmbDocumentTreeServerDataSource */ constructor(host: UmbControllerHostElement) { this.#host = host; @@ -53,7 +53,7 @@ export class DocumentTreeServerDataSource implements UmbTreeDataSource { /** * Fetches the root items for the tree from the server * @return {*} - * @memberof DocumentTreeServerDataSource + * @memberof UmbDocumentTreeServerDataSource */ async getRootItems() { return tryExecuteAndNotify(this.#host, DocumentResource.getTreeDocumentRoot({})); @@ -63,7 +63,7 @@ export class DocumentTreeServerDataSource implements UmbTreeDataSource { * Fetches the children of a given parent id from the server * @param {(string | null)} parentId * @return {*} - * @memberof DocumentTreeServerDataSource + * @memberof UmbDocumentTreeServerDataSource */ async getChildrenOf(parentId: string | null) { if (!parentId) { @@ -83,7 +83,7 @@ export class DocumentTreeServerDataSource implements UmbTreeDataSource { * Fetches the items for the given ids from the server * @param {Array} ids * @return {*} - * @memberof DocumentTreeServerDataSource + * @memberof UmbDocumentTreeServerDataSource */ async getItems(ids: Array) { if (!ids) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/workspace/logviewer.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/workspace/logviewer.context.ts index 95bf69be44..73c793e4dd 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/workspace/logviewer.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/workspace/logviewer.context.ts @@ -3,9 +3,9 @@ import { UmbBasicState, UmbArrayState, createObservablePart, - DeepState, + UmbDeepState, UmbObjectState, - StringState, + UmbStringState, } from '@umbraco-cms/backoffice/observable-api'; import { DirectionModel, @@ -61,28 +61,28 @@ export class UmbLogViewerWorkspaceContext { #savedSearches = new UmbObjectState(undefined); savedSearches = createObservablePart(this.#savedSearches, (data) => data?.items); - #logCount = new DeepState(null); + #logCount = new UmbDeepState(null); logCount = createObservablePart(this.#logCount, (data) => data); - #dateRange = new DeepState(this.defaultDateRange); + #dateRange = new UmbDeepState(this.defaultDateRange); dateRange = createObservablePart(this.#dateRange, (data) => data); - #loggers = new DeepState(null); + #loggers = new UmbDeepState(null); loggers = createObservablePart(this.#loggers, (data) => data?.items); #canShowLogs = new UmbBasicState(null); canShowLogs = createObservablePart(this.#canShowLogs, (data) => data); - #filterExpression = new StringState(''); + #filterExpression = new UmbStringState(''); filterExpression = createObservablePart(this.#filterExpression, (data) => data); - #messageTemplates = new DeepState(null); + #messageTemplates = new UmbDeepState(null); messageTemplates = createObservablePart(this.#messageTemplates, (data) => data); #logLevelsFilter = new UmbArrayState([]); logLevelsFilter = createObservablePart(this.#logLevelsFilter, (data) => data); - #logs = new DeepState(null); + #logs = new UmbDeepState(null); logs = createObservablePart(this.#logs, (data) => data?.items); logsTotal = createObservablePart(this.#logs, (data) => data?.total); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/collection/collection.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/collection/collection.context.ts index 3d417cdf4a..4f2512206c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/collection/collection.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/collection/collection.context.ts @@ -25,7 +25,7 @@ export class UmbCollectionContext = { "Smartypants, double quotes" and 'single quotes'`, typescript: `import { UmbTemplateRepository } from '../repository/template.repository'; import { UmbWorkspaceContext } from '../../../shared/components/workspace/workspace-context/workspace-context'; - import { createObservablePart, DeepState } from '@umbraco-cms/observable-api'; + import { createObservablePart, UmbDeepState } from '@umbraco-cms/observable-api'; import { TemplateModel } from '@umbraco-cms/backend-api'; import { UmbControllerHostElement } from '@umbraco-cms/controller'; export class UmbTemplateWorkspaceContext extends UmbWorkspaceContext { - #data = new DeepState(undefined); + #data = new UmbDeepState(undefined); data = this.#data.asObservable(); name = createObservablePart(this.#data, (data) => data?.name); content = createObservablePart(this.#data, (data) => data?.content); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar/section-sidebar.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar/section-sidebar.context.ts index 799d6f015b..8185a4f502 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar/section-sidebar.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar/section-sidebar.context.ts @@ -1,19 +1,19 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { StringState, UmbBooleanState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbStringState, UmbBooleanState } from '@umbraco-cms/backoffice/observable-api'; export class UmbSectionSidebarContext { #host: UmbControllerHostElement; #contextMenuIsOpen = new UmbBooleanState(false); contextMenuIsOpen = this.#contextMenuIsOpen.asObservable(); - #entityType = new StringState(undefined); + #entityType = new UmbStringState(undefined); entityType = this.#entityType.asObservable(); - #unique = new StringState(undefined); + #unique = new UmbStringState(undefined); unique = this.#unique.asObservable(); - #headline = new StringState(undefined); + #headline = new UmbStringState(undefined); headline = this.#headline.asObservable(); constructor(host: UmbControllerHostElement) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section.context.ts index 41622825a7..628062ceb0 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section.context.ts @@ -1,14 +1,14 @@ import type { ManifestSection } from '@umbraco-cms/backoffice/extensions-registry'; import type { Entity } from '@umbraco-cms/backoffice/models'; -import { UmbObjectState, StringState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbObjectState, UmbStringState } from '@umbraco-cms/backoffice/observable-api'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; export type ActiveTreeItemType = Entity | undefined; export class UmbSectionContext { - #manifestAlias = new StringState(undefined); - #manifestPathname = new StringState(undefined); - #manifestLabel = new StringState(undefined); + #manifestAlias = new UmbStringState(undefined); + #manifestPathname = new UmbStringState(undefined); + #manifestLabel = new UmbStringState(undefined); public readonly alias = this.#manifestAlias.asObservable(); public readonly pathname = this.#manifestPathname.asObservable(); public readonly label = this.#manifestLabel.asObservable(); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/context-menu/tree-context-menu-page.service.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/context-menu/tree-context-menu-page.service.ts index d82eb782bf..584b77456a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/context-menu/tree-context-menu-page.service.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/context-menu/tree-context-menu-page.service.ts @@ -2,7 +2,7 @@ import { UUITextStyles } from '@umbraco-ui/uui-css'; import { css, nothing, PropertyValueMap } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; -import { DeepState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbDeepState } from '@umbraco-cms/backoffice/observable-api'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; // TODO: Refactor this, its not a service and the data should be handled by a context api. @@ -13,7 +13,7 @@ export class UmbTreeContextMenuPageServiceElement extends UmbLitElement { @property({ type: Object }) public actionEntity: any = { key: '', name: '' }; - #entity = new DeepState({ key: '', name: '' } as any); + #entity = new UmbDeepState({ key: '', name: '' } as any); public readonly entity = this.#entity.asObservable(); @state() diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree-item-base/tree-item-base.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree-item-base/tree-item-base.context.ts index 9f85452b99..9c81962047 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree-item-base/tree-item-base.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree-item-base/tree-item-base.context.ts @@ -7,7 +7,12 @@ import { UmbSectionContext, UMB_SECTION_CONTEXT_TOKEN } from '../../section/sect import { UmbTreeContextBase } from '../tree.context'; import { UmbTreeItemContext } from '../tree-item.context.interface'; import { ManifestEntityAction } from '@umbraco-cms/backoffice/extensions-registry'; -import { UmbBooleanState, DeepState, StringState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; +import { + UmbBooleanState, + UmbDeepState, + UmbStringState, + UmbObserverController, +} from '@umbraco-cms/backoffice/observable-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbContextConsumerController, @@ -27,7 +32,7 @@ export class UmbTreeItemContextBase(undefined); + #treeItem = new UmbDeepState(undefined); treeItem = this.#treeItem.asObservable(); #hasChildren = new UmbBooleanState(false); @@ -48,7 +53,7 @@ export class UmbTreeItemContextBase>[]); + #selection = new UmbDeepState(>[]); public readonly selection = this.#selection.asObservable(); repository?: UmbTreeRepository; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace-property/workspace-property.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace-property/workspace-property.context.ts index 9cbb1616de..5cad4cae04 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace-property/workspace-property.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace-property/workspace-property.context.ts @@ -6,7 +6,7 @@ import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controlle import { UmbClassState, UmbObjectState, - StringState, + UmbStringState, UmbObserverController, } from '@umbraco-cms/backoffice/observable-api'; import { @@ -43,7 +43,7 @@ export class UmbWorkspacePropertyContext { #variantId = new UmbClassState(undefined); public readonly variantId = this.#variantId.asObservable(); - private _variantDifference = new StringState(undefined); + private _variantDifference = new UmbStringState(undefined); public readonly variantDifference = this._variantDifference.asObservable(); private _workspaceContext?: UmbWorkspaceVariableEntityContextInterface; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-variant/workspace-variant.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-variant/workspace-variant.context.ts index 2393a6c6e3..4364c6d3b8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-variant/workspace-variant.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-variant/workspace-variant.context.ts @@ -11,7 +11,7 @@ import { import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbClassState, - NumberState, + UmbNumberState, UmbObjectState, UmbObserverController, } from '@umbraco-cms/backoffice/observable-api'; @@ -27,7 +27,7 @@ export class UmbWorkspaceVariantContext { return this.#workspaceContext; } - #index = new NumberState(undefined); + #index = new UmbNumberState(undefined); index = this.#index.asObservable(); #currentVariant = new UmbObjectState(undefined); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-actions/shared/property-action-menu/property-action-menu.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-actions/shared/property-action-menu/property-action-menu.context.ts index 3a8205847f..ef67ddc26c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-actions/shared/property-action-menu/property-action-menu.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-actions/shared/property-action-menu/property-action-menu.context.ts @@ -1,9 +1,9 @@ import { UmbContextProviderController } from '@umbraco-cms/backoffice/context-api'; import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { DeepState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbDeepState } from '@umbraco-cms/backoffice/observable-api'; export class UmbPropertyActionMenuContext { - #isOpen = new DeepState(false); + #isOpen = new UmbDeepState(false); public readonly isOpen = this.#isOpen.asObservable(); constructor(host: UmbControllerHostElement) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/workspace/template-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/workspace/template-workspace.context.ts index d4f7541846..89983e09f5 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/workspace/template-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/workspace/template-workspace.context.ts @@ -1,11 +1,11 @@ import { UmbTemplateRepository } from '../repository/template.repository'; import { UmbWorkspaceContext } from '../../../shared/components/workspace/workspace-context/workspace-context'; -import { createObservablePart, DeepState } from '@umbraco-cms/backoffice/observable-api'; +import { createObservablePart, UmbDeepState } from '@umbraco-cms/backoffice/observable-api'; import { TemplateResponseModel } from '@umbraco-cms/backoffice/backend-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; export class UmbTemplateWorkspaceContext extends UmbWorkspaceContext { - #data = new DeepState(undefined); + #data = new UmbDeepState(undefined); data = this.#data.asObservable(); name = createObservablePart(this.#data, (data) => data?.name); content = createObservablePart(this.#data, (data) => data?.content); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/themes/theme.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/themes/theme.context.ts index 959c8f19ef..1d3829bf8a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/themes/theme.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/themes/theme.context.ts @@ -1,7 +1,7 @@ import { map } from 'rxjs'; import { manifests } from './manifests'; import { UmbContextProviderController, UmbContextToken } from '@umbraco-cms/backoffice/context-api'; -import { StringState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; +import { UmbStringState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { ManifestTheme } from '@umbraco-cms/backoffice/extensions-registry'; @@ -11,7 +11,7 @@ const LOCAL_STORAGE_KEY = 'umb-theme-alias'; export class UmbThemeContext { private _host: UmbControllerHostElement; - #theme = new StringState('umb-light-theme'); + #theme = new UmbStringState('umb-light-theme'); public readonly theme = this.#theme.asObservable(); private themeSubscription?: UmbObserverController; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/users/current-user/current-user-history.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/users/current-user/current-user-history.store.ts index 2a5df8b61f..888278353b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/users/current-user/current-user-history.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/users/current-user/current-user-history.store.ts @@ -1,5 +1,5 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; -import { DeepState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbDeepState } from '@umbraco-cms/backoffice/observable-api'; export type UmbModelType = 'dialog' | 'sidebar'; @@ -10,7 +10,7 @@ export type UmbCurrentUserHistoryItem = { }; export class UmbCurrentUserHistoryStore { - #history = new DeepState(>[]); + #history = new UmbDeepState(>[]); public readonly history = this.#history.asObservable(); public readonly latestHistory = this.#history.getObservablePart((historyItems) => historyItems.slice(-10)); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/users/user-section/views/users/section-view-users.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/users/user-section/views/users/section-view-users.element.ts index 2cebe636ce..64f9e96e23 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/users/user-section/views/users/section-view-users.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/users/user-section/views/users/section-view-users.element.ts @@ -11,7 +11,7 @@ import './workspace-view-users-selection.element'; import type { UserDetails } from '@umbraco-cms/backoffice/models'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; -import { DeepState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbDeepState } from '@umbraco-cms/backoffice/observable-api'; import type { ManifestWorkspace } from '@umbraco-cms/backoffice/extensions-registry'; @customElement('umb-section-view-users') @@ -37,13 +37,13 @@ export class UmbSectionViewUsersElement extends UmbLitElement { // TODO: This must be turned into context api: Maybe its a Collection View (SectionView Collection View)? private _userStore?: UmbUserStore; - #selection = new DeepState(>[]); + #selection = new UmbDeepState(>[]); public readonly selection = this.#selection.asObservable(); - #users = new DeepState(>[]); + #users = new UmbDeepState(>[]); public readonly users = this.#users.asObservable(); - #search = new DeepState(''); + #search = new UmbDeepState(''); public readonly search = this.#search.asObservable(); constructor() { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/users/users/repository/user.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/users/users/repository/user.store.ts index bdf016f8eb..c074c2f3cb 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/users/users/repository/user.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/users/users/repository/user.store.ts @@ -1,5 +1,5 @@ import type { UserDetails } from '@umbraco-cms/backoffice/models'; -import { UmbArrayState, NumberState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState, UmbNumberState } from '@umbraco-cms/backoffice/observable-api'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import { UmbEntityDetailStore, UmbStoreBase } from '@umbraco-cms/backoffice/store'; import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; @@ -18,7 +18,7 @@ export class UmbUserStore extends UmbStoreBase implements UmbEntityDetailStore([], (x) => x.id); public users = this.#users.asObservable(); - #totalUsers = new NumberState(0); + #totalUsers = new UmbNumberState(0); public readonly totalUsers = this.#totalUsers.asObservable(); constructor(host: UmbControllerHostElement) { diff --git a/src/Umbraco.Web.UI.Client/src/installer/installer.context.ts b/src/Umbraco.Web.UI.Client/src/installer/installer.context.ts index 3c19c9f491..30b4c7350a 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/installer.context.ts +++ b/src/Umbraco.Web.UI.Client/src/installer/installer.context.ts @@ -8,7 +8,7 @@ import { } from '@umbraco-cms/backoffice/backend-api'; import { tryExecute } from '@umbraco-cms/backoffice/resources'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; -import { UmbObjectState, NumberState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbObjectState, UmbNumberState } from '@umbraco-cms/backoffice/observable-api'; /** * Context API for the installer @@ -23,7 +23,7 @@ export class UmbInstallerContext { }); public readonly data = this._data.asObservable(); - private _currentStep = new NumberState(1); + private _currentStep = new UmbNumberState(1); public readonly currentStep = this._currentStep.asObservable(); private _settings = new UmbObjectState(undefined); From c81a57a1c5dde6f2479b709b6a3e216d8b80feb0 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Sun, 16 Apr 2023 21:06:04 +0200 Subject: [PATCH 064/156] add umb prefix --- .../repository/media-type.repository.ts | 4 ++-- .../sources/media-type.tree.server.data.ts | 12 ++++++------ .../media/media/repository/media.repository.ts | 4 ++-- .../repository/sources/media.tree.server.data.ts | 16 ++++++++-------- .../repository/member-group.repository.ts | 4 ++-- .../sources/member-group.tree.server.data.ts | 16 ++++++++-------- 6 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/repository/media-type.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/repository/media-type.repository.ts index 898e1ab966..56e3769a84 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/repository/media-type.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/repository/media-type.repository.ts @@ -1,7 +1,7 @@ import { UmbMediaTypeTreeStore, UMB_MEDIA_TYPE_TREE_STORE_CONTEXT_TOKEN } from './media-type.tree.store'; import { UmbMediaTypeDetailServerDataSource } from './sources/media-type.detail.server.data'; import { UmbMediaTypeStore, UMB_MEDIA_TYPE_STORE_CONTEXT_TOKEN } from './media-type.detail.store'; -import { MediaTypeTreeServerDataSource } from './sources/media-type.tree.server.data'; +import { UmbMediaTypeTreeServerDataSource } from './sources/media-type.tree.server.data'; import { ProblemDetailsModel } from '@umbraco-cms/backoffice/backend-api'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; @@ -26,7 +26,7 @@ export class UmbMediaTypeRepository implements UmbTreeRepository { this.#host = host; // TODO: figure out how spin up get the correct data source - this.#treeSource = new MediaTypeTreeServerDataSource(this.#host); + this.#treeSource = new UmbMediaTypeTreeServerDataSource(this.#host); this.#detailSource = new UmbMediaTypeDetailServerDataSource(this.#host); this.#init = Promise.all([ diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/repository/sources/media-type.tree.server.data.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/repository/sources/media-type.tree.server.data.ts index 6d164599f4..12401f3fe9 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/repository/sources/media-type.tree.server.data.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/repository/sources/media-type.tree.server.data.ts @@ -6,10 +6,10 @@ import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; /** * A data source for the MediaType tree that fetches data from the server * @export - * @class MediaTypeTreeServerDataSource - * @implements {MediaTypeTreeDataSource} + * @class UmbMediaTypeTreeServerDataSource + * @implements {UmbTreeDataSource} */ -export class MediaTypeTreeServerDataSource implements UmbTreeDataSource { +export class UmbMediaTypeTreeServerDataSource implements UmbTreeDataSource { #host: UmbControllerHostElement; /** @@ -24,7 +24,7 @@ export class MediaTypeTreeServerDataSource implements UmbTreeDataSource { /** * Fetches the root items for the tree from the server * @return {*} - * @memberof MediaTypeTreeServerDataSource + * @memberof UmbMediaTypeTreeServerDataSource */ async getRootItems() { return tryExecuteAndNotify(this.#host, MediaTypeResource.getTreeMediaTypeRoot({})); @@ -34,7 +34,7 @@ export class MediaTypeTreeServerDataSource implements UmbTreeDataSource { * Fetches the children of a given parent id from the server * @param {(string | null)} parentId * @return {*} - * @memberof MediaTypeTreeServerDataSource + * @memberof UmbMediaTypeTreeServerDataSource */ async getChildrenOf(parentId: string | null) { if (!parentId) { @@ -54,7 +54,7 @@ export class MediaTypeTreeServerDataSource implements UmbTreeDataSource { * Fetches the items for the given ids from the server * @param {Array} ids * @return {*} - * @memberof MediaTypeTreeServerDataSource + * @memberof UmbMediaTypeTreeServerDataSource */ async getItems(ids: Array) { if (!ids || ids.length === 0) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/repository/media.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/repository/media.repository.ts index 28e2aed79d..77554e0894 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/repository/media.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/repository/media.repository.ts @@ -1,5 +1,5 @@ import type { MediaDetails } from '../'; -import { MediaTreeServerDataSource } from './sources/media.tree.server.data'; +import { UmbMediaTreeServerDataSource } from './sources/media.tree.server.data'; import { UmbMediaTreeStore, UMB_MEDIA_TREE_STORE_CONTEXT_TOKEN } from './media.tree.store'; import { UmbMediaStore, UMB_MEDIA_STORE_CONTEXT_TOKEN } from './media.store'; import { UmbMediaDetailServerDataSource } from './sources/media.detail.server.data'; @@ -36,7 +36,7 @@ export class UmbMediaRepository this.#host = host; // TODO: figure out how spin up get the correct data source - this.#treeSource = new MediaTreeServerDataSource(this.#host); + this.#treeSource = new UmbMediaTreeServerDataSource(this.#host); this.#detailDataSource = new UmbMediaDetailServerDataSource(this.#host); new UmbContextConsumerController(this.#host, UMB_MEDIA_TREE_STORE_CONTEXT_TOKEN, (instance) => { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/repository/sources/media.tree.server.data.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/repository/sources/media.tree.server.data.ts index 096d2b2814..ee50c0ce1d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/repository/sources/media.tree.server.data.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/repository/sources/media.tree.server.data.ts @@ -6,10 +6,10 @@ import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; /** * A data source for the Media tree that fetches data from the server * @export - * @class MediaTreeServerDataSource - * @implements {MediaTreeDataSource} + * @class UmbMediaTreeServerDataSource + * @implements {UmbTreeDataSource} */ -export class MediaTreeServerDataSource implements UmbTreeDataSource { +export class UmbMediaTreeServerDataSource implements UmbTreeDataSource { #host: UmbControllerHostElement; // TODO: how do we handle trashed items? @@ -42,9 +42,9 @@ export class MediaTreeServerDataSource implements UmbTreeDataSource { } /** - * Creates an instance of MediaTreeServerDataSource. + * Creates an instance of UmbMediaTreeServerDataSource. * @param {UmbControllerHostElement} host - * @memberof MediaTreeServerDataSource + * @memberof UmbMediaTreeServerDataSource */ constructor(host: UmbControllerHostElement) { this.#host = host; @@ -53,7 +53,7 @@ export class MediaTreeServerDataSource implements UmbTreeDataSource { /** * Fetches the root items for the tree from the server * @return {*} - * @memberof MediaTreeServerDataSource + * @memberof UmbMediaTreeServerDataSource */ async getRootItems() { return tryExecuteAndNotify(this.#host, MediaResource.getTreeMediaRoot({})); @@ -63,7 +63,7 @@ export class MediaTreeServerDataSource implements UmbTreeDataSource { * Fetches the children of a given parent id from the server * @param {(string | null)} parentId * @return {*} - * @memberof MediaTreeServerDataSource + * @memberof UmbMediaTreeServerDataSource */ async getChildrenOf(parentId: string | null) { if (!parentId) { @@ -83,7 +83,7 @@ export class MediaTreeServerDataSource implements UmbTreeDataSource { * Fetches the items for the given ids from the server * @param {Array} ids * @return {*} - * @memberof MediaTreeServerDataSource + * @memberof UmbMediaTreeServerDataSource */ async getItems(ids: Array) { if (!ids) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/repository/member-group.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/repository/member-group.repository.ts index 572e6d7fd0..22f2dceff6 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/repository/member-group.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/repository/member-group.repository.ts @@ -1,7 +1,7 @@ import { UmbMemberGroupTreeStore, UMB_MEMBER_GROUP_TREE_STORE_CONTEXT_TOKEN } from './member-group.tree.store'; import { UmbMemberGroupDetailServerDataSource } from './sources/member-group.detail.server.data'; import { UmbMemberGroupStore, UMB_MEMBER_GROUP_STORE_CONTEXT_TOKEN } from './member-group.store'; -import { MemberGroupTreeServerDataSource } from './sources/member-group.tree.server.data'; +import { UmbMemberGroupTreeServerDataSource } from './sources/member-group.tree.server.data'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; @@ -26,7 +26,7 @@ export class UmbMemberGroupRepository implements UmbTreeRepository, UmbDetailRep constructor(host: UmbControllerHostElement) { this.#host = host; // TODO: figure out how spin up get the correct data source - this.#treeSource = new MemberGroupTreeServerDataSource(this.#host); + this.#treeSource = new UmbMemberGroupTreeServerDataSource(this.#host); this.#detailSource = new UmbMemberGroupDetailServerDataSource(this.#host); new UmbContextConsumerController(this.#host, UMB_MEMBER_GROUP_TREE_STORE_CONTEXT_TOKEN, (instance) => { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/repository/sources/member-group.tree.server.data.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/repository/sources/member-group.tree.server.data.ts index bfb95a7473..7535e756ea 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/repository/sources/member-group.tree.server.data.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/repository/sources/member-group.tree.server.data.ts @@ -6,16 +6,16 @@ import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; /** * A data source for the Member Group tree that fetches data from the server * @export - * @class MemberGroupTreeServerDataSource - * @implements {MemberGroupTreeDataSource} + * @class UmbMemberGroupTreeServerDataSource + * @implements {UmbTreeDataSource} */ -export class MemberGroupTreeServerDataSource implements UmbTreeDataSource { +export class UmbMemberGroupTreeServerDataSource implements UmbTreeDataSource { #host: UmbControllerHostElement; /** - * Creates an instance of MemberGroupTreeServerDataSource. + * Creates an instance of UmbMemberGroupTreeServerDataSource. * @param {UmbControllerHostElement} host - * @memberof MemberGroupTreeServerDataSource + * @memberof UmbMemberGroupTreeServerDataSource */ constructor(host: UmbControllerHostElement) { this.#host = host; @@ -24,7 +24,7 @@ export class MemberGroupTreeServerDataSource implements UmbTreeDataSource { /** * Fetches the root items for the tree from the server * @return {*} - * @memberof MemberGroupTreeServerDataSource + * @memberof UmbMemberGroupTreeServerDataSource */ async getRootItems() { return tryExecuteAndNotify(this.#host, MemberGroupResource.getTreeMemberGroupRoot({})); @@ -34,7 +34,7 @@ export class MemberGroupTreeServerDataSource implements UmbTreeDataSource { * Fetches the children of a given parent id from the server * @param {(string | null)} parentId * @return {*} - * @memberof MemberGroupTreeServerDataSource + * @memberof UmbMemberGroupTreeServerDataSource */ async getChildrenOf(parentId: string | null) { // Not implemented for this tree @@ -45,7 +45,7 @@ export class MemberGroupTreeServerDataSource implements UmbTreeDataSource { * Fetches the items for the given ids from the server * @param {Array} ids * @return {*} - * @memberof MemberGroupTreeServerDataSource + * @memberof UmbMemberGroupTreeServerDataSource */ async getItems(ids: Array) { if (!ids || ids.length === 0) { From b0bd02df28257911ba062dec08b87a577922e553 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Sun, 16 Apr 2023 21:22:28 +0200 Subject: [PATCH 065/156] add umb prefix --- .../repository/member-type.repository.ts | 4 ++-- .../sources/member-type.tree.server.data.ts | 12 ++++++------ .../extension-slot/extension-slot.test.ts | 13 +++++++------ 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/repository/member-type.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/repository/member-type.repository.ts index 620347e0b4..fe51a1c02c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/repository/member-type.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/repository/member-type.repository.ts @@ -1,4 +1,4 @@ -import { MemberTypeTreeServerDataSource } from './sources/member-type.tree.server.data'; +import { UmbMemberTypeTreeServerDataSource } from './sources/member-type.tree.server.data'; import { UmbMemberTypeTreeStore, UMB_MEMBER_TYPE_TREE_STORE_CONTEXT_TOKEN } from './member-type.tree.store'; import { UmbMemberTypeStore, UMB_MEMBER_TYPE_STORE_CONTEXT_TOKEN } from './member-type.store'; import { UmbMemberTypeDetailServerDataSource } from './sources/member-type.detail.server.data'; @@ -30,7 +30,7 @@ export class UmbMemberTypeRepository implements UmbTreeRepository, this.#host = host; // TODO: figure out how spin up get the correct data source - this.#treeSource = new MemberTypeTreeServerDataSource(this.#host); + this.#treeSource = new UmbMemberTypeTreeServerDataSource(this.#host); this.#detailSource = new UmbMemberTypeDetailServerDataSource(this.#host); this.#init = Promise.all([ diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/repository/sources/member-type.tree.server.data.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/repository/sources/member-type.tree.server.data.ts index 0c1abf952a..40c09a25fc 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/repository/sources/member-type.tree.server.data.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/repository/sources/member-type.tree.server.data.ts @@ -6,10 +6,10 @@ import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; /** * A data source for the MemberType tree that fetches data from the server * @export - * @class MemberTypeTreeServerDataSource - * @implements {MemberTypeTreeDataSource} + * @class UmbMemberTypeTreeServerDataSource + * @implements {UmbTreeDataSource} */ -export class MemberTypeTreeServerDataSource implements UmbTreeDataSource { +export class UmbMemberTypeTreeServerDataSource implements UmbTreeDataSource { #host: UmbControllerHostElement; /** @@ -24,7 +24,7 @@ export class MemberTypeTreeServerDataSource implements UmbTreeDataSource { /** * Fetches the root items for the tree from the server * @return {*} - * @memberof MemberTypeTreeServerDataSource + * @memberof UmbMemberTypeTreeServerDataSource */ async getRootItems() { return tryExecuteAndNotify(this.#host, MemberTypeResource.getTreeMemberTypeRoot({})); @@ -34,7 +34,7 @@ export class MemberTypeTreeServerDataSource implements UmbTreeDataSource { * Fetches the children of a given parent id from the server * @param {(string | null)} parentId * @return {*} - * @memberof MemberTypeTreeServerDataSource + * @memberof UmbMemberTypeTreeServerDataSource */ async getChildrenOf(parentId: string | null) { const error: ProblemDetailsModel = { title: 'Not implemented for Member Type' }; @@ -45,7 +45,7 @@ export class MemberTypeTreeServerDataSource implements UmbTreeDataSource { * Fetches the items for the given ids from the server * @param {Array} ids * @return {*} - * @memberof MemberTypeTreeServerDataSource + * @memberof UmbMemberTypeTreeServerDataSource */ async getItems(ids: Array) { if (!ids || ids.length === 0) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/extension-slot/extension-slot.test.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/extension-slot/extension-slot.test.ts index a61451b20b..3fba5e41f1 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/extension-slot/extension-slot.test.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/extension-slot/extension-slot.test.ts @@ -3,10 +3,9 @@ import { expect, fixture, html } from '@open-wc/testing'; import { InitializedExtension, UmbExtensionSlotElement } from './extension-slot.element'; import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api'; import { ManifestDashboard } from '@umbraco-cms/backoffice/extensions-registry'; -import { defaultA11yConfig } from '@umbraco-cms/internal/test-utils'; -@customElement('test-extension-slot-manifest-element') -class MyExtensionSlotManifestElement extends HTMLElement {} +@customElement('umb-test-extension-slot-manifest-element') +class UmbTestExtensionSlotManifestElement extends HTMLElement {} function sleep(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); @@ -52,7 +51,7 @@ describe('UmbExtensionSlotElement', () => { type: 'dashboard', alias: 'unit-test-ext-slot-element-manifest', name: 'unit-test-extension', - elementName: 'test-extension-slot-manifest-element', + elementName: 'umb-test-extension-slot-manifest-element', meta: { pathname: 'test/test', }, @@ -75,7 +74,7 @@ describe('UmbExtensionSlotElement', () => { await sleep(0); - expect(element.shadowRoot!.firstElementChild).to.be.instanceOf(MyExtensionSlotManifestElement); + expect(element.shadowRoot!.firstElementChild).to.be.instanceOf(UmbTestExtensionSlotManifestElement); }); it('use the render method', async () => { @@ -90,7 +89,9 @@ describe('UmbExtensionSlotElement', () => { await sleep(0); expect(element.shadowRoot!.firstElementChild?.nodeName).to.be.equal('BLA'); - expect(element.shadowRoot!.firstElementChild?.firstElementChild).to.be.instanceOf(MyExtensionSlotManifestElement); + expect(element.shadowRoot!.firstElementChild?.firstElementChild).to.be.instanceOf( + UmbTestExtensionSlotManifestElement + ); }); }); }); From 952d585df7bff768428d21b1f52c47d6a91dc2b0 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Sun, 16 Apr 2023 21:28:56 +0200 Subject: [PATCH 066/156] add umb prefix --- .../provide/context-provider.controller.test.ts | 4 ++-- .../libs/controller/controller.test.ts | 8 ++++---- .../members/members/repository/member.repository.ts | 6 +++--- .../repository/sources/member.tree.server.data.ts | 12 ++++++------ 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/context-api/provide/context-provider.controller.test.ts b/src/Umbraco.Web.UI.Client/libs/context-api/provide/context-provider.controller.test.ts index 83bd2a2621..d09e43fb44 100644 --- a/src/Umbraco.Web.UI.Client/libs/context-api/provide/context-provider.controller.test.ts +++ b/src/Umbraco.Web.UI.Client/libs/context-api/provide/context-provider.controller.test.ts @@ -7,8 +7,8 @@ class UmbTestContextProviderControllerClass { prop = 'value from provider'; } -class ControllerHostElement extends UmbLitElement {} -const controllerHostElement = defineCE(ControllerHostElement); +class UmbTestControllerHostElement extends UmbLitElement {} +const controllerHostElement = defineCE(UmbTestControllerHostElement); describe('UmbContextProviderController', () => { let instance: UmbTestContextProviderControllerClass; diff --git a/src/Umbraco.Web.UI.Client/libs/controller/controller.test.ts b/src/Umbraco.Web.UI.Client/libs/controller/controller.test.ts index 993bc546ca..deda6a09e1 100644 --- a/src/Umbraco.Web.UI.Client/libs/controller/controller.test.ts +++ b/src/Umbraco.Web.UI.Client/libs/controller/controller.test.ts @@ -3,18 +3,18 @@ import { customElement } from 'lit/decorators.js'; import { UmbControllerHostElement, UmbControllerHostMixin } from './controller-host.mixin'; import { UmbContextProviderController } from '@umbraco-cms/backoffice/context-api'; -class MyClass { +class UmbTestContext { prop = 'value from provider'; } @customElement('test-my-controller-host') -export class MyHostElement extends UmbControllerHostMixin(HTMLElement) {} +export class UmbTestControllerHostElement extends UmbControllerHostMixin(HTMLElement) {} describe('UmbContextProvider', () => { type NewType = UmbControllerHostElement; let hostElement: NewType; - const contextInstance = new MyClass(); + const contextInstance = new UmbTestContext(); beforeEach(() => { hostElement = document.createElement('test-my-controller-host') as UmbControllerHostElement; @@ -35,7 +35,7 @@ describe('UmbContextProvider', () => { describe('Unique controllers replace each other', () => { it('has a host property', () => { const firstCtrl = new UmbContextProviderController(hostElement, 'my-test-context', contextInstance); - const secondCtrl = new UmbContextProviderController(hostElement, 'my-test-context', new MyClass()); + const secondCtrl = new UmbContextProviderController(hostElement, 'my-test-context', new UmbTestContext()); expect(hostElement.hasController(firstCtrl)).to.be.false; expect(hostElement.hasController(secondCtrl)).to.be.true; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/repository/member.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/repository/member.repository.ts index cf91bf0bf9..39fbb84c35 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/repository/member.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/repository/member.repository.ts @@ -1,5 +1,5 @@ import { UmbMemberTreeStore, UMB_MEMBER_TREE_STORE_CONTEXT_TOKEN } from './member.tree.store'; -import { MemberTreeServerDataSource } from './sources/member.tree.server.data'; +import { UmbMemberTreeServerDataSource } from './sources/member.tree.server.data'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; @@ -8,7 +8,7 @@ import { ProblemDetailsModel } from '@umbraco-cms/backoffice/backend-api'; export class UmbMemberRepository implements UmbTreeRepository { #host: UmbControllerHostElement; - #dataSource: MemberTreeServerDataSource; + #dataSource: UmbMemberTreeServerDataSource; #treeStore?: UmbMemberTreeStore; #notificationContext?: UmbNotificationContext; #initResolver?: () => void; @@ -17,7 +17,7 @@ export class UmbMemberRepository implements UmbTreeRepository { constructor(host: UmbControllerHostElement) { this.#host = host; // TODO: figure out how spin up get the correct data source - this.#dataSource = new MemberTreeServerDataSource(this.#host); + this.#dataSource = new UmbMemberTreeServerDataSource(this.#host); new UmbContextConsumerController(this.#host, UMB_MEMBER_TREE_STORE_CONTEXT_TOKEN, (instance) => { this.#treeStore = instance; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/repository/sources/member.tree.server.data.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/repository/sources/member.tree.server.data.ts index b386fb52e2..903c63ef9f 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/repository/sources/member.tree.server.data.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/repository/sources/member.tree.server.data.ts @@ -4,16 +4,16 @@ import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; /** * A data source for the Member tree that fetches data from the server * @export - * @class MemberTreeServerDataSource + * @class UmbMemberTreeServerDataSource * @implements {MemberTreeDataSource} */ -export class MemberTreeServerDataSource implements MemberTreeDataSource { +export class UmbMemberTreeServerDataSource implements MemberTreeDataSource { #host: UmbControllerHostElement; /** - * Creates an instance of MemberTreeServerDataSource. + * Creates an instance of UmbMemberTreeServerDataSource. * @param {UmbControllerHostElement} host - * @memberof MemberTreeServerDataSource + * @memberof UmbMemberTreeServerDataSource */ constructor(host: UmbControllerHostElement) { this.#host = host; @@ -22,7 +22,7 @@ export class MemberTreeServerDataSource implements MemberTreeDataSource { /** * Fetches the root items for the tree from the server * @return {*} - * @memberof MemberTreeServerDataSource + * @memberof UmbMemberTreeServerDataSource */ async getRootItems() { const response = await fetch('/umbraco/management/api/v1/tree/member/root'); @@ -36,7 +36,7 @@ export class MemberTreeServerDataSource implements MemberTreeDataSource { * Fetches the items for the given ids from the server * @param {Array} ids * @return {*} - * @memberof MemberTreeServerDataSource + * @memberof UmbMemberTreeServerDataSource */ async getItems(ids: Array) { const response = await fetch('/umbraco/management/api/v1/tree/member/item'); From 6b68ce68a8e7d5cff3afaa3e494117f8d6da7280 Mon Sep 17 00:00:00 2001 From: Nathan Woulfe Date: Mon, 17 Apr 2023 13:34:21 +1000 Subject: [PATCH 067/156] needs to be called after setting OpenAPI config --- src/Umbraco.Web.UI.Client/src/app.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/app.ts b/src/Umbraco.Web.UI.Client/src/app.ts index 35bcc3afd1..af690fdd6e 100644 --- a/src/Umbraco.Web.UI.Client/src/app.ts +++ b/src/Umbraco.Web.UI.Client/src/app.ts @@ -63,7 +63,6 @@ export class UmbAppElement extends UmbLitElement { super(); this.#umbIconRegistry.attach(this); this.#uuiIconRegistry.attach(this); - this.#setInitStatus(); } connectedCallback() { @@ -76,6 +75,7 @@ export class UmbAppElement extends UmbLitElement { OpenAPI.WITH_CREDENTIALS = true; this.provideContext('UMBRACOBASE', OpenAPI.BASE); + this.#setInitStatus(); // Listen for the debug event from the component this.addEventListener(umbDebugContextEventType, (event: any) => { From 346981d03b434168c9e234a785d5fda0d728c0fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 17 Apr 2023 09:55:25 +0200 Subject: [PATCH 068/156] add type --- src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts index d3cc5c6683..c541ddb01e 100644 --- a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts +++ b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts @@ -650,7 +650,7 @@ export class UmbSorterController implements UmbControllerInterface { private autoScrollY = 0; private handleAutoScroll(clientX: number, clientY: number) { - let scrollRect = null; + let scrollRect: DOMRect = null; if (this.#scrollElement) { this.#autoScrollEl = this.#scrollElement; scrollRect = this.#autoScrollEl.getBoundingClientRect(); From 3f9f972b9ac2c6d078ea015da22b135f64d1ef79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 17 Apr 2023 09:56:45 +0200 Subject: [PATCH 069/156] correct type --- src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts index c541ddb01e..2bafd25926 100644 --- a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts +++ b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts @@ -650,7 +650,7 @@ export class UmbSorterController implements UmbControllerInterface { private autoScrollY = 0; private handleAutoScroll(clientX: number, clientY: number) { - let scrollRect: DOMRect = null; + let scrollRect: DOMRect | null = null; if (this.#scrollElement) { this.#autoScrollEl = this.#scrollElement; scrollRect = this.#autoScrollEl.getBoundingClientRect(); @@ -663,7 +663,7 @@ export class UmbSorterController implements UmbControllerInterface { right: window.innerWidth, height: window.innerHeight, width: window.innerWidth, - }; + } as DOMRect; } const scrollWidth = this.#autoScrollEl.scrollWidth; From 0880c199f016e9ff85894fe08fdc559a089e47a0 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Apr 2023 10:41:41 +0200 Subject: [PATCH 070/156] add support for multiple + request items in context --- .../token/data-type-picker-modal.token.ts | 1 + .../libs/picker/picker.context.ts | 40 ++++++++++++++++--- .../data-type-input.context.ts | 4 +- .../data-type-input.element.ts | 19 ++++++--- .../data-type-picker-modal.element.ts | 36 ++++++++--------- 5 files changed, 68 insertions(+), 32 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/modal/token/data-type-picker-modal.token.ts b/src/Umbraco.Web.UI.Client/libs/modal/token/data-type-picker-modal.token.ts index aa6b1ea39c..51d90eb871 100644 --- a/src/Umbraco.Web.UI.Client/libs/modal/token/data-type-picker-modal.token.ts +++ b/src/Umbraco.Web.UI.Client/libs/modal/token/data-type-picker-modal.token.ts @@ -2,6 +2,7 @@ import { UmbModalToken } from '@umbraco-cms/backoffice/modal'; export interface UmbDataTypePickerModalData { selection?: Array; + multiple?: boolean; } export interface UmbDataTypePickerModalResult { diff --git a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts b/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts index 0144293104..ec653c4704 100644 --- a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts +++ b/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts @@ -9,19 +9,22 @@ import { UmbModalToken, } from '@umbraco-cms/backoffice/modal'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; +import { ItemResponseModelBaseModel } from '@umbraco-cms/backoffice/backend-api'; -export class UmbPickerContext { +export class UmbPickerContext { host: UmbControllerHostElement; modalAlias: UmbModalToken | string; - repository?: RepositoryType; + repository?: UmbTreeRepository; public modalContext?: UmbModalContext; #selection = new ArrayState([]); selection = this.#selection.asObservable(); - #items = new ArrayState([]); - items = this.#items.asObservable(); + #selectedItems = new ArrayState([]); + selectedItems = this.#selectedItems.asObservable(); + + #selectedItemsObserver?: UmbObserverController; max = Infinity; min = 0; @@ -40,7 +43,7 @@ export class UmbPickerContext { if (!repositoryManifest) return; try { - const result = await createExtensionClass(repositoryManifest, [this.host]); + const result = await createExtensionClass(repositoryManifest, [this.host]); this.repository = result; } catch (error) { throw new Error('Could not create repository with alias: ' + repositoryAlias + ''); @@ -61,6 +64,7 @@ export class UmbPickerContext { this.#selection.next(selection); } + // TODO: this need to accept an options object at some point to pass to the modal context openPicker() { if (!this.modalContext) throw new Error('Modal context is not initialized'); @@ -71,10 +75,12 @@ export class UmbPickerContext { modalHandler?.onSubmit().then(({ selection }: any) => { this.setSelection(selection); + // TODO: we only want to request items that are not already in the selectedItems array + this.#requestItems(); }); } - async removeItem(unique: string) { + async requestRemoveItem(unique: string) { if (!this.repository) throw new Error('Repository is not initialized'); const { data } = await this.repository.requestTreeItems([unique]); @@ -88,7 +94,29 @@ export class UmbPickerContext { }); await modalHandler?.onSubmit(); + this.#removeItem(unique); + } + + async #requestItems() { + if (!this.repository) throw new Error('Repository is not initialized'); + if (this.#selectedItemsObserver) this.#selectedItemsObserver.destroy(); + + const { asObservable } = await this.repository.requestTreeItems(this.getSelection()); + + if (asObservable) { + this.#selectedItemsObserver = new UmbObserverController(this.host, asObservable(), (data) => { + this.#selectedItems.next(data); + }); + } + } + + #removeItem(unique: string) { const newSelection = this.getSelection().filter((value) => value !== unique); this.setSelection(newSelection); + + // remove items items from selectedItems array + // TODO: id won't always be available on the model, so we need to get the unique property from somewhere. Maybe the repository? + const newSelectedItems = this.#selectedItems.value.filter((item) => item.id !== unique); + this.#selectedItems.next(newSelectedItems); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.context.ts index 2f91e61fea..fc528332e8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.context.ts @@ -1,9 +1,9 @@ import { UmbPickerContext } from '@umbraco-cms/backoffice/picker'; -import { UmbDataTypeRepository } from '../../repository/data-type.repository'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UMB_DATA_TYPE_PICKER_MODAL } from '@umbraco-cms/backoffice/modal'; +import { DataTypeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; -export class UmbDataTypePickerContext extends UmbPickerContext { +export class UmbDataTypePickerContext extends UmbPickerContext { constructor(host: UmbControllerHostElement) { super(host, 'Umb.Repository.DataType', UMB_DATA_TYPE_PICKER_MODAL); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts index 126c0d97f5..d7bb8935bd 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts @@ -5,7 +5,6 @@ import { FormControlMixin } from '@umbraco-ui/uui-base/lib/mixins'; import { UmbDataTypePickerContext } from './data-type-input.context'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import type { DataTypeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; -import { UMB_DATA_TYPE_PICKER_MODAL } from '@umbraco-cms/backoffice/modal'; @customElement('umb-data-type-input') export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) { @@ -24,7 +23,11 @@ export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) { * @default undefined */ @property({ type: Number }) - min?: number; + public set min(value: number | undefined) { + if (value !== undefined) { + this.#pickerContext.min = value; + } + } /** * Min validation message. @@ -42,7 +45,11 @@ export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) { * @default undefined */ @property({ type: Number }) - max?: number; + public set max(value: number | undefined) { + if (value !== undefined) { + this.#pickerContext.max = value; + } + } /** * Max validation message. @@ -90,7 +97,7 @@ export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) { ); this.observe(this.#pickerContext.selection, (selection) => (this.selectedIds = selection)); - //this.observe(this.#pickerContext.items, (items) => (this._items = items)); + this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems)); } protected getFormElement() { @@ -110,7 +117,9 @@ export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) { return html` - this.#pickerContext.removeItem(item.id)} label="Remove Data Type ${item.name}" + this.#pickerContext.requestRemoveItem(item.id)} + label="Remove Data Type ${item.name}" >Remove diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/modal/data-type-picker/data-type-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/modal/data-type-picker/data-type-picker-modal.element.ts index dd4d6d3a25..ea1cae5dfb 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/modal/data-type-picker/data-type-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/modal/data-type-picker/data-type-picker-modal.element.ts @@ -3,8 +3,8 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property, state } from 'lit/decorators.js'; import type { UmbTreeElement } from '../../../../shared/components/tree/tree.element'; import { - UmbDocumentTypePickerModalData, - UmbDocumentTypePickerModalResult, + UmbDataTypePickerModalData, + UmbDataTypePickerModalResult, UmbModalHandler, } from '@umbraco-cms/backoffice/modal'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; @@ -15,55 +15,53 @@ export class UmbDataTypePickerModalElement extends UmbLitElement { static styles = [UUITextStyles, css``]; @property({ attribute: false }) - modalHandler?: UmbModalHandler; + modalHandler?: UmbModalHandler; @property({ type: Object, attribute: false }) - data?: UmbDocumentTypePickerModalData; + data?: UmbDataTypePickerModalData; @state() _selection: Array = []; @state() - _multiple = true; + _multiple = false; connectedCallback() { super.connectedCallback(); this._selection = this.data?.selection ?? []; - this._multiple = this.data?.multiple ?? true; + this._multiple = this.data?.multiple ?? false; } - private _handleSelectionChange(e: CustomEvent) { + #onSelectionChange(e: CustomEvent) { e.stopPropagation(); const element = e.target as UmbTreeElement; - //TODO: Should multiple property be implemented here or be passed down into umb-tree? - this._selection = this._multiple ? element.selection : [element.selection[element.selection.length - 1]]; + this._selection = element.selection; } - private _submit() { + #submit() { this.modalHandler?.submit({ selection: this._selection }); } - private _close() { + #close() { this.modalHandler?.reject(); } render() { return html` - + - -
+ selectable + ?multiple=${this._multiple}>
- - + +
-
+ `; } } From 1b0d2ebec273ced2440d40e61c9a6dde5fc53c0c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Apr 2023 10:47:38 +0200 Subject: [PATCH 071/156] look in selected items instead of requesting the repository --- src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts b/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts index ec653c4704..28256deb05 100644 --- a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts +++ b/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts @@ -83,12 +83,13 @@ export class UmbPickerContext { async requestRemoveItem(unique: string) { if (!this.repository) throw new Error('Repository is not initialized'); - const { data } = await this.repository.requestTreeItems([unique]); - if (!data) throw new Error('Could not find item with unique id: ' + unique); + // TODO: id won't always be available on the model, so we need to get the unique property from somewhere. Maybe the repository? + const item = this.#selectedItems.value.find((item) => item.id === unique); + if (!item) throw new Error('Could not find item with unique: ' + unique); const modalHandler = this.modalContext?.open(UMB_CONFIRM_MODAL, { color: 'danger', - headline: `Remove ${data[0].name}?`, + headline: `Remove ${item.name}?`, content: 'Are you sure you want to remove this item', confirmLabel: 'Remove', }); From a7b2aec5d28db3a5a96b49292902c225d70e647e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 17 Apr 2023 11:04:56 +0200 Subject: [PATCH 072/156] ideas for testing --- .../libs/sorter/sorter.controller.test.ts | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.test.ts diff --git a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.test.ts b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.test.ts new file mode 100644 index 0000000000..8d2671bef2 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.test.ts @@ -0,0 +1,71 @@ +import { expect, oneEvent } from '@open-wc/testing'; +import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; +import { customElement } from 'lit/decorators'; +import { UmbSorterConfig, UmbSorterController } from './sorter.controller'; + +type SortEntryType = { + id: string; + value: string; +}; + +const sorterConfig: UmbSorterConfig = { + compareElementToModel: (element: HTMLElement, model: SortEntryType) => { + return element.getAttribute('id') === model.id; + }, + querySelectModelToElement: (container: HTMLElement, modelEntry: SortEntryType) => { + return container.querySelector('data-sort-entry-id[' + modelEntry.id + ']'); + }, + identifier: 'test-sorter', + itemSelector: 'li', +}; + +const model: Array = [ + { + id: '0', + value: 'Entry 0', + }, + { + id: '1', + value: 'Entry 1', + }, + { + id: '2', + value: 'Entry 2', + }, +]; + +@customElement('test-my-sorter-controller') +class MyTestSorterControllerElement extends UmbLitElement { + public sorter; + + constructor() { + super(); + + this.sorter = new UmbSorterController(this, sorterConfig); + this.sorter.setModel(model); + } +} + +describe('UmbContextConsumer', () => { + let hostElement: MyTestSorterControllerElement; + let controller: UmbSorterController; + + beforeEach(() => { + hostElement = document.createElement('test-my-sorter-controller') as MyTestSorterControllerElement; + controller = (hostElement as any).__umbBlockGridSorterController(); + }); + + describe('Public API', () => { + describe('methods', () => { + it('element gets a internal public method on to retrieve controller', () => { + //expect(hostElement).to.have.property('__umbBlockGridSorterController').that.is.a('function'); + expect(controller).to.not.eq(undefined); + }); + }); + }); + + // TODO: Testing ideas: + // - Test that the model is updated correctly? + // - Test that the DOM is updated correctly? + // - Use the controller to sort the DOM and test that the model is updated correctly... +}); From 42610b8483d642856ffa11e6cd3959f328630a18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 17 Apr 2023 11:05:01 +0200 Subject: [PATCH 073/156] type corrections --- .../libs/sorter/sorter.controller.ts | 110 +++++++++++++----- 1 file changed, 79 insertions(+), 31 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts index 2bafd25926..4da2065bb5 100644 --- a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts +++ b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts @@ -1,9 +1,10 @@ import { UmbControllerInterface, UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; +import { NullValue } from 'rollup'; const autoScrollSensitivity = 50; const autoScrollSpeed = 16; -function isWithinRect(x: number, y: number, rect: DOMRect, modifier: number = 0) { +function isWithinRect(x: number, y: number, rect: DOMRect, modifier = 0) { return x > rect.left - modifier && x < rect.right + modifier && y > rect.top - modifier && y < rect.bottom + modifier; } @@ -61,14 +62,14 @@ function destroyPreventEvent(element: Element) { element.removeAttribute('draggable'); } -export type UmbSorterConfig = { +type INTERNAL_UmbSorterConfig = { compareElementToModel: (el: HTMLElement, modelEntry: T) => boolean; - querySelectModelToElement: (container: HTMLElement, modelEntry: T) => HTMLElement; + querySelectModelToElement: (container: HTMLElement, modelEntry: T) => HTMLElement | null; identifier: string; - ignorerSelector: string; itemSelector: string; - placeholderClass: string; containerSelector: string; + ignorerSelector: string; + placeholderClass: string; draggableSelector?: string; boundarySelector?: string; dataTransferResolver?: (dataTransfer: DataTransfer | null, currentItem: T) => void; @@ -98,6 +99,19 @@ export type UmbSorterConfig = { }) => void; }; +// External type with some properties optional, as they have defaults: +export type UmbSorterConfig = Omit< + INTERNAL_UmbSorterConfig, + 'placeholderClass' | 'ignorerSelector' | 'containerSelector' +> & + Partial, 'placeholderClass' | 'ignorerSelector' | 'containerSelector'>>; + +/** + * @export + * @class UmbSorterController + * @implements {UmbControllerInterface} + * @description This controller can make user able to sort items. + */ export class UmbSorterController implements UmbControllerInterface { #host; #config; @@ -106,8 +120,9 @@ export class UmbSorterController implements UmbControllerInterface { #model: Array = []; #rqaId?: number; + #containerElement!: Element; #currentContainerVM = this; - #currentContainerElement: Element; + #currentContainerElement: Element | null = null; #scrollElement?: Element | null; #currentElement?: HTMLElement; @@ -126,10 +141,15 @@ export class UmbSorterController implements UmbControllerInterface { constructor(host: UmbControllerHostElement, config: UmbSorterConfig) { this.#host = host; - this.#config = config; + + // Set defaults: + config.ignorerSelector ??= 'a, img, iframe'; + config.placeholderClass ??= 'umb-drag-placeholder'; + + this.#config = config as INTERNAL_UmbSorterConfig; host.addController(this); - this.#currentContainerElement = host; + //this.#currentContainerElement = host; this.#observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { @@ -146,33 +166,52 @@ export class UmbSorterController implements UmbControllerInterface { }); }); - (host as any)['__umbBlockGridSorterController'] = () => { - return this; - }; host.addEventListener('dragover', preventDragOver); } setModel(model: Array) { + if (this.#model) { + // TODO: Some updates might need to be done, as the modal is about to changed? Do make the changes after setting the model?.. + } this.#model = model; - // TODO: Some update? } hostConnected() { - this.#observer.observe(this.#host, { childList: true, subtree: false }); + const containerEl = + (this.#config.containerSelector ? this.#host.querySelector(this.#config.containerSelector) : this.#host) ?? + this.#host; + + (containerEl as any)['__umbBlockGridSorterController'] = () => { + return this; + }; + + if (this.#currentContainerElement === this.#containerElement) { + this.#currentContainerElement = containerEl; + } + this.#containerElement = containerEl; + + // TODO: Clean up?? + this.#observer.disconnect(); + this.#observer.observe(this.#containerElement, { childList: true, subtree: false }); } hostDisconnected() { + // TODO: Clean up?? this.#observer.disconnect(); } setupItem(element: HTMLElement) { - setupIgnorerElements(element, this.#config.ignorerSelector); + if (this.#config.ignorerSelector) { + setupIgnorerElements(element, this.#config.ignorerSelector); + } element.draggable = true; element.addEventListener('dragstart', this.handleDragStart); } destroyItem(element: HTMLElement) { - destroyIgnorerElements(element, this.#config.ignorerSelector); + if (this.#config.ignorerSelector) { + destroyIgnorerElements(element, this.#config.ignorerSelector); + } element.removeEventListener('dragstart', this.handleDragStart); } @@ -271,7 +310,11 @@ export class UmbSorterController implements UmbControllerInterface { if (movingItemIndex < this.#model.length - 1) { const afterItem = this.#model[movingItemIndex + 1]; const afterEl = this.#config.querySelectModelToElement(this.#host, afterItem); - this.#host.insertBefore(this.#currentElement, afterEl); + if (afterEl) { + this.#host.insertBefore(this.#currentElement, afterEl); + } else { + this.#host.appendChild(this.#currentElement); + } } else { this.#host.appendChild(this.#currentElement); } @@ -285,7 +328,7 @@ export class UmbSorterController implements UmbControllerInterface { cancelAnimationFrame(this.#rqaId); } - this.#currentContainerElement = this.#host; + this.#currentContainerElement = this.#containerElement; this.#currentContainerVM = this; this.#rqaId = undefined; @@ -315,7 +358,7 @@ export class UmbSorterController implements UmbControllerInterface { this.#dragX = clientX; this.#dragY = clientY; - handleAutoScroll(this.#dragX, this.#dragY); + this.handleAutoScroll(this.#dragX, this.#dragY); this.#currentDragRect = this.#currentDragElement!.getBoundingClientRect(); const insideCurrentRect = isWithinRect(this.#dragX, this.#dragY, this.#currentDragRect); @@ -343,7 +386,7 @@ export class UmbSorterController implements UmbControllerInterface { const currentBoundaryElement = (this.#config.boundarySelector ? this.#currentContainerElement.closest(this.#config.boundarySelector) - : this.#currentContainerElement) || this.#currentContainerElement; + : this.#currentContainerElement) ?? this.#currentContainerElement; const currentBoundaryRect = currentBoundaryElement.getBoundingClientRect(); @@ -355,18 +398,22 @@ export class UmbSorterController implements UmbControllerInterface { if (!isWithinRect(this.#dragX, this.#dragY, currentBoundaryRect, offsetEdge)) { // we are outside the current container boundary, so lets see if there is a parent we can move. const parentNode = this.#currentContainerElement.parentNode; - const parentContainer = parentNode ? (parentNode as HTMLElement).closest(this.#config.containerSelector) : null; - if (parentContainer) { - const parentContainerVM = (parentContainer as any)['__umbBlockGridSorterController'](); - if (parentContainerVM.unique === this.unique) { - this.#currentContainerElement = parentContainer; - this.#currentContainerVM = parentContainerVM; - if (this.#config.onContainerChange) { - this.#config.onContainerChange({ - item: this.#currentItem, - element: this.#currentElement, - //ownerVM: this.#currentContainerVM.ownerVM, - }); + if (parentNode) { + const parentContainer = this.#config.containerSelector + ? (parentNode as HTMLElement).closest(this.#config.containerSelector) + : null; + if (parentContainer) { + const parentContainerVM = (parentContainer as any)['__umbBlockGridSorterController'](); + if (parentContainerVM.unique === this.unique) { + this.#currentContainerElement = parentContainer as Element; + this.#currentContainerVM = parentContainerVM; + if (this.#config.onContainerChange) { + this.#config.onContainerChange({ + item: this.#currentItem, + element: this.#currentElement, + //ownerVM: this.#currentContainerVM.ownerVM, + }); + } } } } @@ -736,6 +783,7 @@ export class UmbSorterController implements UmbControllerInterface { (this.#host as any)['__umbBlockGridSorterController'] = null; this.#host.removeEventListener('dragover', preventDragOver); + // TODO: Clean up items?? this.#observer.disconnect(); // For auto scroller: From f7d4c8d76db065a945c57dce6ea51f865724f816 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 17 Apr 2023 11:05:37 +0200 Subject: [PATCH 074/156] imports --- src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts index 4da2065bb5..13014e52bb 100644 --- a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts +++ b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts @@ -1,5 +1,4 @@ import { UmbControllerInterface, UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { NullValue } from 'rollup'; const autoScrollSensitivity = 50; const autoScrollSpeed = 16; From c4b2ddef5524503b98eaa732ec4e12b9d7878061 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Apr 2023 11:10:04 +0200 Subject: [PATCH 075/156] add null check for add --- .../components/data-type-input/data-type-input.element.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts index d7bb8935bd..db4aafbef9 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts @@ -114,11 +114,12 @@ export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) { } private _renderItem(item: DataTypeItemResponseModel) { + if (!item.id) return; return html` this.#pickerContext.requestRemoveItem(item.id)} + @click=${() => this.#pickerContext.requestRemoveItem(item.id!)} label="Remove Data Type ${item.name}" >Remove From 9b686f46a982ceb71c253213ec665f04c7f8ddad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 17 Apr 2023 11:33:45 +0200 Subject: [PATCH 076/156] sorter lib --- .../document-type-workspace-view-edit-properties.element.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts index 73eea4e334..120de1b390 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts @@ -8,6 +8,7 @@ import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import { DocumentTypePropertyTypeResponseModel } from '@umbraco-cms/backoffice/backend-api'; import { UMB_MODAL_CONTEXT_TOKEN, UMB_PROPERTY_SETTINGS_MODAL } from '@umbraco-cms/backoffice/modal'; import './document-type-workspace-view-edit-property.element'; +import { UmbSorterController } from '@umbraco-cms/sorter'; @customElement('umb-document-type-workspace-view-edit-properties') export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitElement { @@ -46,12 +47,15 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle #modalContext?: typeof UMB_MODAL_CONTEXT_TOKEN.TYPE; + #propertySorter = new UmbSorterController(this, sorterConfig); + constructor() { super(); this.consumeContext(UMB_MODAL_CONTEXT_TOKEN, (instance) => (this.#modalContext = instance)); this.observe(this._propertyStructureHelper.propertyStructure, (propertyStructure) => { this._propertyStructure = propertyStructure; + this.#propertySorter.setModel(this._propertyStructure); }); } From aedcf6c3d8062af0f6678e77372a47d2bcf9eee4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 17 Apr 2023 11:33:48 +0200 Subject: [PATCH 077/156] . --- .../shared/components/code-editor/code-editor.stories.ts | 1 + src/Umbraco.Web.UI.Client/tsconfig.json | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/code-editor/code-editor.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/code-editor/code-editor.stories.ts index e8d7805abe..90ff666790 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/code-editor/code-editor.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/code-editor/code-editor.stories.ts @@ -190,6 +190,7 @@ const codeSnippets: Record = { "@umbraco-cms/workspace": ["libs/workspace"], "@umbraco-cms/utils": ["libs/utils"], "@umbraco-cms/router": ["libs/router"], + "@umbraco-cms/sorter": ["libs/sorter"], "@umbraco-cms/test-utils": ["libs/test-utils"], "@umbraco-cms/repository": ["libs/repository"], "@umbraco-cms/resources": ["libs/resources"], diff --git a/src/Umbraco.Web.UI.Client/tsconfig.json b/src/Umbraco.Web.UI.Client/tsconfig.json index 147a4a8288..31cdde98e2 100644 --- a/src/Umbraco.Web.UI.Client/tsconfig.json +++ b/src/Umbraco.Web.UI.Client/tsconfig.json @@ -36,6 +36,7 @@ "@umbraco-cms/backoffice/repository": ["libs/repository"], "@umbraco-cms/backoffice/resources": ["libs/resources"], "@umbraco-cms/backoffice/router": ["libs/router"], + "@umbraco-cms/backoffice/sorter": ["libs/sorter"], "@umbraco-cms/backoffice/store": ["libs/store"], "@umbraco-cms/backoffice/utils": ["libs/utils"], "@umbraco-cms/backoffice/workspace": ["libs/workspace"], From 35d61c85d6e623ff60bafb5f2e863f891f0cce86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 17 Apr 2023 12:38:48 +0200 Subject: [PATCH 078/156] get rid of this annoying console --- .../workspace/workspace-layout/workspace-layout.element.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-layout/workspace-layout.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-layout/workspace-layout.element.ts index 48c6859ea2..99bf3fe996 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-layout/workspace-layout.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-layout/workspace-layout.element.ts @@ -135,14 +135,9 @@ export class UmbWorkspaceLayoutElement extends UmbLitElement { } return createExtensionElement(view); }, - setup: (component, info) => { + setup: (component) => { if (component && 'manifest' in component) { component.manifest = view; - } else { - console.group(`[UmbWorkspaceLayout] Failed to setup component for route: ${info.match.route.path}`); - console.log('Matched route', info.match.route); - console.error('Missing property "manifest" on component', component); - console.groupEnd(); } }, }; From f2c9c23b0086dc96707b5840730418f6305b4f51 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Apr 2023 15:43:59 +0200 Subject: [PATCH 079/156] use picker context in language picker --- .../libs/picker/picker.context.ts | 17 ++++- .../input-language-picker.context.ts | 10 +++ .../input-language-picker.element.ts | 71 ++++--------------- 3 files changed, 37 insertions(+), 61 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.context.ts diff --git a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts b/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts index 28256deb05..eea965a1d2 100644 --- a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts +++ b/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts @@ -10,11 +10,13 @@ import { } from '@umbraco-cms/backoffice/modal'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; import { ItemResponseModelBaseModel } from '@umbraco-cms/backoffice/backend-api'; +import { UmbChangeEvent } from '@umbraco-cms/backoffice/events'; export class UmbPickerContext { host: UmbControllerHostElement; modalAlias: UmbModalToken | string; repository?: UmbTreeRepository; + #getUnique: (entry: ItemType) => string | undefined; public modalContext?: UmbModalContext; @@ -29,9 +31,17 @@ export class UmbPickerContext { max = Infinity; min = 0; - constructor(host: UmbControllerHostElement, repositoryAlias: string, modalAlias: UmbModalToken | string) { + /* TODO: find a better way to have a getUniqueMethod. If we want to support trees/items of different types, + then it need to be bound to the type and can't be a generic method we pass in. */ + constructor( + host: UmbControllerHostElement, + repositoryAlias: string, + modalAlias: UmbModalToken | string, + getUniqueMethod?: (entry: ItemType) => string | undefined + ) { this.host = host; this.modalAlias = modalAlias; + this.#getUnique = getUniqueMethod || ((entry) => entry.id || ''); // TODO: unsure a method can't be called before everything is initialized new UmbObserverController( @@ -75,6 +85,7 @@ export class UmbPickerContext { modalHandler?.onSubmit().then(({ selection }: any) => { this.setSelection(selection); + this.host.dispatchEvent(new UmbChangeEvent()); // TODO: we only want to request items that are not already in the selectedItems array this.#requestItems(); }); @@ -84,7 +95,7 @@ export class UmbPickerContext { if (!this.repository) throw new Error('Repository is not initialized'); // TODO: id won't always be available on the model, so we need to get the unique property from somewhere. Maybe the repository? - const item = this.#selectedItems.value.find((item) => item.id === unique); + const item = this.#selectedItems.value.find((item) => this.#getUnique(item) === unique); if (!item) throw new Error('Could not find item with unique: ' + unique); const modalHandler = this.modalContext?.open(UMB_CONFIRM_MODAL, { @@ -117,7 +128,7 @@ export class UmbPickerContext { // remove items items from selectedItems array // TODO: id won't always be available on the model, so we need to get the unique property from somewhere. Maybe the repository? - const newSelectedItems = this.#selectedItems.value.filter((item) => item.id !== unique); + const newSelectedItems = this.#selectedItems.value.filter((item) => this.#getUnique(item) !== unique); this.#selectedItems.next(newSelectedItems); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.context.ts new file mode 100644 index 0000000000..d9807b1246 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.context.ts @@ -0,0 +1,10 @@ +import { UmbPickerContext } from '@umbraco-cms/backoffice/picker'; +import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; +import { UMB_LANGUAGE_PICKER_MODAL } from '@umbraco-cms/backoffice/modal'; +import type { LanguageItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; + +export class UmbLanguagePickerContext extends UmbPickerContext { + constructor(host: UmbControllerHostElement) { + super(host, 'Umb.Repository.Language', UMB_LANGUAGE_PICKER_MODAL, (item) => item.isoCode); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts index df04084af4..7de61d2d50 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts @@ -3,17 +3,9 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property, state } from 'lit/decorators.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { FormControlMixin } from '@umbraco-ui/uui-base/lib/mixins'; -import { UmbLanguageRepository } from '../../../settings/languages/repository/language.repository'; -import { - UmbModalContext, - UMB_MODAL_CONTEXT_TOKEN, - UMB_CONFIRM_MODAL, - UMB_LANGUAGE_PICKER_MODAL, -} from '@umbraco-cms/backoffice/modal'; -import { UmbChangeEvent } from '@umbraco-cms/backoffice/events'; +import { UmbLanguagePickerContext } from './input-language-picker.context'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import type { LanguageResponseModel } from '@umbraco-cms/backoffice/backend-api'; -import type { UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; @customElement('umb-input-language-picker') export class UmbInputLanguagePickerElement extends FormControlMixin(UmbLitElement) { @@ -71,7 +63,6 @@ export class UmbInputLanguagePickerElement extends FormControlMixin(UmbLitElemen public set selectedIsoCodes(isoCodes: Array) { this._selectedIsoCodes = isoCodes; super.value = isoCodes.join(','); - this._observePickedItems(); } @property() @@ -82,11 +73,9 @@ export class UmbInputLanguagePickerElement extends FormControlMixin(UmbLitElemen } @state() - private _items?: Array; + private _items: Array = []; - private _modalContext?: UmbModalContext; - private _repository = new UmbLanguageRepository(this); - private _pickedItemsObserver?: UmbObserverController; + #pickerContext = new UmbLanguagePickerContext(this); constructor() { super(); @@ -103,60 +92,23 @@ export class UmbInputLanguagePickerElement extends FormControlMixin(UmbLitElemen () => !!this.max && this._selectedIsoCodes.length > this.max ); - this.consumeContext(UMB_MODAL_CONTEXT_TOKEN, (instance) => { - this._modalContext = instance; - }); + this.observe(this.#pickerContext.selection, (selection) => (this.selectedIsoCodes = selection)); + this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems)); } protected getFormElement() { return undefined; } - private async _observePickedItems() { - this._pickedItemsObserver?.destroy(); - if (!this._repository) return; - - const { asObservable } = await this._repository.requestItems(this._selectedIsoCodes); - - this._pickedItemsObserver = this.observe(asObservable(), (items) => { - this._items = items; - }); - } - private _openPicker() { - const modalHandler = this._modalContext?.open(UMB_LANGUAGE_PICKER_MODAL, { - multiple: this.max === 1 ? false : true, - selection: [...this._selectedIsoCodes], - filter: this.filter, - }); - - modalHandler?.onSubmit().then(({ selection }) => { - this._setSelection(selection); - }); - } - - private _removeItem(item: LanguageResponseModel) { - const modalHandler = this._modalContext?.open(UMB_CONFIRM_MODAL, { - color: 'danger', - headline: `Remove ${item.name}?`, - content: 'Are you sure you want to remove this item', - confirmLabel: 'Remove', - }); - - modalHandler?.onSubmit().then(() => { - const newSelection = this._selectedIsoCodes.filter((value) => value !== item.isoCode); - this._setSelection(newSelection); - }); - } - - private _setSelection(newSelection: Array) { - this.selectedIsoCodes = newSelection; - this.dispatchEvent(new UmbChangeEvent()); + // TODO: add filter + // filter: this.filter, + this.#pickerContext.openPicker(); } render() { return html` - ${this._items?.map((item) => this._renderItem(item))} + ${this._items.map((item) => this._renderItem(item))} - this._removeItem(item)} label="Remove ${item.name}">Remove + this.#pickerContext.requestRemoveItem(item.isoCode!)} label="Remove ${item.name}" + >Remove `; From 586a73bfd2d6c40265fbd1ef42b444ee8205da66 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Apr 2023 16:18:28 +0200 Subject: [PATCH 080/156] add item data source --- .../libs/repository/data-source/index.ts | 1 + .../repository/data-source/item-data-source.interface.ts | 5 +++++ .../repository/data-source/tree-data-source.interface.ts | 2 ++ 3 files changed, 8 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/libs/repository/data-source/item-data-source.interface.ts diff --git a/src/Umbraco.Web.UI.Client/libs/repository/data-source/index.ts b/src/Umbraco.Web.UI.Client/libs/repository/data-source/index.ts index 905a6849fe..2f13c24fbc 100644 --- a/src/Umbraco.Web.UI.Client/libs/repository/data-source/index.ts +++ b/src/Umbraco.Web.UI.Client/libs/repository/data-source/index.ts @@ -2,3 +2,4 @@ export * from './data-source-response.interface'; export * from './data-source.interface'; export * from './folder-data-source.interface'; export * from './tree-data-source.interface'; +export * from './item-data-source.interface'; diff --git a/src/Umbraco.Web.UI.Client/libs/repository/data-source/item-data-source.interface.ts b/src/Umbraco.Web.UI.Client/libs/repository/data-source/item-data-source.interface.ts new file mode 100644 index 0000000000..88fb741ee3 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/repository/data-source/item-data-source.interface.ts @@ -0,0 +1,5 @@ +import type { DataSourceResponse } from '@umbraco-cms/backoffice/repository'; + +export interface UmbItemDataSource { + getItems(unique: Array): Promise>>; +} diff --git a/src/Umbraco.Web.UI.Client/libs/repository/data-source/tree-data-source.interface.ts b/src/Umbraco.Web.UI.Client/libs/repository/data-source/tree-data-source.interface.ts index ae57ef57af..52f623e13b 100644 --- a/src/Umbraco.Web.UI.Client/libs/repository/data-source/tree-data-source.interface.ts +++ b/src/Umbraco.Web.UI.Client/libs/repository/data-source/tree-data-source.interface.ts @@ -3,5 +3,7 @@ import type { DataSourceResponse } from '@umbraco-cms/backoffice/repository'; export interface UmbTreeDataSource { getRootItems(): Promise>; getChildrenOf(parentUnique: string): Promise>; + + // TODO: remove this when all repositories are migrated to the new items interface getItems(unique: Array): Promise>>; } From 459df80680105abf1c7c9d224b3172841589dec4 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Apr 2023 16:18:55 +0200 Subject: [PATCH 081/156] add item repository --- src/Umbraco.Web.UI.Client/libs/repository/index.ts | 1 + .../libs/repository/item-repository.interface.ts | 11 +++++++++++ .../libs/repository/tree-repository.interface.ts | 8 ++++++-- 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/libs/repository/item-repository.interface.ts diff --git a/src/Umbraco.Web.UI.Client/libs/repository/index.ts b/src/Umbraco.Web.UI.Client/libs/repository/index.ts index 9dcba782ba..94fb4c295d 100644 --- a/src/Umbraco.Web.UI.Client/libs/repository/index.ts +++ b/src/Umbraco.Web.UI.Client/libs/repository/index.ts @@ -2,3 +2,4 @@ export * from './data-source'; export * from './detail-repository.interface'; export * from './tree-repository.interface'; export * from './folder-repository.interface'; +export * from './item-repository.interface'; diff --git a/src/Umbraco.Web.UI.Client/libs/repository/item-repository.interface.ts b/src/Umbraco.Web.UI.Client/libs/repository/item-repository.interface.ts new file mode 100644 index 0000000000..1afb646c9f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/repository/item-repository.interface.ts @@ -0,0 +1,11 @@ +import type { Observable } from 'rxjs'; +import { ProblemDetailsModel } from '@umbraco-cms/backoffice/backend-api'; + +export interface UmbItemRepository { + requestItems: (uniques: string[]) => Promise<{ + data: Array | undefined; + error: ProblemDetailsModel | undefined; + asObservable?: () => Observable>; + }>; + items: (uniques: string[]) => Promise>>; +} diff --git a/src/Umbraco.Web.UI.Client/libs/repository/tree-repository.interface.ts b/src/Umbraco.Web.UI.Client/libs/repository/tree-repository.interface.ts index 4ef19c3920..ea3f76cc71 100644 --- a/src/Umbraco.Web.UI.Client/libs/repository/tree-repository.interface.ts +++ b/src/Umbraco.Web.UI.Client/libs/repository/tree-repository.interface.ts @@ -17,7 +17,9 @@ export interface UmbTreeRepository Observable; }>; - requestTreeItems: (uniques: string[]) => Promise<{ + + // TODO: remove this when all repositories are migrated to the new interface items interface + requestTreeItems?: (uniques: string[]) => Promise<{ data: Array | undefined; error: ProblemDetailsModel | undefined; asObservable?: () => Observable; @@ -25,5 +27,7 @@ export interface UmbTreeRepository Promise>; treeItemsOf: (parentUnique: string | null) => Promise>; - treeItems: (uniques: string[]) => Promise>; + + // TODO: remove this when all repositories are migrated to the new items interface + treeItems?: (uniques: string[]) => Promise>; } From 94bb58c1708565c3e1277a14b43eaee7598d3706 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Apr 2023 16:19:14 +0200 Subject: [PATCH 082/156] add language item server source --- .../sources/language-item.server.data.ts | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/sources/language-item.server.data.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/sources/language-item.server.data.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/sources/language-item.server.data.ts new file mode 100644 index 0000000000..807565c841 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/sources/language-item.server.data.ts @@ -0,0 +1,35 @@ +import { LanguageResource, LanguageItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; +import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; +import { UmbItemDataSource } from '@umbraco-cms/backoffice/repository'; + +/** + * A data source for Languages that fetches Language items from the server + * @export + * @class UmbLanguageItemServerDataSource + * @implements {UmbItemDataSource} + */ +export class UmbLanguageItemServerDataSource implements UmbItemDataSource { + #host: UmbControllerHostElement; + + constructor(host: UmbControllerHostElement) { + this.#host = host; + } + + /** + * Fetches Language items the given iso codes from the server + * @param {string[]} isoCodes + * @return {*} + * @memberof UmbLanguageItemServerDataSource + */ + async getItems(isoCodes: string[]) { + if (!isoCodes) throw new Error('Iso Codes are missing'); + + return tryExecuteAndNotify( + this.#host, + LanguageResource.getLanguageItem({ + isoCode: isoCodes, + }) + ); + } +} From 542ecfcb41b2416fabc1de0652adc61d8ed48625 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Apr 2023 16:56:05 +0200 Subject: [PATCH 083/156] move store crud logic to base class, add interface + add item store interface --- .../libs/store/entity-tree-store.ts | 46 +++++-------------- .../libs/store/file-system-tree.store.ts | 46 +++++-------------- .../libs/store/item-store.interface.ts | 7 +++ .../libs/store/store-base.ts | 43 ++++++++++++++++- .../libs/store/store.interface.ts | 5 ++ src/Umbraco.Web.UI.Client/libs/store/store.ts | 1 + .../libs/store/tree-store.interface.ts | 8 ++-- 7 files changed, 81 insertions(+), 75 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/libs/store/item-store.interface.ts create mode 100644 src/Umbraco.Web.UI.Client/libs/store/store.interface.ts diff --git a/src/Umbraco.Web.UI.Client/libs/store/entity-tree-store.ts b/src/Umbraco.Web.UI.Client/libs/store/entity-tree-store.ts index ea94db043a..b7817f6c8e 100644 --- a/src/Umbraco.Web.UI.Client/libs/store/entity-tree-store.ts +++ b/src/Umbraco.Web.UI.Client/libs/store/entity-tree-store.ts @@ -1,49 +1,27 @@ import { EntityTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; -import { ArrayState, partialUpdateFrozenArray } from '@umbraco-cms/backoffice/observable-api'; +import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; import { UmbStoreBase, UmbTreeStore } from '@umbraco-cms/backoffice/store'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; /** * @export * @class UmbEntityTreeStore * @extends {UmbStoreBase} - * @description - General Tree Data Store + * @description - Entity Tree Store */ -export class UmbEntityTreeStore extends UmbStoreBase implements UmbTreeStore { - #data = new ArrayState([], (x) => x.id); - - /** - * Appends items to the store - * @param {Array} items - * @memberof UmbEntityTreeStore - */ - appendItems(items: Array) { - this.#data.append(items); - } - - /** - * Updates an item in the store - * @param {string} id - * @param {Partial} data - * @memberof UmbEntityTreeStore - */ - updateItem(id: string, data: Partial) { - this.#data.next(partialUpdateFrozenArray(this.#data.getValue(), data, (entry) => entry.id === id)); - } - - /** - * Removes an item from the store - * @param {string} id - * @memberof UmbEntityTreeStore - */ - removeItem(id: string) { - this.#data.removeOne(id); +export class UmbEntityTreeStore + extends UmbStoreBase + implements UmbTreeStore +{ + constructor(host: UmbControllerHostElement, storeAlias: string) { + super(host, storeAlias, new ArrayState([], (x) => x.id)); } /** * An observable to observe the root items * @memberof UmbEntityTreeStore */ - rootItems = this.#data.getObservablePart((items) => items.filter((item) => item.parentId === null)); + rootItems = this._data.getObservablePart((items) => items.filter((item) => item.parentId === null)); /** * Returns an observable to observe the children of a given parent @@ -52,7 +30,7 @@ export class UmbEntityTreeStore extends UmbStoreBase implements UmbTreeStore items.filter((item) => item.parentId === parentId)); + return this._data.getObservablePart((items) => items.filter((item) => item.parentId === parentId)); } /** @@ -62,6 +40,6 @@ export class UmbEntityTreeStore extends UmbStoreBase implements UmbTreeStore) { - return this.#data.getObservablePart((items) => items.filter((item) => ids.includes(item.id ?? ''))); + return this._data.getObservablePart((items) => items.filter((item) => ids.includes(item.id ?? ''))); } } diff --git a/src/Umbraco.Web.UI.Client/libs/store/file-system-tree.store.ts b/src/Umbraco.Web.UI.Client/libs/store/file-system-tree.store.ts index 8afa8ca62e..e1f7eff059 100644 --- a/src/Umbraco.Web.UI.Client/libs/store/file-system-tree.store.ts +++ b/src/Umbraco.Web.UI.Client/libs/store/file-system-tree.store.ts @@ -1,49 +1,27 @@ import { FileSystemTreeItemPresentationModel } from '@umbraco-cms/backoffice/backend-api'; -import { ArrayState, partialUpdateFrozenArray } from '@umbraco-cms/backoffice/observable-api'; +import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; import { UmbStoreBase, UmbTreeStore } from '@umbraco-cms/backoffice/store'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; /** * @export * @class UmbFileSystemTreeStore * @extends {UmbStoreBase} - * @description - General Tree Data Store + * @description - File System Tree Store */ -export class UmbFileSystemTreeStore extends UmbStoreBase implements UmbTreeStore { - #data = new ArrayState([], (x) => x.path); - - /** - * Appends items to the store - * @param {Array} items - * @memberof UmbFileSystemTreeStore - */ - appendItems(items: Array) { - this.#data.append(items); - } - - /** - * Updates an item in the store - * @param {string} path - * @param {Partial} data - * @memberof UmbFileSystemTreeStore - */ - updateItem(path: string, data: Partial) { - this.#data.appendOne(data); - } - - /** - * Removes an item from the store - * @param {string} path - * @memberof UmbFileSystemTreeStore - */ - removeItem(path: string) { - this.#data.removeOne(path); +export class UmbFileSystemTreeStore + extends UmbStoreBase + implements UmbTreeStore +{ + constructor(host: UmbControllerHostElement, storeAlias: string) { + super(host, storeAlias, new ArrayState([], (x) => x.path)); } /** * An observable to observe the root items * @memberof UmbFileSystemTreeStore */ - rootItems = this.#data.getObservablePart((items) => items.filter((item) => item.path?.includes('/') === false)); + rootItems = this._data.getObservablePart((items) => items.filter((item) => item.path?.includes('/') === false)); /** * Returns an observable to observe the children of a given parent @@ -52,7 +30,7 @@ export class UmbFileSystemTreeStore extends UmbStoreBase implements UmbTreeStore * @memberof UmbFileSystemTreeStore */ childrenOf(parentPath: string | null) { - return this.#data.getObservablePart((items) => items.filter((item) => item.path?.startsWith(parentPath + '/'))); + return this._data.getObservablePart((items) => items.filter((item) => item.path?.startsWith(parentPath + '/'))); } /** @@ -62,6 +40,6 @@ export class UmbFileSystemTreeStore extends UmbStoreBase implements UmbTreeStore * @memberof UmbFileSystemTreeStore */ items(paths: Array) { - return this.#data.getObservablePart((items) => items.filter((item) => paths.includes(item.path ?? ''))); + return this._data.getObservablePart((items) => items.filter((item) => paths.includes(item.path ?? ''))); } } diff --git a/src/Umbraco.Web.UI.Client/libs/store/item-store.interface.ts b/src/Umbraco.Web.UI.Client/libs/store/item-store.interface.ts new file mode 100644 index 0000000000..d5d8e3d124 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/store/item-store.interface.ts @@ -0,0 +1,7 @@ +import type { Observable } from 'rxjs'; +import { ItemResponseModelBaseModel } from '../backend-api'; +import { UmbStore } from './store.interface'; + +export interface UmbItemStore extends UmbStore { + items: (uniques: Array) => Observable>; +} diff --git a/src/Umbraco.Web.UI.Client/libs/store/store-base.ts b/src/Umbraco.Web.UI.Client/libs/store/store-base.ts index 4021307cd6..36589bda21 100644 --- a/src/Umbraco.Web.UI.Client/libs/store/store-base.ts +++ b/src/Umbraco.Web.UI.Client/libs/store/store-base.ts @@ -1,9 +1,48 @@ +import { UmbStore } from './store.interface'; import { UmbContextProviderController } from '@umbraco-cms/backoffice/context-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; +import { ArrayState, partialUpdateFrozenArray } from '@umbraco-cms/backoffice/observable-api'; // TODO: Make a Store interface? -export class UmbStoreBase { - constructor(protected _host: UmbControllerHostElement, public readonly storeAlias: string) { +export class UmbStoreBase implements UmbStore { + protected _host: UmbControllerHostElement; + protected _data: ArrayState; + + public readonly storeAlias: string; + + constructor(_host: UmbControllerHostElement, storeAlias: string, data: ArrayState) { + this._host = _host; + this.storeAlias = storeAlias; + this._data = data; + new UmbContextProviderController(_host, storeAlias, this); } + + /** + * Appends items to the store + * @param {Array} items + * @memberof UmbEntityTreeStore + */ + appendItems(items: Array) { + this._data.append(items); + } + + /** + * Updates an item in the store + * @param {string} id + * @param {Partial} data + * @memberof UmbEntityTreeStore + */ + updateItem(id: string, data: Partial) { + this._data.next(partialUpdateFrozenArray(this._data.getValue(), data, (entry) => entry.id === id)); + } + + /** + * Removes an item from the store + * @param {string} id + * @memberof UmbEntityTreeStore + */ + removeItem(id: string) { + this._data.removeOne(id); + } } diff --git a/src/Umbraco.Web.UI.Client/libs/store/store.interface.ts b/src/Umbraco.Web.UI.Client/libs/store/store.interface.ts new file mode 100644 index 0000000000..0f094a1d4f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/store/store.interface.ts @@ -0,0 +1,5 @@ +export interface UmbStore { + appendItems: (items: Array) => void; + updateItem: (unique: string, item: Partial) => void; + removeItem: (unique: string) => void; +} diff --git a/src/Umbraco.Web.UI.Client/libs/store/store.ts b/src/Umbraco.Web.UI.Client/libs/store/store.ts index 4961162767..b2c48aedde 100644 --- a/src/Umbraco.Web.UI.Client/libs/store/store.ts +++ b/src/Umbraco.Web.UI.Client/libs/store/store.ts @@ -1,3 +1,4 @@ +// TODO: delete when the last usages are gone import type { Observable } from 'rxjs'; export interface UmbDataStoreIdentifiers { diff --git a/src/Umbraco.Web.UI.Client/libs/store/tree-store.interface.ts b/src/Umbraco.Web.UI.Client/libs/store/tree-store.interface.ts index 80a366ada5..cbe7b563d8 100644 --- a/src/Umbraco.Web.UI.Client/libs/store/tree-store.interface.ts +++ b/src/Umbraco.Web.UI.Client/libs/store/tree-store.interface.ts @@ -1,12 +1,10 @@ import type { Observable } from 'rxjs'; import { TreeItemPresentationModel } from '../backend-api'; +import { UmbStore } from './store.interface'; -export interface UmbTreeStore { - appendItems: (items: Array) => void; - updateItem: (unique: string, item: Partial) => void; - removeItem: (unique: string) => void; - +export interface UmbTreeStore extends UmbStore { rootItems: Observable>; childrenOf: (parentUnique: string | null) => Observable>; + // TODO: remove this one when all repositories are using an item store items: (uniques: Array) => Observable>; } From ba9676d92ad935b999719c7a7097afb17b403a0d Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Apr 2023 17:12:26 +0200 Subject: [PATCH 084/156] temp updates to follow store interface --- .../libs/picker/picker.context.ts | 8 ++-- .../repository/item-repository.interface.ts | 4 +- .../libs/store/store-base.ts | 2 +- .../document-blueprint.detail.store.ts | 17 +++---- .../languages/repository/language.store.ts | 15 ++++--- .../repository/relation-type.store.ts | 14 +++--- .../templates/repository/template.store.ts | 8 ++-- .../dictionary/repository/dictionary.store.ts | 12 ++--- .../repository/user-group.store.ts | 2 +- .../users/users/repository/user.store.ts | 45 +++++++++---------- 10 files changed, 65 insertions(+), 62 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts b/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts index eea965a1d2..fc28b6f84b 100644 --- a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts +++ b/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts @@ -1,4 +1,4 @@ -import { UmbTreeRepository } from '../repository'; +import { UmbItemRepository, UmbTreeRepository } from '@umbraco-cms/backoffice/repository'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { ArrayState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; import { createExtensionClass, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api'; @@ -15,7 +15,7 @@ import { UmbChangeEvent } from '@umbraco-cms/backoffice/events'; export class UmbPickerContext { host: UmbControllerHostElement; modalAlias: UmbModalToken | string; - repository?: UmbTreeRepository; + repository?: UmbItemRepository; #getUnique: (entry: ItemType) => string | undefined; public modalContext?: UmbModalContext; @@ -53,7 +53,7 @@ export class UmbPickerContext { if (!repositoryManifest) return; try { - const result = await createExtensionClass(repositoryManifest, [this.host]); + const result = await createExtensionClass>(repositoryManifest, [this.host]); this.repository = result; } catch (error) { throw new Error('Could not create repository with alias: ' + repositoryAlias + ''); @@ -113,7 +113,7 @@ export class UmbPickerContext { if (!this.repository) throw new Error('Repository is not initialized'); if (this.#selectedItemsObserver) this.#selectedItemsObserver.destroy(); - const { asObservable } = await this.repository.requestTreeItems(this.getSelection()); + const { asObservable } = await this.repository.requestItems(this.getSelection()); if (asObservable) { this.#selectedItemsObserver = new UmbObserverController(this.host, asObservable(), (data) => { diff --git a/src/Umbraco.Web.UI.Client/libs/repository/item-repository.interface.ts b/src/Umbraco.Web.UI.Client/libs/repository/item-repository.interface.ts index 1afb646c9f..74395f85de 100644 --- a/src/Umbraco.Web.UI.Client/libs/repository/item-repository.interface.ts +++ b/src/Umbraco.Web.UI.Client/libs/repository/item-repository.interface.ts @@ -1,7 +1,7 @@ import type { Observable } from 'rxjs'; -import { ProblemDetailsModel } from '@umbraco-cms/backoffice/backend-api'; +import { ItemResponseModelBaseModel, ProblemDetailsModel } from '@umbraco-cms/backoffice/backend-api'; -export interface UmbItemRepository { +export interface UmbItemRepository { requestItems: (uniques: string[]) => Promise<{ data: Array | undefined; error: ProblemDetailsModel | undefined; diff --git a/src/Umbraco.Web.UI.Client/libs/store/store-base.ts b/src/Umbraco.Web.UI.Client/libs/store/store-base.ts index 36589bda21..d1a454c1ee 100644 --- a/src/Umbraco.Web.UI.Client/libs/store/store-base.ts +++ b/src/Umbraco.Web.UI.Client/libs/store/store-base.ts @@ -4,7 +4,7 @@ import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { ArrayState, partialUpdateFrozenArray } from '@umbraco-cms/backoffice/observable-api'; // TODO: Make a Store interface? -export class UmbStoreBase implements UmbStore { +export class UmbStoreBase implements UmbStore { protected _host: UmbControllerHostElement; protected _data: ArrayState; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-blueprints/document-blueprint.detail.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-blueprints/document-blueprint.detail.store.ts index f60b478a36..db04e8c9b1 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-blueprints/document-blueprint.detail.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-blueprints/document-blueprint.detail.store.ts @@ -11,11 +11,12 @@ import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; * @description - Data Store for Document Blueprints */ export class UmbDocumentBlueprintStore extends UmbStoreBase { - // TODO: use the right type: - #data = new ArrayState([], (x) => x.id); - constructor(host: UmbControllerHostElement) { - super(host, UMB_DOCUMENT_BLUEPRINT_STORE_CONTEXT_TOKEN.toString()); + super( + host, + UMB_DOCUMENT_BLUEPRINT_STORE_CONTEXT_TOKEN.toString(), + new ArrayState([], (x) => x.id) + ); } /** @@ -29,10 +30,10 @@ export class UmbDocumentBlueprintStore extends UmbStoreBase { fetch(`/umbraco/management/api/v1/document-blueprint/details/${id}`) .then((res) => res.json()) .then((data) => { - this.#data.append(data); + this._data.append(data); }); - return this.#data.getObservablePart((documents) => documents.find((document) => document.id === id)); + return this._data.getObservablePart((documents) => documents.find((document) => document.id === id)); } getScaffold(entityType: string, parentId: string | null) { @@ -68,7 +69,7 @@ export class UmbDocumentBlueprintStore extends UmbStoreBase { }) .then((res) => res.json()) .then((data: Array) => { - this.#data.append(data); + this._data.append(data); }); } @@ -89,7 +90,7 @@ export class UmbDocumentBlueprintStore extends UmbStoreBase { }, }); - this.#data.remove(ids); + this._data.remove(ids); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language.store.ts index 820b66fc50..cba0758559 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language.store.ts @@ -13,23 +13,24 @@ export const UMB_LANGUAGE_STORE_CONTEXT_TOKEN = new UmbContextToken([], (x) => x.isoCode); - data = this.#data.asObservable(); - constructor(host: UmbControllerHostElement) { - super(host, UMB_LANGUAGE_STORE_CONTEXT_TOKEN.toString()); + super( + host, + UMB_LANGUAGE_STORE_CONTEXT_TOKEN.toString(), + new ArrayState([], (x) => x.isoCode) + ); } append(language: LanguageResponseModel) { - this.#data.append([language]); + this._data.append([language]); } remove(uniques: string[]) { - this.#data.remove(uniques); + this._data.remove(uniques); } // TODO: how do we best handle this? They might have a smaller data set than the details items(isoCodes: Array) { - return this.#data.getObservablePart((items) => items.filter((item) => isoCodes.includes(item.isoCode ?? ''))); + return this._data.getObservablePart((items) => items.filter((item) => isoCodes.includes(item.isoCode ?? ''))); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/relation-type.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/relation-type.store.ts index f8ac1dd072..b61c3fbb15 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/relation-type.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/relation-type.store.ts @@ -13,15 +13,17 @@ export const UMB_RELATION_TYPE_STORE_CONTEXT_TOKEN = new UmbContextToken([], (x) => x.id); - /** * Creates an instance of UmbRelationTypeStore. * @param {UmbControllerHostElement} host * @memberof UmbRelationTypeStore */ constructor(host: UmbControllerHostElement) { - super(host, UMB_RELATION_TYPE_STORE_CONTEXT_TOKEN.toString()); + super( + host, + UMB_RELATION_TYPE_STORE_CONTEXT_TOKEN.toString(), + new ArrayState([], (x) => x.id) + ); } /** @@ -30,7 +32,7 @@ export class UmbRelationTypeStore extends UmbStoreBase { * @memberof UmbRelationTypeStore */ append(RelationType: RelationTypeResponseModel) { - this.#data.append([RelationType]); + this._data.append([RelationType]); } /** @@ -39,7 +41,7 @@ export class UmbRelationTypeStore extends UmbStoreBase { * @memberof UmbRelationTypeStore */ byKey(id: RelationTypeResponseModel['id']) { - return this.#data.getObservablePart((x) => x.find((y) => y.id === id)); + return this._data.getObservablePart((x) => x.find((y) => y.id === id)); } /** @@ -48,6 +50,6 @@ export class UmbRelationTypeStore extends UmbStoreBase { * @memberof UmbRelationTypeStore */ remove(uniques: Array) { - this.#data.remove(uniques); + this._data.remove(uniques); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/repository/template.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/repository/template.store.ts index edebf64d61..14443211e5 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/repository/template.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/repository/template.store.ts @@ -11,15 +11,13 @@ import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controlle * @description - Data Store for Templates */ export class UmbTemplateStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.id); - /** * Creates an instance of UmbTemplateStore. * @param {UmbControllerHostElement} host * @memberof UmbTemplateStore */ constructor(host: UmbControllerHostElement) { - super(host, UMB_TEMPLATE_STORE_CONTEXT_TOKEN.toString()); + super(host, UMB_TEMPLATE_STORE_CONTEXT_TOKEN.toString(), new ArrayState([], (x) => x.id)); } /** @@ -28,7 +26,7 @@ export class UmbTemplateStore extends UmbStoreBase { * @memberof UmbTemplateStore */ append(template: TemplateResponseModel) { - this.#data.append([template]); + this._data.append([template]); } /** @@ -37,7 +35,7 @@ export class UmbTemplateStore extends UmbStoreBase { * @memberof UmbTemplateStore */ remove(uniques: string[]) { - this.#data.remove(uniques); + this._data.remove(uniques); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/repository/dictionary.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/repository/dictionary.store.ts index c4b62e7c82..1f1f3d5bb5 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/repository/dictionary.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/repository/dictionary.store.ts @@ -11,18 +11,20 @@ import { DictionaryItemResponseModel } from '@umbraco-cms/backoffice/backend-api * @description - Data Store for Dictionary */ export class UmbDictionaryStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.id); - constructor(host: UmbControllerHostElement) { - super(host, UMB_DICTIONARY_STORE_CONTEXT_TOKEN.toString()); + super( + host, + UMB_DICTIONARY_STORE_CONTEXT_TOKEN.toString(), + new ArrayState([], (x) => x.id) + ); } append(dictionary: DictionaryItemResponseModel) { - this.#data.append([dictionary]); + this._data.append([dictionary]); } remove(uniques: string[]) { - this.#data.remove(uniques); + this._data.remove(uniques); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/repository/user-group.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/repository/user-group.store.ts index 64197bb05b..f42ad27bd8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/repository/user-group.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/repository/user-group.store.ts @@ -20,7 +20,7 @@ export class UmbUserGroupStore extends UmbStoreBase implements UmbEntityDetailSt public groups = this.#groups.asObservable(); constructor(host: UmbControllerHostElement) { - super(host, UMB_USER_GROUP_STORE_CONTEXT_TOKEN.toString()); + super(host, UMB_USER_GROUP_STORE_CONTEXT_TOKEN.toString(), new ArrayState([], (x) => x.id)); } getScaffold(entityType: string, parentId: string | null) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/users/users/repository/user.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/users/users/repository/user.store.ts index a52581484d..8f635de3d7 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/users/users/repository/user.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/users/users/repository/user.store.ts @@ -15,14 +15,13 @@ export const UMB_USER_STORE_CONTEXT_TOKEN = new UmbContextToken('U * @description - Data Store for Users */ export class UmbUserStore extends UmbStoreBase implements UmbEntityDetailStore { - #users = new ArrayState([], (x) => x.id); - public users = this.#users.asObservable(); + public users = this._data.asObservable(); #totalUsers = new NumberState(0); public readonly totalUsers = this.#totalUsers.asObservable(); constructor(host: UmbControllerHostElement) { - super(host, UMB_USER_STORE_CONTEXT_TOKEN.toString()); + super(host, UMB_USER_STORE_CONTEXT_TOKEN.toString(), new ArrayState([], (x) => x.id)); } getScaffold(entityType: string, parentId: string | null) { @@ -52,7 +51,7 @@ export class UmbUserStore extends UmbStoreBase implements UmbEntityDetailStore res.json()) .then((data) => { this.#totalUsers.next(data.total); - this.#users.next(data.items); + this._data.next(data.items); }); return this.users; @@ -70,10 +69,10 @@ export class UmbUserStore extends UmbStoreBase implements UmbEntityDetailStore res.json()) .then((data) => { - this.#users.appendOne(data); + this._data.appendOne(data); }); - return this.#users.getObservablePart((users: Array) => + return this._data.getObservablePart((users: Array) => users.find((user: UmbUserStoreItemType) => user.id === id) ); } @@ -89,10 +88,10 @@ export class UmbUserStore extends UmbStoreBase implements UmbEntityDetailStore res.json()) .then((data) => { - this.#users.append(data); + this._data.append(data); }); - return this.#users.getObservablePart((users: Array) => + return this._data.getObservablePart((users: Array) => users.filter((user: UmbUserStoreItemType) => ids.includes(user.id)) ); } @@ -105,10 +104,10 @@ export class UmbUserStore extends UmbStoreBase implements UmbEntityDetailStore res.json()) .then((data) => { - this.#users.append(data); + this._data.append(data); }); - return this.#users.getObservablePart((users: Array) => + return this._data.getObservablePart((users: Array) => users.filter((user: UmbUserStoreItemType) => user.name.toLocaleLowerCase().includes(name)) ); } @@ -124,13 +123,13 @@ export class UmbUserStore extends UmbStoreBase implements UmbEntityDetailStore enabledKeys.includes(user.id)); + const storedUsers = this._data.getValue().filter((user) => enabledKeys.includes(user.id)); storedUsers.forEach((user) => { user.status = 'enabled'; }); - this.#users.append(storedUsers); + this._data.append(storedUsers); } catch (error) { console.error('Enable Users failed', error); } @@ -147,17 +146,17 @@ export class UmbUserStore extends UmbStoreBase implements UmbEntityDetailStore enabledKeys.includes(user.id)); + const storedUsers = this._data.getValue().filter((user) => enabledKeys.includes(user.id)); storedUsers.forEach((user) => { if (userKeys.includes(user.id)) { user.userGroups.push(userGroup); } else { - user.userGroups = user.userGroups.filter((group) => group !== userGroup); + user.userGroups = user.userGroups.filter((group: any) => group !== userGroup); } }); - this.#users.append(storedUsers); + this._data.append(storedUsers); } catch (error) { console.error('Add user group failed', error); } @@ -174,13 +173,13 @@ export class UmbUserStore extends UmbStoreBase implements UmbEntityDetailStore enabledKeys.includes(user.id)); + const storedUsers = this._data.getValue().filter((user) => enabledKeys.includes(user.id)); storedUsers.forEach((user) => { - user.userGroups = user.userGroups.filter((group) => group !== userGroup); + user.userGroups = user.userGroups.filter((group: any) => group !== userGroup); }); - this.#users.append(storedUsers); + this._data.append(storedUsers); } catch (error) { console.error('Remove user group failed', error); } @@ -197,13 +196,13 @@ export class UmbUserStore extends UmbStoreBase implements UmbEntityDetailStore disabledKeys.includes(user.id)); + const storedUsers = this._data.getValue().filter((user) => disabledKeys.includes(user.id)); storedUsers.forEach((user) => { user.status = 'disabled'; }); - this.#users.append(storedUsers); + this._data.append(storedUsers); } catch (error) { console.error('Disable Users failed', error); } @@ -220,7 +219,7 @@ export class UmbUserStore extends UmbStoreBase implements UmbEntityDetailStore Date: Mon, 17 Apr 2023 17:21:52 +0200 Subject: [PATCH 085/156] update to follow interface --- .../backoffice/members/members/member.detail.store.ts | 9 ++++----- .../members/members/repository/member.store.ts | 8 +++----- .../settings/data-types/repository/data-type.store.ts | 10 ++++------ 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/member.detail.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/member.detail.store.ts index 973f79f5c4..bde96e2b76 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/member.detail.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/member.detail.store.ts @@ -13,11 +13,10 @@ import { UmbEntityDetailStore, UmbStoreBase } from '@umbraco-cms/backoffice/stor * @description - Data Store for Members */ export class UmbMemberStore extends UmbStoreBase implements UmbEntityDetailStore { - #data = new ArrayState([], (x) => x.id); - public groups = this.#data.asObservable(); + public groups = this._data.asObservable(); constructor(private host: UmbControllerHostElement) { - super(host, UMB_MEMBER_STORE_CONTEXT_TOKEN.toString()); + super(host, UMB_MEMBER_STORE_CONTEXT_TOKEN.toString(), new ArrayState([], (x) => x.id)); } getScaffold(entityType: string, parentId: string | null) { @@ -40,10 +39,10 @@ export class UmbMemberStore extends UmbStoreBase implements UmbEntityDetailStore // temp until Resource is updated const member = umbMemberData.getById(id); if (member) { - this.#data.appendOne(member); + this._data.appendOne(member); } - return createObservablePart(this.#data, (members) => members.find((member) => member.id === id) as MemberDetails); + return createObservablePart(this._data, (members) => members.find((member) => member.id === id) as MemberDetails); } async save(member: Array): Promise { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/repository/member.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/repository/member.store.ts index 4b01b1a8d8..22b5aefdbc 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/repository/member.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/repository/member.store.ts @@ -11,18 +11,16 @@ import type { MemberDetails } from '@umbraco-cms/backoffice/models'; * @description - Data Store for Members */ export class UmbMemberStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.id); - constructor(host: UmbControllerHostElement) { - super(host, UMB_MEMBER_STORE_CONTEXT_TOKEN.toString()); + super(host, UMB_MEMBER_STORE_CONTEXT_TOKEN.toString(), new ArrayState([], (x) => x.id)); } append(member: MemberDetails) { - this.#data.append([member]); + this._data.append([member]); } remove(uniques: string[]) { - this.#data.remove(uniques); + this._data.remove(uniques); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.store.ts index 71db9b0013..7367352df8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.store.ts @@ -13,15 +13,13 @@ export const UMB_DATA_TYPE_STORE_CONTEXT_TOKEN = new UmbContextToken([], (x) => x.id); - /** * Creates an instance of UmbDataTypeStore. * @param {UmbControllerHostElement} host * @memberof UmbDataTypeStore */ constructor(host: UmbControllerHostElement) { - super(host, UMB_DATA_TYPE_STORE_CONTEXT_TOKEN.toString()); + super(host, UMB_DATA_TYPE_STORE_CONTEXT_TOKEN.toString(), new ArrayState([], (x) => x.id)); } /** @@ -30,7 +28,7 @@ export class UmbDataTypeStore extends UmbStoreBase { * @memberof UmbDataTypeStore */ append(dataType: DataTypeResponseModel) { - this.#data.append([dataType]); + this._data.append([dataType]); } /** @@ -39,7 +37,7 @@ export class UmbDataTypeStore extends UmbStoreBase { * @memberof UmbDataTypeStore */ byId(id: DataTypeResponseModel['id']) { - return this.#data.getObservablePart((x) => x.find((y) => y.id === id)); + return this._data.getObservablePart((x) => x.find((y) => y.id === id)); } /** @@ -48,6 +46,6 @@ export class UmbDataTypeStore extends UmbStoreBase { * @memberof UmbDataTypeStore */ remove(uniques: Array) { - this.#data.remove(uniques); + this._data.remove(uniques); } } From e84fde8ad95145a61c3d4a37413c2ae2ff81a948 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Apr 2023 20:37:55 +0200 Subject: [PATCH 086/156] register language item store --- .../libs/extensions-registry/models.ts | 3 +- .../libs/extensions-registry/store.models.ts | 6 ++- src/Umbraco.Web.UI.Client/libs/store/index.ts | 1 + .../libs/store/item-store.interface.ts | 2 +- .../libs/store/store-base.ts | 10 ++--- .../repository/document-type.store.ts | 14 ++++--- .../documents/repository/document.store.ts | 10 ++--- .../repository/media-type.detail.store.ts | 8 ++-- .../media/media/repository/media.store.ts | 8 ++-- .../repository/member-group.store.ts | 8 ++-- .../repository/member-type.store.ts | 8 ++-- .../packages/repository/package.store.ts | 4 +- .../repository/language-item.store.ts | 41 +++++++++++++++++++ .../repository/language.repository.ts | 41 +++++++++++++------ .../languages/repository/language.store.ts | 2 + .../languages/repository/manifests.ts | 11 ++++- 16 files changed, 122 insertions(+), 55 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language-item.store.ts diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts index 387abf6331..d49d57d2bb 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts @@ -24,7 +24,7 @@ import type { ManifestWorkspaceView } from './workspace-view.models'; import type { ManifestWorkspaceViewCollection } from './workspace-view-collection.models'; import type { ManifestRepository } from './repository.models'; import type { ManifestModal } from './modal.models'; -import type { ManifestStore, ManifestTreeStore } from './store.models'; +import type { ManifestStore, ManifestTreeStore, ManifestItemStore } from './store.models'; import type { ClassConstructor } from '@umbraco-cms/backoffice/models'; export * from './collection-view.models'; @@ -89,6 +89,7 @@ export type ManifestTypes = | ManifestModal | ManifestStore | ManifestTreeStore + | ManifestItemStore | ManifestBase; export type ManifestStandardTypes = ManifestTypes['type']; diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/store.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/store.models.ts index 18e8c10c17..dbca5d6956 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/store.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/store.models.ts @@ -1,5 +1,5 @@ import type { ManifestClass } from './models'; -import { UmbStoreBase, UmbTreeStore } from '@umbraco-cms/backoffice/store'; +import { UmbItemStore, UmbStoreBase, UmbTreeStore } from '@umbraco-cms/backoffice/store'; export interface ManifestStore extends ManifestClass { type: 'store'; @@ -8,3 +8,7 @@ export interface ManifestStore extends ManifestClass { export interface ManifestTreeStore extends ManifestClass { type: 'treeStore'; } + +export interface ManifestItemStore extends ManifestClass { + type: 'itemStore'; +} diff --git a/src/Umbraco.Web.UI.Client/libs/store/index.ts b/src/Umbraco.Web.UI.Client/libs/store/index.ts index f9152d3ebd..a72d304eca 100644 --- a/src/Umbraco.Web.UI.Client/libs/store/index.ts +++ b/src/Umbraco.Web.UI.Client/libs/store/index.ts @@ -3,3 +3,4 @@ export * from './store-base'; export * from './entity-tree-store'; export * from './file-system-tree.store'; export * from './tree-store.interface'; +export * from './item-store.interface'; diff --git a/src/Umbraco.Web.UI.Client/libs/store/item-store.interface.ts b/src/Umbraco.Web.UI.Client/libs/store/item-store.interface.ts index d5d8e3d124..a68e83b5c1 100644 --- a/src/Umbraco.Web.UI.Client/libs/store/item-store.interface.ts +++ b/src/Umbraco.Web.UI.Client/libs/store/item-store.interface.ts @@ -2,6 +2,6 @@ import type { Observable } from 'rxjs'; import { ItemResponseModelBaseModel } from '../backend-api'; import { UmbStore } from './store.interface'; -export interface UmbItemStore extends UmbStore { +export interface UmbItemStore extends UmbStore { items: (uniques: Array) => Observable>; } diff --git a/src/Umbraco.Web.UI.Client/libs/store/store-base.ts b/src/Umbraco.Web.UI.Client/libs/store/store-base.ts index d1a454c1ee..5092c7bba2 100644 --- a/src/Umbraco.Web.UI.Client/libs/store/store-base.ts +++ b/src/Umbraco.Web.UI.Client/libs/store/store-base.ts @@ -1,7 +1,7 @@ import { UmbStore } from './store.interface'; import { UmbContextProviderController } from '@umbraco-cms/backoffice/context-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { ArrayState, partialUpdateFrozenArray } from '@umbraco-cms/backoffice/observable-api'; +import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; // TODO: Make a Store interface? export class UmbStoreBase implements UmbStore { @@ -33,8 +33,8 @@ export class UmbStoreBase implements UmbStore} data * @memberof UmbEntityTreeStore */ - updateItem(id: string, data: Partial) { - this._data.next(partialUpdateFrozenArray(this._data.getValue(), data, (entry) => entry.id === id)); + updateItem(unique: string, data: Partial) { + this._data.updateOne(unique, data); } /** @@ -42,7 +42,7 @@ export class UmbStoreBase implements UmbStore([], (x) => x.id); - /** * Creates an instance of UmbDocumentTypeStore. * @param {UmbControllerHostElement} host * @memberof UmbDocumentTypeStore */ constructor(host: UmbControllerHostElement) { - super(host, UMB_DOCUMENT_TYPE_STORE_CONTEXT_TOKEN.toString()); + super( + host, + UMB_DOCUMENT_TYPE_STORE_CONTEXT_TOKEN.toString(), + new ArrayState([], (x) => x.id) + ); } /** @@ -28,7 +30,7 @@ export class UmbDocumentTypeStore extends UmbStoreBase { * @memberof UmbDocumentTypeStore */ append(document: DocumentTypeResponseModel) { - this.#data.append([document]); + this._data.append([document]); } /** @@ -37,7 +39,7 @@ export class UmbDocumentTypeStore extends UmbStoreBase { * @memberof UmbDocumentTypeStore */ byId(id: DocumentTypeResponseModel['id']) { - return this.#data.getObservablePart((x) => x.find((y) => y.id === id)); + return this._data.getObservablePart((x) => x.find((y) => y.id === id)); } /** @@ -46,7 +48,7 @@ export class UmbDocumentTypeStore extends UmbStoreBase { * @memberof UmbDocumentTypeStore */ remove(uniques: Array) { - this.#data.remove(uniques); + this._data.remove(uniques); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/document.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/document.store.ts index d53818f95e..ed2fb34fb2 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/document.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/document.store.ts @@ -11,15 +11,13 @@ import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; * @description - Data Store for Template Details */ export class UmbDocumentStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.id); - /** * Creates an instance of UmbDocumentDetailStore. * @param {UmbControllerHostElement} host * @memberof UmbDocumentDetailStore */ constructor(host: UmbControllerHostElement) { - super(host, UMB_DOCUMENT_STORE_CONTEXT_TOKEN.toString()); + super(host, UMB_DOCUMENT_STORE_CONTEXT_TOKEN.toString(), new ArrayState([], (x) => x.id)); } /** @@ -28,7 +26,7 @@ export class UmbDocumentStore extends UmbStoreBase { * @memberof UmbDocumentDetailStore */ append(document: DocumentResponseModel) { - this.#data.append([document]); + this._data.append([document]); } /** @@ -37,7 +35,7 @@ export class UmbDocumentStore extends UmbStoreBase { * @memberof UmbDocumentStore */ byKey(id: DocumentResponseModel['id']) { - return this.#data.getObservablePart((x) => x.find((y) => y.id === id)); + return this._data.getObservablePart((x) => x.find((y) => y.id === id)); } /** @@ -46,7 +44,7 @@ export class UmbDocumentStore extends UmbStoreBase { * @memberof UmbDocumentDetailStore */ remove(uniques: Array) { - this.#data.remove(uniques); + this._data.remove(uniques); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/repository/media-type.detail.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/repository/media-type.detail.store.ts index d6ef9c0fa9..555d7fa0f3 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/repository/media-type.detail.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/repository/media-type.detail.store.ts @@ -11,18 +11,16 @@ import type { MediaTypeDetails } from '@umbraco-cms/backoffice/models'; * @description - Details Data Store for Media Types */ export class UmbMediaTypeStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.id); - constructor(host: UmbControllerHostElement) { - super(host, UMB_MEDIA_TYPE_STORE_CONTEXT_TOKEN.toString()); + super(host, UMB_MEDIA_TYPE_STORE_CONTEXT_TOKEN.toString(), new ArrayState([], (x) => x.id)); } append(mediaType: MediaTypeDetails) { - this.#data.append([mediaType]); + this._data.append([mediaType]); } remove(uniques: string[]) { - this.#data.remove(uniques); + this._data.remove(uniques); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/repository/media.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/repository/media.store.ts index ddc1a8b5fc..dff90e3885 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/repository/media.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/repository/media.store.ts @@ -11,15 +11,13 @@ import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; * @description - Data Store for Template Details */ export class UmbMediaStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.id); - /** * Creates an instance of UmbMediaStore. * @param {UmbControllerHostElement} host * @memberof UmbMediaStore */ constructor(host: UmbControllerHostElement) { - super(host, UMB_MEDIA_STORE_CONTEXT_TOKEN.toString()); + super(host, UMB_MEDIA_STORE_CONTEXT_TOKEN.toString(), new ArrayState([], (x) => x.id)); } /** @@ -28,7 +26,7 @@ export class UmbMediaStore extends UmbStoreBase { * @memberof UmbMediaStore */ append(media: MediaDetails) { - this.#data.append([media]); + this._data.append([media]); } /** @@ -37,7 +35,7 @@ export class UmbMediaStore extends UmbStoreBase { * @memberof UmbMediaStore */ remove(uniques: string[]) { - this.#data.remove(uniques); + this._data.remove(uniques); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/repository/member-group.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/repository/member-group.store.ts index 38fd8ede11..30ed7f8785 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/repository/member-group.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/repository/member-group.store.ts @@ -11,18 +11,16 @@ import { UmbStoreBase } from '@umbraco-cms/backoffice/store'; * @description - Data Store for Member Groups */ export class UmbMemberGroupStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.id); - constructor(host: UmbControllerHostElement) { - super(host, UMB_MEMBER_GROUP_STORE_CONTEXT_TOKEN.toString()); + super(host, UMB_MEMBER_GROUP_STORE_CONTEXT_TOKEN.toString(), new ArrayState([], (x) => x.id)); } append(memberGroup: MemberGroupDetails) { - this.#data.append([memberGroup]); + this._data.append([memberGroup]); } remove(uniques: string[]) { - this.#data.remove(uniques); + this._data.remove(uniques); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/repository/member-type.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/repository/member-type.store.ts index b9afd506a2..5d0bf4bcfd 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/repository/member-type.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/repository/member-type.store.ts @@ -11,18 +11,16 @@ import type { MemberTypeDetails } from '@umbraco-cms/backoffice/models'; * @description - Data Store for Member Types */ export class UmbMemberTypeStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.id); - constructor(host: UmbControllerHostElement) { - super(host, UMB_MEMBER_TYPE_STORE_CONTEXT_TOKEN.toString()); + super(host, UMB_MEMBER_TYPE_STORE_CONTEXT_TOKEN.toString(), new ArrayState([], (x) => x.id)); } append(MemberType: MemberTypeDetails) { - this.#data.append([MemberType]); + this._data.append([MemberType]); } remove(uniques: string[]) { - this.#data.remove(uniques); + this._data.remove(uniques); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/package.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/package.store.ts index 8ed4792471..3eeacc0b15 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/package.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/package.store.ts @@ -42,7 +42,9 @@ export class UmbPackageStore extends UmbStoreBase { * @memberof PackageStore */ constructor(host: UmbControllerHostElement) { - super(host, UMB_PACKAGE_STORE_TOKEN.toString()); + // TODO: revisit this store. Is it ok to have multiple data sets? + // temp hack to satisfy the base class + super(host, UMB_PACKAGE_STORE_TOKEN.toString(), new ArrayState([], (x) => x.name)); } /** diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language-item.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language-item.store.ts new file mode 100644 index 0000000000..5c1645003d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language-item.store.ts @@ -0,0 +1,41 @@ +import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; +import { UmbStoreBase } from '@umbraco-cms/backoffice/store'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; +import { ArrayState, partialUpdateFrozenArray } from '@umbraco-cms/backoffice/observable-api'; +import { LanguageResponseModel } from '@umbraco-cms/backoffice/backend-api'; +import type { UmbItemStore } from '@umbraco-cms/backoffice/store'; + +export const UMB_LANGUAGE_ITEM_STORE_CONTEXT_TOKEN = new UmbContextToken('UmbLanguageItemStore'); + +/** + * @export + * @class UmbLanguageItemStore + * @extends {UmbStoreBase} + * @description - Store for Languages items + */ +export class UmbLanguageItemStore + extends UmbStoreBase + implements UmbItemStore +{ + constructor(host: UmbControllerHostElement) { + super( + host, + UMB_LANGUAGE_ITEM_STORE_CONTEXT_TOKEN.toString(), + new ArrayState([], (x) => x.isoCode) + ); + } + + /** + * Updates an item in the store + * @param {string} isoCode + * @param {Partial} data + * @memberof UmbLanguageItemStore + */ + updateItem(isoCode: string, data: Partial) { + this._data.next(partialUpdateFrozenArray(this._data.getValue(), data, (entry) => entry.isoCode === isoCode)); + } + + items(isoCodes: Array) { + return this._data.getObservablePart((items) => items.filter((item) => isoCodes.includes(item.isoCode ?? ''))); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language.repository.ts index d37dada762..cd854018d4 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language.repository.ts @@ -1,17 +1,26 @@ import { UmbLanguageServerDataSource } from './sources/language.server.data'; import { UmbLanguageStore, UMB_LANGUAGE_STORE_CONTEXT_TOKEN } from './language.store'; +import { UmbLanguageItemServerDataSource } from './sources/language-item.server.data'; +import { UMB_LANGUAGE_ITEM_STORE_CONTEXT_TOKEN, UmbLanguageItemStore } from './language-item.store'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification'; -import { LanguageResponseModel, ProblemDetailsModel } from '@umbraco-cms/backoffice/backend-api'; +import { + LanguageItemResponseModel, + LanguageResponseModel, + ProblemDetailsModel, +} from '@umbraco-cms/backoffice/backend-api'; +import { UmbItemRepository } from '@umbraco-cms/backoffice/repository'; -export class UmbLanguageRepository { - #init!: Promise; +export class UmbLanguageRepository implements UmbItemRepository { + #init: Promise; #host: UmbControllerHostElement; #dataSource: UmbLanguageServerDataSource; + #itemDataSource: UmbLanguageItemServerDataSource; #languageStore?: UmbLanguageStore; + #languageItemStore?: UmbLanguageItemStore; #notificationContext?: UmbNotificationContext; @@ -19,15 +28,21 @@ export class UmbLanguageRepository { this.#host = host; this.#dataSource = new UmbLanguageServerDataSource(this.#host); + this.#itemDataSource = new UmbLanguageItemServerDataSource(this.#host); this.#init = Promise.all([ new UmbContextConsumerController(this.#host, UMB_NOTIFICATION_CONTEXT_TOKEN, (instance) => { this.#notificationContext = instance; - }), + }).asPromise(), new UmbContextConsumerController(this.#host, UMB_LANGUAGE_STORE_CONTEXT_TOKEN, (instance) => { this.#languageStore = instance; }).asPromise(), + + new UmbContextConsumerController(this.#host, UMB_LANGUAGE_ITEM_STORE_CONTEXT_TOKEN, (instance) => { + this.#languageItemStore = instance; + debugger; + }).asPromise(), ]); } @@ -59,19 +74,19 @@ export class UmbLanguageRepository { } async requestItems(isoCodes: Array) { - // HACK: filter client side until we have a proper server side endpoint - // TODO: we will get a different size model here, how do we handle that in the store? - const { data, error } = await this.requestLanguages(); - - let items = undefined; + await this.#init; + const { data, error } = await this.#itemDataSource.getItems(isoCodes); if (data) { - // TODO: how do we best handle this? They might have a smaller data set than the details - items = data.items = data.items.filter((x) => isoCodes.includes(x.isoCode!)); - data.items.forEach((x) => this.#languageStore?.append(x)); + this.#languageItemStore?.appendItems(data); } - return { data: items, error, asObservable: () => this.#languageStore!.items(isoCodes) }; + return { data, error, asObservable: () => this.#languageItemStore!.items(isoCodes) }; + } + + async items(isoCodes: Array) { + await this.#init; + return this.#languageItemStore!.items(isoCodes); } /** diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language.store.ts index cba0758559..8cb8c55a0a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language.store.ts @@ -13,6 +13,8 @@ export const UMB_LANGUAGE_STORE_CONTEXT_TOKEN = new UmbContextToken Date: Mon, 17 Apr 2023 20:41:54 +0200 Subject: [PATCH 087/156] remove redundant update method --- .../languages/repository/language-item.store.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language-item.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language-item.store.ts index 5c1645003d..26eaa68a76 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language-item.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language-item.store.ts @@ -25,16 +25,6 @@ export class UmbLanguageItemStore ); } - /** - * Updates an item in the store - * @param {string} isoCode - * @param {Partial} data - * @memberof UmbLanguageItemStore - */ - updateItem(isoCode: string, data: Partial) { - this._data.next(partialUpdateFrozenArray(this._data.getValue(), data, (entry) => entry.isoCode === isoCode)); - } - items(isoCodes: Array) { return this._data.getObservablePart((items) => items.filter((item) => isoCodes.includes(item.isoCode ?? ''))); } From d1bf7885d1a879240bf2d148788b8191199de7bb Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Apr 2023 20:49:57 +0200 Subject: [PATCH 088/156] check for item stores --- src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts index c4590ec1ee..8d83bc998d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts @@ -71,7 +71,7 @@ export class UmbBackofficeElement extends UmbLitElement { this.provideContext(UMB_CURRENT_USER_HISTORY_STORE_CONTEXT_TOKEN, new UmbCurrentUserHistoryStore()); // Register All Stores - this.observe(umbExtensionsRegistry.extensionsOfTypes(['store', 'treeStore']), (stores) => { + this.observe(umbExtensionsRegistry.extensionsOfTypes(['store', 'treeStore', 'itemStore']), (stores) => { stores.forEach((store) => createExtensionClass(store, [this])); }); } From 92f1de1497e73767ca7d39bc4826200669bcdda1 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Apr 2023 20:50:44 +0200 Subject: [PATCH 089/156] remove debugger --- .../settings/languages/repository/language.repository.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language.repository.ts index cd854018d4..243a7f3791 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language.repository.ts @@ -41,7 +41,6 @@ export class UmbLanguageRepository implements UmbItemRepository { this.#languageItemStore = instance; - debugger; }).asPromise(), ]); } From 8fa8f4b7fdf0ce81a4ae3dd1e95caf0c417b72c7 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Apr 2023 20:50:51 +0200 Subject: [PATCH 090/156] add todo --- src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts index 8d83bc998d..116be1ac07 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts @@ -71,6 +71,7 @@ export class UmbBackofficeElement extends UmbLitElement { this.provideContext(UMB_CURRENT_USER_HISTORY_STORE_CONTEXT_TOKEN, new UmbCurrentUserHistoryStore()); // Register All Stores + // TODO: can we use kinds here so we don't have to hardcode the types? this.observe(umbExtensionsRegistry.extensionsOfTypes(['store', 'treeStore', 'itemStore']), (stores) => { stores.forEach((store) => createExtensionClass(store, [this])); }); From d28f3d47c6f3078ca3d5990a65911a066337c1d3 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Apr 2023 21:14:33 +0200 Subject: [PATCH 091/156] mock item request --- src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts | 6 +++--- .../src/core/mocks/data/languages.data.ts | 4 ++++ .../src/core/mocks/domains/language.handlers.ts | 7 +++++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts b/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts index fc28b6f84b..bd5fda6a2e 100644 --- a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts +++ b/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts @@ -116,9 +116,9 @@ export class UmbPickerContext { const { asObservable } = await this.repository.requestItems(this.getSelection()); if (asObservable) { - this.#selectedItemsObserver = new UmbObserverController(this.host, asObservable(), (data) => { - this.#selectedItems.next(data); - }); + this.#selectedItemsObserver = new UmbObserverController(this.host, asObservable(), (data) => + this.#selectedItems.next(data) + ); } } diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/data/languages.data.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/data/languages.data.ts index 142e8b426d..5d0be1a5f6 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/data/languages.data.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/data/languages.data.ts @@ -16,6 +16,10 @@ class UmbLanguagesData extends UmbData { return this.data.find((item) => item.isoCode === isoCode); } + getItems(isoCodes: Array) { + return this.data.filter((item) => isoCodes.indexOf(item.isoCode || '') !== -1); + } + insert(language: LanguageResponseModel) { const foundIndex = this.data.findIndex((item) => item.isoCode === language.isoCode); diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/language.handlers.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/language.handlers.ts index 41158abe5b..b6e4557351 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/language.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/language.handlers.ts @@ -5,6 +5,13 @@ import { umbracoPath } from '@umbraco-cms/backoffice/utils'; // TODO: add schema export const handlers = [ + rest.get(umbracoPath('/language/item'), (req, res, ctx) => { + const isoCodes = req.url.searchParams.getAll('isoCode'); + if (!isoCodes) return; + const items = umbLanguagesData.getItems(isoCodes); + return res(ctx.status(200), ctx.json(items)); + }), + rest.get(umbracoPath('/language'), (req, res, ctx) => { const skip = req.url.searchParams.get('skip'); const skipNumber = skip ? Number.parseInt(skip) : undefined; From e4209d1e7e89f43580bb660219247b1aca85022f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Apr 2023 21:58:15 +0200 Subject: [PATCH 092/156] add getter for min a max --- .../libs/picker/picker.context.ts | 11 +++---- .../data-type-input.element.ts | 5 ++++ .../input-language-picker.element.ts | 29 +++++++++++++------ 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts b/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts index bd5fda6a2e..9b49179712 100644 --- a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts +++ b/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts @@ -1,4 +1,4 @@ -import { UmbItemRepository, UmbTreeRepository } from '@umbraco-cms/backoffice/repository'; +import { UmbItemRepository } from '@umbraco-cms/backoffice/repository'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { ArrayState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; import { createExtensionClass, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api'; @@ -14,7 +14,7 @@ import { UmbChangeEvent } from '@umbraco-cms/backoffice/events'; export class UmbPickerContext { host: UmbControllerHostElement; - modalAlias: UmbModalToken | string; + modalAlias: string | UmbModalToken; repository?: UmbItemRepository; #getUnique: (entry: ItemType) => string | undefined; @@ -36,7 +36,7 @@ export class UmbPickerContext { constructor( host: UmbControllerHostElement, repositoryAlias: string, - modalAlias: UmbModalToken | string, + modalAlias: string | UmbModalToken, getUniqueMethod?: (entry: ItemType) => string | undefined ) { this.host = host; @@ -74,13 +74,14 @@ export class UmbPickerContext { this.#selection.next(selection); } - // TODO: this need to accept an options object at some point to pass to the modal context - openPicker() { + // TODO: revisit this method. How do we best pass picker data? + openPicker(pickerData: any) { if (!this.modalContext) throw new Error('Modal context is not initialized'); const modalHandler = this.modalContext.open(this.modalAlias, { multiple: this.max === 1 ? false : true, selection: [...this.getSelection()], + ...pickerData, }); modalHandler?.onSubmit().then(({ selection }: any) => { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts index db4aafbef9..7e86e55ce4 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts @@ -44,11 +44,16 @@ export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) { * @attr * @default undefined */ + private _max: number | undefined; @property({ type: Number }) + public get max(): number | undefined { + return this._max; + } public set max(value: number | undefined) { if (value !== undefined) { this.#pickerContext.max = value; } + this._max = value; } /** diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts index 7de61d2d50..961f3f9572 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts @@ -21,10 +21,15 @@ export class UmbInputLanguagePickerElement extends FormControlMixin(UmbLitElemen * This is a minimum amount of selected items in this input. * @type {number} * @attr - * @default undefined + * @default 0 */ @property({ type: Number }) - min?: number; + public get min(): number { + return this.#pickerContext.min; + } + public set min(value: number) { + this.#pickerContext.min = value; + } /** * Min validation message. @@ -39,10 +44,15 @@ export class UmbInputLanguagePickerElement extends FormControlMixin(UmbLitElemen * This is a maximum amount of selected items in this input. * @type {number} * @attr - * @default undefined + * @default Infinite */ @property({ type: Number }) - max?: number; + public get max(): number { + return this.#pickerContext.max; + } + public set max(value: number) { + this.#pickerContext.max = value; + } /** * Max validation message. @@ -92,7 +102,7 @@ export class UmbInputLanguagePickerElement extends FormControlMixin(UmbLitElemen () => !!this.max && this._selectedIsoCodes.length > this.max ); - this.observe(this.#pickerContext.selection, (selection) => (this.selectedIsoCodes = selection)); + this.observe(this.#pickerContext.selection, (selection) => (this._selectedIsoCodes = selection)); this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems)); } @@ -101,14 +111,15 @@ export class UmbInputLanguagePickerElement extends FormControlMixin(UmbLitElemen } private _openPicker() { - // TODO: add filter - // filter: this.filter, - this.#pickerContext.openPicker(); + this.#pickerContext.openPicker({ + filter: this.filter, + hello: 'world', + }); } render() { return html` - ${this._items.map((item) => this._renderItem(item))} + ${this._items.map((item) => this._renderItem(item))} Date: Mon, 17 Apr 2023 22:00:41 +0200 Subject: [PATCH 093/156] clean up --- .../libs/picker/picker.context.ts | 2 +- .../data-type-input.element.ts | 27 +++++++++---------- .../input-language-picker.element.ts | 2 +- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts b/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts index 9b49179712..42f9ec025d 100644 --- a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts +++ b/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts @@ -75,7 +75,7 @@ export class UmbPickerContext { } // TODO: revisit this method. How do we best pass picker data? - openPicker(pickerData: any) { + openPicker(pickerData?: any) { if (!this.modalContext) throw new Error('Modal context is not initialized'); const modalHandler = this.modalContext.open(this.modalAlias, { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts index 7e86e55ce4..58d541eeb9 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts @@ -20,13 +20,14 @@ export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) { * This is a minimum amount of selected items in this input. * @type {number} * @attr - * @default undefined + * @default 0 */ @property({ type: Number }) - public set min(value: number | undefined) { - if (value !== undefined) { - this.#pickerContext.min = value; - } + public get min(): number { + return this.#pickerContext.min; + } + public set min(value: number) { + this.#pickerContext.min = value; } /** @@ -42,18 +43,14 @@ export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) { * This is a maximum amount of selected items in this input. * @type {number} * @attr - * @default undefined + * @default Infinity */ - private _max: number | undefined; @property({ type: Number }) - public get max(): number | undefined { - return this._max; + public get max(): number { + return this.#pickerContext.max; } - public set max(value: number | undefined) { - if (value !== undefined) { - this.#pickerContext.max = value; - } - this._max = value; + public set max(value: number) { + this.#pickerContext.max = value; } /** @@ -101,7 +98,7 @@ export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) { () => !!this.max && this._selectedIds.length > this.max ); - this.observe(this.#pickerContext.selection, (selection) => (this.selectedIds = selection)); + this.observe(this.#pickerContext.selection, (selection) => (this._selectedIds = selection)); this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems)); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts index 961f3f9572..53e5a7ff46 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts @@ -44,7 +44,7 @@ export class UmbInputLanguagePickerElement extends FormControlMixin(UmbLitElemen * This is a maximum amount of selected items in this input. * @type {number} * @attr - * @default Infinite + * @default Infinity */ @property({ type: Number }) public get max(): number { From d65cf550bcd46831eb486f2cd102fba41cfcb39f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 18 Apr 2023 12:55:53 +0200 Subject: [PATCH 094/156] initial sorting implementation --- .../PropertyTypeResponseModelBaseModel.ts | 21 +++---- .../filter-frozen-array.function.ts | 13 ++++ .../libs/observable-api/index.ts | 1 + .../libs/sorter/sorter.controller.ts | 55 +++++++++++----- ...-workspace-view-edit-properties.element.ts | 63 ++++++++++++------- ...pe-workspace-view-edit-property.element.ts | 6 +- ...nt-type-workspace-view-edit-tab.element.ts | 2 + ...rkspace-property-structure-helper.class.ts | 35 ++++++++--- .../workspace-structure-manager.class.ts | 24 +++++++ 9 files changed, 162 insertions(+), 58 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/libs/observable-api/filter-frozen-array.function.ts diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PropertyTypeResponseModelBaseModel.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PropertyTypeResponseModelBaseModel.ts index ad3a59bbbf..72adb84e18 100644 --- a/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PropertyTypeResponseModelBaseModel.ts +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PropertyTypeResponseModelBaseModel.ts @@ -6,15 +6,14 @@ import type { PropertyTypeAppearanceModel } from './PropertyTypeAppearanceModel' import type { PropertyTypeValidationModel } from './PropertyTypeValidationModel'; export type PropertyTypeResponseModelBaseModel = { - id?: string; - containerId?: string | null; - alias?: string; - name?: string; - description?: string | null; - dataTypeId?: string; - variesByCulture?: boolean; - variesBySegment?: boolean; - validation?: PropertyTypeValidationModel; - appearance?: PropertyTypeAppearanceModel; + id?: string; + containerId?: string | null; + alias?: string; + name?: string; + description?: string | null; + dataTypeId?: string; + variesByCulture?: boolean; + variesBySegment?: boolean; + validation?: PropertyTypeValidationModel; + appearance?: PropertyTypeAppearanceModel; }; - diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/filter-frozen-array.function.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/filter-frozen-array.function.ts new file mode 100644 index 0000000000..7d3e5a2e0c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/filter-frozen-array.function.ts @@ -0,0 +1,13 @@ +/** + * @export + * @method filterFrozenArray + * @param {Array} data - RxJS Subject to use for this Observable. + * @param {(entry: T) => boolean} filterMethod - Method to filter the array. + * @description - Creates a RxJS Observable from RxJS Subject. + * @example Example remove an entry of a ArrayState or a part of DeepState/ObjectState it which is an array. Where the key is unique and the item will be updated if matched with existing. + * const newDataSet = filterFrozenArray(mySubject.getValue(), x => x.id !== "myKey"); + * mySubject.next(newDataSet); + */ +export function filterFrozenArray(data: T[], filterMethod: (entry: T) => boolean): T[] { + return [...data].filter((x) => filterMethod(x)); +} diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/index.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/index.ts index c18d4495b7..e0edfe4be9 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/index.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/index.ts @@ -10,5 +10,6 @@ export * from './array-state'; export * from './object-state'; export * from './create-observable-part.function'; export * from './append-to-frozen-array.function'; +export * from './filter-frozen-array.function'; export * from './partial-update-frozen-array.function'; export * from './mapping-function'; diff --git a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts index 13014e52bb..554b9e5a4e 100644 --- a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts +++ b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts @@ -96,6 +96,8 @@ type INTERNAL_UmbSorterConfig = { placeholderIsInThisRow: boolean; horizontalPlaceAfter: boolean; }) => void; + performItemInsert?: (argument: { item: T; newIndex: number }) => Promise | boolean; + performItemRemove?: (argument: { item: T }) => Promise | boolean; }; // External type with some properties optional, as they have defaults: @@ -191,7 +193,10 @@ export class UmbSorterController implements UmbControllerInterface { // TODO: Clean up?? this.#observer.disconnect(); - this.#observer.observe(this.#containerElement, { childList: true, subtree: false }); + this.#observer.observe(this.#containerElement.shadowRoot ?? this.#containerElement, { + childList: true, + subtree: false, + }); } hostDisconnected() { // TODO: Clean up?? @@ -227,7 +232,7 @@ export class UmbSorterController implements UmbControllerInterface { } if (!this.#scrollElement) { - this.#scrollElement = getParentScrollElement(this.#host, true); + this.#scrollElement = getParentScrollElement(this.#containerElement, true); } const element = (event.target as HTMLElement).closest(this.#config.itemSelector); @@ -270,7 +275,7 @@ export class UmbSorterController implements UmbControllerInterface { // We must wait one frame before changing the look of the block. this.#rqaId = requestAnimationFrame(() => { - // It should be okay to use the same rqafId, as the move does not or is okay not to happen on first frame/drag-move. + // It should be okay to use the same rqaId, as the move does not or is okay not to happen on first frame/drag-move. this.#rqaId = undefined; if (this.#currentElement) { this.#currentElement.style.transform = ''; @@ -279,7 +284,7 @@ export class UmbSorterController implements UmbControllerInterface { }); }; - handleDragEnd = () => { + handleDragEnd = async () => { if (!this.#currentElement || !this.#currentItem) { return; } @@ -292,7 +297,7 @@ export class UmbSorterController implements UmbControllerInterface { this.stopAutoScroll(); this.removeAllowIndication(); - if (this.#currentContainerVM.sync(this.#currentElement, this) === false) { + if ((await this.#currentContainerVM.sync(this.#currentElement, this)) === false) { // Sync could not succeed, might be because item is not allowed here. this.#currentContainerVM = this; @@ -419,7 +424,11 @@ export class UmbSorterController implements UmbControllerInterface { } // We want to retrieve the children of the container, every time to ensure we got the right order and index - const orderedContainerElements = Array.from(this.#currentContainerElement.children); + const orderedContainerElements = Array.from( + this.#currentContainerElement.shadowRoot + ? this.#currentContainerElement.shadowRoot.children + : this.#currentContainerElement.children + ); const currentContainerRect = this.#currentContainerElement.getBoundingClientRect(); @@ -573,18 +582,20 @@ export class UmbSorterController implements UmbControllerInterface { }; move(orderedContainerElements: Array, newElIndex: number) { - if (!this.#currentElement || !this.#currentItem) return; + if (!this.#currentElement || !this.#currentItem || !this.#currentContainerElement) return; newElIndex = newElIndex === -1 ? orderedContainerElements.length : newElIndex; + const containerElement = this.#currentContainerElement.shadowRoot ?? this.#currentContainerElement; + const placeBeforeElement = orderedContainerElements[newElIndex]; if (placeBeforeElement) { // We do not need to move this, if the element to be placed before is it self. if (placeBeforeElement !== this.#currentElement) { - this.#currentContainerElement.insertBefore(this.#currentElement, placeBeforeElement); + containerElement.insertBefore(this.#currentElement, placeBeforeElement); } } else { - this.#currentContainerElement.appendChild(this.#currentElement); + containerElement.appendChild(this.#currentElement); } if (this.#config.onChange) { @@ -605,13 +616,18 @@ export class UmbSorterController implements UmbControllerInterface { return this.#model.find((entry: T) => this.#config.compareElementToModel(element, entry)); } - public removeItem(item: T) { + public async removeItem(item: T) { if (!item) { return null; } - const oldIndex = this.#model.indexOf(item); - if (oldIndex !== -1) { - return this.#model.splice(oldIndex, 1)[0]; + + if (this.#config.performItemRemove) { + return await this.#config.performItemRemove({ item }); + } else { + const oldIndex = this.#model.indexOf(item); + if (oldIndex !== -1) { + return this.#model.splice(oldIndex, 1)[0]; + } } return null; } @@ -620,7 +636,7 @@ export class UmbSorterController implements UmbControllerInterface { return this.#model.filter((x) => x !== item).length > 0; } - public sync(element: HTMLElement, fromVm: UmbSorterController) { + public async sync(element: HTMLElement, fromVm: UmbSorterController) { const movingItem = fromVm.getItemOfElement(element); if (!movingItem) { console.error('Could not find item of sync item'); @@ -651,11 +667,18 @@ export class UmbSorterController implements UmbControllerInterface { let newIndex = this.#model.length; if (nextEl) { // We had a reference element, we want to get the index of it. - // This is problem if a item is being moved forward? + // This is might a problem if a item is being moved forward? (was also like this in the AngularJS version...) newIndex = this.#model.findIndex((entry) => this.#config.compareElementToModel(nextEl! as HTMLElement, entry)); } - this.#model.splice(newIndex, 0, movingItem); + if (this.#config.performItemInsert) { + const result = await this.#config.performItemInsert({ item: movingItem, newIndex }); + if (result === false) { + return false; + } + } else { + this.#model.splice(newIndex, 0, movingItem); + } const eventData = { item: movingItem, fromController: fromVm, toController: this }; if (fromVm !== this) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts index 120de1b390..99818e9e19 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts @@ -2,18 +2,53 @@ import { css, html } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property, state } from 'lit/decorators.js'; import { repeat } from 'lit/directives/repeat.js'; +import { UmbSorterController, UmbSorterConfig } from '@umbraco-cms/backoffice/sorter'; +import { ifDefined } from 'lit/directives/if-defined.js'; import { UmbWorkspacePropertyStructureHelper } from '../../../../../shared/components/workspace/workspace-context/workspace-property-structure-helper.class'; import { PropertyContainerTypes } from '../../../../../shared/components/workspace/workspace-context/workspace-structure-manager.class'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import { DocumentTypePropertyTypeResponseModel } from '@umbraco-cms/backoffice/backend-api'; import { UMB_MODAL_CONTEXT_TOKEN, UMB_PROPERTY_SETTINGS_MODAL } from '@umbraco-cms/backoffice/modal'; import './document-type-workspace-view-edit-property.element'; -import { UmbSorterController } from '@umbraco-cms/sorter'; +const SORTER_CONFIG: UmbSorterConfig = { + compareElementToModel: (element: HTMLElement, model: DocumentTypePropertyTypeResponseModel) => { + return element.getAttribute('data-umb-property-id') === model.id; + }, + querySelectModelToElement: (container: HTMLElement, modelEntry: DocumentTypePropertyTypeResponseModel) => { + return container.querySelector('data-umb-property-id[' + modelEntry.id + ']'); + }, + identifier: 'content-type-property-sorter', + itemSelector: '[data-umb-property-id][data-property-of-owner-document]', +}; @customElement('umb-document-type-workspace-view-edit-properties') export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitElement { + #propertySorter = new UmbSorterController(this, { + ...SORTER_CONFIG, + performItemInsert: (args) => { + let sortOrder = 0; + if (this._propertyStructure.length > 0) { + if (args.newIndex === 0) { + // TODO: Remove as any when sortOrder is added to the model: + sortOrder = ((this._propertyStructure[0] as any).sortOrder ?? 0) - 1; + } else { + sortOrder = + ((this._propertyStructure[Math.min(args.newIndex, this._propertyStructure.length - 1)] as any).sortOrder ?? + 0) + 1; + } + } + console.log('insert', args.item.id, sortOrder); + return this._propertyStructureHelper.insertProperty(args.item, sortOrder); + }, + performItemRemove: (args) => { + console.log('remove', args.item.id); + return this._propertyStructureHelper.removeProperty(args.item.id!); + }, + }); + private _containerId: string | undefined; + @property({ type: String, attribute: 'container-id', reflect: false }) public get containerId(): string | undefined { return this._containerId; } @@ -47,8 +82,6 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle #modalContext?: typeof UMB_MODAL_CONTEXT_TOKEN.TYPE; - #propertySorter = new UmbSorterController(this, sorterConfig); - constructor() { super(); @@ -79,6 +112,11 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle (property) => property.alias, (property) => html` { this._propertyStructureHelper.partialUpdateProperty(property.id, event.detail); @@ -99,25 +137,6 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle border-bottom: 0; } - .property { - display: grid; - grid-template-columns: 200px auto; - column-gap: var(--uui-size-layout-2); - border-bottom: 1px solid var(--uui-color-divider); - padding: var(--uui-size-layout-1) 0; - container-type: inline-size; - } - - .property > div { - grid-column: span 2; - } - - @container (width > 600px) { - .property:not([orientation='vertical']) > div { - grid-column: span 1; - } - } - #add { width: 100%; } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts index 6b0b0d3ea8..9e08199e49 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts @@ -50,7 +50,7 @@ export class UmbDocumentTypeWorkspacePropertyElement extends LitElement { }}>

-
+
` : ''; } @@ -95,6 +95,10 @@ export class UmbDocumentTypeWorkspacePropertyElement extends LitElement { height: min-content; z-index: 2; } + + #editor { + background-color: var(--uui-color-background); + } `, ]; } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-tab.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-tab.element.ts index 6b3c935ea8..8bf2ac1618 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-tab.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-tab.element.ts @@ -87,6 +87,7 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { ? html` @@ -97,6 +98,7 @@ export class UmbDocumentTypeWorkspaceViewEditTabElement extends UmbLitElement { (group) => group.name, (group) => html` ` diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-property-structure-helper.class.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-property-structure-helper.class.ts index 8a3f2e2844..eae3858873 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-property-structure-helper.class.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-property-structure-helper.class.ts @@ -1,6 +1,9 @@ import { UmbDocumentWorkspaceContext } from '../../../../documents/documents/workspace/document-workspace.context'; import { PropertyContainerTypes } from './workspace-structure-manager.class'; -import { DocumentTypePropertyTypeResponseModel } from '@umbraco-cms/backoffice/backend-api'; +import { + DocumentTypePropertyTypeResponseModel, + PropertyTypeResponseModelBaseModel, +} from '@umbraco-cms/backoffice/backend-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbContextConsumerController, UMB_ENTITY_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/context-api'; import { ArrayState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; @@ -20,6 +23,8 @@ export class UmbWorkspacePropertyStructureHelper { constructor(host: UmbControllerHostElement) { this.#host = host; + // TODO: Remove as any when sortOrder is implemented: + this.#propertyStructure.sortBy((a, b) => ((a as any).sortOrder ?? 0) - ((b as any).sortOrder ?? 0)); this.#init = new UmbContextConsumerController(host, UMB_ENTITY_WORKSPACE_CONTEXT, (context) => { this.#workspaceContext = context as UmbDocumentWorkspaceContext; this._observeGroupContainers(); @@ -86,11 +91,6 @@ export class UmbWorkspacePropertyStructureHelper { } }); - if (_propertyStructure.length > 0) { - // TODO: End-point: Missing sort order? - //_propertyStructure = _propertyStructure.sort((a, b) => (a.sortOrder || 0) - (b.sortOrder || 0)); - } - // Fire update to subscribers: this.#propertyStructure.next(_propertyStructure); }, @@ -101,11 +101,30 @@ export class UmbWorkspacePropertyStructureHelper { // TODO: consider moving this to another class, to separate 'viewer' from 'manipulator': /** Manipulate methods: */ - async addProperty(ownerKey?: string, sortOrder?: number) { + async addProperty(ownerId?: string, sortOrder?: number) { await this.#init; if (!this.#workspaceContext) return; - return await this.#workspaceContext.structure.createProperty(null, ownerKey, sortOrder); + return await this.#workspaceContext.structure.createProperty(null, ownerId, sortOrder); + } + + async insertProperty(property: PropertyTypeResponseModelBaseModel, sortOrder = 0) { + await this.#init; + if (!this.#workspaceContext) return false; + + const newProperty = { ...property, sortOrder }; + + // TODO: Remove as any when server model has gotten sortOrder: + await this.#workspaceContext.structure.insertProperty(null, newProperty); + return true; + } + + async removeProperty(propertyId: string) { + await this.#init; + if (!this.#workspaceContext) return false; + + await this.#workspaceContext.structure.removeProperty(null, propertyId); + return true; } // Takes optional arguments as this is easier for the implementation in the view: diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-structure-manager.class.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-structure-manager.class.ts index fd6d6ad19b..7d8d2f84d0 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-structure-manager.class.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-structure-manager.class.ts @@ -13,6 +13,8 @@ import { UmbObserverController, MappingFunction, partialUpdateFrozenArray, + appendToFrozenArray, + filterFrozenArray, } from '@umbraco-cms/backoffice/observable-api'; export type PropertyContainerTypes = 'Group' | 'Tab'; @@ -218,6 +220,28 @@ export class UmbWorkspacePropertyStructureManager x.id === documentTypeId)?.properties ?? []; + + const properties = appendToFrozenArray(frozenProperties, property, (x) => x.id === property.id); + + this.#documentTypes.updateOne(documentTypeId, { properties }); + } + + async removeProperty(documentTypeId: string | null, propertyId: string) { + await this.#init; + documentTypeId = documentTypeId ?? this.#rootDocumentTypeId!; + + const frozenProperties = this.#documentTypes.getValue().find((x) => x.id === documentTypeId)?.properties ?? []; + + const properties = filterFrozenArray(frozenProperties, (x) => x.id === propertyId); + + this.#documentTypes.updateOne(documentTypeId, { properties }); + } + async updateProperty( documentTypeId: string | null, propertyId: string, From 12ba3536c1d135717b6f7b71adf4719a575bf6a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 18 Apr 2023 13:21:12 +0200 Subject: [PATCH 095/156] working drag --- .../libs/sorter/sorter.controller.ts | 18 ++++++++++++++---- ...e-workspace-view-edit-properties.element.ts | 6 ++++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts index 554b9e5a4e..c703df63de 100644 --- a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts +++ b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts @@ -66,6 +66,7 @@ type INTERNAL_UmbSorterConfig = { querySelectModelToElement: (container: HTMLElement, modelEntry: T) => HTMLElement | null; identifier: string; itemSelector: string; + disabledItemSelector?: string; containerSelector: string; ignorerSelector: string; placeholderClass: string; @@ -115,7 +116,7 @@ export type UmbSorterConfig = Omit< */ export class UmbSorterController implements UmbControllerInterface { #host; - #config; + #config: INTERNAL_UmbSorterConfig; #observer; #model: Array = []; @@ -208,8 +209,10 @@ export class UmbSorterController implements UmbControllerInterface { setupIgnorerElements(element, this.#config.ignorerSelector); } - element.draggable = true; - element.addEventListener('dragstart', this.handleDragStart); + if (!this.#config.disabledItemSelector || !element.matches(this.#config.disabledItemSelector)) { + element.draggable = true; + element.addEventListener('dragstart', this.handleDragStart); + } } destroyItem(element: HTMLElement) { @@ -367,7 +370,7 @@ export class UmbSorterController implements UmbControllerInterface { this.#currentDragRect = this.#currentDragElement!.getBoundingClientRect(); const insideCurrentRect = isWithinRect(this.#dragX, this.#dragY, this.#currentDragRect); if (!insideCurrentRect) { - if (this.#rqaId === null) { + if (this.#rqaId === undefined) { this.#rqaId = requestAnimationFrame(this.moveCurrentElement); } } @@ -380,6 +383,8 @@ export class UmbSorterController implements UmbControllerInterface { return; } + console.log('moveCurrentElement!!!'); + const currentElementRect = this.#currentElement.getBoundingClientRect(); const insideCurrentRect = isWithinRect(this.#dragX, this.#dragY, currentElementRect); if (insideCurrentRect) { @@ -430,6 +435,8 @@ export class UmbSorterController implements UmbControllerInterface { : this.#currentContainerElement.children ); + console.log('orderedContainerElements', orderedContainerElements); + const currentContainerRect = this.#currentContainerElement.getBoundingClientRect(); // gather elements on the same row. @@ -665,6 +672,9 @@ export class UmbSorterController implements UmbControllerInterface { } let newIndex = this.#model.length; + + console.log('NextEl:', nextEl); + if (nextEl) { // We had a reference element, we want to get the index of it. // This is might a problem if a item is being moved forward? (was also like this in the AngularJS version...) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts index 99818e9e19..185044e267 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts @@ -19,7 +19,8 @@ const SORTER_CONFIG: UmbSorterConfig = { return container.querySelector('data-umb-property-id[' + modelEntry.id + ']'); }, identifier: 'content-type-property-sorter', - itemSelector: '[data-umb-property-id][data-property-of-owner-document]', + itemSelector: '[data-umb-property-id]', + disabledItemSelector: ':not([data-property-of-owner-document])', }; @customElement('umb-document-type-workspace-view-edit-properties') export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitElement { @@ -28,6 +29,7 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle performItemInsert: (args) => { let sortOrder = 0; if (this._propertyStructure.length > 0) { + console.log('args.newIndex', args.newIndex); if (args.newIndex === 0) { // TODO: Remove as any when sortOrder is added to the model: sortOrder = ((this._propertyStructure[0] as any).sortOrder ?? 0) - 1; @@ -109,7 +111,7 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle render() { return html`${repeat( this._propertyStructure, - (property) => property.alias, + (property) => property.alias ?? '' + property.containerId ?? '' + (property as any).sortOrder ?? '', (property) => html` Date: Tue, 18 Apr 2023 13:22:28 +0200 Subject: [PATCH 096/156] clean up --- src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts index c703df63de..687d43b378 100644 --- a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts +++ b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts @@ -383,8 +383,6 @@ export class UmbSorterController implements UmbControllerInterface { return; } - console.log('moveCurrentElement!!!'); - const currentElementRect = this.#currentElement.getBoundingClientRect(); const insideCurrentRect = isWithinRect(this.#dragX, this.#dragY, currentElementRect); if (insideCurrentRect) { @@ -435,8 +433,6 @@ export class UmbSorterController implements UmbControllerInterface { : this.#currentContainerElement.children ); - console.log('orderedContainerElements', orderedContainerElements); - const currentContainerRect = this.#currentContainerElement.getBoundingClientRect(); // gather elements on the same row. @@ -673,8 +669,6 @@ export class UmbSorterController implements UmbControllerInterface { let newIndex = this.#model.length; - console.log('NextEl:', nextEl); - if (nextEl) { // We had a reference element, we want to get the index of it. // This is might a problem if a item is being moved forward? (was also like this in the AngularJS version...) From f25880706f4e62df3bc9184a3b4a777372336c11 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 18 Apr 2023 13:29:14 +0200 Subject: [PATCH 097/156] add $type to folder mock data --- src/Umbraco.Web.UI.Client/src/core/mocks/data/utils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/data/utils.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/data/utils.ts index 5c847f47e8..527d5c6304 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/data/utils.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/data/utils.ts @@ -25,6 +25,7 @@ export const createEntityTreeItem = (item: any): EntityTreeItemResponseModel => export const createFolderTreeItem = (item: any): FolderTreeItemResponseModel => { return { ...createEntityTreeItem(item), + $type: 'FolderTreeItemResponseModel', isFolder: item.isFolder, }; }; From a3d85e89730d2805ac819931637f47945881ac08 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 18 Apr 2023 13:29:31 +0200 Subject: [PATCH 098/156] remove type from mock database --- .../src/core/mocks/data/data-type.data.ts | 134 +++++++----------- 1 file changed, 51 insertions(+), 83 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/data/data-type.data.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/data/data-type.data.ts index fccf52dbfa..dfea186e10 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/data/data-type.data.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/data/data-type.data.ts @@ -4,21 +4,20 @@ import type { FolderTreeItemResponseModel, DataTypeResponseModel, CreateFolderRequestModel, + DataTypeItemResponseModel, } from '@umbraco-cms/backoffice/backend-api'; // TODO: investigate why we don't get an type as part of the DataTypeModel -export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | FolderTreeItemResponseModel> = [ +export const data: Array = [ { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Folder 1', id: 'dt-folder1', parentId: null, isFolder: true, }, { - $type: 'data-type', - type: 'data-type', + $type: '', id: '0cc0eba1-9960-42c9-bf9b-60e150b429ae', parentId: null, name: 'Textstring', @@ -27,8 +26,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Text', id: 'dt-textBox', parentId: null, @@ -42,8 +40,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde ], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Text Area', id: 'dt-textArea', parentId: null, @@ -52,8 +49,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'My JS Property Editor', id: 'dt-custom', parentId: null, @@ -62,8 +58,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Color Picker', id: 'dt-colorPicker', parentId: null, @@ -118,8 +113,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde ], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Content Picker', id: 'dt-contentPicker', parentId: null, @@ -133,8 +127,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde ], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Eye Dropper', id: 'dt-eyeDropper', parentId: null, @@ -170,8 +163,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde ], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Multi URL Picker', id: 'dt-multiUrlPicker', parentId: null, @@ -201,8 +193,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde ], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Multi Node Tree Picker', id: 'dt-multiNodeTreePicker', parentId: null, @@ -211,8 +202,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Date Picker', id: 'dt-datePicker', parentId: null, @@ -230,9 +220,8 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde ], }, { - $type: 'data-type', + $type: '', name: 'Date Picker With Time', - type: 'data-type', id: 'dt-datePicker-time', parentId: null, propertyEditorAlias: 'Umbraco.DateTime', @@ -249,9 +238,8 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde ], }, { - $type: 'data-type', + $type: '', name: 'Time', - type: 'data-type', id: 'dt-time', parentId: null, propertyEditorAlias: 'Umbraco.DateTime', @@ -268,8 +256,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde ], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Email', id: 'dt-email', parentId: null, @@ -278,8 +265,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Multiple Text String', id: 'dt-multipleTextString', parentId: null, @@ -297,8 +283,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde ], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Dropdown', id: 'dt-dropdown', parentId: null, @@ -307,8 +292,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Slider', id: 'dt-slider', parentId: null, @@ -342,8 +326,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde ], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Toggle', id: 'dt-toggle', parentId: null, @@ -369,8 +352,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde ], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Tags', id: 'dt-tags', parentId: null, @@ -379,8 +361,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Markdown Editor', id: 'dt-markdownEditor', parentId: null, @@ -389,8 +370,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Radio Button List', id: 'dt-radioButtonList', parentId: null, @@ -408,8 +388,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde ], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Checkbox List', id: 'dt-checkboxList', parentId: null, @@ -427,8 +406,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde ], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Block List', id: 'dt-blockList', parentId: null, @@ -437,8 +415,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Media Picker', id: 'dt-mediaPicker', parentId: null, @@ -447,8 +424,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Image Cropper', id: 'dt-imageCropper', parentId: null, @@ -457,8 +433,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Upload Field', id: 'dt-uploadField', parentId: null, @@ -472,8 +447,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde ], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Block Grid', id: 'dt-blockGrid', parentId: null, @@ -482,8 +456,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Collection View', id: 'dt-collectionView', parentId: null, @@ -492,8 +465,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Icon Picker', id: 'dt-iconPicker', parentId: null, @@ -502,8 +474,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Number Range', id: 'dt-numberRange', parentId: null, @@ -512,8 +483,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Order Direction', id: 'dt-orderDirection', parentId: null, @@ -522,8 +492,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Overlay Size', id: 'dt-overlaySize', parentId: null, @@ -532,8 +501,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Rich Text Editor', id: 'dt-richTextEditor', parentId: null, @@ -542,8 +510,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Label', id: 'dt-label', parentId: null, @@ -552,8 +519,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Integer', id: 'dt-integer', parentId: null, @@ -562,8 +528,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Decimal', id: 'dt-decimal', parentId: null, @@ -572,8 +537,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'User Picker', id: 'dt-userPicker', parentId: null, @@ -582,8 +546,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Member Picker', id: 'dt-memberPicker', parentId: null, @@ -592,8 +555,7 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde values: [], }, { - $type: 'data-type', - type: 'data-type', + $type: '', name: 'Member Group Picker', id: 'dt-memberGroupPicker', parentId: null, @@ -603,6 +565,13 @@ export const data: Array<(DataTypeResponseModel & { type: 'data-type' }) | Folde }, ]; +const createDataTypeItem = (item: DataTypeResponseModel | FolderTreeItemResponseModel): DataTypeItemResponseModel => { + return { + id: item.id, + name: item.name, + }; +}; + // Temp mocked database // TODO: all properties are optional in the server schema. I don't think this is correct. // eslint-disable-next-line @typescript-eslint/ban-ts-comment @@ -622,9 +591,9 @@ class UmbDataTypeData extends UmbEntityData createFolderTreeItem(item)); } - getTreeItem(ids: Array): Array { + getItems(ids: Array): Array { const items = this.data.filter((item) => ids.includes(item.id ?? '')); - return items.map((item) => createFolderTreeItem(item)); + return items.map((item) => createDataTypeItem(item)); } createFolder(folder: CreateFolderRequestModel & { id: string | undefined }) { @@ -632,8 +601,7 @@ class UmbDataTypeData extends UmbEntityData Date: Tue, 18 Apr 2023 13:29:48 +0200 Subject: [PATCH 099/156] rename data base get item method --- .../src/core/mocks/domains/data-type/item.handlers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/data-type/item.handlers.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/data-type/item.handlers.ts index 24d17c79e0..5601aae644 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/data-type/item.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/data-type/item.handlers.ts @@ -7,7 +7,7 @@ export const itemHandlers = [ rest.get(umbracoPath(`${slug}/item`), (req, res, ctx) => { const ids = req.url.searchParams.getAll('id'); if (!ids) return; - const items = umbDataTypeData.getTreeItem(ids); + const items = umbDataTypeData.getItems(ids); return res(ctx.status(200), ctx.json(items)); }), ]; From 36607d9e1e00c2cbacc12ad77c86b353f2bbd40a Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 18 Apr 2023 13:30:54 +0200 Subject: [PATCH 100/156] rename methods to legacy to prevent naming clash --- .../libs/repository/tree-repository.interface.ts | 4 ++-- .../document-types/repository/document-type.repository.ts | 4 ++-- .../documents/documents/repository/document.repository.ts | 4 ++-- .../media/media-types/repository/media-type.repository.ts | 4 ++-- .../media/media/entity-bulk-actions/trash/trash.action.ts | 2 +- .../src/backoffice/media/media/repository/media.repository.ts | 4 ++-- .../member-groups/repository/member-group.repository.ts | 4 ++-- .../members/member-types/repository/member-type.repository.ts | 4 ++-- .../members/members/repository/member.repository.ts | 4 ++-- .../relation-types/repository/relation-type.repository.ts | 4 ++-- .../input-media-picker/input-media-picker.element.ts | 2 +- .../input-template-picker/input-template-picker.element.ts | 2 +- .../stylesheets/repository/stylesheet.repository.ts | 4 ++-- .../templating/templates/repository/template.repository.ts | 4 ++-- .../dictionary/repository/dictionary.repository.ts | 4 ++-- 15 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/repository/tree-repository.interface.ts b/src/Umbraco.Web.UI.Client/libs/repository/tree-repository.interface.ts index ea3f76cc71..17ddc1a2d4 100644 --- a/src/Umbraco.Web.UI.Client/libs/repository/tree-repository.interface.ts +++ b/src/Umbraco.Web.UI.Client/libs/repository/tree-repository.interface.ts @@ -19,7 +19,7 @@ export interface UmbTreeRepository; // TODO: remove this when all repositories are migrated to the new interface items interface - requestTreeItems?: (uniques: string[]) => Promise<{ + requestItemsLegacy?: (uniques: string[]) => Promise<{ data: Array | undefined; error: ProblemDetailsModel | undefined; asObservable?: () => Observable; @@ -29,5 +29,5 @@ export interface UmbTreeRepository Promise>; // TODO: remove this when all repositories are migrated to the new items interface - treeItems?: (uniques: string[]) => Promise>; + itemsLegacy?: (uniques: string[]) => Promise>; } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/document-type.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/document-type.repository.ts index 78c9ac203c..7f9856c282 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/document-type.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/document-type.repository.ts @@ -77,7 +77,7 @@ export class UmbDocumentTypeRepository implements UmbTreeRepository, U return { data, error, asObservable: () => this.#treeStore!.childrenOf(parentId) }; } - async requestTreeItems(ids: Array) { + async requestItemsLegacy(ids: Array) { await this.#init; if (!ids) { @@ -100,7 +100,7 @@ export class UmbDocumentTypeRepository implements UmbTreeRepository, U return this.#treeStore!.childrenOf(parentId); } - async treeItems(ids: Array) { + async itemsLegacy(ids: Array) { await this.#init; return this.#treeStore!.items(ids); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/document.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/document.repository.ts index 91d485f05c..266ba1452e 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/document.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/document.repository.ts @@ -82,7 +82,7 @@ export class UmbDocumentRepository implements UmbTreeRepository, UmbDe return { data, error, asObservable: () => this.#treeStore!.childrenOf(parentId) }; } - async requestTreeItems(ids: Array) { + async requestItemsLegacy(ids: Array) { await this.#init; if (!ids) { @@ -105,7 +105,7 @@ export class UmbDocumentRepository implements UmbTreeRepository, UmbDe return this.#treeStore!.childrenOf(parentId); } - async treeItems(ids: Array) { + async itemsLegacy(ids: Array) { await this.#init; return this.#treeStore!.items(ids); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/repository/media-type.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/repository/media-type.repository.ts index 898e1ab966..8b86ca2a60 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/repository/media-type.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/repository/media-type.repository.ts @@ -73,7 +73,7 @@ export class UmbMediaTypeRepository implements UmbTreeRepository { return { data, error, asObservable: () => this.#treeStore!.childrenOf(parentId) }; } - async requestTreeItems(ids: Array) { + async requestItemsLegacy(ids: Array) { await this.#init; if (!ids) { @@ -96,7 +96,7 @@ export class UmbMediaTypeRepository implements UmbTreeRepository { return this.#treeStore!.childrenOf(parentId); } - async treeItems(ids: Array) { + async itemsLegacy(ids: Array) { await this.#init; return this.#treeStore!.items(ids); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/entity-bulk-actions/trash/trash.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/entity-bulk-actions/trash/trash.action.ts index 4a40576216..ef1200f2e9 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/entity-bulk-actions/trash/trash.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/entity-bulk-actions/trash/trash.action.ts @@ -21,7 +21,7 @@ export class UmbMediaTrashEntityBulkAction extends UmbEntityBulkActionBase this.#treeStore!.childrenOf(parentId) }; } - async requestTreeItems(ids: Array) { + async requestItemsLegacy(ids: Array) { await this.#init; if (!ids) { @@ -119,7 +119,7 @@ export class UmbMediaRepository return this.#treeStore!.childrenOf(parentId); } - async treeItems(ids: Array) { + async itemsLegacy(ids: Array) { await this.#init; return this.#treeStore!.items(ids); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/repository/member-group.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/repository/member-group.repository.ts index 572e6d7fd0..66b5214b9c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/repository/member-group.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/repository/member-group.repository.ts @@ -59,7 +59,7 @@ export class UmbMemberGroupRepository implements UmbTreeRepository, UmbDetailRep return { data: undefined, error }; } - async requestTreeItems(ids: Array) { + async requestItemsLegacy(ids: Array) { await this.#init; if (!ids) { @@ -82,7 +82,7 @@ export class UmbMemberGroupRepository implements UmbTreeRepository, UmbDetailRep return this.#treeStore!.childrenOf(parentId); } - async treeItems(ids: Array) { + async itemsLegacy(ids: Array) { await this.#init; return this.#treeStore!.items(ids); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/repository/member-type.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/repository/member-type.repository.ts index 620347e0b4..5eb492cc40 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/repository/member-type.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/repository/member-type.repository.ts @@ -77,7 +77,7 @@ export class UmbMemberTypeRepository implements UmbTreeRepository, return { data, error, asObservable: () => this.#treeStore!.childrenOf(parentId) }; } - async requestTreeItems(ids: Array) { + async requestItemsLegacy(ids: Array) { await this.#init; if (!ids) { @@ -100,7 +100,7 @@ export class UmbMemberTypeRepository implements UmbTreeRepository, return this.#treeStore!.childrenOf(parentId); } - async treeItems(ids: Array) { + async itemsLegacy(ids: Array) { await this.#init; return this.#treeStore!.items(ids); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/repository/member.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/repository/member.repository.ts index cf91bf0bf9..2045c3d3ee 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/repository/member.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/repository/member.repository.ts @@ -58,7 +58,7 @@ export class UmbMemberRepository implements UmbTreeRepository { return { data: undefined, error }; } - async requestTreeItems(ids: Array) { + async requestItemsLegacy(ids: Array) { await this.#init; if (!ids) { @@ -81,7 +81,7 @@ export class UmbMemberRepository implements UmbTreeRepository { return this.#treeStore!.childrenOf(parentId); } - async treeItems(ids: Array) { + async itemsLegacy(ids: Array) { await this.#init; return this.#treeStore!.items(ids); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/relation-type.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/relation-type.repository.ts index 52249a2896..b24c3b5e1b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/relation-type.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/relation-types/repository/relation-type.repository.ts @@ -74,7 +74,7 @@ export class UmbRelationTypeRepository return { data: undefined, error }; } - async requestTreeItems(ids: Array) { + async requestItemsLegacy(ids: Array) { if (!ids) throw new Error('Ids are missing'); await this.#init; @@ -93,7 +93,7 @@ export class UmbRelationTypeRepository return this.#treeStore!.childrenOf(parentId); } - async treeItems(ids: Array) { + async itemsLegacy(ids: Array) { await this.#init; return this.#treeStore!.items(ids); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-media-picker/input-media-picker.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-media-picker/input-media-picker.element.ts index f324ca44be..cf3afb8554 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-media-picker/input-media-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-media-picker/input-media-picker.element.ts @@ -129,7 +129,7 @@ export class UmbInputMediaPickerElement extends FormControlMixin(UmbLitElement) this._pickedItemsObserver?.destroy(); // TODO: consider changing this to the list data endpoint when it is available - const { asObservable } = await this._repository.requestTreeItems(this._selectedIds); + const { asObservable } = await this._repository.requestItemsLegacy(this._selectedIds); if (!asObservable) return; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-template-picker/input-template-picker.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-template-picker/input-template-picker.element.ts index aa47ff72d6..770ec1cfd7 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-template-picker/input-template-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-template-picker/input-template-picker.element.ts @@ -87,7 +87,7 @@ export class UmbInputTemplatePickerElement extends FormControlMixin(UmbLitElemen async #observePickedTemplates() { this.observe( - await this._templateRepository.treeItems(this._allowedKeys), + await this._templateRepository.itemsLegacy(this._allowedKeys), (data) => { this._pickedTemplates = data; }, diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/templating/stylesheets/repository/stylesheet.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/templating/stylesheets/repository/stylesheet.repository.ts index fd73a0cda1..6660a94e1d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/templating/stylesheets/repository/stylesheet.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/templating/stylesheets/repository/stylesheet.repository.ts @@ -76,7 +76,7 @@ export class UmbStylesheetRepository return { data, error, asObservable: () => this.#treeStore!.childrenOf(path) }; } - async requestTreeItems(paths: Array) { + async requestItemsLegacy(paths: Array) { if (!paths) throw new Error('Paths are missing'); await this.#init; const { data, error } = await this.#treeDataSource.getItems(paths); @@ -94,7 +94,7 @@ export class UmbStylesheetRepository return this.#treeStore!.childrenOf(parentPath); } - async treeItems(paths: Array) { + async itemsLegacy(paths: Array) { if (!paths) throw new Error('Paths are missing'); await this.#init; return this.#treeStore!.items(paths); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/repository/template.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/repository/template.repository.ts index 0ec0c4baa7..5bfdb6c6bd 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/repository/template.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/repository/template.repository.ts @@ -82,7 +82,7 @@ export class UmbTemplateRepository return { data, error, asObservable: () => this.#treeStore!.childrenOf(parentId) }; } - async requestTreeItems(ids: Array) { + async requestItemsLegacy(ids: Array) { await this.#init; if (!ids) { @@ -105,7 +105,7 @@ export class UmbTemplateRepository return this.#treeStore!.childrenOf(parentId); } - async treeItems(ids: Array) { + async itemsLegacy(ids: Array) { await this.#init; return this.#treeStore!.items(ids); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/repository/dictionary.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/repository/dictionary.repository.ts index 0ce6e7db0f..b231ade1a0 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/repository/dictionary.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/repository/dictionary.repository.ts @@ -86,7 +86,7 @@ export class UmbDictionaryRepository return { data, error, asObservable: () => this.#treeStore!.childrenOf(parentId) }; } - async requestTreeItems(ids: Array) { + async requestItemsLegacy(ids: Array) { await this.#init; if (!ids) { @@ -109,7 +109,7 @@ export class UmbDictionaryRepository return this.#treeStore!.childrenOf(parentId); } - async treeItems(ids: Array) { + async itemsLegacy(ids: Array) { await this.#init; return this.#treeStore!.items(ids); } From 431cef5c44c2afebb2d7b5c3f1495d0b898bd0f4 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 18 Apr 2023 13:31:07 +0200 Subject: [PATCH 101/156] data and error are optional --- .../libs/repository/item-repository.interface.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/repository/item-repository.interface.ts b/src/Umbraco.Web.UI.Client/libs/repository/item-repository.interface.ts index 74395f85de..3f92cb70e8 100644 --- a/src/Umbraco.Web.UI.Client/libs/repository/item-repository.interface.ts +++ b/src/Umbraco.Web.UI.Client/libs/repository/item-repository.interface.ts @@ -3,8 +3,8 @@ import { ItemResponseModelBaseModel, ProblemDetailsModel } from '@umbraco-cms/ba export interface UmbItemRepository { requestItems: (uniques: string[]) => Promise<{ - data: Array | undefined; - error: ProblemDetailsModel | undefined; + data?: Array | undefined; + error?: ProblemDetailsModel | undefined; asObservable?: () => Observable>; }>; items: (uniques: string[]) => Promise>>; From ca553d9fd933de953b011e08a4f65dbb88099594 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 18 Apr 2023 13:31:20 +0200 Subject: [PATCH 102/156] add data type item store --- .../repository/data-type-item.store.ts | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type-item.store.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type-item.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type-item.store.ts new file mode 100644 index 0000000000..2a16ad7b55 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type-item.store.ts @@ -0,0 +1,36 @@ +import { DataTypeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; +import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; +import { UmbItemStore, UmbStoreBase } from '@umbraco-cms/backoffice/store'; +import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; + +/** + * @export + * @class UmbDataTypeItemStore + * @extends {UmbStoreBase} + * @description - Data Store for Data Type items + */ + +export class UmbDataTypeItemStore + extends UmbStoreBase + implements UmbItemStore +{ + /** + * Creates an instance of UmbDataTypeItemStore. + * @param {UmbControllerHostElement} host + * @memberof UmbDataTypeItemStore + */ + constructor(host: UmbControllerHostElement) { + super( + host, + UMB_DATA_TYPE_ITEM_STORE_CONTEXT_TOKEN.toString(), + new ArrayState([], (x) => x.id) + ); + } + + items(ids: Array) { + return this._data.getObservablePart((items) => items.filter((item) => ids.includes(item.id ?? ''))); + } +} + +export const UMB_DATA_TYPE_ITEM_STORE_CONTEXT_TOKEN = new UmbContextToken('UmbDataTypeItemStore'); From d959c7be02b79081b0adb63c7043fc9ef0886bf9 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 18 Apr 2023 13:31:32 +0200 Subject: [PATCH 103/156] add data type item data source --- .../sources/data-type-item.server.data.ts | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/sources/data-type-item.server.data.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/sources/data-type-item.server.data.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/sources/data-type-item.server.data.ts new file mode 100644 index 0000000000..ae7943c5ab --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/sources/data-type-item.server.data.ts @@ -0,0 +1,39 @@ +import type { UmbItemDataSource } from '@umbraco-cms/backoffice/repository'; +import { DataTypeItemResponseModel, DataTypeResource } from '@umbraco-cms/backoffice/backend-api'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; +import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; + +/** + * A data source for Data Type items that fetches data from the server + * @export + * @class UmbDataTypeItemServerDataSource + * @implements {DocumentTreeDataSource} + */ +export class UmbDataTypeItemServerDataSource implements UmbItemDataSource { + #host: UmbControllerHostElement; + + /** + * Creates an instance of UmbDataTypeItemServerDataSource. + * @param {UmbControllerHostElement} host + * @memberof UmbDataTypeItemServerDataSource + */ + constructor(host: UmbControllerHostElement) { + this.#host = host; + } + + /** + * Fetches the items for the given ids from the server + * @param {Array} ids + * @return {*} + * @memberof UmbDataTypeItemServerDataSource + */ + async getItems(ids: Array) { + if (!ids) throw new Error('Ids are missing'); + return tryExecuteAndNotify( + this.#host, + DataTypeResource.getDataTypeItem({ + id: ids, + }) + ); + } +} From 36e90edef6bbaf0fbe1266bb5ab00f24c655ba8c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 18 Apr 2023 13:31:50 +0200 Subject: [PATCH 104/156] update repository to use the correct data source and store to get items --- .../repository/data-type.repository.ts | 70 +++++++++++-------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.repository.ts index 21a4d02041..8c9d99ad8f 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.repository.ts @@ -3,18 +3,15 @@ import { UmbDataTypeStore, UMB_DATA_TYPE_STORE_CONTEXT_TOKEN } from './data-type import { UmbDataTypeServerDataSource } from './sources/data-type.server.data'; import { UmbDataTypeTreeStore, UMB_DATA_TYPE_TREE_STORE_CONTEXT_TOKEN } from './data-type.tree.store'; import { UmbDataTypeFolderServerDataSource } from './sources/data-type-folder.server.data'; -import type { - UmbTreeDataSource, - UmbTreeRepository, - UmbDetailRepository, - UmbFolderDataSource, - UmbDataSource, -} from '@umbraco-cms/backoffice/repository'; +import { UmbDataTypeItemServerDataSource } from './sources/data-type-item.server.data'; +import { UMB_DATA_TYPE_ITEM_STORE_CONTEXT_TOKEN, UmbDataTypeItemStore } from './data-type-item.store'; +import type { UmbTreeRepository, UmbDetailRepository, UmbItemRepository } from '@umbraco-cms/backoffice/repository'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; import { CreateDataTypeRequestModel, CreateFolderRequestModel, + DataTypeItemResponseModel, DataTypeResponseModel, FolderModelBaseModel, FolderTreeItemResponseModel, @@ -25,20 +22,23 @@ import { UmbFolderRepository } from '@umbraco-cms/backoffice/repository'; export class UmbDataTypeRepository implements + UmbItemRepository, UmbTreeRepository, UmbDetailRepository, UmbFolderRepository { - #init!: Promise; + #init: Promise; #host: UmbControllerHostElement; - #treeSource: UmbTreeDataSource; - #detailSource: UmbDataSource; - #folderSource: UmbFolderDataSource; + #treeSource: UmbDataTypeTreeServerDataSource; + #detailSource: UmbDataTypeServerDataSource; + #folderSource: UmbDataTypeFolderServerDataSource; + #itemSource: UmbDataTypeItemServerDataSource; #detailStore?: UmbDataTypeStore; #treeStore?: UmbDataTypeTreeStore; + #itemStore?: UmbDataTypeItemStore; #notificationContext?: UmbNotificationContext; @@ -49,22 +49,28 @@ export class UmbDataTypeRepository this.#treeSource = new UmbDataTypeTreeServerDataSource(this.#host); this.#detailSource = new UmbDataTypeServerDataSource(this.#host); this.#folderSource = new UmbDataTypeFolderServerDataSource(this.#host); + this.#itemSource = new UmbDataTypeItemServerDataSource(this.#host); this.#init = Promise.all([ - new UmbContextConsumerController(this.#host, UMB_DATA_TYPE_TREE_STORE_CONTEXT_TOKEN, (instance) => { - this.#treeStore = instance; - }), - new UmbContextConsumerController(this.#host, UMB_DATA_TYPE_STORE_CONTEXT_TOKEN, (instance) => { this.#detailStore = instance; - }), + }).asPromise(), + + new UmbContextConsumerController(this.#host, UMB_DATA_TYPE_TREE_STORE_CONTEXT_TOKEN, (instance) => { + this.#treeStore = instance; + }).asPromise(), + + new UmbContextConsumerController(this.#host, UMB_DATA_TYPE_ITEM_STORE_CONTEXT_TOKEN, (instance) => { + this.#itemStore = instance; + }).asPromise(), new UmbContextConsumerController(this.#host, UMB_NOTIFICATION_CONTEXT_TOKEN, (instance) => { this.#notificationContext = instance; - }), + }).asPromise(), ]); } + // TREE: async requestRootTreeItems() { await this.#init; @@ -90,15 +96,6 @@ export class UmbDataTypeRepository return { data, error, asObservable: () => this.#treeStore!.childrenOf(parentId) }; } - async requestTreeItems(ids: Array) { - if (!ids) throw new Error('Keys are missing'); - await this.#init; - - const { data, error } = await this.#treeSource.getItems(ids); - - return { data, error, asObservable: () => this.#treeStore!.items(ids) }; - } - async rootTreeItems() { await this.#init; return this.#treeStore!.rootItems; @@ -110,13 +107,26 @@ export class UmbDataTypeRepository return this.#treeStore!.childrenOf(parentId); } - async treeItems(ids: Array) { + // ITEMS: + async requestItems(ids: Array) { + if (!ids) throw new Error('Keys are missing'); await this.#init; - return this.#treeStore!.items(ids); + + const { data, error } = await this.#itemSource.getItems(ids); + + if (data) { + this.#itemStore?.appendItems(data); + } + + return { data, error, asObservable: () => this.#itemStore!.items(ids) }; + } + + async items(ids: Array) { + await this.#init; + return this.#itemStore!.items(ids); } // DETAILS: - async createScaffold(parentId: string | null) { if (parentId === undefined) throw new Error('Parent id is missing'); await this.#init; @@ -210,7 +220,7 @@ export class UmbDataTypeRepository return { error }; } - // folder + // Folder: async createFolderScaffold(parentId: string | null) { if (parentId === undefined) throw new Error('Parent id is missing'); return this.#folderSource.createScaffold(parentId); From 5f28851e744451968f8cdea18b66d89ce24a1b89 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 18 Apr 2023 13:34:26 +0200 Subject: [PATCH 105/156] remove temp model modification --- .../data-types/repository/sources/data-type.server.data.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/sources/data-type.server.data.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/sources/data-type.server.data.ts index 0d70c24d85..c8108c42ea 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/sources/data-type.server.data.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/sources/data-type.server.data.ts @@ -67,7 +67,7 @@ export class UmbDataTypeServerDataSource * @return {*} * @memberof UmbDataTypeServerDataSource */ - async insert(dataType: CreateDataTypeRequestModel & { id: string }) { + async insert(dataType: CreateDataTypeRequestModel) { if (!dataType) throw new Error('Data Type is missing'); if (!dataType.id) throw new Error('Data Type id is missing'); From ae5aa7ae9a9904f202d12acd2e88e0b089d55a51 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 18 Apr 2023 13:36:31 +0200 Subject: [PATCH 106/156] remove comment --- .../settings/data-types/repository/data-type.repository.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.repository.ts index 8c9d99ad8f..00b37ea660 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.repository.ts @@ -197,8 +197,6 @@ export class UmbDataTypeRepository return { error }; } - // General: - async delete(id: string) { if (!id) throw new Error('Data Type id is missing'); await this.#init; From 399b8307dc24ea626d262ebd909756b4fb8645fa Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 18 Apr 2023 13:46:03 +0200 Subject: [PATCH 107/156] register data type item store --- .../data-types/repository/manifests.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/manifests.ts index 0217359bf7..60ce0e41e6 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/manifests.ts @@ -1,7 +1,13 @@ import { UmbDataTypeRepository } from '../repository/data-type.repository'; +import { UmbDataTypeItemStore } from './data-type-item.store'; import { UmbDataTypeStore } from './data-type.store'; import { UmbDataTypeTreeStore } from './data-type.tree.store'; -import type { ManifestStore, ManifestTreeStore, ManifestRepository } from '@umbraco-cms/backoffice/extensions-registry'; +import type { + ManifestStore, + ManifestTreeStore, + ManifestRepository, + ManifestItemStore, +} from '@umbraco-cms/backoffice/extensions-registry'; export const DATA_TYPE_REPOSITORY_ALIAS = 'Umb.Repository.DataType'; @@ -14,6 +20,7 @@ const repository: ManifestRepository = { export const DATA_TYPE_STORE_ALIAS = 'Umb.Store.DataType'; export const DATA_TYPE_TREE_STORE_ALIAS = 'Umb.Store.DataTypeTree'; +export const DATA_TYPE_ITEM_STORE_ALIAS = 'Umb.Store.DataTypeItem'; const store: ManifestStore = { type: 'store', @@ -29,4 +36,11 @@ const treeStore: ManifestTreeStore = { class: UmbDataTypeTreeStore, }; -export const manifests = [repository, store, treeStore]; +const itemStore: ManifestItemStore = { + type: 'itemStore', + alias: DATA_TYPE_ITEM_STORE_ALIAS, + name: 'Data Type Item Store', + class: UmbDataTypeItemStore, +}; + +export const manifests = [repository, store, treeStore, itemStore]; From 5eb320fa3fde5faac5261e4d98e7fe96d4c4004f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 18 Apr 2023 13:46:15 +0200 Subject: [PATCH 108/156] add back type for now --- .../src/core/mocks/data/data-type.data.ts | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/data/data-type.data.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/data/data-type.data.ts index dfea186e10..404e42482b 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/data/data-type.data.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/data/data-type.data.ts @@ -11,6 +11,7 @@ import type { export const data: Array = [ { $type: '', + type: 'data-type', name: 'Folder 1', id: 'dt-folder1', parentId: null, @@ -18,6 +19,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', id: '0cc0eba1-9960-42c9-bf9b-60e150b429ae', parentId: null, name: 'Textstring', @@ -27,6 +29,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Text', id: 'dt-textBox', parentId: null, @@ -41,6 +44,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Text Area', id: 'dt-textArea', parentId: null, @@ -50,6 +54,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'My JS Property Editor', id: 'dt-custom', parentId: null, @@ -59,6 +64,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Color Picker', id: 'dt-colorPicker', parentId: null, @@ -114,6 +120,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Content Picker', id: 'dt-contentPicker', parentId: null, @@ -128,6 +135,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Eye Dropper', id: 'dt-eyeDropper', parentId: null, @@ -164,6 +172,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Multi URL Picker', id: 'dt-multiUrlPicker', parentId: null, @@ -194,6 +203,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Multi Node Tree Picker', id: 'dt-multiNodeTreePicker', parentId: null, @@ -203,6 +213,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Date Picker', id: 'dt-datePicker', parentId: null, @@ -221,6 +232,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Date Picker With Time', id: 'dt-datePicker-time', parentId: null, @@ -239,6 +251,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Time', id: 'dt-time', parentId: null, @@ -257,6 +270,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Email', id: 'dt-email', parentId: null, @@ -266,6 +280,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Multiple Text String', id: 'dt-multipleTextString', parentId: null, @@ -284,6 +299,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Dropdown', id: 'dt-dropdown', parentId: null, @@ -293,6 +309,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Slider', id: 'dt-slider', parentId: null, @@ -327,6 +344,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Toggle', id: 'dt-toggle', parentId: null, @@ -353,6 +371,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Tags', id: 'dt-tags', parentId: null, @@ -362,6 +381,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Markdown Editor', id: 'dt-markdownEditor', parentId: null, @@ -371,6 +391,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Radio Button List', id: 'dt-radioButtonList', parentId: null, @@ -389,6 +410,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Checkbox List', id: 'dt-checkboxList', parentId: null, @@ -407,6 +429,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Block List', id: 'dt-blockList', parentId: null, @@ -416,6 +439,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Media Picker', id: 'dt-mediaPicker', parentId: null, @@ -425,6 +449,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Image Cropper', id: 'dt-imageCropper', parentId: null, @@ -434,6 +459,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Upload Field', id: 'dt-uploadField', parentId: null, @@ -448,6 +474,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Block Grid', id: 'dt-blockGrid', parentId: null, @@ -457,6 +484,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Collection View', id: 'dt-collectionView', parentId: null, @@ -466,6 +494,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Icon Picker', id: 'dt-iconPicker', parentId: null, @@ -475,6 +504,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Number Range', id: 'dt-numberRange', parentId: null, @@ -484,6 +514,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Order Direction', id: 'dt-orderDirection', parentId: null, @@ -493,6 +524,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Overlay Size', id: 'dt-overlaySize', parentId: null, @@ -502,6 +534,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Rich Text Editor', id: 'dt-richTextEditor', parentId: null, @@ -511,6 +544,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Label', id: 'dt-label', parentId: null, @@ -520,6 +554,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Integer', id: 'dt-integer', parentId: null, @@ -529,6 +564,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Decimal', id: 'dt-decimal', parentId: null, @@ -538,6 +574,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'User Picker', id: 'dt-userPicker', parentId: null, @@ -547,6 +584,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Member Picker', id: 'dt-memberPicker', parentId: null, @@ -556,6 +594,7 @@ export const data: Array = }, { $type: '', + type: 'data-type', name: 'Member Group Picker', id: 'dt-memberGroupPicker', parentId: null, From e1745685c0ddf0483f76420922cd02e96916bed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 18 Apr 2023 15:21:30 +0200 Subject: [PATCH 109/156] containerSelector --- .../libs/sorter/sorter.controller.ts | 65 ++++++++++++------- ...-workspace-view-edit-properties.element.ts | 48 ++++++-------- ...pe-workspace-view-edit-property.element.ts | 20 +++++- 3 files changed, 82 insertions(+), 51 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts index 687d43b378..31c27ccd55 100644 --- a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts +++ b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts @@ -122,7 +122,7 @@ export class UmbSorterController implements UmbControllerInterface { #model: Array = []; #rqaId?: number; - #containerElement!: Element; + #containerElement!: HTMLElement; #currentContainerVM = this; #currentContainerElement: Element | null = null; @@ -146,7 +146,7 @@ export class UmbSorterController implements UmbControllerInterface { // Set defaults: config.ignorerSelector ??= 'a, img, iframe'; - config.placeholderClass ??= 'umb-drag-placeholder'; + config.placeholderClass ??= '--umb-sorter-placeholder'; this.#config = config as INTERNAL_UmbSorterConfig; host.addController(this); @@ -167,8 +167,6 @@ export class UmbSorterController implements UmbControllerInterface { }); }); }); - - host.addEventListener('dragover', preventDragOver); } setModel(model: Array) { @@ -179,29 +177,46 @@ export class UmbSorterController implements UmbControllerInterface { } hostConnected() { + requestAnimationFrame(this._onFirstRender); + } + private _onFirstRender = () => { const containerEl = - (this.#config.containerSelector ? this.#host.querySelector(this.#config.containerSelector) : this.#host) ?? - this.#host; - - (containerEl as any)['__umbBlockGridSorterController'] = () => { - return this; - }; + (this.#config.containerSelector + ? this.#host.shadowRoot!.querySelector(this.#config.containerSelector) + : this.#host) ?? this.#host; if (this.#currentContainerElement === this.#containerElement) { this.#currentContainerElement = containerEl; } - this.#containerElement = containerEl; + this.#containerElement = containerEl as HTMLElement; + this.#containerElement.addEventListener('dragover', preventDragOver); + + (this.#containerElement as any)['__umbBlockGridSorterController'] = () => { + return this; + }; + + console.log('containerEl', this.#containerElement.shadowRoot ?? this.#containerElement); // TODO: Clean up?? this.#observer.disconnect(); - this.#observer.observe(this.#containerElement.shadowRoot ?? this.#containerElement, { + + const containerElement = this.#containerElement.shadowRoot ?? this.#containerElement; + containerElement.querySelectorAll(this.#config.itemSelector).forEach((child) => { + if (child.matches && child.matches(this.#config.itemSelector)) { + this.setupItem(child as HTMLElement); + } + }); + this.#observer.observe(containerElement, { childList: true, subtree: false, }); - } + }; hostDisconnected() { // TODO: Clean up?? this.#observer.disconnect(); + (this.#containerElement as any)['__umbBlockGridSorterController'] = undefined; + this.#containerElement.removeEventListener('dragover', preventDragOver); + (this.#containerElement as any) = undefined; } setupItem(element: HTMLElement) { @@ -316,14 +331,14 @@ export class UmbSorterController implements UmbControllerInterface { const movingItemIndex = this.#model.indexOf(this.#currentItem); if (movingItemIndex < this.#model.length - 1) { const afterItem = this.#model[movingItemIndex + 1]; - const afterEl = this.#config.querySelectModelToElement(this.#host, afterItem); + const afterEl = this.#config.querySelectModelToElement(this.#containerElement, afterItem); if (afterEl) { - this.#host.insertBefore(this.#currentElement, afterEl); + this.#containerElement.insertBefore(this.#currentElement, afterEl); } else { - this.#host.appendChild(this.#currentElement); + this.#containerElement.appendChild(this.#currentElement); } } else { - this.#host.appendChild(this.#currentElement); + this.#containerElement.appendChild(this.#currentElement); } } @@ -406,6 +421,7 @@ export class UmbSorterController implements UmbControllerInterface { // we are outside the current container boundary, so lets see if there is a parent we can move. const parentNode = this.#currentContainerElement.parentNode; if (parentNode) { + // TODO: support multiple parent shadowDOMs? const parentContainer = this.#config.containerSelector ? (parentNode as HTMLElement).closest(this.#config.containerSelector) : null; @@ -429,8 +445,8 @@ export class UmbSorterController implements UmbControllerInterface { // We want to retrieve the children of the container, every time to ensure we got the right order and index const orderedContainerElements = Array.from( this.#currentContainerElement.shadowRoot - ? this.#currentContainerElement.shadowRoot.children - : this.#currentContainerElement.children + ? this.#currentContainerElement.shadowRoot.querySelectorAll(this.#config.itemSelector) + : this.#currentContainerElement.querySelectorAll(this.#config.itemSelector) ); const currentContainerRect = this.#currentContainerElement.getBoundingClientRect(); @@ -478,6 +494,7 @@ export class UmbSorterController implements UmbControllerInterface { // If we are inside the found element, lets look for sub containers. // use the itemHasNestedContainersResolver, if not configured fallback to looking for the existence of a container via DOM. + // TODO: Ability to look into shadowDOMs for sub containers? if ( isInsideFound && this.#config.itemHasNestedContainersResolver ? this.#config.itemHasNestedContainersResolver(foundEl) @@ -669,6 +686,13 @@ export class UmbSorterController implements UmbControllerInterface { let newIndex = this.#model.length; + const movingItemIndex = this.#model.indexOf(movingItem); + + console.log('this.#model', this.#model, movingItemIndex); + + if (movingItemIndex !== -1 && movingItemIndex <= movingItemIndex) { + newIndex--; + } if (nextEl) { // We had a reference element, we want to get the index of it. // This is might a problem if a item is being moved forward? (was also like this in the AngularJS version...) @@ -806,9 +830,6 @@ export class UmbSorterController implements UmbControllerInterface { this._lastIndicationContainerVM = null; - (this.#host as any)['__umbBlockGridSorterController'] = null; - this.#host.removeEventListener('dragover', preventDragOver); - // TODO: Clean up items?? this.#observer.disconnect(); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts index 185044e267..f000b6917b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts @@ -21,6 +21,7 @@ const SORTER_CONFIG: UmbSorterConfig = { identifier: 'content-type-property-sorter', itemSelector: '[data-umb-property-id]', disabledItemSelector: ':not([data-property-of-owner-document])', + containerSelector: '#property-list', }; @customElement('umb-document-type-workspace-view-edit-properties') export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitElement { @@ -31,7 +32,7 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle if (this._propertyStructure.length > 0) { console.log('args.newIndex', args.newIndex); if (args.newIndex === 0) { - // TODO: Remove as any when sortOrder is added to the model: + // TODO: Remove 'as any' when sortOrder is added to the model: sortOrder = ((this._propertyStructure[0] as any).sortOrder ?? 0) - 1; } else { sortOrder = @@ -39,11 +40,9 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle 0) + 1; } } - console.log('insert', args.item.id, sortOrder); return this._propertyStructureHelper.insertProperty(args.item, sortOrder); }, performItemRemove: (args) => { - console.log('remove', args.item.id); return this._propertyStructureHelper.removeProperty(args.item.id!); }, }); @@ -109,36 +108,29 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle } render() { - return html`${repeat( - this._propertyStructure, - (property) => property.alias ?? '' + property.containerId ?? '' + (property as any).sortOrder ?? '', - (property) => - html` { - this._propertyStructureHelper.partialUpdateProperty(property.id, event.detail); - }}>` - )} Add property `; + return html`
+ ${repeat( + this._propertyStructure, + (property) => property.alias ?? '' + property.containerId ?? '' + (property as any).sortOrder ?? '', + (property) => + html` { + this._propertyStructureHelper.partialUpdateProperty(property.id, event.detail); + }}>` + )} +
+ Add property `; } static styles = [ UUITextStyles, css` - .property:first-of-type { - padding-top: 0; - } - .property { - border-bottom: 1px solid var(--uui-color-divider); - } - .property:last-child { - border-bottom: 0; - } - #add { width: 100%; } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts index 9e08199e49..2739bc0508 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts @@ -81,9 +81,27 @@ export class UmbDocumentTypeWorkspacePropertyElement extends LitElement { border-bottom: none; } - :host-context(umb-variantable-property:first-of-type) { + :host(:first-of-type) { padding-top: 0; } + :host([data-property-of-owner-document]) { + cursor: grab; + } + + // PLaceholder style, used when property is being dragged. + :host(.--umb-sorter-placeholder) { + height: 2px; + } + :host(.--umb-sorter-placeholder) > div { + display: none; + } + :host(.--umb-sorter-placeholder)::after { + content: ''; + display:block: + grid-column: span 2; + width: 100%; + border-top: 2px solid blue; + } p { margin-bottom: 0; From 65db67f530100b2a342720e4e5008190a05a55c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 18 Apr 2023 15:34:44 +0200 Subject: [PATCH 110/156] clean up --- src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts | 2 -- .../document-type-workspace-view-edit-properties.element.ts | 1 - 2 files changed, 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts index 31c27ccd55..86a3288439 100644 --- a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts +++ b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts @@ -688,8 +688,6 @@ export class UmbSorterController implements UmbControllerInterface { const movingItemIndex = this.#model.indexOf(movingItem); - console.log('this.#model', this.#model, movingItemIndex); - if (movingItemIndex !== -1 && movingItemIndex <= movingItemIndex) { newIndex--; } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts index f000b6917b..fd85f91100 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts @@ -30,7 +30,6 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle performItemInsert: (args) => { let sortOrder = 0; if (this._propertyStructure.length > 0) { - console.log('args.newIndex', args.newIndex); if (args.newIndex === 0) { // TODO: Remove 'as any' when sortOrder is added to the model: sortOrder = ((this._propertyStructure[0] as any).sortOrder ?? 0) - 1; From 74f9e7e89b6922442c53492a7be50fa1c7bf3e0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 18 Apr 2023 15:39:45 +0200 Subject: [PATCH 111/156] styling --- .../document-type-workspace-view-edit-property.element.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts index 2739bc0508..c717f09f81 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts @@ -97,8 +97,7 @@ export class UmbDocumentTypeWorkspacePropertyElement extends LitElement { } :host(.--umb-sorter-placeholder)::after { content: ''; - display:block: - grid-column: span 2; + grid-column: span 2; width: 100%; border-top: 2px solid blue; } From 30fb10a26eb5a981b608d12d6b5dce7371fbb1df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 18 Apr 2023 15:42:17 +0200 Subject: [PATCH 112/156] notes --- .../document-type-workspace-view-edit-property.element.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts index c717f09f81..e540c4e191 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts @@ -88,7 +88,7 @@ export class UmbDocumentTypeWorkspacePropertyElement extends LitElement { cursor: grab; } - // PLaceholder style, used when property is being dragged. + /* Placeholder style, used when property is being dragged.*/ :host(.--umb-sorter-placeholder) { height: 2px; } @@ -100,6 +100,8 @@ export class UmbDocumentTypeWorkspacePropertyElement extends LitElement { grid-column: span 2; width: 100%; border-top: 2px solid blue; + border-radius: 1px; + /* TODO: Make use of same highlight color as UUI and the same Animation. Consider making this a component/(available style) in UUI? */ } p { From 7aaf208dc5fec03c1068293d02d6f48aaa7b1246 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 18 Apr 2023 21:14:31 +0200 Subject: [PATCH 113/156] add logic to move data type --- .../data-source-response.interface.ts | 5 ++- .../libs/repository/data-source/index.ts | 1 + .../data-source/move-data-source.interface.ts | 5 +++ .../libs/repository/index.ts | 1 + .../repository/move-repository.interface.ts | 5 +++ .../data-types/entity-actions/manifests.ts | 10 +++-- .../entity-actions/move/manifests.ts | 24 +++++++++++ .../entity-actions/move/move.action.ts | 26 +++++++++++ .../backoffice/settings/data-types/index.ts | 2 + .../repository/data-type.repository.ts | 34 ++++++++++++--- .../sources/data-type-move.server.data.ts | 43 +++++++++++++++++++ .../src/core/mocks/data/entity.data.ts | 6 ++- .../src/core/mocks/domains/data-type/index.ts | 3 +- .../mocks/domains/data-type/move.handlers.ts | 18 ++++++++ .../src/core/mocks/domains/media.handlers.ts | 4 +- 15 files changed, 173 insertions(+), 14 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/libs/repository/data-source/move-data-source.interface.ts create mode 100644 src/Umbraco.Web.UI.Client/libs/repository/move-repository.interface.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/move/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/move/move.action.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/sources/data-type-move.server.data.ts create mode 100644 src/Umbraco.Web.UI.Client/src/core/mocks/domains/data-type/move.handlers.ts diff --git a/src/Umbraco.Web.UI.Client/libs/repository/data-source/data-source-response.interface.ts b/src/Umbraco.Web.UI.Client/libs/repository/data-source/data-source-response.interface.ts index a3ee6e90f0..2360da75a8 100644 --- a/src/Umbraco.Web.UI.Client/libs/repository/data-source/data-source-response.interface.ts +++ b/src/Umbraco.Web.UI.Client/libs/repository/data-source/data-source-response.interface.ts @@ -1,6 +1,9 @@ import type { ProblemDetailsModel } from '@umbraco-cms/backoffice/backend-api'; -export interface DataSourceResponse { +export interface DataSourceResponse extends UmbDataSourceErrorResponse { data?: T; +} + +export interface UmbDataSourceErrorResponse { error?: ProblemDetailsModel; } diff --git a/src/Umbraco.Web.UI.Client/libs/repository/data-source/index.ts b/src/Umbraco.Web.UI.Client/libs/repository/data-source/index.ts index 2f13c24fbc..3851c96686 100644 --- a/src/Umbraco.Web.UI.Client/libs/repository/data-source/index.ts +++ b/src/Umbraco.Web.UI.Client/libs/repository/data-source/index.ts @@ -3,3 +3,4 @@ export * from './data-source.interface'; export * from './folder-data-source.interface'; export * from './tree-data-source.interface'; export * from './item-data-source.interface'; +export * from './move-data-source.interface'; diff --git a/src/Umbraco.Web.UI.Client/libs/repository/data-source/move-data-source.interface.ts b/src/Umbraco.Web.UI.Client/libs/repository/data-source/move-data-source.interface.ts new file mode 100644 index 0000000000..c0639e31ce --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/repository/data-source/move-data-source.interface.ts @@ -0,0 +1,5 @@ +import type { UmbDataSourceErrorResponse } from '@umbraco-cms/backoffice/repository'; + +export interface UmbMoveDataSource { + move(unique: string, targetUnique: string): Promise; +} diff --git a/src/Umbraco.Web.UI.Client/libs/repository/index.ts b/src/Umbraco.Web.UI.Client/libs/repository/index.ts index 94fb4c295d..0c73ef0870 100644 --- a/src/Umbraco.Web.UI.Client/libs/repository/index.ts +++ b/src/Umbraco.Web.UI.Client/libs/repository/index.ts @@ -3,3 +3,4 @@ export * from './detail-repository.interface'; export * from './tree-repository.interface'; export * from './folder-repository.interface'; export * from './item-repository.interface'; +export * from './move-repository.interface'; diff --git a/src/Umbraco.Web.UI.Client/libs/repository/move-repository.interface.ts b/src/Umbraco.Web.UI.Client/libs/repository/move-repository.interface.ts new file mode 100644 index 0000000000..f8e5889300 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/repository/move-repository.interface.ts @@ -0,0 +1,5 @@ +import { UmbRepositoryErrorResponse } from './detail-repository.interface'; + +export interface UmbMoveRepository { + move(unique: string, targetUnique: string): Promise; +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/manifests.ts index 54e8288b16..eb57a2b500 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/manifests.ts @@ -1,5 +1,7 @@ +import { DATA_TYPE_ENTITY_TYPE } from '..'; import { DATA_TYPE_REPOSITORY_ALIAS } from '../repository/manifests'; import { manifests as createManifests } from './create/manifests'; +import { manifests as moveManifests } from './move/manifests'; import { UmbDeleteEntityAction, UmbDeleteFolderEntityAction, @@ -20,7 +22,7 @@ const entityActions: Array = [ api: UmbDeleteEntityAction, }, conditions: { - entityType: 'data-type', + entityType: DATA_TYPE_ENTITY_TYPE, }, }, { @@ -35,7 +37,7 @@ const entityActions: Array = [ api: UmbDeleteFolderEntityAction, }, conditions: { - entityType: 'data-type', + entityType: DATA_TYPE_ENTITY_TYPE, }, }, { @@ -50,9 +52,9 @@ const entityActions: Array = [ api: UmbFolderUpdateEntityAction, }, conditions: { - entityType: 'data-type', + entityType: DATA_TYPE_ENTITY_TYPE, }, }, ]; -export const manifests = [...entityActions, ...createManifests]; +export const manifests = [...entityActions, ...createManifests, ...moveManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/move/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/move/manifests.ts new file mode 100644 index 0000000000..f476c53b40 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/move/manifests.ts @@ -0,0 +1,24 @@ +import { DATA_TYPE_ENTITY_TYPE } from '../..'; +import { DATA_TYPE_REPOSITORY_ALIAS } from '../../repository/manifests'; +import { UmbMoveDataTypeEntityAction } from './move.action'; +import { ManifestTypes } from '@umbraco-cms/backoffice/extensions-registry'; + +const entityActions: Array = [ + { + type: 'entityAction', + alias: 'Umb.EntityAction.DataType.Move', + name: 'Move Data Type Entity Action', + weight: 900, + meta: { + icon: 'umb:trash', + label: 'Move...', + repositoryAlias: DATA_TYPE_REPOSITORY_ALIAS, + api: UmbMoveDataTypeEntityAction, + }, + conditions: { + entityType: DATA_TYPE_ENTITY_TYPE, + }, + }, +]; + +export const manifests = [...entityActions]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/move/move.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/move/move.action.ts new file mode 100644 index 0000000000..de2e690ede --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/move/move.action.ts @@ -0,0 +1,26 @@ +import { UmbDataTypeRepository } from '../../repository/data-type.repository'; +import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; +import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN, UMB_DATA_TYPE_PICKER_MODAL } from '@umbraco-cms/backoffice/modal'; +import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; + +export class UmbMoveDataTypeEntityAction extends UmbEntityActionBase { + #modalContext?: UmbModalContext; + + constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) { + super(host, repositoryAlias, unique); + + new UmbContextConsumerController(this.host, UMB_MODAL_CONTEXT_TOKEN, (instance) => { + this.#modalContext = instance; + }); + } + + async execute() { + if (!this.#modalContext) throw new Error('Modal context is not available'); + if (!this.repository) throw new Error('Repository is not available'); + + const modalHandler = this.#modalContext?.open(UMB_DATA_TYPE_PICKER_MODAL); + const { selection } = await modalHandler.onSubmit(); + await this.repository.move(this.unique, selection[0]); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/index.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/index.ts index 758f322450..44cb2b0223 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/index.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/index.ts @@ -1 +1,3 @@ import './components'; + +export const DATA_TYPE_ENTITY_TYPE = 'data-type'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.repository.ts index 00b37ea660..2f49e173f2 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.repository.ts @@ -1,11 +1,18 @@ import { UmbDataTypeTreeServerDataSource } from './sources/data-type.tree.server.data'; +import { UmbDataTypeMoveServerDataSource } from './sources/data-type-move.server.data'; import { UmbDataTypeStore, UMB_DATA_TYPE_STORE_CONTEXT_TOKEN } from './data-type.store'; import { UmbDataTypeServerDataSource } from './sources/data-type.server.data'; import { UmbDataTypeTreeStore, UMB_DATA_TYPE_TREE_STORE_CONTEXT_TOKEN } from './data-type.tree.store'; import { UmbDataTypeFolderServerDataSource } from './sources/data-type-folder.server.data'; import { UmbDataTypeItemServerDataSource } from './sources/data-type-item.server.data'; import { UMB_DATA_TYPE_ITEM_STORE_CONTEXT_TOKEN, UmbDataTypeItemStore } from './data-type-item.store'; -import type { UmbTreeRepository, UmbDetailRepository, UmbItemRepository } from '@umbraco-cms/backoffice/repository'; +import type { + UmbTreeRepository, + UmbDetailRepository, + UmbItemRepository, + UmbFolderRepository, + UmbMoveRepository, +} from '@umbraco-cms/backoffice/repository'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; import { @@ -18,14 +25,14 @@ import { UpdateDataTypeRequestModel, } from '@umbraco-cms/backoffice/backend-api'; import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification'; -import { UmbFolderRepository } from '@umbraco-cms/backoffice/repository'; export class UmbDataTypeRepository implements UmbItemRepository, UmbTreeRepository, UmbDetailRepository, - UmbFolderRepository + UmbFolderRepository, + UmbMoveRepository { #init: Promise; @@ -35,6 +42,7 @@ export class UmbDataTypeRepository #detailSource: UmbDataTypeServerDataSource; #folderSource: UmbDataTypeFolderServerDataSource; #itemSource: UmbDataTypeItemServerDataSource; + #moveSource: UmbDataTypeMoveServerDataSource; #detailStore?: UmbDataTypeStore; #treeStore?: UmbDataTypeTreeStore; @@ -50,6 +58,7 @@ export class UmbDataTypeRepository this.#detailSource = new UmbDataTypeServerDataSource(this.#host); this.#folderSource = new UmbDataTypeFolderServerDataSource(this.#host); this.#itemSource = new UmbDataTypeItemServerDataSource(this.#host); + this.#moveSource = new UmbDataTypeMoveServerDataSource(this.#host); this.#init = Promise.all([ new UmbContextConsumerController(this.#host, UMB_DATA_TYPE_STORE_CONTEXT_TOKEN, (instance) => { @@ -156,7 +165,6 @@ export class UmbDataTypeRepository async create(dataType: CreateDataTypeRequestModel) { if (!dataType) throw new Error('Data Type is missing'); if (!dataType.id) throw new Error('Data Type id is missing'); - await this.#init; const { error } = await this.#detailSource.insert(dataType); @@ -177,7 +185,6 @@ export class UmbDataTypeRepository async save(id: string, updatedDataType: UpdateDataTypeRequestModel) { if (!id) throw new Error('Data Type id is missing'); if (!updatedDataType) throw new Error('Data Type is missing'); - await this.#init; const { error } = await this.#detailSource.update(id, updatedDataType); @@ -221,6 +228,7 @@ export class UmbDataTypeRepository // Folder: async createFolderScaffold(parentId: string | null) { if (parentId === undefined) throw new Error('Parent id is missing'); + await this.#init; return this.#folderSource.createScaffold(parentId); } @@ -242,6 +250,7 @@ export class UmbDataTypeRepository async deleteFolder(id: string) { if (!id) throw new Error('Key is missing'); + await this.#init; const { error } = await this.#folderSource.delete(id); @@ -255,6 +264,7 @@ export class UmbDataTypeRepository async updateFolder(id: string, folder: FolderModelBaseModel) { if (!id) throw new Error('Key is missing'); if (!folder) throw new Error('Folder data is missing'); + await this.#init; const { error } = await this.#folderSource.update(id, folder); @@ -267,6 +277,7 @@ export class UmbDataTypeRepository async requestFolder(id: string) { if (!id) throw new Error('Key is missing'); + await this.#init; const { data, error } = await this.#folderSource.get(id); @@ -276,6 +287,19 @@ export class UmbDataTypeRepository return { data, error }; } + + // Actions + async move(id: string, targetId: string) { + await this.#init; + const { error } = await this.#moveSource.move(id, targetId); + + if (!error) { + this.#treeStore?.updateItem(id, { parentId: targetId }); + this.#treeStore?.updateItem(targetId, { hasChildren: true }); + } + + return { error }; + } } export const createTreeItem = (item: CreateDataTypeRequestModel): FolderTreeItemResponseModel => { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/sources/data-type-move.server.data.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/sources/data-type-move.server.data.ts new file mode 100644 index 0000000000..c6759d7676 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/sources/data-type-move.server.data.ts @@ -0,0 +1,43 @@ +import { DataTypeResource } from '@umbraco-cms/backoffice/backend-api'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; +import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; +import { UmbMoveDataSource } from '@umbraco-cms/backoffice/repository'; + +/** + * A data source for Data Type items that fetches data from the server + * @export + * @class UmbDataTypeMoveServerDataSource + */ +export class UmbDataTypeMoveServerDataSource implements UmbMoveDataSource { + #host: UmbControllerHostElement; + + /** + * Creates an instance of UmbDataTypeMoveServerDataSource. + * @param {UmbControllerHostElement} host + * @memberof UmbDataTypeMoveServerDataSource + */ + constructor(host: UmbControllerHostElement) { + this.#host = host; + } + + /** + * Move an item for the given id to the target id + * @param {Array} id + * @return {*} + * @memberof UmbDataTypeMoveServerDataSource + */ + async move(id: string, targetId: string) { + if (!id) throw new Error('Id is missing'); + if (!targetId) throw new Error('Target Id is missing'); + + return tryExecuteAndNotify( + this.#host, + DataTypeResource.postDataTypeByIdMove({ + id, + requestBody: { + targetId, + }, + }) + ); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/data/entity.data.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/data/entity.data.ts index d3a7356430..19f132d492 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/data/entity.data.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/data/entity.data.ts @@ -44,6 +44,9 @@ export class UmbEntityData extends UmbData { } move(ids: Array, destinationKey: string) { + const destinationItem = this.getById(destinationKey); + if (!destinationItem) throw new Error(`Destination item with key ${destinationKey} not found`); + const items = this.getByIds(ids); const movedItems = items.map((item) => { return { @@ -53,7 +56,8 @@ export class UmbEntityData extends UmbData { }); movedItems.forEach((movedItem) => this.updateData(movedItem)); - return movedItems; + destinationItem.hasChildren = true; + this.updateData(destinationItem); } trash(ids: Array) { diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/data-type/index.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/data-type/index.ts index fb46e23ffd..3cd1dc2d02 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/data-type/index.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/data-type/index.ts @@ -2,5 +2,6 @@ import { folderHandlers } from './folder.handlers'; import { treeHandlers } from './tree.handlers'; import { detailHandlers } from './detail.handlers'; import { itemHandlers } from './item.handlers'; +import { moveHandlers } from './move.handlers'; -export const handlers = [...treeHandlers, ...itemHandlers, ...folderHandlers, ...detailHandlers]; +export const handlers = [...treeHandlers, ...itemHandlers, ...folderHandlers, ...moveHandlers, ...detailHandlers]; diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/data-type/move.handlers.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/data-type/move.handlers.ts new file mode 100644 index 0000000000..daf980630f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/data-type/move.handlers.ts @@ -0,0 +1,18 @@ +import { rest } from 'msw'; +import { umbDataTypeData } from '../../data/data-type.data'; +import { slug } from './slug'; +import { umbracoPath } from '@umbraco-cms/backoffice/utils'; + +export const moveHandlers = [ + rest.post(umbracoPath(`${slug}/:id/move`), async (req, res, ctx) => { + const id = req.params.id as string; + if (!id) return; + + const data = await req.json(); + if (!data) return; + + umbDataTypeData.move([id], data.targetId); + + return res(ctx.status(200)); + }), +]; diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/media.handlers.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/media.handlers.ts index efb5a91845..dc28dbd021 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/media.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/media.handlers.ts @@ -26,8 +26,8 @@ export const handlers = [ rest.post('/umbraco/management/api/v1/media/move', async (req, res, ctx) => { const data = await req.json(); if (!data) return; - const moved = umbMediaData.move(data.ids, data.destination); - return res(ctx.status(200), ctx.json(moved)); + umbMediaData.move(data.ids, data.destination); + return res(ctx.status(200)); }), rest.post('/umbraco/management/api/v1/media/trash', async (req, res, ctx) => { From 5f023603c409ec1c193bf07c7c2c83c8821fb4f6 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 18 Apr 2023 21:25:37 +0200 Subject: [PATCH 114/156] change to move icon --- .../settings/data-types/entity-actions/move/manifests.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/move/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/move/manifests.ts index f476c53b40..11e7c1740a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/move/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/move/manifests.ts @@ -10,7 +10,7 @@ const entityActions: Array = [ name: 'Move Data Type Entity Action', weight: 900, meta: { - icon: 'umb:trash', + icon: 'umb:enter', label: 'Move...', repositoryAlias: DATA_TYPE_REPOSITORY_ALIAS, api: UmbMoveDataTypeEntityAction, From d8f9688f8a339254b8773049a5bdad44b50113ac Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 19 Apr 2023 09:33:20 +0200 Subject: [PATCH 115/156] add todos --- .../libs/entity-action/actions/move/move.action.ts | 2 ++ .../settings/data-types/entity-actions/move/move.action.ts | 1 + 2 files changed, 3 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/libs/entity-action/actions/move/move.action.ts b/src/Umbraco.Web.UI.Client/libs/entity-action/actions/move/move.action.ts index 2744029e82..dd4a7f2905 100644 --- a/src/Umbraco.Web.UI.Client/libs/entity-action/actions/move/move.action.ts +++ b/src/Umbraco.Web.UI.Client/libs/entity-action/actions/move/move.action.ts @@ -1,6 +1,8 @@ import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; +// TODO: investigate what we need to finish the generic move action. We would need to open a picker, which requires a modal token, +// maybe we can use kinds to make a specific manifest to the move action. export class UmbMoveEntityAction }> extends UmbEntityActionBase { constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) { super(host, repositoryAlias, unique); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/move/move.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/move/move.action.ts index de2e690ede..9d24d65844 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/move/move.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/move/move.action.ts @@ -4,6 +4,7 @@ import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN, UMB_DATA_TYPE_PICKER_MODAL } from '@umbraco-cms/backoffice/modal'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; +// TODO: investigate what we need to make a generic move action export class UmbMoveDataTypeEntityAction extends UmbEntityActionBase { #modalContext?: UmbModalContext; From e60de8cb9879c1587d0987127fc4556715ae9fd2 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 19 Apr 2023 09:53:45 +0200 Subject: [PATCH 116/156] update interfaces --- .../actions/delete-folder/delete-folder.action.ts | 5 +++-- .../libs/entity-action/actions/delete/delete.action.ts | 5 +++-- .../libs/entity-action/actions/trash/trash.action.ts | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/entity-action/actions/delete-folder/delete-folder.action.ts b/src/Umbraco.Web.UI.Client/libs/entity-action/actions/delete-folder/delete-folder.action.ts index 9a2adadb0b..594d0be5f4 100644 --- a/src/Umbraco.Web.UI.Client/libs/entity-action/actions/delete-folder/delete-folder.action.ts +++ b/src/Umbraco.Web.UI.Client/libs/entity-action/actions/delete-folder/delete-folder.action.ts @@ -2,9 +2,10 @@ import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN, UMB_CONFIRM_MODAL } from '@umbraco-cms/backoffice/modal'; +import { UmbFolderRepository, UmbItemRepository } from '@umbraco-cms/backoffice/repository'; export class UmbDeleteFolderEntityAction< - T extends { deleteFolder(unique: string): Promise; requestTreeItems(uniques: Array): any } + T extends UmbItemRepository & UmbFolderRepository > extends UmbEntityActionBase { #modalContext?: UmbModalContext; @@ -19,7 +20,7 @@ export class UmbDeleteFolderEntityAction< async execute() { if (!this.repository || !this.#modalContext) return; - const { data } = await this.repository.requestTreeItems([this.unique]); + const { data } = await this.repository.requestItems([this.unique]); if (data) { const item = data[0]; diff --git a/src/Umbraco.Web.UI.Client/libs/entity-action/actions/delete/delete.action.ts b/src/Umbraco.Web.UI.Client/libs/entity-action/actions/delete/delete.action.ts index d290a1f912..c53a418502 100644 --- a/src/Umbraco.Web.UI.Client/libs/entity-action/actions/delete/delete.action.ts +++ b/src/Umbraco.Web.UI.Client/libs/entity-action/actions/delete/delete.action.ts @@ -2,9 +2,10 @@ import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN, UMB_CONFIRM_MODAL } from '@umbraco-cms/backoffice/modal'; +import { UmbDetailRepository, UmbItemRepository } from '@umbraco-cms/backoffice/repository'; export class UmbDeleteEntityAction< - T extends { delete(unique: string): Promise; requestTreeItems(uniques: Array): any } + T extends UmbDetailRepository & UmbItemRepository > extends UmbEntityActionBase { #modalContext?: UmbModalContext; @@ -19,7 +20,7 @@ export class UmbDeleteEntityAction< async execute() { if (!this.repository || !this.#modalContext) return; - const { data } = await this.repository.requestTreeItems([this.unique]); + const { data } = await this.repository.requestItems([this.unique]); if (data) { const item = data[0]; diff --git a/src/Umbraco.Web.UI.Client/libs/entity-action/actions/trash/trash.action.ts b/src/Umbraco.Web.UI.Client/libs/entity-action/actions/trash/trash.action.ts index 2b86b4d56c..1ed2a69beb 100644 --- a/src/Umbraco.Web.UI.Client/libs/entity-action/actions/trash/trash.action.ts +++ b/src/Umbraco.Web.UI.Client/libs/entity-action/actions/trash/trash.action.ts @@ -2,9 +2,10 @@ import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN, UMB_CONFIRM_MODAL } from '@umbraco-cms/backoffice/modal'; +import { UmbItemRepository } from '@umbraco-cms/backoffice/repository'; export class UmbTrashEntityAction< - T extends { trash(unique: Array): Promise; requestTreeItems(uniques: Array): any } + T extends UmbItemRepository & { trash(unique: Array): Promise } > extends UmbEntityActionBase { #modalContext?: UmbModalContext; @@ -19,7 +20,7 @@ export class UmbTrashEntityAction< async execute() { if (!this.repository) return; - const { data } = await this.repository.requestTreeItems([this.unique]); + const { data } = await this.repository.requestItems([this.unique]); if (data) { const item = data[0]; From 67efb13438fe4cd0b391a5879bbe9fffff4eddc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 19 Apr 2023 13:05:45 +0200 Subject: [PATCH 117/156] inherited props --- .../repository/document-type.repository.ts | 34 ++++++++++++++++--- ...-workspace-view-edit-properties.element.ts | 4 +-- ...pe-workspace-view-edit-property.element.ts | 33 ++++++++++++++++-- .../src/core/mocks/data/document-type.data.ts | 4 +-- 4 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/document-type.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/document-type.repository.ts index 78c9ac203c..31518f738c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/document-type.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/document-type.repository.ts @@ -5,7 +5,11 @@ import { UmbDocumentTypeStore, UMB_DOCUMENT_TYPE_STORE_CONTEXT_TOKEN } from './d import type { UmbTreeDataSource, UmbTreeRepository, UmbDetailRepository } from '@umbraco-cms/backoffice/repository'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; -import { ProblemDetailsModel, DocumentTypeResponseModel } from '@umbraco-cms/backoffice/backend-api'; +import { + ProblemDetailsModel, + DocumentTypeResponseModel, + FolderTreeItemResponseModel, +} from '@umbraco-cms/backoffice/backend-api'; import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification'; type ItemType = DocumentTypeResponseModel; @@ -141,19 +145,22 @@ export class UmbDocumentTypeRepository implements UmbTreeRepository, U // Could potentially be general methods: - async create(template: ItemType) { - if (!template || !template.id) throw new Error('Template is missing'); + async create(documentType: ItemType) { + if (!documentType || !documentType.id) throw new Error('Template is missing'); await this.#init; - const { error } = await this.#detailDataSource.insert(template); + const { error } = await this.#detailDataSource.insert(documentType); if (!error) { + const treeItem = createTreeItem(documentType); + this.#treeStore?.appendItems([treeItem]); + const notification = { data: { message: `Document created` } }; this.#notificationContext?.peek('positive', notification); // TODO: we currently don't use the detail store for anything. // Consider to look up the data before fetching from the server - this.#detailStore?.append(template); + //this.#detailStore?.append(documentType); // TODO: Update tree store with the new item? or ask tree to request the new item? } @@ -206,3 +213,20 @@ export class UmbDocumentTypeRepository implements UmbTreeRepository, U return { error }; } } + +export const createTreeItem = (item: ItemType): FolderTreeItemResponseModel => { + if (!item) throw new Error('item is null or undefined'); + if (!item.id) throw new Error('item.id is null or undefined'); + + // TODO: needs parentID, this is missing in the current model. Should be good when updated to a createModel. + return { + $type: 'FolderTreeItemResponseModel', + type: 'data-type', + parentId: null, + name: item.name, + id: item.id, + isFolder: false, + isContainer: false, + hasChildren: false, + }; +}; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts index fd85f91100..d2b22d0081 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts @@ -20,7 +20,7 @@ const SORTER_CONFIG: UmbSorterConfig = { }, identifier: 'content-type-property-sorter', itemSelector: '[data-umb-property-id]', - disabledItemSelector: ':not([data-property-of-owner-document])', + disabledItemSelector: '[inherited]', containerSelector: '#property-list', }; @customElement('umb-document-type-workspace-view-edit-properties') @@ -117,7 +117,7 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle data-umb-property-id=${property.id} data-property-container-is=${property.containerId} data-container-id=${this.containerId} - ?data-property-of-owner-document=${ifDefined(property.containerId === this.containerId)} + ?inherited=${ifDefined(property.containerId !== this.containerId)} .property=${property} @partial-property-update=${(event: CustomEvent) => { this._propertyStructureHelper.partialUpdateProperty(property.id, event.detail); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts index e540c4e191..fe56c18d60 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts @@ -19,6 +19,16 @@ export class UmbDocumentTypeWorkspacePropertyElement extends LitElement { @property({ type: Object }) public property?: PropertyTypeResponseModelBaseModel; + /** + * Inherited, Determines if the property is part of the main document type thats being edited. + * If true, then the property is inherited from another document type, not a part of the main document type. + * @type {boolean} + * @attr + * @default undefined + */ + @property({ type: Boolean }) + public inherited?: boolean; + _firePartialUpdate(propertyName: string, value: string | number | boolean | null | undefined) { const partialObject = {} as any; partialObject[propertyName] = value; @@ -26,8 +36,20 @@ export class UmbDocumentTypeWorkspacePropertyElement extends LitElement { this.dispatchEvent(new CustomEvent('partial-property-update', { detail: partialObject })); } - render() { - // TODO: Only show alias on label if user has access to DocumentType within settings: + renderInheritedProperty() { + return this.property + ? html` + +
+ ` + : ''; + } + + renderEditableProperty() { return this.property ? html` `; @@ -88,14 +87,6 @@ export class UmbTemplateCardElement extends FormControlMixin(UmbLitElement) { padding: var(--uui-size-4); } - :host([default]) #card { - border: 1px solid var(--uui-color-selected); - outline: 1px solid var(--uui-color-selected); - } - #card:has(uui-button:hover) { - border: 1px solid var(--uui-color-selected); - } - #bottom { margin-top: auto; } From f6970b5b6c01dd7aa4c9ae557efa1f464720c08f Mon Sep 17 00:00:00 2001 From: Jason Elkin Date: Thu, 16 Mar 2023 11:20:45 +0000 Subject: [PATCH 127/156] Remove invalid dot from email and URL validation strings --- .../property-settings/property-settings-modal.element.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/modals/property-settings/property-settings-modal.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/modals/property-settings/property-settings-modal.element.ts index c57165fe42..3e345aad1e 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/modals/property-settings/property-settings-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/modals/property-settings/property-settings-modal.element.ts @@ -127,7 +127,7 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement Date: Thu, 20 Apr 2023 13:03:15 +0200 Subject: [PATCH 128/156] correct import --- .../document-type-workspace-view-edit-properties.element.ts | 2 +- .../search/components/log-viewer-search-input-modal.element.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts index d2b22d0081..10e37d583a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts @@ -2,10 +2,10 @@ import { css, html } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property, state } from 'lit/decorators.js'; import { repeat } from 'lit/directives/repeat.js'; -import { UmbSorterController, UmbSorterConfig } from '@umbraco-cms/backoffice/sorter'; import { ifDefined } from 'lit/directives/if-defined.js'; import { UmbWorkspacePropertyStructureHelper } from '../../../../../shared/components/workspace/workspace-context/workspace-property-structure-helper.class'; import { PropertyContainerTypes } from '../../../../../shared/components/workspace/workspace-context/workspace-structure-manager.class'; +import { UmbSorterController, UmbSorterConfig } from '@umbraco-cms/backoffice/sorter'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import { DocumentTypePropertyTypeResponseModel } from '@umbraco-cms/backoffice/backend-api'; import { UMB_MODAL_CONTEXT_TOKEN, UMB_PROPERTY_SETTINGS_MODAL } from '@umbraco-cms/backoffice/modal'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/workspace/views/search/components/log-viewer-search-input-modal.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/workspace/views/search/components/log-viewer-search-input-modal.element.ts index 7fc279c8eb..7266e6c8d3 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/workspace/views/search/components/log-viewer-search-input-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/workspace/views/search/components/log-viewer-search-input-modal.element.ts @@ -1,9 +1,9 @@ import { html, css } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, query, state } from 'lit/decorators.js'; +import { UUIInputElement } from '@umbraco-ui/uui'; import { UmbModalBaseElement } from '@umbraco-cms/internal/modal'; import { SavedLogSearchPresenationBaseModel } from '@umbraco-cms/backoffice/backend-api'; -import { UUIInputElement } from '@umbraco-ui/uui'; @customElement('umb-log-viewer-save-search-modal') export default class UmbLogViewerSaveSearchModalElement extends UmbModalBaseElement< From 8ce8c769f1d696a274c4b22f744e12b8e560899b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 20 Apr 2023 13:05:27 +0200 Subject: [PATCH 129/156] correct story --- .../shared/modals/icon-picker/icon-picker-modal.stories.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/modals/icon-picker/icon-picker-modal.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/modals/icon-picker/icon-picker-modal.stories.ts index 53ee8a5bdb..17de382faf 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/modals/icon-picker/icon-picker-modal.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/modals/icon-picker/icon-picker-modal.stories.ts @@ -14,8 +14,8 @@ export default { } as Meta; const data: UmbIconPickerModalData = { - multiple: true, - selection: [], + color: undefined, + icon: undefined, }; export const Overview: Story = () => html` From feb315079a9e8e7fb5abd53c0a54d0e12653c3bf Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 20 Apr 2023 13:06:05 +0200 Subject: [PATCH 130/156] update after merge --- src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts | 6 +++--- src/Umbraco.Web.UI.Client/libs/store/store-base.ts | 6 +++--- .../src/backoffice/packages/repository/package.store.ts | 2 +- .../settings/data-types/repository/data-type-item.store.ts | 4 ++-- .../settings/languages/repository/language-item.store.ts | 4 ++-- .../users/user-groups/repository/user-group.store.ts | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts b/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts index 42f9ec025d..1f3b8601ce 100644 --- a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts +++ b/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts @@ -1,6 +1,6 @@ import { UmbItemRepository } from '@umbraco-cms/backoffice/repository'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { ArrayState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; import { createExtensionClass, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api'; import { UMB_CONFIRM_MODAL, @@ -20,10 +20,10 @@ export class UmbPickerContext { public modalContext?: UmbModalContext; - #selection = new ArrayState([]); + #selection = new UmbArrayState([]); selection = this.#selection.asObservable(); - #selectedItems = new ArrayState([]); + #selectedItems = new UmbArrayState([]); selectedItems = this.#selectedItems.asObservable(); #selectedItemsObserver?: UmbObserverController; diff --git a/src/Umbraco.Web.UI.Client/libs/store/store-base.ts b/src/Umbraco.Web.UI.Client/libs/store/store-base.ts index 5092c7bba2..dcd9244391 100644 --- a/src/Umbraco.Web.UI.Client/libs/store/store-base.ts +++ b/src/Umbraco.Web.UI.Client/libs/store/store-base.ts @@ -1,16 +1,16 @@ import { UmbStore } from './store.interface'; import { UmbContextProviderController } from '@umbraco-cms/backoffice/context-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; // TODO: Make a Store interface? export class UmbStoreBase implements UmbStore { protected _host: UmbControllerHostElement; - protected _data: ArrayState; + protected _data: UmbArrayState; public readonly storeAlias: string; - constructor(_host: UmbControllerHostElement, storeAlias: string, data: ArrayState) { + constructor(_host: UmbControllerHostElement, storeAlias: string, data: UmbArrayState) { this._host = _host; this.storeAlias = storeAlias; this._data = data; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/package.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/package.store.ts index ad5d0886a7..13a9ce6aa9 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/package.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/package.store.ts @@ -44,7 +44,7 @@ export class UmbPackageStore extends UmbStoreBase { constructor(host: UmbControllerHostElement) { // TODO: revisit this store. Is it ok to have multiple data sets? // temp hack to satisfy the base class - super(host, UMB_PACKAGE_STORE_TOKEN.toString(), new ArrayState([], (x) => x.name)); + super(host, UMB_PACKAGE_STORE_TOKEN.toString(), new UmbArrayState([], (x) => x.name)); } /** diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type-item.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type-item.store.ts index 2a16ad7b55..8fe3a5205a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type-item.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type-item.store.ts @@ -2,7 +2,7 @@ import { DataTypeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbItemStore, UmbStoreBase } from '@umbraco-cms/backoffice/store'; -import { ArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; /** * @export @@ -24,7 +24,7 @@ export class UmbDataTypeItemStore super( host, UMB_DATA_TYPE_ITEM_STORE_CONTEXT_TOKEN.toString(), - new ArrayState([], (x) => x.id) + new UmbArrayState([], (x) => x.id) ); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language-item.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language-item.store.ts index 26eaa68a76..e475a0d96b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language-item.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/repository/language-item.store.ts @@ -1,7 +1,7 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import { UmbStoreBase } from '@umbraco-cms/backoffice/store'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; -import { ArrayState, partialUpdateFrozenArray } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; import { LanguageResponseModel } from '@umbraco-cms/backoffice/backend-api'; import type { UmbItemStore } from '@umbraco-cms/backoffice/store'; @@ -21,7 +21,7 @@ export class UmbLanguageItemStore super( host, UMB_LANGUAGE_ITEM_STORE_CONTEXT_TOKEN.toString(), - new ArrayState([], (x) => x.isoCode) + new UmbArrayState([], (x) => x.isoCode) ); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/repository/user-group.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/repository/user-group.store.ts index 33c3b013d6..b3eb6f3cd6 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/repository/user-group.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/repository/user-group.store.ts @@ -20,7 +20,7 @@ export class UmbUserGroupStore extends UmbStoreBase implements UmbEntityDetailSt public groups = this.#groups.asObservable(); constructor(host: UmbControllerHostElement) { - super(host, UMB_USER_GROUP_STORE_CONTEXT_TOKEN.toString(), new ArrayState([], (x) => x.id)); + super(host, UMB_USER_GROUP_STORE_CONTEXT_TOKEN.toString(), new UmbArrayState([], (x) => x.id)); } getScaffold(entityType: string, parentId: string | null) { From fe76963986478a17af9d0dee3f4877ab40c1394b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 20 Apr 2023 13:20:10 +0200 Subject: [PATCH 131/156] remove local selectedIds --- .../data-type-input/data-type-input.element.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts index 58d541eeb9..eaa458eeb6 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts @@ -62,17 +62,16 @@ export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) { @property({ type: String, attribute: 'min-message' }) maxMessage = 'This field exceeds the allowed amount of items'; - private _selectedIds: Array = []; public get selectedIds(): Array { - return this._selectedIds; + return this.#pickerContext.getSelection(); } public set selectedIds(ids: Array) { - this._selectedIds = ids; - super.value = ids.join(','); + this.#pickerContext.setSelection(ids); } @property() public set value(idsString: string) { + super.value = idsString; if (idsString !== this._value) { this.selectedIds = idsString.split(/[ ,]+/); } @@ -89,16 +88,16 @@ export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) { this.addValidator( 'rangeUnderflow', () => this.minMessage, - () => !!this.min && this._selectedIds.length < this.min + () => !!this.min && this.#pickerContext.getSelection().length < this.min ); this.addValidator( 'rangeOverflow', () => this.maxMessage, - () => !!this.max && this._selectedIds.length > this.max + () => !!this.max && this.#pickerContext.getSelection().length > this.max ); - this.observe(this.#pickerContext.selection, (selection) => (this._selectedIds = selection)); + this.observe(this.#pickerContext.selection, (selection) => (super.value = selection.join(','))); this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems)); } From da19377d0f2da612d6f9139824da1bb9c93905ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 20 Apr 2023 13:25:14 +0200 Subject: [PATCH 132/156] simpler solution --- .../components/data-type-input/data-type-input.element.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts index eaa458eeb6..a82fdd2557 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts @@ -71,10 +71,8 @@ export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) { @property() public set value(idsString: string) { - super.value = idsString; - if (idsString !== this._value) { - this.selectedIds = idsString.split(/[ ,]+/); - } + // Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection. + this.selectedIds = idsString.split(/[ ,]+/); } @state() From 5a9816575293af88aa7be16125e918dd803bba4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 20 Apr 2023 13:25:23 +0200 Subject: [PATCH 133/156] language input --- .../input-language-picker.element.ts | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts index 53e5a7ff46..285202350e 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts @@ -66,20 +66,17 @@ export class UmbInputLanguagePickerElement extends FormControlMixin(UmbLitElemen @property({ type: Object, attribute: false }) public filter: (language: LanguageResponseModel) => boolean = () => true; - private _selectedIsoCodes: Array = []; public get selectedIsoCodes(): Array { - return this._selectedIsoCodes; + return this.#pickerContext.getSelection(); } - public set selectedIsoCodes(isoCodes: Array) { - this._selectedIsoCodes = isoCodes; - super.value = isoCodes.join(','); + public set selectedIsoCodes(ids: Array) { + this.#pickerContext.setSelection(ids); } @property() public set value(isoCodesString: string) { - if (isoCodesString !== this._value) { - this.selectedIsoCodes = isoCodesString.split(/[ ,]+/); - } + // Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection. + this.selectedIsoCodes = isoCodesString.split(/[ ,]+/); } @state() @@ -93,16 +90,16 @@ export class UmbInputLanguagePickerElement extends FormControlMixin(UmbLitElemen this.addValidator( 'rangeUnderflow', () => this.minMessage, - () => !!this.min && this._selectedIsoCodes.length < this.min + () => !!this.min && this.#pickerContext.getSelection().length < this.min ); this.addValidator( 'rangeOverflow', () => this.maxMessage, - () => !!this.max && this._selectedIsoCodes.length > this.max + () => !!this.max && this.#pickerContext.getSelection().length > this.max ); - this.observe(this.#pickerContext.selection, (selection) => (this._selectedIsoCodes = selection)); + this.observe(this.#pickerContext.selection, (selection) => (super.value = selection.join(','))); this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems)); } @@ -125,7 +122,7 @@ export class UmbInputLanguagePickerElement extends FormControlMixin(UmbLitElemen look="placeholder" @click=${this._openPicker} label="open" - ?disabled="${this._selectedIsoCodes.length === this.max}" + ?disabled="${this._items.length === this.max}" >Add
`; From 2bec8f3ffb8c3d15f2bebafddc7716cee798336e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 20 Apr 2023 13:25:59 +0200 Subject: [PATCH 134/156] move style --- .../input-language-picker.element.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts index 285202350e..db52b5c846 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts @@ -9,14 +9,6 @@ import type { LanguageResponseModel } from '@umbraco-cms/backoffice/backend-api' @customElement('umb-input-language-picker') export class UmbInputLanguagePickerElement extends FormControlMixin(UmbLitElement) { - static styles = [ - UUITextStyles, - css` - #add-button { - width: 100%; - } - `, - ]; /** * This is a minimum amount of selected items in this input. * @type {number} @@ -141,6 +133,15 @@ export class UmbInputLanguagePickerElement extends FormControlMixin(UmbLitElemen `; } + + static styles = [ + UUITextStyles, + css` + #add-button { + width: 100%; + } + `, + ]; } export default UmbInputLanguagePickerElement; From 17c08741b8bc78635508528394c21bc3eeff3536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 20 Apr 2023 13:26:22 +0200 Subject: [PATCH 135/156] move style to bottom --- .../data-type-input/data-type-input.element.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts index a82fdd2557..c8c28070e2 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.element.ts @@ -8,14 +8,6 @@ import type { DataTypeItemResponseModel } from '@umbraco-cms/backoffice/backend- @customElement('umb-data-type-input') export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) { - static styles = [ - UUITextStyles, - css` - #add-button { - width: 100%; - } - `, - ]; /** * This is a minimum amount of selected items in this input. * @type {number} @@ -126,6 +118,15 @@ export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) {
`; } + + static styles = [ + UUITextStyles, + css` + #add-button { + width: 100%; + } + `, + ]; } export default UmbDataTypeInputElement; From e61763524f81957abf55d70871932ae8cce359e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 20 Apr 2023 13:28:48 +0200 Subject: [PATCH 136/156] todo comment --- src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts b/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts index 1f3b8601ce..183b5fc6ac 100644 --- a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts +++ b/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts @@ -75,6 +75,7 @@ export class UmbPickerContext { } // TODO: revisit this method. How do we best pass picker data? + // If modalAlias is a ModalToken, then via TS, we should get the correct type for pickerData. Otherwise fallback to unknown. openPicker(pickerData?: any) { if (!this.modalContext) throw new Error('Modal context is not initialized'); From ece6e59a707544a3130f6d9406fd22f7f9868366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 20 Apr 2023 13:28:53 +0200 Subject: [PATCH 137/156] clean up --- .../input-language-picker/input-language-picker.element.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts index db52b5c846..2be4babdbd 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts @@ -102,7 +102,6 @@ export class UmbInputLanguagePickerElement extends FormControlMixin(UmbLitElemen private _openPicker() { this.#pickerContext.openPicker({ filter: this.filter, - hello: 'world', }); } From 8687efd7b263751ef96cb075a9b268f880b53640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 20 Apr 2023 13:34:01 +0200 Subject: [PATCH 138/156] rename picker context to picker input context --- src/Umbraco.Web.UI.Client/libs/picker-input/index.ts | 1 + .../picker-input.context.ts} | 2 +- src/Umbraco.Web.UI.Client/libs/picker/index.ts | 1 - .../components/data-type-input/data-type-input.context.ts | 4 ++-- .../input-language-picker/input-language-picker.context.ts | 4 ++-- src/Umbraco.Web.UI.Client/tsconfig.json | 3 +-- 6 files changed, 7 insertions(+), 8 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/libs/picker-input/index.ts rename src/Umbraco.Web.UI.Client/libs/{picker/picker.context.ts => picker-input/picker-input.context.ts} (98%) delete mode 100644 src/Umbraco.Web.UI.Client/libs/picker/index.ts diff --git a/src/Umbraco.Web.UI.Client/libs/picker-input/index.ts b/src/Umbraco.Web.UI.Client/libs/picker-input/index.ts new file mode 100644 index 0000000000..74b8745179 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/picker-input/index.ts @@ -0,0 +1 @@ +export * from './picker-input.context'; diff --git a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts b/src/Umbraco.Web.UI.Client/libs/picker-input/picker-input.context.ts similarity index 98% rename from src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts rename to src/Umbraco.Web.UI.Client/libs/picker-input/picker-input.context.ts index 183b5fc6ac..3c8bae91c2 100644 --- a/src/Umbraco.Web.UI.Client/libs/picker/picker.context.ts +++ b/src/Umbraco.Web.UI.Client/libs/picker-input/picker-input.context.ts @@ -12,7 +12,7 @@ import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-ap import { ItemResponseModelBaseModel } from '@umbraco-cms/backoffice/backend-api'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/events'; -export class UmbPickerContext { +export class UmbPickerInputContext { host: UmbControllerHostElement; modalAlias: string | UmbModalToken; repository?: UmbItemRepository; diff --git a/src/Umbraco.Web.UI.Client/libs/picker/index.ts b/src/Umbraco.Web.UI.Client/libs/picker/index.ts deleted file mode 100644 index 49b83a7cbe..0000000000 --- a/src/Umbraco.Web.UI.Client/libs/picker/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './picker.context'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.context.ts index fc528332e8..7da977cf7c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.context.ts @@ -1,9 +1,9 @@ -import { UmbPickerContext } from '@umbraco-cms/backoffice/picker'; +import { UmbPickerInputContext } from 'libs/picker-input'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UMB_DATA_TYPE_PICKER_MODAL } from '@umbraco-cms/backoffice/modal'; import { DataTypeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; -export class UmbDataTypePickerContext extends UmbPickerContext { +export class UmbDataTypePickerContext extends UmbPickerInputContext { constructor(host: UmbControllerHostElement) { super(host, 'Umb.Repository.DataType', UMB_DATA_TYPE_PICKER_MODAL); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.context.ts index d9807b1246..18756c4894 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.context.ts @@ -1,9 +1,9 @@ -import { UmbPickerContext } from '@umbraco-cms/backoffice/picker'; +import { UmbPickerInputContext } from 'libs/picker-input'; import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UMB_LANGUAGE_PICKER_MODAL } from '@umbraco-cms/backoffice/modal'; import type { LanguageItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; -export class UmbLanguagePickerContext extends UmbPickerContext { +export class UmbLanguagePickerContext extends UmbPickerInputContext { constructor(host: UmbControllerHostElement) { super(host, 'Umb.Repository.Language', UMB_LANGUAGE_PICKER_MODAL, (item) => item.isoCode); } diff --git a/src/Umbraco.Web.UI.Client/tsconfig.json b/src/Umbraco.Web.UI.Client/tsconfig.json index 4331c9a1ae..cf14c77b4f 100644 --- a/src/Umbraco.Web.UI.Client/tsconfig.json +++ b/src/Umbraco.Web.UI.Client/tsconfig.json @@ -39,12 +39,11 @@ "@umbraco-cms/backoffice/store": ["libs/store"], "@umbraco-cms/backoffice/utils": ["libs/utils"], "@umbraco-cms/backoffice/workspace": ["libs/workspace"], - "@umbraco-cms/backoffice/picker": ["libs/picker"], + "@umbraco-cms/backoffice/picker": ["libs/picker-input"], "@umbraco-cms/internal/lit-element": ["src/core/lit-element"], "@umbraco-cms/internal/modal": ["src/core/modal"], "@umbraco-cms/internal/router": ["src/core/router"], "@umbraco-cms/internal/test-utils": ["utils/test-utils.ts"] - } }, "include": ["src/**/*.ts", "apps/**/*.ts", "libs/**/*.ts", "e2e/**/*.ts"], From 16def43e91f2ae0499308cddd3d1308854987b15 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 20 Apr 2023 13:44:45 +0200 Subject: [PATCH 139/156] update imports --- .../components/data-type-input/data-type-input.context.ts | 2 +- .../input-language-picker/input-language-picker.context.ts | 2 +- src/Umbraco.Web.UI.Client/web-test-runner.config.mjs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.context.ts index 7da977cf7c..06b3e5762e 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/components/data-type-input/data-type-input.context.ts @@ -1,4 +1,4 @@ -import { UmbPickerInputContext } from 'libs/picker-input'; +import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UMB_DATA_TYPE_PICKER_MODAL } from '@umbraco-cms/backoffice/modal'; import { DataTypeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.context.ts index 18756c4894..80568ccff4 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.context.ts @@ -1,4 +1,4 @@ -import { UmbPickerInputContext } from 'libs/picker-input'; +import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input'; import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UMB_LANGUAGE_PICKER_MODAL } from '@umbraco-cms/backoffice/modal'; import type { LanguageItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; diff --git a/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs b/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs index 1c2161cc20..8f411f5ca9 100644 --- a/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs +++ b/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs @@ -56,7 +56,7 @@ export default { '@umbraco-cms/backoffice/store': './libs/store/index.ts', '@umbraco-cms/backoffice/utils': './libs/utils/index.ts', '@umbraco-cms/backoffice/workspace': './libs/workspace/index.ts', - '@umbraco-cms/backoffice/picker': './libs/picker/index.ts', + '@umbraco-cms/backoffice/picker-input': './libs/picker-input/index.ts', '@umbraco-cms/internal/lit-element': './src/core/lit-element/index.ts', '@umbraco-cms/internal/modal': './src/core/modal/index.ts', '@umbraco-cms/internal/router': './src/core/router/index.ts', From be8e46915f6df0cacbfb5e85fedbfb76c279b31e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 20 Apr 2023 13:49:23 +0200 Subject: [PATCH 140/156] update import alias --- src/Umbraco.Web.UI.Client/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/tsconfig.json b/src/Umbraco.Web.UI.Client/tsconfig.json index cf14c77b4f..65560fc2ce 100644 --- a/src/Umbraco.Web.UI.Client/tsconfig.json +++ b/src/Umbraco.Web.UI.Client/tsconfig.json @@ -39,7 +39,7 @@ "@umbraco-cms/backoffice/store": ["libs/store"], "@umbraco-cms/backoffice/utils": ["libs/utils"], "@umbraco-cms/backoffice/workspace": ["libs/workspace"], - "@umbraco-cms/backoffice/picker": ["libs/picker-input"], + "@umbraco-cms/backoffice/picker-input": ["libs/picker-input"], "@umbraco-cms/internal/lit-element": ["src/core/lit-element"], "@umbraco-cms/internal/modal": ["src/core/modal"], "@umbraco-cms/internal/router": ["src/core/router"], From a390d9716169412f60f013b099a053ada73835a5 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 20 Apr 2023 13:51:45 +0200 Subject: [PATCH 141/156] dump package json schema in dist folder to be included in libs on npm --- src/Umbraco.Web.UI.Client/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 5d2efff018..43f9908f11 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -45,7 +45,7 @@ "format:fix": "npm run format -- --write", "generate:api": "openapi --input https://raw.githubusercontent.com/umbraco/Umbraco-CMS/v13/dev/src/Umbraco.Cms.Api.Management/OpenApi.json --output libs/backend-api/src --postfix Resource --useOptions", "generate:api-dev": "openapi --input http://localhost:11000/umbraco/swagger/v1/swagger.json --output libs/backend-api/src --postfix Resource --useOptions", - "generate:jsonschema": "typescript-json-schema --required --include \"./libs/extensions-registry/*.ts\" --out types/umbraco-package-schema.json tsconfig.json UmbracoPackage", + "generate:jsonschema": "typescript-json-schema --required --include \"./libs/extensions-registry/*.ts\" --out dist/libs/umbraco-package-schema.json tsconfig.json UmbracoPackage", "storybook": "npm run wc-analyze && storybook dev -p 6006", "storybook:build": "npm run wc-analyze && storybook build", "build-storybook": "npm run wc-analyze && storybook build", From 450617156676970defef7b93e65bb06c5e88006f Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 20 Apr 2023 13:51:55 +0200 Subject: [PATCH 142/156] build cms prereqs on each build --- src/Umbraco.Web.UI.Client/package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 43f9908f11..37f3c65f60 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -30,8 +30,9 @@ "build": "tsc && vite build --mode staging", "build:libs": "npm run wc-analyze && npm run wc-analyze:vscode && rollup -c rollup-libs.config.js && node utils/move-libs.js", "build:for:static": "tsc && vite build", - "build:for:cms": "tsc && npm run build:libs && npm run generate:jsonschema && vite build -c vite.cms.config.ts", - "build:for:cms:watch": "tsc && npm run build:libs && vite build -c vite.cms.config.ts --watch", + "build:cms:prereq": "tsc && npm run build:libs && npm run generate:jsonschema", + "build:for:cms": "npm run build:cms:prereq && vite build -c vite.cms.config.ts", + "build:for:cms:watch": "npm run build:cms:prereq && vite build -c vite.cms.config.ts --watch", "preview": "vite preview --open", "test": "web-test-runner --coverage", "test:watch": "web-test-runner --watch", From 0480885de506d2978c2bd90bfa93b5b45698f202 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 20 Apr 2023 14:24:22 +0200 Subject: [PATCH 143/156] dump wca files directly in dist/libs --- src/Umbraco.Web.UI.Client/package.json | 4 ++-- src/Umbraco.Web.UI.Client/utils/move-libs.js | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 37f3c65f60..40fa2acea1 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -51,8 +51,8 @@ "storybook:build": "npm run wc-analyze && storybook build", "build-storybook": "npm run wc-analyze && storybook build", "generate:icons": "node ./devops/icons/index.js", - "wc-analyze": "wca **/*.element.ts --outFile custom-elements.json", - "wc-analyze:vscode": "wca **/*.element.ts --format vscode --outFile vscode-html-custom-data.json", + "wc-analyze": "wca **/*.element.ts --outFile dist/libs/custom-elements.json", + "wc-analyze:vscode": "wca **/*.element.ts --format vscode --outFile dist/libs/vscode-html-custom-data.json", "new-extension": "plop --plopfile ./devops/plop/plop.js", "compile": "tsc", "check": "npm run lint && npm run compile && npm run build-storybook" diff --git a/src/Umbraco.Web.UI.Client/utils/move-libs.js b/src/Umbraco.Web.UI.Client/utils/move-libs.js index 59c3f7d044..f6acff0560 100644 --- a/src/Umbraco.Web.UI.Client/utils/move-libs.js +++ b/src/Umbraco.Web.UI.Client/utils/move-libs.js @@ -23,8 +23,6 @@ const outputDir = '../Umbraco.Cms.StaticAssets/wwwroot/umbraco/backoffice/libs'; // Copy package files cpSync(`${srcDir}/package.json`, `${inputDir}/package.json`, { recursive: true }); cpSync(`${srcDir}/README.md`, `${inputDir}/README.md`, { recursive: true }); -cpSync(`${rootDir}/custom-elements.json`, `${inputDir}/custom-elements.json`, { recursive: true }); -cpSync(`${rootDir}/vscode-html-custom-data.json`, `${inputDir}/vscode-html-custom-data.json`, { recursive: true }); const libs = readdirSync(inputDir); From 8cbf3e9bab52d8260a81a885040a4230669dd6c2 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 20 Apr 2023 14:24:52 +0200 Subject: [PATCH 144/156] move umbraco-package-schema.json directly with move-libs instead of vite --- src/Umbraco.Web.UI.Client/utils/move-libs.js | 2 ++ src/Umbraco.Web.UI.Client/vite.cms.config.ts | 14 ++------------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/utils/move-libs.js b/src/Umbraco.Web.UI.Client/utils/move-libs.js index f6acff0560..4fa8dc8702 100644 --- a/src/Umbraco.Web.UI.Client/utils/move-libs.js +++ b/src/Umbraco.Web.UI.Client/utils/move-libs.js @@ -19,10 +19,12 @@ const rootDir = './'; const srcDir = './libs'; const inputDir = './dist/libs'; const outputDir = '../Umbraco.Cms.StaticAssets/wwwroot/umbraco/backoffice/libs'; +const executableDir = '../Umbraco.Web.UI.New'; // Copy package files cpSync(`${srcDir}/package.json`, `${inputDir}/package.json`, { recursive: true }); cpSync(`${srcDir}/README.md`, `${inputDir}/README.md`, { recursive: true }); +cpSync(`${inputDir}/umbraco-package-schema.json`, `${executableDir}/umbraco-json-schema.json`, { recursive: true }); const libs = readdirSync(inputDir); diff --git a/src/Umbraco.Web.UI.Client/vite.cms.config.ts b/src/Umbraco.Web.UI.Client/vite.cms.config.ts index 4cca6ea50c..a2ac17fd86 100644 --- a/src/Umbraco.Web.UI.Client/vite.cms.config.ts +++ b/src/Umbraco.Web.UI.Client/vite.cms.config.ts @@ -11,7 +11,7 @@ export default defineConfig({ fileName: 'main', }, rollupOptions: { - external: [/^@umbraco-cms\/backoffice\//] + external: [/^@umbraco-cms\/backoffice\//], }, outDir: '../Umbraco.Cms.StaticAssets/wwwroot/umbraco/backoffice', emptyOutDir: false, @@ -19,15 +19,5 @@ export default defineConfig({ }, base: '/umbraco/backoffice/', mode: 'production', - plugins: [ - ...plugins, - viteStaticCopy({ - targets: [ - { - src: 'types/umbraco-package-schema.json', - dest: '../../../../Umbraco.Web.UI.New', - }, - ], - }), - ], + plugins: [...plugins], }); From 58c3cf6e48a939e762c8c3a8f851fb1a00b7d66f Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 20 Apr 2023 14:24:59 +0200 Subject: [PATCH 145/156] improve documentation --- src/Umbraco.Web.UI.Client/utils/move-libs.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/utils/move-libs.js b/src/Umbraco.Web.UI.Client/utils/move-libs.js index 4fa8dc8702..acd4601aa7 100644 --- a/src/Umbraco.Web.UI.Client/utils/move-libs.js +++ b/src/Umbraco.Web.UI.Client/utils/move-libs.js @@ -3,19 +3,15 @@ // Example: import { Foo } from '@umbraco-cms/backoffice/element' -> import { Foo } from './element' // This is needed because the d.ts files are not in the same folder as the source files // and the absolute paths are not valid when the d.ts files are copied to the dist folder -// This is only used when building the d.ts files +// This is only used when building the d.ts files. // -// Usage: node utils/transform-dts.js +// This script also copies the package.json and README.md files to the dist/libs folder +// and the umbraco-package-schema.json file to the Umbraco.Web.UI.New folder // -// Note: This script is not used in the build process, it is only used to transform the d.ts files -// when the d.ts files are copied to the dist folder - -// Note: Updated to help copy the two JSON files generated from webcomponant analyzer tool -// One is specific to VSCode HTMLCutomData for intellisense and the other is a more broad format used in storybook etc +// Usage: node utils/move-libs.js import { readdirSync, readFileSync, writeFileSync, cpSync, mkdirSync } from 'fs'; -const rootDir = './'; const srcDir = './libs'; const inputDir = './dist/libs'; const outputDir = '../Umbraco.Cms.StaticAssets/wwwroot/umbraco/backoffice/libs'; From 7b4752791496916d5a279033a74bd0f2ae3f67e8 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 20 Apr 2023 14:30:24 +0200 Subject: [PATCH 146/156] only copy relevant files --- src/Umbraco.Web.UI.Client/utils/move-libs.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/utils/move-libs.js b/src/Umbraco.Web.UI.Client/utils/move-libs.js index acd4601aa7..405f05af63 100644 --- a/src/Umbraco.Web.UI.Client/utils/move-libs.js +++ b/src/Umbraco.Web.UI.Client/utils/move-libs.js @@ -19,8 +19,11 @@ const executableDir = '../Umbraco.Web.UI.New'; // Copy package files cpSync(`${srcDir}/package.json`, `${inputDir}/package.json`, { recursive: true }); +console.log(`Copied ${srcDir}/package.json to ${inputDir}/package.json`); cpSync(`${srcDir}/README.md`, `${inputDir}/README.md`, { recursive: true }); +console.log(`Copied ${srcDir}/README.md to ${inputDir}/README.md`); cpSync(`${inputDir}/umbraco-package-schema.json`, `${executableDir}/umbraco-json-schema.json`, { recursive: true }); +console.log(`Copied ${inputDir}/umbraco-package-schema.json to ${executableDir}/umbraco-json-schema.json`); const libs = readdirSync(inputDir); @@ -34,6 +37,8 @@ try { // Transform all .d.ts files and copy all other files to the output folder libs.forEach(lib => { + if (lib.endsWith('.js') === false && lib.endsWith('.js.map') === false) return; + console.log(`Transforming ${lib}`); const dtsFile = `${inputDir}/${lib}`; From d123041eb77d7063b3abbe119216b06a8e3f34d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 20 Apr 2023 14:36:49 +0200 Subject: [PATCH 147/156] note --- .../settings/data-types/repository/data-type.repository.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.repository.ts index f293fb3250..52a24e2a58 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.repository.ts @@ -294,6 +294,7 @@ export class UmbDataTypeRepository const { error } = await this.#moveSource.move(id, targetId); if (!error) { + // TODO: Be aware about this responsibility. this.#treeStore?.updateItem(id, { parentId: targetId }); this.#treeStore?.updateItem(targetId, { hasChildren: true }); From f7da3fdb5750c6b775e0977e95476d82e3221880 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 20 Apr 2023 14:41:22 +0200 Subject: [PATCH 148/156] fix name of package-schema --- src/Umbraco.Web.UI.Client/utils/move-libs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/utils/move-libs.js b/src/Umbraco.Web.UI.Client/utils/move-libs.js index 405f05af63..76c29dade7 100644 --- a/src/Umbraco.Web.UI.Client/utils/move-libs.js +++ b/src/Umbraco.Web.UI.Client/utils/move-libs.js @@ -23,7 +23,7 @@ console.log(`Copied ${srcDir}/package.json to ${inputDir}/package.json`); cpSync(`${srcDir}/README.md`, `${inputDir}/README.md`, { recursive: true }); console.log(`Copied ${srcDir}/README.md to ${inputDir}/README.md`); cpSync(`${inputDir}/umbraco-package-schema.json`, `${executableDir}/umbraco-json-schema.json`, { recursive: true }); -console.log(`Copied ${inputDir}/umbraco-package-schema.json to ${executableDir}/umbraco-json-schema.json`); +console.log(`Copied ${inputDir}/umbraco-package-schema.json to ${executableDir}/umbraco-package-schema.json`); const libs = readdirSync(inputDir); From 9f36ebedd7929dbd7ae5ce80a32a80b5dea11f7c Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 20 Apr 2023 14:41:33 +0200 Subject: [PATCH 149/156] move libs as last step --- src/Umbraco.Web.UI.Client/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 40fa2acea1..ebefbf1bec 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -28,9 +28,9 @@ "scripts": { "dev": "vite", "build": "tsc && vite build --mode staging", - "build:libs": "npm run wc-analyze && npm run wc-analyze:vscode && rollup -c rollup-libs.config.js && node utils/move-libs.js", + "build:libs": "npm run wc-analyze && npm run wc-analyze:vscode && rollup -c rollup-libs.config.js", "build:for:static": "tsc && vite build", - "build:cms:prereq": "tsc && npm run build:libs && npm run generate:jsonschema", + "build:cms:prereq": "tsc && npm run build:libs && npm run generate:jsonschema && node utils/move-libs.js", "build:for:cms": "npm run build:cms:prereq && vite build -c vite.cms.config.ts", "build:for:cms:watch": "npm run build:cms:prereq && vite build -c vite.cms.config.ts --watch", "preview": "vite preview --open", From 12cd6b9a95602138a8ef5e5aa71dc801c9943083 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 20 Apr 2023 15:02:00 +0200 Subject: [PATCH 150/156] make sure all prereqs are present in build:libs --- src/Umbraco.Web.UI.Client/package.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index ebefbf1bec..f2aef92bcc 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -28,11 +28,10 @@ "scripts": { "dev": "vite", "build": "tsc && vite build --mode staging", - "build:libs": "npm run wc-analyze && npm run wc-analyze:vscode && rollup -c rollup-libs.config.js", + "build:libs": "npm run wc-analyze && npm run wc-analyze:vscode && npm run generate:jsonschema && rollup -c rollup-libs.config.js && node utils/move-libs.js", "build:for:static": "tsc && vite build", - "build:cms:prereq": "tsc && npm run build:libs && npm run generate:jsonschema && node utils/move-libs.js", - "build:for:cms": "npm run build:cms:prereq && vite build -c vite.cms.config.ts", - "build:for:cms:watch": "npm run build:cms:prereq && vite build -c vite.cms.config.ts --watch", + "build:for:cms": "tsc && npm run build:libs && vite build -c vite.cms.config.ts", + "build:for:cms:watch": "tsc && npm run build:libs && vite build -c vite.cms.config.ts --watch", "preview": "vite preview --open", "test": "web-test-runner --coverage", "test:watch": "web-test-runner --watch", From 588887b779bf556062af80a21c0ad55a64e811cb Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 20 Apr 2023 15:03:58 +0200 Subject: [PATCH 151/156] fix storybook build --- src/Umbraco.Web.UI.Client/.storybook/preview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/.storybook/preview.js b/src/Umbraco.Web.UI.Client/.storybook/preview.js index 822d951f3a..e55d5c7558 100644 --- a/src/Umbraco.Web.UI.Client/.storybook/preview.js +++ b/src/Umbraco.Web.UI.Client/.storybook/preview.js @@ -13,7 +13,7 @@ import { UmbDocumentTypeStore } from '../src/backoffice/documents/document-types import { UmbDocumentStore } from '../src/backoffice/documents/documents/repository/document.store.ts'; import { UmbDocumentTreeStore } from '../src/backoffice/documents/documents/repository/document.tree.store.ts'; -import customElementManifests from '../custom-elements.json'; +import customElementManifests from '../dist/libs/custom-elements.json'; import { UmbIconStore } from '../src/core/stores/icon/icon.store'; import { onUnhandledRequest } from '../src/core/mocks/browser'; import { handlers } from '../src/core/mocks/browser-handlers'; From 39ecc9fd32c1ee9fb179fedca5aa6be70e470d00 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 20 Apr 2023 15:21:08 +0200 Subject: [PATCH 152/156] Feature: Data Type Copy Action (#653) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add copy data source * add copy repo * add copy logic to mock db * add copy request interceptor * add data type copy server data source * add copy method to data type repo * add data type copy entity action * show copied notification * update hasChildren flag * use correct icon * note --------- Co-authored-by: Niels Lyngsø Co-authored-by: Niels Lyngsø --- .../repository/copy-repository.interface.ts | 5 +++ .../data-source/copy-data-source.interface.ts | 5 +++ .../libs/repository/data-source/index.ts | 1 + .../libs/repository/index.ts | 1 + .../entity-actions/copy/copy.action.ts | 27 ++++++++++++ .../entity-actions/copy/manifests.ts | 24 +++++++++++ .../data-types/entity-actions/manifests.ts | 4 +- .../repository/data-type.repository.ts | 26 ++++++++++- .../sources/data-type-copy.server.data.ts | 43 +++++++++++++++++++ .../src/core/mocks/data/entity.data.ts | 25 +++++++++++ .../mocks/domains/data-type/copy.handlers.ts | 18 ++++++++ .../src/core/mocks/domains/data-type/index.ts | 10 ++++- 12 files changed, 185 insertions(+), 4 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/libs/repository/copy-repository.interface.ts create mode 100644 src/Umbraco.Web.UI.Client/libs/repository/data-source/copy-data-source.interface.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/copy/copy.action.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/copy/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/sources/data-type-copy.server.data.ts create mode 100644 src/Umbraco.Web.UI.Client/src/core/mocks/domains/data-type/copy.handlers.ts diff --git a/src/Umbraco.Web.UI.Client/libs/repository/copy-repository.interface.ts b/src/Umbraco.Web.UI.Client/libs/repository/copy-repository.interface.ts new file mode 100644 index 0000000000..f9621e0c30 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/repository/copy-repository.interface.ts @@ -0,0 +1,5 @@ +import { UmbRepositoryResponse } from './detail-repository.interface'; + +export interface UmbCopyRepository { + copy(unique: string, targetUnique: string): Promise>; +} diff --git a/src/Umbraco.Web.UI.Client/libs/repository/data-source/copy-data-source.interface.ts b/src/Umbraco.Web.UI.Client/libs/repository/data-source/copy-data-source.interface.ts new file mode 100644 index 0000000000..b9d41d7971 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/repository/data-source/copy-data-source.interface.ts @@ -0,0 +1,5 @@ +import type { DataSourceResponse } from '@umbraco-cms/backoffice/repository'; + +export interface UmbCopyDataSource { + copy(unique: string, targetUnique: string): Promise>; +} diff --git a/src/Umbraco.Web.UI.Client/libs/repository/data-source/index.ts b/src/Umbraco.Web.UI.Client/libs/repository/data-source/index.ts index 3851c96686..08d765462a 100644 --- a/src/Umbraco.Web.UI.Client/libs/repository/data-source/index.ts +++ b/src/Umbraco.Web.UI.Client/libs/repository/data-source/index.ts @@ -4,3 +4,4 @@ export * from './folder-data-source.interface'; export * from './tree-data-source.interface'; export * from './item-data-source.interface'; export * from './move-data-source.interface'; +export * from './copy-data-source.interface'; diff --git a/src/Umbraco.Web.UI.Client/libs/repository/index.ts b/src/Umbraco.Web.UI.Client/libs/repository/index.ts index 0c73ef0870..ba407c2083 100644 --- a/src/Umbraco.Web.UI.Client/libs/repository/index.ts +++ b/src/Umbraco.Web.UI.Client/libs/repository/index.ts @@ -4,3 +4,4 @@ export * from './tree-repository.interface'; export * from './folder-repository.interface'; export * from './item-repository.interface'; export * from './move-repository.interface'; +export * from './copy-repository.interface'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/copy/copy.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/copy/copy.action.ts new file mode 100644 index 0000000000..9b2fd19b53 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/copy/copy.action.ts @@ -0,0 +1,27 @@ +import { UmbDataTypeRepository } from '../../repository/data-type.repository'; +import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; +import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN, UMB_DATA_TYPE_PICKER_MODAL } from '@umbraco-cms/backoffice/modal'; +import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; + +// TODO: investigate what we need to make a generic copy action +export class UmbCopyDataTypeEntityAction extends UmbEntityActionBase { + #modalContext?: UmbModalContext; + + constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) { + super(host, repositoryAlias, unique); + + new UmbContextConsumerController(this.host, UMB_MODAL_CONTEXT_TOKEN, (instance) => { + this.#modalContext = instance; + }); + } + + async execute() { + if (!this.#modalContext) throw new Error('Modal context is not available'); + if (!this.repository) throw new Error('Repository is not available'); + + const modalHandler = this.#modalContext?.open(UMB_DATA_TYPE_PICKER_MODAL); + const { selection } = await modalHandler.onSubmit(); + await this.repository.copy(this.unique, selection[0]); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/copy/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/copy/manifests.ts new file mode 100644 index 0000000000..726637162b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/copy/manifests.ts @@ -0,0 +1,24 @@ +import { DATA_TYPE_ENTITY_TYPE } from '../..'; +import { DATA_TYPE_REPOSITORY_ALIAS } from '../../repository/manifests'; +import { UmbCopyDataTypeEntityAction } from './copy.action'; +import { ManifestTypes } from '@umbraco-cms/backoffice/extensions-registry'; + +const entityActions: Array = [ + { + type: 'entityAction', + alias: 'Umb.EntityAction.DataType.Copy', + name: 'Copy Data Type Entity Action', + weight: 900, + meta: { + icon: 'umb:documents', + label: 'Copy to...', + repositoryAlias: DATA_TYPE_REPOSITORY_ALIAS, + api: UmbCopyDataTypeEntityAction, + }, + conditions: { + entityType: DATA_TYPE_ENTITY_TYPE, + }, + }, +]; + +export const manifests = [...entityActions]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/manifests.ts index eb57a2b500..64d90c4142 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/entity-actions/manifests.ts @@ -2,6 +2,8 @@ import { DATA_TYPE_ENTITY_TYPE } from '..'; import { DATA_TYPE_REPOSITORY_ALIAS } from '../repository/manifests'; import { manifests as createManifests } from './create/manifests'; import { manifests as moveManifests } from './move/manifests'; +import { manifests as copyManifests } from './copy/manifests'; + import { UmbDeleteEntityAction, UmbDeleteFolderEntityAction, @@ -57,4 +59,4 @@ const entityActions: Array = [ }, ]; -export const manifests = [...entityActions, ...createManifests, ...moveManifests]; +export const manifests = [...entityActions, ...createManifests, ...moveManifests, ...copyManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.repository.ts index 52a24e2a58..fb2608ef19 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.repository.ts @@ -6,12 +6,14 @@ import { UmbDataTypeTreeStore, UMB_DATA_TYPE_TREE_STORE_CONTEXT_TOKEN } from './ import { UmbDataTypeFolderServerDataSource } from './sources/data-type-folder.server.data'; import { UmbDataTypeItemServerDataSource } from './sources/data-type-item.server.data'; import { UMB_DATA_TYPE_ITEM_STORE_CONTEXT_TOKEN, UmbDataTypeItemStore } from './data-type-item.store'; +import { UmbDataTypeCopyServerDataSource } from './sources/data-type-copy.server.data'; import type { UmbTreeRepository, UmbDetailRepository, UmbItemRepository, UmbFolderRepository, UmbMoveRepository, + UmbCopyRepository, } from '@umbraco-cms/backoffice/repository'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; @@ -25,14 +27,14 @@ import { UpdateDataTypeRequestModel, } from '@umbraco-cms/backoffice/backend-api'; import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification'; - export class UmbDataTypeRepository implements UmbItemRepository, UmbTreeRepository, UmbDetailRepository, UmbFolderRepository, - UmbMoveRepository + UmbMoveRepository, + UmbCopyRepository { #init: Promise; @@ -43,6 +45,7 @@ export class UmbDataTypeRepository #folderSource: UmbDataTypeFolderServerDataSource; #itemSource: UmbDataTypeItemServerDataSource; #moveSource: UmbDataTypeMoveServerDataSource; + #copySource: UmbDataTypeCopyServerDataSource; #detailStore?: UmbDataTypeStore; #treeStore?: UmbDataTypeTreeStore; @@ -59,6 +62,7 @@ export class UmbDataTypeRepository this.#folderSource = new UmbDataTypeFolderServerDataSource(this.#host); this.#itemSource = new UmbDataTypeItemServerDataSource(this.#host); this.#moveSource = new UmbDataTypeMoveServerDataSource(this.#host); + this.#copySource = new UmbDataTypeCopyServerDataSource(this.#host); this.#init = Promise.all([ new UmbContextConsumerController(this.#host, UMB_DATA_TYPE_STORE_CONTEXT_TOKEN, (instance) => { @@ -304,6 +308,24 @@ export class UmbDataTypeRepository return { error }; } + + async copy(id: string, targetId: string) { + await this.#init; + const { data: dataTypeCopyId, error } = await this.#copySource.copy(id, targetId); + if (error) return { error }; + + if (dataTypeCopyId) { + const { data: dataTypeCopy } = await this.requestById(dataTypeCopyId); + if (!dataTypeCopy) throw new Error('Could not find copied data type'); + this.#treeStore?.appendItems([dataTypeCopy]); + this.#treeStore?.updateItem(targetId, { hasChildren: true }); + + const notification = { data: { message: `Data type copied` } }; + this.#notificationContext?.peek('positive', notification); + } + + return { data: dataTypeCopyId }; + } } export const createTreeItem = (item: CreateDataTypeRequestModel): FolderTreeItemResponseModel => { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/sources/data-type-copy.server.data.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/sources/data-type-copy.server.data.ts new file mode 100644 index 0000000000..d322063e48 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/sources/data-type-copy.server.data.ts @@ -0,0 +1,43 @@ +import { DataTypeResource } from '@umbraco-cms/backoffice/backend-api'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller'; +import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; +import { UmbCopyDataSource } from '@umbraco-cms/backoffice/repository'; + +/** + * A data source for Data Type items that fetches data from the server + * @export + * @class UmbDataTypeCopyServerDataSource + */ +export class UmbDataTypeCopyServerDataSource implements UmbCopyDataSource { + #host: UmbControllerHostElement; + + /** + * Creates an instance of UmbDataTypeCopyServerDataSource. + * @param {UmbControllerHostElement} host + * @memberof UmbDataTypeCopyServerDataSource + */ + constructor(host: UmbControllerHostElement) { + this.#host = host; + } + + /** + * Copy an item for the given id to the target id + * @param {Array} id + * @return {*} + * @memberof UmbDataTypeCopyServerDataSource + */ + async copy(id: string, targetId: string) { + if (!id) throw new Error('Id is missing'); + if (!targetId) throw new Error('Target Id is missing'); + + return tryExecuteAndNotify( + this.#host, + DataTypeResource.postDataTypeByIdCopy({ + id, + requestBody: { + targetId, + }, + }) + ); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/data/entity.data.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/data/entity.data.ts index 19f132d492..9eb9ba8be8 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/data/entity.data.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/data/entity.data.ts @@ -1,3 +1,4 @@ +import { v4 as uuid } from 'uuid'; import { UmbData } from './data'; import type { Entity } from '@umbraco-cms/backoffice/models'; @@ -60,6 +61,30 @@ export class UmbEntityData extends UmbData { this.updateData(destinationItem); } + copy(ids: Array, destinationKey: string) { + const destinationItem = this.getById(destinationKey); + if (!destinationItem) throw new Error(`Destination item with key ${destinationKey} not found`); + + // TODO: Notice we don't add numbers to the 'copy' name. + const items = this.getByIds(ids); + const copyItems = items.map((item) => { + return { + ...item, + name: item.name + ' Copy', + id: uuid(), + parentId: destinationKey, + }; + }); + + copyItems.forEach((copyItem) => this.insert(copyItem)); + const newIds = copyItems.map((item) => item.id); + + destinationItem.hasChildren = true; + this.updateData(destinationItem); + + return newIds; + } + trash(ids: Array) { const trashedItems: Array = []; diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/data-type/copy.handlers.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/data-type/copy.handlers.ts new file mode 100644 index 0000000000..1d5b764699 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/data-type/copy.handlers.ts @@ -0,0 +1,18 @@ +import { rest } from 'msw'; +import { umbDataTypeData } from '../../data/data-type.data'; +import { slug } from './slug'; +import { umbracoPath } from '@umbraco-cms/backoffice/utils'; + +export const copyHandlers = [ + rest.post(umbracoPath(`${slug}/:id/copy`), async (req, res, ctx) => { + const id = req.params.id as string; + if (!id) return; + + const data = await req.json(); + if (!data) return; + + const newIds = umbDataTypeData.copy([id], data.targetId); + + return res(ctx.status(200), ctx.set({ Location: newIds[0] })); + }), +]; diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/data-type/index.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/data-type/index.ts index 3cd1dc2d02..706757b33e 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/data-type/index.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/data-type/index.ts @@ -3,5 +3,13 @@ import { treeHandlers } from './tree.handlers'; import { detailHandlers } from './detail.handlers'; import { itemHandlers } from './item.handlers'; import { moveHandlers } from './move.handlers'; +import { copyHandlers } from './copy.handlers'; -export const handlers = [...treeHandlers, ...itemHandlers, ...folderHandlers, ...moveHandlers, ...detailHandlers]; +export const handlers = [ + ...treeHandlers, + ...itemHandlers, + ...folderHandlers, + ...moveHandlers, + ...copyHandlers, + ...detailHandlers, +]; From dbebba85c4cfb8268d26b7c8364ca585cacc464f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 20 Apr 2023 15:23:23 +0200 Subject: [PATCH 153/156] add to web test runner --- src/Umbraco.Web.UI.Client/web-test-runner.config.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs b/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs index 8f411f5ca9..9f26fb1b09 100644 --- a/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs +++ b/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs @@ -60,6 +60,7 @@ export default { '@umbraco-cms/internal/lit-element': './src/core/lit-element/index.ts', '@umbraco-cms/internal/modal': './src/core/modal/index.ts', '@umbraco-cms/internal/router': './src/core/router/index.ts', + '@umbraco-cms/internal/sorter': './src/core/sorter/index.ts', '@umbraco-cms/internal/test-utils': './utils/test-utils.ts', }, }, From 59b1c62fde3972546dab845a4d4e2c51a103df64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 20 Apr 2023 15:32:51 +0200 Subject: [PATCH 154/156] cleaned the tests --- .../libs/sorter/sorter.controller.test.ts | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.test.ts b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.test.ts index 8d2671bef2..793236325b 100644 --- a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.test.ts +++ b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.test.ts @@ -1,6 +1,6 @@ -import { expect, oneEvent } from '@open-wc/testing'; +import { expect, fixture, html } from '@open-wc/testing'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; -import { customElement } from 'lit/decorators'; +import { customElement } from 'lit/decorators.js'; import { UmbSorterConfig, UmbSorterController } from './sorter.controller'; type SortEntryType = { @@ -48,20 +48,9 @@ class MyTestSorterControllerElement extends UmbLitElement { describe('UmbContextConsumer', () => { let hostElement: MyTestSorterControllerElement; - let controller: UmbSorterController; - beforeEach(() => { - hostElement = document.createElement('test-my-sorter-controller') as MyTestSorterControllerElement; - controller = (hostElement as any).__umbBlockGridSorterController(); - }); - - describe('Public API', () => { - describe('methods', () => { - it('element gets a internal public method on to retrieve controller', () => { - //expect(hostElement).to.have.property('__umbBlockGridSorterController').that.is.a('function'); - expect(controller).to.not.eq(undefined); - }); - }); + beforeEach(async () => { + hostElement = await fixture(html` `); }); // TODO: Testing ideas: From 6b1f2092b29593775e6e3d6ac5d86ac49a7f1cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 20 Apr 2023 15:33:15 +0200 Subject: [PATCH 155/156] rename class --- .../libs/sorter/sorter.controller.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.test.ts b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.test.ts index 793236325b..99aaa06f40 100644 --- a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.test.ts +++ b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.test.ts @@ -35,7 +35,7 @@ const model: Array = [ ]; @customElement('test-my-sorter-controller') -class MyTestSorterControllerElement extends UmbLitElement { +class UmbTestSorterControllerElement extends UmbLitElement { public sorter; constructor() { @@ -47,7 +47,7 @@ class MyTestSorterControllerElement extends UmbLitElement { } describe('UmbContextConsumer', () => { - let hostElement: MyTestSorterControllerElement; + let hostElement: UmbTestSorterControllerElement; beforeEach(async () => { hostElement = await fixture(html` `); From 459f4b2dacb441ba29e2339e34dcf2d1d0929215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 20 Apr 2023 15:35:37 +0200 Subject: [PATCH 156/156] rename angular version to txt --- .../libs/sorter/{sorter.angular.js => sorter.angular.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Umbraco.Web.UI.Client/libs/sorter/{sorter.angular.js => sorter.angular.txt} (100%) diff --git a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.angular.js b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.angular.txt similarity index 100% rename from src/Umbraco.Web.UI.Client/libs/sorter/sorter.angular.js rename to src/Umbraco.Web.UI.Client/libs/sorter/sorter.angular.txt