From d0c5945f8f7a85effb2f7b485dc9ac62f1407c20 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 6 Mar 2023 12:50:00 +0000 Subject: [PATCH 001/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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/102] 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 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 027/102] 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 028/102] 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 029/102] 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 030/102] 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 031/102] 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 032/102] 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 033/102] 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 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 034/102] 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 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 035/102] 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 036/102] 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 037/102] 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 038/102] 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 039/102] 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 040/102] 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 041/102] 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 042/102] 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 043/102] 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 0880c199f016e9ff85894fe08fdc559a089e47a0 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Apr 2023 10:41:41 +0200 Subject: [PATCH 044/102] 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 045/102] 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 c4b2ddef5524503b98eaa732ec4e12b9d7878061 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Apr 2023 11:10:04 +0200 Subject: [PATCH 046/102] 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 f2c9c23b0086dc96707b5840730418f6305b4f51 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Apr 2023 15:43:59 +0200 Subject: [PATCH 047/102] 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 048/102] 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 049/102] 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 050/102] 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 051/102] 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 052/102] 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 053/102] 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 054/102] 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 055/102] 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 056/102] 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 057/102] 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 058/102] 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 059/102] 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 060/102] 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 061/102] 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 f25880706f4e62df3bc9184a3b4a777372336c11 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 18 Apr 2023 13:29:14 +0200 Subject: [PATCH 062/102] 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 063/102] 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 064/102] 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 065/102] 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 066/102] 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 067/102] 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 068/102] 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 069/102] 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 070/102] 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 071/102] 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 072/102] 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 073/102] 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 7aaf208dc5fec03c1068293d02d6f48aaa7b1246 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 18 Apr 2023 21:14:31 +0200 Subject: [PATCH 074/102] 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 075/102] 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 076/102] 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 077/102] 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 c33a3e3c50daf97557475169f78bca186349d01f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 19 Apr 2023 13:55:39 +0200 Subject: [PATCH 078/102] update label to "Move to..." --- .../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 11e7c1740a..5e7ff4e7c6 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 @@ -11,7 +11,7 @@ const entityActions: Array = [ weight: 900, meta: { icon: 'umb:enter', - label: 'Move...', + label: 'Move to...', repositoryAlias: DATA_TYPE_REPOSITORY_ALIAS, api: UmbMoveDataTypeEntityAction, }, From 90a572ecf6e6d4ec9b138dc434634d464d08e955 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 19 Apr 2023 14:19:53 +0200 Subject: [PATCH 079/102] show moved notification --- .../settings/data-types/repository/data-type.repository.ts | 3 +++ 1 file changed, 3 insertions(+) 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 2f49e173f2..f293fb3250 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 @@ -296,6 +296,9 @@ export class UmbDataTypeRepository if (!error) { this.#treeStore?.updateItem(id, { parentId: targetId }); this.#treeStore?.updateItem(targetId, { hasChildren: true }); + + const notification = { data: { message: `Data type moved` } }; + this.#notificationContext?.peek('positive', notification); } return { error }; From f6970b5b6c01dd7aa4c9ae557efa1f464720c08f Mon Sep 17 00:00:00 2001 From: Jason Elkin Date: Thu, 16 Mar 2023 11:20:45 +0000 Subject: [PATCH 080/102] 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:06:05 +0200 Subject: [PATCH 081/102] 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 082/102] 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 083/102] 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 084/102] 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 085/102] 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 086/102] 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 087/102] 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 088/102] 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 089/102] 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 090/102] 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 091/102] 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 092/102] 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 093/102] 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 094/102] 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 095/102] 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 096/102] 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 097/102] 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 098/102] 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 099/102] 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 100/102] 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 101/102] 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 102/102] 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';