From fa8f7e9832e423be8e4df1c6ecd59c4fd89cd432 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Wed, 11 Jan 2023 16:22:42 +0100 Subject: [PATCH 1/7] update eslint plugins and install eslint-plugin-wc --- src/Umbraco.Web.UI.Client/package-lock.json | 123 ++++++++++++++------ src/Umbraco.Web.UI.Client/package.json | 14 +-- 2 files changed, 94 insertions(+), 43 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index ad54152aeb..9f8123374c 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -20,7 +20,6 @@ "element-internals-polyfill": "^1.1.18", "lit": "^2.6.0", "lodash": "^4.17.21", - "openapi-typescript-fetch": "^1.1.3", "router-slot": "^1.5.5", "rxjs": "^7.8.0", "uuid": "^9.0.0" @@ -50,12 +49,13 @@ "babel-loader": "^9.1.2", "eslint": "^8.31.0", "eslint-config-prettier": "^8.6.0", - "eslint-import-resolver-typescript": "^3.5.2", + "eslint-import-resolver-typescript": "^3.5.3", "eslint-plugin-import": "^2.26.0", - "eslint-plugin-lit": "^1.7.2", + "eslint-plugin-lit": "^1.8.0", "eslint-plugin-lit-a11y": "^2.3.0", "eslint-plugin-local-rules": "^1.3.2", - "eslint-plugin-storybook": "^0.6.8", + "eslint-plugin-storybook": "^0.6.10", + "eslint-plugin-wc": "^1.4.0", "lit-html": "^2.6.0", "msw": "^0.49.2", "msw-storybook-addon": "^1.6.3", @@ -12853,9 +12853,9 @@ } }, "node_modules/eslint-import-resolver-typescript": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.2.tgz", - "integrity": "sha512-zX4ebnnyXiykjhcBvKIf5TNvt8K7yX6bllTRZ14MiurKPjDpCAZujlszTdB8pcNXhZcOf+god4s9SjQa5GnytQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.3.tgz", + "integrity": "sha512-njRcKYBc3isE42LaTcJNVANR3R99H9bAxBDMNDr2W7yq5gYPxbU3MkdhsQukxZ/Xg9C2vcyLlDsbKfRDg0QvCQ==", "dev": true, "dependencies": { "debug": "^4.3.4", @@ -12989,9 +12989,9 @@ "dev": true }, "node_modules/eslint-plugin-lit": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.7.2.tgz", - "integrity": "sha512-vkz9KvwVfHg7yDQCmokLGzUDypg683miswSw5xBiTszv4Qyus5/CgAK7U7dMgbVBa8G5wxHedY2zr9VCMNTaPQ==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.8.0.tgz", + "integrity": "sha512-wY/Z4SksuTkpELl4okhXHBf63V44PV2n19/HOBa7cPH6g+yyzvIMpIZ26BQbzEC54GwwWoYtONY3WvAjMNV8Cg==", "dev": true, "dependencies": { "parse5": "^6.0.1", @@ -13040,9 +13040,9 @@ "dev": true }, "node_modules/eslint-plugin-storybook": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.6.8.tgz", - "integrity": "sha512-57vyICs19ODx0ql+shM0hKFn4Nvwcrdw29KJbj6QKGZ+Y47aDws/lvBx65++F0vpEsr0lkZljSdUbxWjIP2+Rw==", + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.6.10.tgz", + "integrity": "sha512-3DKXRey06EhwnTKaG6fgMqGTy4C3z6Ikyv6VVixO5BvaExWQe3yGWIAufrC2Et0OaAMIaMwx9KWjqb/Wq+JxPg==", "dev": true, "dependencies": { "@storybook/csf": "^0.0.1", @@ -13066,6 +13066,19 @@ "lodash": "^4.17.15" } }, + "node_modules/eslint-plugin-wc": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-wc/-/eslint-plugin-wc-1.4.0.tgz", + "integrity": "sha512-AmoKhJyBNcS3I+dbS/JTmRSq4REUvQ/JJCeWJezlK8gqTsdr5JD+EAvHldH/tVvU+l6qR2Tykga5hTINP9zS8A==", + "dev": true, + "dependencies": { + "is-valid-element-name": "^1.0.0", + "js-levenshtein-esm": "^1.2.0" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, "node_modules/eslint-rule-extender": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/eslint-rule-extender/-/eslint-rule-extender-0.0.1.tgz", @@ -16565,6 +16578,12 @@ "node": ">=0.10.0" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, "node_modules/is-reference": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.0.tgz", @@ -16721,6 +16740,15 @@ "dev": true, "optional": true }, + "node_modules/is-valid-element-name": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-valid-element-name/-/is-valid-element-name-1.0.0.tgz", + "integrity": "sha512-GZITEJY2LkSjQfaIPBha7eyZv+ge0PhBR7KITeCCWvy7VBQrCUdFkvpI+HrAPQjVtVjy1LvlEkqQTHckoszruw==", + "dev": true, + "dependencies": { + "is-potential-custom-element-name": "^1.0.0" + } + }, "node_modules/is-weakmap": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", @@ -17135,6 +17163,12 @@ "node": ">=0.10.0" } }, + "node_modules/js-levenshtein-esm": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/js-levenshtein-esm/-/js-levenshtein-esm-1.2.0.tgz", + "integrity": "sha512-fzreKVq1eD7eGcQr7MtRpQH94f8gIfhdrc7yeih38xh684TNMK9v5aAu2wxfIRMk/GpAJRrzcirMAPIaSDaByQ==", + "dev": true + }, "node_modules/js-sdsl": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", @@ -20547,15 +20581,6 @@ "node": ">=12" } }, - "node_modules/openapi-typescript-fetch": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/openapi-typescript-fetch/-/openapi-typescript-fetch-1.1.3.tgz", - "integrity": "sha512-smLZPck4OkKMNExcw8jMgrMOGgVGx2N/s6DbKL2ftNl77g5HfoGpZGFy79RBzU/EkaO0OZpwBnslfdBfh7ZcWg==", - "engines": { - "node": ">= 12.0.0", - "npm": ">= 7.0.0" - } - }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -38218,9 +38243,9 @@ } }, "eslint-import-resolver-typescript": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.2.tgz", - "integrity": "sha512-zX4ebnnyXiykjhcBvKIf5TNvt8K7yX6bllTRZ14MiurKPjDpCAZujlszTdB8pcNXhZcOf+god4s9SjQa5GnytQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.3.tgz", + "integrity": "sha512-njRcKYBc3isE42LaTcJNVANR3R99H9bAxBDMNDr2W7yq5gYPxbU3MkdhsQukxZ/Xg9C2vcyLlDsbKfRDg0QvCQ==", "dev": true, "requires": { "debug": "^4.3.4", @@ -38321,9 +38346,9 @@ } }, "eslint-plugin-lit": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.7.2.tgz", - "integrity": "sha512-vkz9KvwVfHg7yDQCmokLGzUDypg683miswSw5xBiTszv4Qyus5/CgAK7U7dMgbVBa8G5wxHedY2zr9VCMNTaPQ==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-lit/-/eslint-plugin-lit-1.8.0.tgz", + "integrity": "sha512-wY/Z4SksuTkpELl4okhXHBf63V44PV2n19/HOBa7cPH6g+yyzvIMpIZ26BQbzEC54GwwWoYtONY3WvAjMNV8Cg==", "dev": true, "requires": { "parse5": "^6.0.1", @@ -38365,9 +38390,9 @@ "dev": true }, "eslint-plugin-storybook": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.6.8.tgz", - "integrity": "sha512-57vyICs19ODx0ql+shM0hKFn4Nvwcrdw29KJbj6QKGZ+Y47aDws/lvBx65++F0vpEsr0lkZljSdUbxWjIP2+Rw==", + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.6.10.tgz", + "integrity": "sha512-3DKXRey06EhwnTKaG6fgMqGTy4C3z6Ikyv6VVixO5BvaExWQe3yGWIAufrC2Et0OaAMIaMwx9KWjqb/Wq+JxPg==", "dev": true, "requires": { "@storybook/csf": "^0.0.1", @@ -38387,6 +38412,16 @@ } } }, + "eslint-plugin-wc": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-wc/-/eslint-plugin-wc-1.4.0.tgz", + "integrity": "sha512-AmoKhJyBNcS3I+dbS/JTmRSq4REUvQ/JJCeWJezlK8gqTsdr5JD+EAvHldH/tVvU+l6qR2Tykga5hTINP9zS8A==", + "dev": true, + "requires": { + "is-valid-element-name": "^1.0.0", + "js-levenshtein-esm": "^1.2.0" + } + }, "eslint-rule-extender": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/eslint-rule-extender/-/eslint-rule-extender-0.0.1.tgz", @@ -40935,6 +40970,12 @@ "isobject": "^3.0.1" } }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, "is-reference": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.0.tgz", @@ -41043,6 +41084,15 @@ "dev": true, "optional": true }, + "is-valid-element-name": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-valid-element-name/-/is-valid-element-name-1.0.0.tgz", + "integrity": "sha512-GZITEJY2LkSjQfaIPBha7eyZv+ge0PhBR7KITeCCWvy7VBQrCUdFkvpI+HrAPQjVtVjy1LvlEkqQTHckoszruw==", + "dev": true, + "requires": { + "is-potential-custom-element-name": "^1.0.0" + } + }, "is-weakmap": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", @@ -41354,6 +41404,12 @@ "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", "dev": true }, + "js-levenshtein-esm": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/js-levenshtein-esm/-/js-levenshtein-esm-1.2.0.tgz", + "integrity": "sha512-fzreKVq1eD7eGcQr7MtRpQH94f8gIfhdrc7yeih38xh684TNMK9v5aAu2wxfIRMk/GpAJRrzcirMAPIaSDaByQ==", + "dev": true + }, "js-sdsl": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", @@ -43936,11 +43992,6 @@ } } }, - "openapi-typescript-fetch": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/openapi-typescript-fetch/-/openapi-typescript-fetch-1.1.3.tgz", - "integrity": "sha512-smLZPck4OkKMNExcw8jMgrMOGgVGx2N/s6DbKL2ftNl77g5HfoGpZGFy79RBzU/EkaO0OZpwBnslfdBfh7ZcWg==" - }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index a210efb369..3e1abf368f 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -35,7 +35,7 @@ "test": "web-test-runner --coverage", "test:watch": "web-test-runner --watch", "test:e2e": "npx playwright test", - "lint": "eslint --cache src e2e", + "lint": "eslint src e2e", "lint:fix": "npm run lint -- --fix", "format": "prettier 'src/**/*.ts'", "format:fix": "npm run format -- --write", @@ -56,17 +56,16 @@ }, "dependencies": { "@umbraco-ui/uui": "^1.0.2", + "@umbraco-ui/uui-color-swatch": "file:umbraco-ui-uui-color-swatch-0.0.0.tgz", + "@umbraco-ui/uui-color-swatches": "file:umbraco-ui-uui-color-swatches-2.0.0.tgz", "@umbraco-ui/uui-css": "^1.0.0", "@umbraco-ui/uui-modal": "file:umbraco-ui-uui-modal-0.0.0.tgz", "@umbraco-ui/uui-modal-container": "file:umbraco-ui-uui-modal-container-0.0.0.tgz", "@umbraco-ui/uui-modal-dialog": "file:umbraco-ui-uui-modal-dialog-0.0.0.tgz", "@umbraco-ui/uui-modal-sidebar": "file:umbraco-ui-uui-modal-sidebar-0.0.0.tgz", - "@umbraco-ui/uui-color-swatches": "file:umbraco-ui-uui-color-swatches-2.0.0.tgz", - "@umbraco-ui/uui-color-swatch": "file:umbraco-ui-uui-color-swatch-0.0.0.tgz", "element-internals-polyfill": "^1.1.18", "lit": "^2.6.0", "lodash": "^4.17.21", - "openapi-typescript-fetch": "^1.1.3", "router-slot": "^1.5.5", "rxjs": "^7.8.0", "uuid": "^9.0.0" @@ -96,12 +95,13 @@ "babel-loader": "^9.1.2", "eslint": "^8.31.0", "eslint-config-prettier": "^8.6.0", - "eslint-import-resolver-typescript": "^3.5.2", + "eslint-import-resolver-typescript": "^3.5.3", "eslint-plugin-import": "^2.26.0", - "eslint-plugin-lit": "^1.7.2", + "eslint-plugin-lit": "^1.8.0", "eslint-plugin-lit-a11y": "^2.3.0", "eslint-plugin-local-rules": "^1.3.2", - "eslint-plugin-storybook": "^0.6.8", + "eslint-plugin-storybook": "^0.6.10", + "eslint-plugin-wc": "^1.4.0", "lit-html": "^2.6.0", "msw": "^0.49.2", "msw-storybook-addon": "^1.6.3", From fcbd777c98bcb4181739c99a08a0bf81763e7d63 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Wed, 11 Jan 2023 16:22:59 +0100 Subject: [PATCH 2/7] cleanup eslint config and enable eslint-plugin-wc --- src/Umbraco.Web.UI.Client/.eslintrc.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/.eslintrc.json b/src/Umbraco.Web.UI.Client/.eslintrc.json index 5034e34797..1d78b5edbf 100644 --- a/src/Umbraco.Web.UI.Client/.eslintrc.json +++ b/src/Umbraco.Web.UI.Client/.eslintrc.json @@ -1,18 +1,18 @@ { "ignorePatterns": ["vite.*.ts"], "root": true, + "plugins": ["eslint-plugin-local-rules"], "extends": ["eslint:recommended", "plugin:import/recommended", "prettier"], - "plugins": ["import", "eslint-plugin-local-rules"], "overrides": [ { "files": ["**/*.ts"], - "plugins": ["import", "@typescript-eslint", "lit", "lit-a11y"], "extends": [ "eslint:recommended", "plugin:import/recommended", "plugin:import/typescript", "plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended", + "plugin:wc/recommended", "plugin:lit/recommended", "plugin:lit-a11y/recommended", "plugin:storybook/recommended", @@ -34,7 +34,8 @@ "import/no-unresolved": "error", "import/order": "warn", "local-rules/bad-type-import": "error", - "local-rules/no-direct-api-import": "warn" + "local-rules/no-direct-api-import": "warn", + "@typescript-eslint/no-non-null-assertion": "off" }, "settings": { "import/parsers": { From be2a105fc21b33bf8d55d51a40b5a6d7da0c2b33 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Wed, 11 Jan 2023 16:23:14 +0100 Subject: [PATCH 3/7] fix errors as listed by eslint-plugin-wc --- .../collection-view-media-grid.element.ts | 47 ++++++++++++------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/collection/views/collection-view-media-grid.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/collection/views/collection-view-media-grid.element.ts index 73f4f93dfb..52d943758a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/collection/views/collection-view-media-grid.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/collection/views/collection-view-media-grid.element.ts @@ -74,23 +74,36 @@ export class UmbCollectionViewsMediaGridElement extends UmbLitElement { constructor() { super(); - document.addEventListener('dragenter', () => { - this.toggleAttribute('dragging', true); - }); - document.addEventListener('dragleave', () => { - this.toggleAttribute('dragging', false); - }); - document.addEventListener('drop', (e) => { - e.preventDefault(); - this.toggleAttribute('dragging', false); - }); + document.addEventListener('dragenter', this._handleDragEnter.bind(this)); + document.addEventListener('dragleave', this._handleDragLeave.bind(this)); + document.addEventListener('drop', this._handleDrop.bind(this)); this.consumeContext('umbCollectionContext', (instance) => { - console.log("umbCollectionContext", instance) + console.log('umbCollectionContext', instance); this._collectionContext = instance; this._observeCollectionContext(); }); } + disconnectedCallback(): void { + super.disconnectedCallback(); + document.removeEventListener('dragenter', this._handleDragEnter.bind(this)); + document.removeEventListener('dragleave', this._handleDragLeave.bind(this)); + document.removeEventListener('drop', this._handleDrop.bind(this)); + } + + private _handleDragEnter() { + this.toggleAttribute('dragging', true); + } + + private _handleDragLeave() { + this.toggleAttribute('dragging', false); + } + + private _handleDrop(e: DragEvent) { + e.preventDefault(); + this.toggleAttribute('dragging', false); + } + private _observeCollectionContext() { if (!this._collectionContext) return; @@ -144,11 +157,13 @@ export class UmbCollectionViewsMediaGridElement extends UmbLitElement { label="Drop files here" accept="">
- ${this._mediaItems ? repeat( - this._mediaItems, - (file, index) => file.key + index, - (file) => this._renderMediaItem(file) - ) : ''} + ${this._mediaItems + ? repeat( + this._mediaItems, + (file, index) => file.key + index, + (file) => this._renderMediaItem(file) + ) + : ''}
`; } From 887efc7e767051e1179bb684d40f8303887f32bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 12 Jan 2023 09:57:26 +0100 Subject: [PATCH 4/7] add and use unique to replace controllers if one of the same type comes along. --- .../consume/context-consumer.controller.ts | 4 ++++ .../context-api/consume/context-consumer.ts | 2 +- .../provide/context-provider.controller.ts | 4 ++++ .../context-api/provide/context-provider.ts | 8 ++++---- .../core/controller/controller-host.mixin.ts | 11 +++++++++++ .../src/core/controller/controller.class.ts | 9 ++++++++- .../core/controller/controller.interface.ts | 1 + .../src/core/element/element.mixin.ts | 6 +++--- .../observable-api/observer.controller.ts | 19 +++++++++++++++++-- .../src/core/observable-api/observer.ts | 12 ++---------- .../src/core/resources/resource.controller.ts | 5 +++-- 11 files changed, 58 insertions(+), 23 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/core/context-api/consume/context-consumer.controller.ts b/src/Umbraco.Web.UI.Client/src/core/context-api/consume/context-consumer.controller.ts index fd89ccf2ea..ecf921af17 100644 --- a/src/Umbraco.Web.UI.Client/src/core/context-api/consume/context-consumer.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/core/context-api/consume/context-consumer.controller.ts @@ -6,6 +6,10 @@ import { UmbControllerHostInterface } from 'src/core/controller/controller-host. export class UmbContextConsumerController extends UmbContextConsumer implements UmbControllerInterface { + public get unique() { + return this._contextAlias; + } + constructor(host:UmbControllerHostInterface, contextAlias: string, callback: UmbContextCallback) { super(host, contextAlias, callback); host.addController(this); diff --git a/src/Umbraco.Web.UI.Client/src/core/context-api/consume/context-consumer.ts b/src/Umbraco.Web.UI.Client/src/core/context-api/consume/context-consumer.ts index 84c8ba1af4..0d6261875a 100644 --- a/src/Umbraco.Web.UI.Client/src/core/context-api/consume/context-consumer.ts +++ b/src/Umbraco.Web.UI.Client/src/core/context-api/consume/context-consumer.ts @@ -23,7 +23,7 @@ export class UmbContextConsumer { * @param {UmbContextCallback} _callback * @memberof UmbContextConsumer */ - constructor(protected host: HostType, private _contextAlias: string, private _callback: UmbContextCallback) {} + constructor(protected host: HostType, protected _contextAlias: string, private _callback: UmbContextCallback) {} private _onResponse = (instance: unknown) => { diff --git a/src/Umbraco.Web.UI.Client/src/core/context-api/provide/context-provider.controller.ts b/src/Umbraco.Web.UI.Client/src/core/context-api/provide/context-provider.controller.ts index efd9d239a8..301f260c27 100644 --- a/src/Umbraco.Web.UI.Client/src/core/context-api/provide/context-provider.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/core/context-api/provide/context-provider.controller.ts @@ -5,6 +5,10 @@ import { UmbControllerHostInterface } from 'src/core/controller/controller-host. export class UmbContextProviderController extends UmbContextProvider implements UmbControllerInterface { + public get unique() { + return this._contextAlias; + } + constructor(host:UmbControllerHostInterface, contextAlias: string, instance: unknown) { super(host, contextAlias, instance); diff --git a/src/Umbraco.Web.UI.Client/src/core/context-api/provide/context-provider.ts b/src/Umbraco.Web.UI.Client/src/core/context-api/provide/context-provider.ts index 3bb525cd56..02d183216f 100644 --- a/src/Umbraco.Web.UI.Client/src/core/context-api/provide/context-provider.ts +++ b/src/Umbraco.Web.UI.Client/src/core/context-api/provide/context-provider.ts @@ -9,8 +9,8 @@ export class UmbContextProvider { protected host: HostType; - private _contextAlias: string; - private _instance: unknown; + protected _contextAlias: string; + #instance: unknown; /** * Creates an instance of UmbContextProvider. @@ -22,7 +22,7 @@ export class UmbContextProvider { constructor(host: HostType, contextAlias: string, instance: unknown) { this.host = host; this._contextAlias = contextAlias; - this._instance = instance; + this.#instance = instance; } /** @@ -51,6 +51,6 @@ export class UmbContextProvider { if (event.contextAlias !== this._contextAlias) return; event.stopPropagation(); - event.callback(this._instance); + event.callback(this.#instance); }; } diff --git a/src/Umbraco.Web.UI.Client/src/core/controller/controller-host.mixin.ts b/src/Umbraco.Web.UI.Client/src/core/controller/controller-host.mixin.ts index ede2d1a138..a71bc71ab7 100644 --- a/src/Umbraco.Web.UI.Client/src/core/controller/controller-host.mixin.ts +++ b/src/Umbraco.Web.UI.Client/src/core/controller/controller-host.mixin.ts @@ -45,6 +45,17 @@ export const UmbControllerHostMixin = (superCl * @param {UmbControllerInterface} ctrl */ addController(ctrl: UmbControllerInterface): void { + + // Check if there is one already with same unique + if(ctrl.unique) { + this.#controllers.forEach(x => { + if(x.unique === ctrl.unique) { + debugger; + this.removeController(x); + } + }); + } + this.#controllers.push(ctrl); if(this.#attached) { ctrl.hostConnected(); diff --git a/src/Umbraco.Web.UI.Client/src/core/controller/controller.class.ts b/src/Umbraco.Web.UI.Client/src/core/controller/controller.class.ts index 355bee9e47..02235df414 100644 --- a/src/Umbraco.Web.UI.Client/src/core/controller/controller.class.ts +++ b/src/Umbraco.Web.UI.Client/src/core/controller/controller.class.ts @@ -4,8 +4,15 @@ import { UmbControllerInterface } from './controller.interface'; export abstract class UmbController implements UmbControllerInterface { protected host?: UmbControllerHostInterface; - constructor(host: UmbControllerHostInterface) { + + private _alias?: string; + public get unique() { + return this._alias; + } + + constructor(host: UmbControllerHostInterface, alias?: string) { this.host = host; + this._alias = alias; this.host.addController(this); } diff --git a/src/Umbraco.Web.UI.Client/src/core/controller/controller.interface.ts b/src/Umbraco.Web.UI.Client/src/core/controller/controller.interface.ts index a70411fca4..f8feb3ff9c 100644 --- a/src/Umbraco.Web.UI.Client/src/core/controller/controller.interface.ts +++ b/src/Umbraco.Web.UI.Client/src/core/controller/controller.interface.ts @@ -1,4 +1,5 @@ export interface UmbControllerInterface { + get unique(): string | undefined; hostConnected(): void; hostDisconnected(): void; destroy(): void; diff --git a/src/Umbraco.Web.UI.Client/src/core/element/element.mixin.ts b/src/Umbraco.Web.UI.Client/src/core/element/element.mixin.ts index 87255a95df..d4bcaf7d3b 100644 --- a/src/Umbraco.Web.UI.Client/src/core/element/element.mixin.ts +++ b/src/Umbraco.Web.UI.Client/src/core/element/element.mixin.ts @@ -12,7 +12,7 @@ interface ResolvedContexts { } export declare class UmbElementMixinInterface extends UmbControllerHostInterface { - observe(source: Observable, callback: (_value: T) => void): UmbObserverController; + observe(source: Observable, callback: (_value: T) => void, unique?: string): UmbObserverController; provideContext(alias: string, instance: unknown): UmbContextProviderController; consumeContext(alias: string, callback: UmbContextCallback): UmbContextConsumerController; consumeAllContexts(contextAliases: string[], callback: (_instances: ResolvedContexts) => void): void; @@ -28,8 +28,8 @@ export const UmbElementMixin = (superClass: T) * @return {UmbObserverController} Reference to a Observer Controller instance * @memberof UmbElementMixin */ - observe(source: Observable, callback: (_value: T) => void): UmbObserverController { - return new UmbObserverController(this, source, callback); + observe(source: Observable, callback: (_value: T) => void, unique?: string): UmbObserverController { + return new UmbObserverController(this, source, callback, unique); } /** diff --git a/src/Umbraco.Web.UI.Client/src/core/observable-api/observer.controller.ts b/src/Umbraco.Web.UI.Client/src/core/observable-api/observer.controller.ts index afc6225df7..6ccf637ff9 100644 --- a/src/Umbraco.Web.UI.Client/src/core/observable-api/observer.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/core/observable-api/observer.controller.ts @@ -6,9 +6,23 @@ import { UmbControllerHostInterface } from 'src/core/controller/controller-host. export class UmbObserverController extends UmbObserver implements UmbControllerInterface { - constructor(host:UmbControllerHostInterface, source: Observable, callback: (_value: T) => void) { + _alias?: string; + public get unique() { + return this._alias; + } + + constructor(host:UmbControllerHostInterface, source: Observable, callback: (_value: T) => void, alias?: string) { super(source, callback); - // TODO: What should happen if source or some? identifier is already present? + this._alias = alias; + + // Lets check if controller is already here: + /* + if (this._subscriptions.has(source)) { + const subscription = this._subscriptions.get(source); + subscription?.unsubscribe(); + } + */ + host.addController(this); } @@ -16,4 +30,5 @@ export class UmbObserverController extends UmbObserver implements UmbContr return; } + } diff --git a/src/Umbraco.Web.UI.Client/src/core/observable-api/observer.ts b/src/Umbraco.Web.UI.Client/src/core/observable-api/observer.ts index d21a9359a0..9fa9968e3f 100644 --- a/src/Umbraco.Web.UI.Client/src/core/observable-api/observer.ts +++ b/src/Umbraco.Web.UI.Client/src/core/observable-api/observer.ts @@ -3,16 +3,8 @@ import { Observable, Subscription } from 'rxjs'; export class UmbObserver { #subscription!: Subscription; - - constructor(source: Observable, callback: (_value: T) => void) { - // TODO: can be transferred to something using alias? - /* - if (this._subscriptions.has(source)) { - const subscription = this._subscriptions.get(source); - subscription?.unsubscribe(); - } - */ + constructor(source: Observable, callback: (_value: T) => void) { this.#subscription = source.subscribe((value) => callback(value)); } @@ -27,4 +19,4 @@ export class UmbObserver { this.#subscription.unsubscribe(); } -}; \ No newline at end of file +}; diff --git a/src/Umbraco.Web.UI.Client/src/core/resources/resource.controller.ts b/src/Umbraco.Web.UI.Client/src/core/resources/resource.controller.ts index 5668c41180..ae3776f47d 100644 --- a/src/Umbraco.Web.UI.Client/src/core/resources/resource.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/core/resources/resource.controller.ts @@ -7,12 +7,13 @@ import { UmbNotificationOptions, UmbNotificationService } from 'src/core/notific import { UmbNotificationDefaultData } from 'src/core/notification/layouts/default'; export class UmbResourceController extends UmbController { + #promise: Promise; #notificationService?: UmbNotificationService; - constructor(host: UmbControllerHostInterface, promise: Promise) { - super(host); + constructor(host: UmbControllerHostInterface, promise: Promise, alias?: string) { + super(host, alias); this.#promise = promise; From 4307846783c56b8746445813f0be536e7d459247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 12 Jan 2023 10:22:34 +0100 Subject: [PATCH 5/7] remove debugger --- .../src/core/controller/controller-host.mixin.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/core/controller/controller-host.mixin.ts b/src/Umbraco.Web.UI.Client/src/core/controller/controller-host.mixin.ts index a71bc71ab7..37291b934e 100644 --- a/src/Umbraco.Web.UI.Client/src/core/controller/controller-host.mixin.ts +++ b/src/Umbraco.Web.UI.Client/src/core/controller/controller-host.mixin.ts @@ -50,7 +50,6 @@ export const UmbControllerHostMixin = (superCl if(ctrl.unique) { this.#controllers.forEach(x => { if(x.unique === ctrl.unique) { - debugger; this.removeController(x); } }); From da6a21ba6753f20f8f47795fc1bbd9c597d809e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 12 Jan 2023 10:22:47 +0100 Subject: [PATCH 6/7] make UmbLitElement non abstract --- .../src/core/element/lit-element.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/core/element/lit-element.element.ts b/src/Umbraco.Web.UI.Client/src/core/element/lit-element.element.ts index 05404a5744..daa2005b81 100644 --- a/src/Umbraco.Web.UI.Client/src/core/element/lit-element.element.ts +++ b/src/Umbraco.Web.UI.Client/src/core/element/lit-element.element.ts @@ -1,6 +1,6 @@ import { LitElement } from 'lit'; import { UmbElementMixin } from './element.mixin'; -export abstract class UmbLitElement extends UmbElementMixin(LitElement) { +export class UmbLitElement extends UmbElementMixin(LitElement) { } From f6d4b15a9f9229047e1ac71565c883e15262d584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 12 Jan 2023 10:22:51 +0100 Subject: [PATCH 7/7] test --- .../src/core/controller/controller.test.ts | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/core/controller/controller.test.ts diff --git a/src/Umbraco.Web.UI.Client/src/core/controller/controller.test.ts b/src/Umbraco.Web.UI.Client/src/core/controller/controller.test.ts new file mode 100644 index 0000000000..4da206b75e --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/core/controller/controller.test.ts @@ -0,0 +1,50 @@ +import { expect } from '@open-wc/testing'; +import { customElement } from 'lit/decorators.js'; +import { UmbContextProviderController } from '../context-api/provide/context-provider.controller'; +import { UmbControllerHostInterface, UmbControllerHostMixin } from './controller-host.mixin'; + +class MyClass { + prop = 'value from provider'; +} + +@customElement('test-my-controller-host') +class MyHostElement extends UmbControllerHostMixin(HTMLElement) { + +} + +describe('UmbContextProvider', () => { + type NewType = UmbControllerHostInterface; + + let hostElement: NewType; + const contextInstance = new MyClass(); + + beforeEach(() => { + hostElement = document.createElement('test-my-controller-host') as UmbControllerHostInterface; + }); + + + describe('Destroyed controllers is gone from host', () => { + it('has a host property', () => { + + const ctrl = new UmbContextProviderController(hostElement, 'my-test-context', contextInstance); + + expect(hostElement.hasController(ctrl)).to.be.true; + + ctrl.destroy(); + + expect(hostElement.hasController(ctrl)).to.be.false; + }); + }); + + describe('Unique controllers replace each other', () => { + it('has a host property', () => { + + const firstCtrl = new UmbContextProviderController(hostElement, 'my-test-context', contextInstance); + const secondCtrl = new UmbContextProviderController(hostElement, 'my-test-context', contextInstance); + + expect(hostElement.hasController(firstCtrl)).to.be.false; + expect(hostElement.hasController(secondCtrl)).to.be.true; + }); + }); + +});