Merge branch 'main' into feature/property-editor-configs-v3
This commit is contained in:
208
src/Umbraco.Web.UI.Client/package-lock.json
generated
208
src/Umbraco.Web.UI.Client/package-lock.json
generated
@@ -17,7 +17,7 @@
|
||||
"@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",
|
||||
"element-internals-polyfill": "^1.1.17",
|
||||
"element-internals-polyfill": "^1.1.18",
|
||||
"lit": "^2.5.0",
|
||||
"lodash": "^4.17.21",
|
||||
"openapi-typescript-fetch": "^1.1.3",
|
||||
@@ -29,7 +29,7 @@
|
||||
"@babel/core": "^7.20.12",
|
||||
"@mdx-js/react": "^2.2.1",
|
||||
"@open-wc/testing": "^3.1.7",
|
||||
"@playwright/test": "^1.29.1",
|
||||
"@playwright/test": "^1.29.2",
|
||||
"@storybook/addon-a11y": "^6.5.15",
|
||||
"@storybook/addon-actions": "^6.5.14",
|
||||
"@storybook/addon-essentials": "^6.5.15",
|
||||
@@ -41,8 +41,8 @@
|
||||
"@types/lodash-es": "^4.17.6",
|
||||
"@types/mocha": "^10.0.0",
|
||||
"@types/uuid": "^9.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.48.0",
|
||||
"@typescript-eslint/parser": "^5.48.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.48.1",
|
||||
"@typescript-eslint/parser": "^5.48.1",
|
||||
"@web/dev-server-esbuild": "^0.3.3",
|
||||
"@web/dev-server-import-maps": "^0.0.7",
|
||||
"@web/test-runner": "^0.15.0",
|
||||
@@ -2897,13 +2897,13 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@playwright/test": {
|
||||
"version": "1.29.1",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.29.1.tgz",
|
||||
"integrity": "sha512-iQxk2DX5U9wOGV3+/Jh9OHPsw5H3mleUL2S4BgQuwtlAfK3PnKvn38m4Rg9zIViGHVW24opSm99HQm/UFLEy6w==",
|
||||
"version": "1.29.2",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.29.2.tgz",
|
||||
"integrity": "sha512-+3/GPwOgcoF0xLz/opTnahel1/y42PdcgZ4hs+BZGIUjtmEFSXGg+nFoaH3NSmuc7a6GSFwXDJ5L7VXpqzigNg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"playwright-core": "1.29.1"
|
||||
"playwright-core": "1.29.2"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
@@ -2913,9 +2913,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@playwright/test/node_modules/playwright-core": {
|
||||
"version": "1.29.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.29.1.tgz",
|
||||
"integrity": "sha512-20Ai3d+lMkWpI9YZYlxk8gxatfgax5STW8GaMozAHwigLiyiKQrdkt7gaoT9UQR8FIVDg6qVXs9IoZUQrDjIIg==",
|
||||
"version": "1.29.2",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.29.2.tgz",
|
||||
"integrity": "sha512-94QXm4PMgFoHAhlCuoWyaBYKb92yOcGVHdQLoxQ7Wjlc7Flg4aC/jbFW7xMR52OfXMVkWicue4WXE7QEegbIRA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
@@ -6375,14 +6375,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.0.tgz",
|
||||
"integrity": "sha512-SVLafp0NXpoJY7ut6VFVUU9I+YeFsDzeQwtK0WZ+xbRN3mtxJ08je+6Oi2N89qDn087COdO0u3blKZNv9VetRQ==",
|
||||
"version": "5.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz",
|
||||
"integrity": "sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "5.48.0",
|
||||
"@typescript-eslint/type-utils": "5.48.0",
|
||||
"@typescript-eslint/utils": "5.48.0",
|
||||
"@typescript-eslint/scope-manager": "5.48.1",
|
||||
"@typescript-eslint/type-utils": "5.48.1",
|
||||
"@typescript-eslint/utils": "5.48.1",
|
||||
"debug": "^4.3.4",
|
||||
"ignore": "^5.2.0",
|
||||
"natural-compare-lite": "^1.4.0",
|
||||
@@ -6423,14 +6423,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.0.tgz",
|
||||
"integrity": "sha512-1mxNA8qfgxX8kBvRDIHEzrRGrKHQfQlbW6iHyfHYS0Q4X1af+S6mkLNtgCOsGVl8+/LUPrqdHMssAemkrQ01qg==",
|
||||
"version": "5.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.1.tgz",
|
||||
"integrity": "sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "5.48.0",
|
||||
"@typescript-eslint/types": "5.48.0",
|
||||
"@typescript-eslint/typescript-estree": "5.48.0",
|
||||
"@typescript-eslint/scope-manager": "5.48.1",
|
||||
"@typescript-eslint/types": "5.48.1",
|
||||
"@typescript-eslint/typescript-estree": "5.48.1",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -6450,13 +6450,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.0.tgz",
|
||||
"integrity": "sha512-0AA4LviDtVtZqlyUQnZMVHydDATpD9SAX/RC5qh6cBd3xmyWvmXYF+WT1oOmxkeMnWDlUVTwdODeucUnjz3gow==",
|
||||
"version": "5.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz",
|
||||
"integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.48.0",
|
||||
"@typescript-eslint/visitor-keys": "5.48.0"
|
||||
"@typescript-eslint/types": "5.48.1",
|
||||
"@typescript-eslint/visitor-keys": "5.48.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
@@ -6467,13 +6467,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.0.tgz",
|
||||
"integrity": "sha512-vbtPO5sJyFjtHkGlGK4Sthmta0Bbls4Onv0bEqOGm7hP9h8UpRsHJwsrCiWtCUndTRNQO/qe6Ijz9rnT/DB+7g==",
|
||||
"version": "5.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz",
|
||||
"integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "5.48.0",
|
||||
"@typescript-eslint/utils": "5.48.0",
|
||||
"@typescript-eslint/typescript-estree": "5.48.1",
|
||||
"@typescript-eslint/utils": "5.48.1",
|
||||
"debug": "^4.3.4",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
@@ -6494,9 +6494,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.0.tgz",
|
||||
"integrity": "sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw==",
|
||||
"version": "5.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz",
|
||||
"integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
@@ -6507,13 +6507,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.0.tgz",
|
||||
"integrity": "sha512-7pjd94vvIjI1zTz6aq/5wwE/YrfIyEPLtGJmRfyNR9NYIW+rOvzzUv3Cmq2hRKpvt6e9vpvPUQ7puzX7VSmsEw==",
|
||||
"version": "5.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz",
|
||||
"integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.48.0",
|
||||
"@typescript-eslint/visitor-keys": "5.48.0",
|
||||
"@typescript-eslint/types": "5.48.1",
|
||||
"@typescript-eslint/visitor-keys": "5.48.1",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
@@ -6549,16 +6549,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.0.tgz",
|
||||
"integrity": "sha512-x2jrMcPaMfsHRRIkL+x96++xdzvrdBCnYRd5QiW5Wgo1OB4kDYPbC1XjWP/TNqlfK93K/lUL92erq5zPLgFScQ==",
|
||||
"version": "5.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz",
|
||||
"integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@types/semver": "^7.3.12",
|
||||
"@typescript-eslint/scope-manager": "5.48.0",
|
||||
"@typescript-eslint/types": "5.48.0",
|
||||
"@typescript-eslint/typescript-estree": "5.48.0",
|
||||
"@typescript-eslint/scope-manager": "5.48.1",
|
||||
"@typescript-eslint/types": "5.48.1",
|
||||
"@typescript-eslint/typescript-estree": "5.48.1",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0",
|
||||
"semver": "^7.3.7"
|
||||
@@ -6590,12 +6590,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.0.tgz",
|
||||
"integrity": "sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q==",
|
||||
"version": "5.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz",
|
||||
"integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.48.0",
|
||||
"@typescript-eslint/types": "5.48.1",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -11810,9 +11810,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/element-internals-polyfill": {
|
||||
"version": "1.1.17",
|
||||
"resolved": "https://registry.npmjs.org/element-internals-polyfill/-/element-internals-polyfill-1.1.17.tgz",
|
||||
"integrity": "sha512-sMDJyJiwvcHB6wLnyG+y/9FRxi/9OyI8bmjyw18K6b5iVlBjmA5CJVTFz4K2I7R53yqevK8WkTrfBmSHJXH9Rw=="
|
||||
"version": "1.1.18",
|
||||
"resolved": "https://registry.npmjs.org/element-internals-polyfill/-/element-internals-polyfill-1.1.18.tgz",
|
||||
"integrity": "sha512-ULyzpzblTZfMPEt83NphWeREajgaKQBNSTXvNBcjTeriIy7GsuAHFUZ0CpHnlDIVdvPlWcewfu7n7vVfiifZlQ=="
|
||||
},
|
||||
"node_modules/element-resize-detector": {
|
||||
"version": "1.2.4",
|
||||
@@ -30476,19 +30476,19 @@
|
||||
}
|
||||
},
|
||||
"@playwright/test": {
|
||||
"version": "1.29.1",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.29.1.tgz",
|
||||
"integrity": "sha512-iQxk2DX5U9wOGV3+/Jh9OHPsw5H3mleUL2S4BgQuwtlAfK3PnKvn38m4Rg9zIViGHVW24opSm99HQm/UFLEy6w==",
|
||||
"version": "1.29.2",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.29.2.tgz",
|
||||
"integrity": "sha512-+3/GPwOgcoF0xLz/opTnahel1/y42PdcgZ4hs+BZGIUjtmEFSXGg+nFoaH3NSmuc7a6GSFwXDJ5L7VXpqzigNg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"playwright-core": "1.29.1"
|
||||
"playwright-core": "1.29.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"playwright-core": {
|
||||
"version": "1.29.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.29.1.tgz",
|
||||
"integrity": "sha512-20Ai3d+lMkWpI9YZYlxk8gxatfgax5STW8GaMozAHwigLiyiKQrdkt7gaoT9UQR8FIVDg6qVXs9IoZUQrDjIIg==",
|
||||
"version": "1.29.2",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.29.2.tgz",
|
||||
"integrity": "sha512-94QXm4PMgFoHAhlCuoWyaBYKb92yOcGVHdQLoxQ7Wjlc7Flg4aC/jbFW7xMR52OfXMVkWicue4WXE7QEegbIRA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@@ -33057,14 +33057,14 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.0.tgz",
|
||||
"integrity": "sha512-SVLafp0NXpoJY7ut6VFVUU9I+YeFsDzeQwtK0WZ+xbRN3mtxJ08je+6Oi2N89qDn087COdO0u3blKZNv9VetRQ==",
|
||||
"version": "5.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz",
|
||||
"integrity": "sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "5.48.0",
|
||||
"@typescript-eslint/type-utils": "5.48.0",
|
||||
"@typescript-eslint/utils": "5.48.0",
|
||||
"@typescript-eslint/scope-manager": "5.48.1",
|
||||
"@typescript-eslint/type-utils": "5.48.1",
|
||||
"@typescript-eslint/utils": "5.48.1",
|
||||
"debug": "^4.3.4",
|
||||
"ignore": "^5.2.0",
|
||||
"natural-compare-lite": "^1.4.0",
|
||||
@@ -33085,53 +33085,53 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.0.tgz",
|
||||
"integrity": "sha512-1mxNA8qfgxX8kBvRDIHEzrRGrKHQfQlbW6iHyfHYS0Q4X1af+S6mkLNtgCOsGVl8+/LUPrqdHMssAemkrQ01qg==",
|
||||
"version": "5.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.1.tgz",
|
||||
"integrity": "sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "5.48.0",
|
||||
"@typescript-eslint/types": "5.48.0",
|
||||
"@typescript-eslint/typescript-estree": "5.48.0",
|
||||
"@typescript-eslint/scope-manager": "5.48.1",
|
||||
"@typescript-eslint/types": "5.48.1",
|
||||
"@typescript-eslint/typescript-estree": "5.48.1",
|
||||
"debug": "^4.3.4"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.0.tgz",
|
||||
"integrity": "sha512-0AA4LviDtVtZqlyUQnZMVHydDATpD9SAX/RC5qh6cBd3xmyWvmXYF+WT1oOmxkeMnWDlUVTwdODeucUnjz3gow==",
|
||||
"version": "5.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz",
|
||||
"integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.48.0",
|
||||
"@typescript-eslint/visitor-keys": "5.48.0"
|
||||
"@typescript-eslint/types": "5.48.1",
|
||||
"@typescript-eslint/visitor-keys": "5.48.1"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/type-utils": {
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.0.tgz",
|
||||
"integrity": "sha512-vbtPO5sJyFjtHkGlGK4Sthmta0Bbls4Onv0bEqOGm7hP9h8UpRsHJwsrCiWtCUndTRNQO/qe6Ijz9rnT/DB+7g==",
|
||||
"version": "5.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz",
|
||||
"integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/typescript-estree": "5.48.0",
|
||||
"@typescript-eslint/utils": "5.48.0",
|
||||
"@typescript-eslint/typescript-estree": "5.48.1",
|
||||
"@typescript-eslint/utils": "5.48.1",
|
||||
"debug": "^4.3.4",
|
||||
"tsutils": "^3.21.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.0.tgz",
|
||||
"integrity": "sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw==",
|
||||
"version": "5.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz",
|
||||
"integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.0.tgz",
|
||||
"integrity": "sha512-7pjd94vvIjI1zTz6aq/5wwE/YrfIyEPLtGJmRfyNR9NYIW+rOvzzUv3Cmq2hRKpvt6e9vpvPUQ7puzX7VSmsEw==",
|
||||
"version": "5.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz",
|
||||
"integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.48.0",
|
||||
"@typescript-eslint/visitor-keys": "5.48.0",
|
||||
"@typescript-eslint/types": "5.48.1",
|
||||
"@typescript-eslint/visitor-keys": "5.48.1",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
@@ -33151,16 +33151,16 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.0.tgz",
|
||||
"integrity": "sha512-x2jrMcPaMfsHRRIkL+x96++xdzvrdBCnYRd5QiW5Wgo1OB4kDYPbC1XjWP/TNqlfK93K/lUL92erq5zPLgFScQ==",
|
||||
"version": "5.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz",
|
||||
"integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@types/semver": "^7.3.12",
|
||||
"@typescript-eslint/scope-manager": "5.48.0",
|
||||
"@typescript-eslint/types": "5.48.0",
|
||||
"@typescript-eslint/typescript-estree": "5.48.0",
|
||||
"@typescript-eslint/scope-manager": "5.48.1",
|
||||
"@typescript-eslint/types": "5.48.1",
|
||||
"@typescript-eslint/typescript-estree": "5.48.1",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0",
|
||||
"semver": "^7.3.7"
|
||||
@@ -33178,12 +33178,12 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.0.tgz",
|
||||
"integrity": "sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q==",
|
||||
"version": "5.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz",
|
||||
"integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.48.0",
|
||||
"@typescript-eslint/types": "5.48.1",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
}
|
||||
},
|
||||
@@ -37472,9 +37472,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"element-internals-polyfill": {
|
||||
"version": "1.1.17",
|
||||
"resolved": "https://registry.npmjs.org/element-internals-polyfill/-/element-internals-polyfill-1.1.17.tgz",
|
||||
"integrity": "sha512-sMDJyJiwvcHB6wLnyG+y/9FRxi/9OyI8bmjyw18K6b5iVlBjmA5CJVTFz4K2I7R53yqevK8WkTrfBmSHJXH9Rw=="
|
||||
"version": "1.1.18",
|
||||
"resolved": "https://registry.npmjs.org/element-internals-polyfill/-/element-internals-polyfill-1.1.18.tgz",
|
||||
"integrity": "sha512-ULyzpzblTZfMPEt83NphWeREajgaKQBNSTXvNBcjTeriIy7GsuAHFUZ0CpHnlDIVdvPlWcewfu7n7vVfiifZlQ=="
|
||||
},
|
||||
"element-resize-detector": {
|
||||
"version": "1.2.4",
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
"@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.17",
|
||||
"element-internals-polyfill": "^1.1.18",
|
||||
"lit": "^2.5.0",
|
||||
"lodash": "^4.17.21",
|
||||
"openapi-typescript-fetch": "^1.1.3",
|
||||
@@ -74,7 +74,7 @@
|
||||
"@babel/core": "^7.20.12",
|
||||
"@mdx-js/react": "^2.2.1",
|
||||
"@open-wc/testing": "^3.1.7",
|
||||
"@playwright/test": "^1.29.1",
|
||||
"@playwright/test": "^1.29.2",
|
||||
"@storybook/addon-a11y": "^6.5.15",
|
||||
"@storybook/addon-actions": "^6.5.14",
|
||||
"@storybook/addon-essentials": "^6.5.15",
|
||||
@@ -86,8 +86,8 @@
|
||||
"@types/lodash-es": "^4.17.6",
|
||||
"@types/mocha": "^10.0.0",
|
||||
"@types/uuid": "^9.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.48.0",
|
||||
"@typescript-eslint/parser": "^5.48.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.48.1",
|
||||
"@typescript-eslint/parser": "^5.48.1",
|
||||
"@web/dev-server-esbuild": "^0.3.3",
|
||||
"@web/dev-server-import-maps": "^0.0.7",
|
||||
"@web/test-runner": "^0.15.0",
|
||||
|
||||
@@ -3,7 +3,7 @@ import { UmbDataStoreBase } from '../../../core/stores/store';
|
||||
import { ApiError, DocumentTypeResource, DocumentTypeTreeItem, ProblemDetails } from '@umbraco-cms/backend-api';
|
||||
import type { DocumentTypeDetails } from '@umbraco-cms/models';
|
||||
|
||||
const isDocumentTypeDetails = (
|
||||
export const isDocumentTypeDetails = (
|
||||
documentType: DocumentTypeDetails | DocumentTypeTreeItem
|
||||
): documentType is DocumentTypeDetails => {
|
||||
return (documentType as DocumentTypeDetails).properties !== undefined;
|
||||
|
||||
@@ -23,4 +23,9 @@ export class UmbWorkspaceDocumentTypeContext extends UmbWorkspaceContentContext<
|
||||
constructor(host: UmbControllerHostInterface) {
|
||||
super(host, DefaultDocumentTypeData, 'umbDocumentTypeStore', 'documentType');
|
||||
}
|
||||
|
||||
|
||||
public setPropertyValue(alias: string, value: unknown) {
|
||||
throw new Error("setPropertyValue is not implemented for UmbWorkspaceDocumentTypeContext")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { UmbNodeStoreBase } from '../../../core/stores/store';
|
||||
import type { DocumentDetails } from '@umbraco-cms/models';
|
||||
import { ApiError, DocumentResource, DocumentTreeItem, FolderTreeItem, ProblemDetails } from '@umbraco-cms/backend-api';
|
||||
|
||||
const isDocumentDetails = (document: DocumentDetails | DocumentTreeItem): document is DocumentDetails => {
|
||||
export const isDocumentDetails = (document: DocumentDetails | DocumentTreeItem): document is DocumentDetails => {
|
||||
return (document as DocumentDetails).data !== undefined;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { UmbWorkspaceContentContext } from '../../../shared/components/workspace/workspace-content/workspace-content.context';
|
||||
import { STORE_ALIAS } from 'src/backoffice/documents/documents/document.store';
|
||||
import { isDocumentDetails, STORE_ALIAS as DOCUMENT_STORE_ALIAS } from 'src/backoffice/documents/documents/document.store';
|
||||
import type { UmbDocumentStore, UmbDocumentStoreItemType } from 'src/backoffice/documents/documents/document.store';
|
||||
import { UmbControllerHostInterface } from 'src/core/controller/controller-host.mixin';
|
||||
import type { DocumentDetails } from '@umbraco-cms/models';
|
||||
|
||||
const DefaultDocumentData = {
|
||||
key: '',
|
||||
@@ -34,11 +35,26 @@ const DefaultDocumentData = {
|
||||
|
||||
export class UmbWorkspaceDocumentContext extends UmbWorkspaceContentContext<UmbDocumentStoreItemType, UmbDocumentStore> {
|
||||
constructor(host: UmbControllerHostInterface) {
|
||||
super(host, DefaultDocumentData, STORE_ALIAS, 'document');
|
||||
super(host, DefaultDocumentData, DOCUMENT_STORE_ALIAS, 'document');
|
||||
}
|
||||
|
||||
public setPropertyValue(alias: string, value: unknown) {
|
||||
const data = this.getData();
|
||||
// TODO: make sure to check that we have a details model:
|
||||
// TODO: make a Method to cast
|
||||
if(isDocumentDetails(data)) {
|
||||
const newDataSet = (data as DocumentDetails).data.map((entry) => {
|
||||
if (entry.alias === alias) {
|
||||
return {alias: alias, value: value};
|
||||
}
|
||||
return entry;
|
||||
});
|
||||
|
||||
|
||||
this.update({data: newDataSet} as Partial<UmbDocumentStoreItemType>);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
concept notes:
|
||||
|
||||
@@ -51,4 +67,4 @@ export class UmbWorkspaceDocumentContext extends UmbWorkspaceContentContext<UmbD
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
@@ -35,4 +35,8 @@ export class UmbWorkspaceMediaContext extends UmbWorkspaceContentContext<UmbMedi
|
||||
constructor(host: UmbControllerHostInterface) {
|
||||
super(host, DefaultMediaData, 'umbMediaStore', 'media');
|
||||
}
|
||||
|
||||
public setPropertyValue(alias: string, value: unknown) {
|
||||
throw new Error("setPropertyValue is not implemented for UmbWorkspaceMediaContext")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ export class UmbDashboardPerformanceProfilingElement extends UmbLitElement {
|
||||
@state()
|
||||
private _profilingPerformance = false;
|
||||
|
||||
connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
constructor() {
|
||||
super();
|
||||
this._getProfilingStatus();
|
||||
this._profilingPerformance = localStorage.getItem('profilingPerformance') === 'true';
|
||||
}
|
||||
|
||||
@@ -10,6 +10,11 @@ const isDataTypeDetails = (dataType: DataTypeDetails | FolderTreeItem): dataType
|
||||
// TODO: can we make is easy to reuse store methods across different stores?
|
||||
|
||||
export type UmbDataTypeStoreItemType = DataTypeDetails | FolderTreeItem;
|
||||
|
||||
// TODO: research how we write names of global consts.
|
||||
export const STORE_ALIAS = 'umbDataTypeStore';
|
||||
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @class UmbDataTypesStore
|
||||
@@ -18,7 +23,7 @@ export type UmbDataTypeStoreItemType = DataTypeDetails | FolderTreeItem;
|
||||
*/
|
||||
export class UmbDataTypeStore extends UmbDataStoreBase<UmbDataTypeStoreItemType> {
|
||||
|
||||
public readonly storeAlias = 'umbDataTypeStore';
|
||||
public readonly storeAlias = STORE_ALIAS;
|
||||
|
||||
/**
|
||||
* @description - Request a Data Type by key. The Data Type is added to the store and is returned as an Observable.
|
||||
|
||||
@@ -2,14 +2,13 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
|
||||
import { css, html } from 'lit';
|
||||
import { ifDefined } from 'lit-html/directives/if-defined.js';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { EMPTY, of, switchMap } from 'rxjs';
|
||||
|
||||
import { UmbDataTypeStore } from '../../../settings/data-types/data-type.store';
|
||||
import type { ContentProperty, ManifestTypes } from '@umbraco-cms/models';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/extensions-registry';
|
||||
import type { ContentProperty, DataTypeDetails } from '@umbraco-cms/models';
|
||||
|
||||
import '../entity-property/entity-property.element';
|
||||
import '../workspace-property/workspace-property.element';
|
||||
import { UmbLitElement } from '@umbraco-cms/element';
|
||||
import { UmbObserverController } from '@umbraco-cms/observable-api';
|
||||
|
||||
@customElement('umb-content-property')
|
||||
export class UmbContentPropertyElement extends UmbLitElement {
|
||||
@@ -22,18 +21,22 @@ export class UmbContentPropertyElement extends UmbLitElement {
|
||||
`,
|
||||
];
|
||||
|
||||
// TODO: Consider if we just need to get the DataType Key?..
|
||||
private _property?: ContentProperty;
|
||||
@property({ type: Object, attribute: false })
|
||||
public get property(): ContentProperty | undefined {
|
||||
return this._property;
|
||||
}
|
||||
public set property(value: ContentProperty | undefined) {
|
||||
const oldProperty = this._property;
|
||||
this._property = value;
|
||||
this._observeDataType();
|
||||
if(this._property?.dataTypeKey !== oldProperty?.dataTypeKey) {
|
||||
this._observeDataType(this._property?.dataTypeKey);
|
||||
}
|
||||
}
|
||||
|
||||
@property()
|
||||
value?: string;
|
||||
value?: object | string;
|
||||
|
||||
@state()
|
||||
private _propertyEditorUIAlias?: string;
|
||||
@@ -42,43 +45,40 @@ export class UmbContentPropertyElement extends UmbLitElement {
|
||||
private _dataTypeData?: any;
|
||||
|
||||
private _dataTypeStore?: UmbDataTypeStore;
|
||||
private _dataTypeObserver?: UmbObserverController<DataTypeDetails | null>;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext('umbDataTypeStore', (instance) => {
|
||||
this._dataTypeStore = instance;
|
||||
this._observeDataType();
|
||||
this._observeDataType(this._property?.dataTypeKey);
|
||||
});
|
||||
}
|
||||
|
||||
private _observeDataType() {
|
||||
if (!this._dataTypeStore || !this._property) return;
|
||||
private _observeDataType(dataTypeKey?: string) {
|
||||
if (!this._dataTypeStore) return;
|
||||
|
||||
this.observe(
|
||||
this._dataTypeStore.getByKey(this._property.dataTypeKey).pipe(
|
||||
switchMap((dataType) => {
|
||||
if (!dataType?.propertyEditorUIAlias) return EMPTY;
|
||||
this._dataTypeData = dataType.data;
|
||||
return umbExtensionsRegistry.getByAlias(dataType.propertyEditorUIAlias) ?? of(null);
|
||||
})
|
||||
),
|
||||
(manifest) => {
|
||||
if (manifest?.type === 'propertyEditorUI') {
|
||||
this._propertyEditorUIAlias = manifest.alias;
|
||||
this._dataTypeObserver?.destroy();
|
||||
if(dataTypeKey) {
|
||||
this._dataTypeObserver = this.observe(
|
||||
this._dataTypeStore.getByKey(dataTypeKey),
|
||||
(dataType) => {
|
||||
this._dataTypeData = dataType?.data;
|
||||
this._propertyEditorUIAlias = dataType?.propertyEditorUIAlias || undefined;
|
||||
}
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`<umb-entity-property
|
||||
label=${ifDefined(this.property?.label)}
|
||||
description=${ifDefined(this.property?.description)}
|
||||
alias="${ifDefined(this.property?.alias)}"
|
||||
return html`<umb-workspace-property
|
||||
alias=${ifDefined(this._property?.alias)}
|
||||
label=${ifDefined(this._property?.label)}
|
||||
description=${ifDefined(this._property?.description)}
|
||||
property-editor-ui-alias="${ifDefined(this._propertyEditorUIAlias)}"
|
||||
.value="${this.value}"
|
||||
.config="${this._dataTypeData}"></umb-entity-property>`;
|
||||
.value=${this.value}
|
||||
.config=${this._dataTypeData}></umb-workspace-property>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import { Meta, Story } from '@storybook/web-components';
|
||||
import { html } from 'lit-html';
|
||||
|
||||
import type { UmbEntityPropertyElement } from './entity-property.element';
|
||||
import './entity-property.element';
|
||||
|
||||
export default {
|
||||
title: 'Components/Entity Property',
|
||||
component: 'umb-entity-property',
|
||||
id: 'umb-entity-property',
|
||||
} as Meta;
|
||||
|
||||
export const AAAOverview: Story<UmbEntityPropertyElement> = () =>
|
||||
html` <umb-entity-property
|
||||
label="Property"
|
||||
description="Description"
|
||||
alias="textProperty"
|
||||
property-editor-ui-alias="Umb.PropertyEditorUI.TextBox"
|
||||
.value="${'Hello'}"></umb-entity-property>`;
|
||||
AAAOverview.storyName = 'Overview';
|
||||
@@ -1,64 +0,0 @@
|
||||
import { BehaviorSubject, Observable } from "rxjs";
|
||||
|
||||
export type WorkspacePropertyData<ValueType> = {
|
||||
alias?: string | null;
|
||||
label?: string | null;
|
||||
value?: ValueType | null;
|
||||
};
|
||||
|
||||
|
||||
|
||||
export class UmbWorkspacePropertyContext<ValueType> {
|
||||
|
||||
|
||||
private _data: BehaviorSubject<WorkspacePropertyData<ValueType>>;
|
||||
public readonly data: Observable<WorkspacePropertyData<ValueType>>;
|
||||
|
||||
|
||||
#defaultValue!: ValueType | null;
|
||||
|
||||
|
||||
constructor(defaultValue: ValueType | null) {
|
||||
|
||||
this.#defaultValue = defaultValue;
|
||||
|
||||
// TODO: How do we connect this value with parent context?
|
||||
// Ensuring the property editor value-property is updated...
|
||||
|
||||
this._data = new BehaviorSubject({value: defaultValue} as WorkspacePropertyData<ValueType>);
|
||||
this.data = this._data.asObservable();
|
||||
}
|
||||
|
||||
/*
|
||||
hostConnected() {
|
||||
|
||||
}
|
||||
|
||||
hostDisconnected() {
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
public getData() {
|
||||
return this._data.getValue();
|
||||
}
|
||||
|
||||
|
||||
public update(data: Partial<WorkspacePropertyData<ValueType>>) {
|
||||
this._data.next({ ...this.getData(), ...data });
|
||||
}
|
||||
|
||||
public resetValue() {
|
||||
console.log("property context reset")
|
||||
|
||||
this.update({value: this.#defaultValue})
|
||||
}
|
||||
|
||||
|
||||
// TODO: how can we make sure to call this.
|
||||
public destroy(): void {
|
||||
this._data.unsubscribe();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
import { UmbWorkspaceContentContext } from "../workspace/workspace-content/workspace-content.context";
|
||||
import type { DataTypeDetails } from "@umbraco-cms/models";
|
||||
import { UmbControllerHostInterface } from "src/core/controller/controller-host.mixin";
|
||||
import { CreateObservablePart, UniqueBehaviorSubject } from "src/core/observable-api/unique-behavior-subject";
|
||||
import { UmbContextProviderController } from "src/core/context-api/provide/context-provider.controller";
|
||||
import { UmbContextConsumerController } from "src/core/context-api/consume/context-consumer.controller";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// If we get this from the server then we can consider using TypeScripts Partial<> around the model from the Management-API.
|
||||
export type WorkspacePropertyData<ValueType> = {
|
||||
alias?: string;
|
||||
label?: string;
|
||||
description?: string;
|
||||
value?: ValueType | null;
|
||||
config?: DataTypeDetails['data'];// This could potentially then come from hardcoded JS object and not the DataType store.
|
||||
};
|
||||
|
||||
export class UmbWorkspacePropertyContext<ValueType = unknown> {
|
||||
|
||||
|
||||
private _providerController: UmbContextProviderController;
|
||||
|
||||
private _data = new UniqueBehaviorSubject<WorkspacePropertyData<ValueType>>({});
|
||||
|
||||
public readonly alias = CreateObservablePart(this._data, data => data.alias);
|
||||
public readonly label = CreateObservablePart(this._data, data => data.label);
|
||||
public readonly description = CreateObservablePart(this._data, data => data.description);
|
||||
public readonly value = CreateObservablePart(this._data, data => data.value);
|
||||
public readonly config = CreateObservablePart(this._data, data => data.config);
|
||||
|
||||
private _workspaceContext?: UmbWorkspaceContentContext;
|
||||
|
||||
|
||||
constructor(host:UmbControllerHostInterface) {
|
||||
|
||||
new UmbContextConsumerController(host, 'umbWorkspaceContext', (workspaceContext) => {
|
||||
this._workspaceContext = workspaceContext;
|
||||
});
|
||||
|
||||
this._providerController = new UmbContextProviderController(host, 'umbPropertyContext', this);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public setAlias(alias: WorkspacePropertyData<ValueType>['alias']) {
|
||||
this._data.update({alias: alias});
|
||||
}
|
||||
public setLabel(label: WorkspacePropertyData<ValueType>['label']) {
|
||||
this._data.update({label: label});
|
||||
}
|
||||
public setDescription(description: WorkspacePropertyData<ValueType>['description']) {
|
||||
this._data.update({description: description});
|
||||
}
|
||||
public setValue(value: WorkspacePropertyData<ValueType>['value']) {
|
||||
|
||||
if(value === this._data.getValue().value) return;
|
||||
|
||||
this._data.update({value: value});
|
||||
|
||||
const alias = this._data.getValue().alias;
|
||||
if(alias) {
|
||||
this._workspaceContext?.setPropertyValue(alias, value);
|
||||
}
|
||||
}
|
||||
public setConfig(config: WorkspacePropertyData<ValueType>['config']) {
|
||||
this._data.update({config: config});
|
||||
}
|
||||
|
||||
public resetValue() {
|
||||
this.setValue(null);// TODO: Consider if this can be configured/provided from Property Editor or DataType Configuration or even locally specified in DocumentType.
|
||||
}
|
||||
|
||||
// TODO: how can we make sure to call this.
|
||||
public destroy(): void {
|
||||
this._data.unsubscribe();
|
||||
this._providerController.destroy(); // This would also be handled by the controller host, but if someone wanted to replace/remove this context without the host being destroyed. Then we have clean up out selfs here.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
|
||||
import { css, html, PropertyValueMap } from 'lit';
|
||||
import { css, html } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { ifDefined } from 'lit-html/directives/if-defined.js';
|
||||
import { UmbWorkspacePropertyContext } from './workspace-property.context';
|
||||
import { createExtensionElement } from '@umbraco-cms/extensions-api';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/extensions-registry';
|
||||
import type { ManifestPropertyEditorUI, ManifestTypes } from '@umbraco-cms/models';
|
||||
import type { DataTypePropertyData, ManifestPropertyEditorUI, ManifestTypes } from '@umbraco-cms/models';
|
||||
|
||||
import '../../property-actions/shared/property-action-menu/property-action-menu.element';
|
||||
import 'src/backoffice/shared/components/workspace/workspace-property-layout/workspace-property-layout.element';
|
||||
@@ -12,14 +13,13 @@ import { UmbObserverController } from 'src/core/observable-api/observer.controll
|
||||
import { UmbLitElement } from '@umbraco-cms/element';
|
||||
|
||||
/**
|
||||
* @element umb-entity-property
|
||||
* @element umb-workspace-property
|
||||
* @description - Component for displaying a entity property. The Element will render a Property Editor based on the Property Editor UI alias passed to the element.
|
||||
* The element will also render all Property Actions related to the Property Editor.
|
||||
*/
|
||||
|
||||
// TODO: get rid of the other mixins:
|
||||
@customElement('umb-entity-property')
|
||||
export class UmbEntityPropertyElement extends UmbLitElement {
|
||||
@customElement('umb-workspace-property')
|
||||
export class UmbWorkspacePropertyElement extends UmbLitElement {
|
||||
static styles = [
|
||||
UUITextStyles,
|
||||
css`
|
||||
@@ -48,6 +48,12 @@ export class UmbEntityPropertyElement extends UmbLitElement {
|
||||
`,
|
||||
];
|
||||
|
||||
@state()
|
||||
private _label?:string;
|
||||
|
||||
@state()
|
||||
private _description?:string;
|
||||
|
||||
/**
|
||||
* Label. Name of the property
|
||||
* @type {string}
|
||||
@@ -55,7 +61,9 @@ export class UmbEntityPropertyElement extends UmbLitElement {
|
||||
* @default ''
|
||||
*/
|
||||
@property({ type: String })
|
||||
public label = '';
|
||||
public set label(label: string) {
|
||||
this._propertyContext.setLabel(label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Description: render a description underneath the label.
|
||||
@@ -64,7 +72,9 @@ export class UmbEntityPropertyElement extends UmbLitElement {
|
||||
* @default ''
|
||||
*/
|
||||
@property({ type: String })
|
||||
public description = '';
|
||||
public set description(description: string) {
|
||||
this._propertyContext.setDescription(description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias
|
||||
@@ -74,7 +84,9 @@ export class UmbEntityPropertyElement extends UmbLitElement {
|
||||
* @default ''
|
||||
*/
|
||||
@property({ type: String })
|
||||
public alias = '';
|
||||
public set alias(alias: string) {
|
||||
this._propertyContext.setAlias(alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Property Editor UI Alias. Render the Property Editor UI registered for this alias.
|
||||
@@ -85,10 +97,8 @@ export class UmbEntityPropertyElement extends UmbLitElement {
|
||||
*/
|
||||
private _propertyEditorUIAlias = '';
|
||||
@property({ type: String, attribute: 'property-editor-ui-alias' })
|
||||
public get propertyEditorUIAlias(): string {
|
||||
return this._propertyEditorUIAlias;
|
||||
}
|
||||
public set propertyEditorUIAlias(value: string) {
|
||||
if(this._propertyEditorUIAlias === value) return;
|
||||
this._propertyEditorUIAlias = value;
|
||||
this._observePropertyEditorUI();
|
||||
}
|
||||
@@ -96,12 +106,14 @@ export class UmbEntityPropertyElement extends UmbLitElement {
|
||||
/**
|
||||
* Property Editor UI Alias. Render the Property Editor UI registered for this alias.
|
||||
* @public
|
||||
* @type {string}
|
||||
* @type {unknown}
|
||||
* @attr
|
||||
* @default ''
|
||||
* @default undefined
|
||||
*/
|
||||
@property({ type: Object, attribute: false })
|
||||
public value?: any;
|
||||
@property({attribute: false })
|
||||
public set value(value: unknown) {
|
||||
this._propertyContext.setValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Config. Configuration to pass to the Property Editor UI. This is also the configuration data stored on the Data Type.
|
||||
@@ -111,82 +123,93 @@ export class UmbEntityPropertyElement extends UmbLitElement {
|
||||
* @default ''
|
||||
*/
|
||||
@property({ type: Object, attribute: false })
|
||||
public config?: any;
|
||||
public set config(value: DataTypePropertyData[]) {
|
||||
this._propertyContext.setConfig(value);
|
||||
}
|
||||
|
||||
// TODO: make interface for UMBPropertyEditorElement
|
||||
@state()
|
||||
private _element?: { value?: any; config?: any } & HTMLElement; // TODO: invent interface for propertyEditorUI.
|
||||
|
||||
|
||||
// TODO: How to get proper default value?
|
||||
private _propertyContext = new UmbWorkspacePropertyContext<string>("");
|
||||
private _propertyContext = new UmbWorkspacePropertyContext(this);
|
||||
|
||||
private propertyEditorUIObserver?: UmbObserverController<ManifestTypes>;
|
||||
|
||||
private _valueObserver?: UmbObserverController<unknown>;
|
||||
private _configObserver?: UmbObserverController<unknown>;
|
||||
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.provideContext('umbPropertyContext', this._propertyContext);
|
||||
|
||||
this._observePropertyEditorUI();
|
||||
this.addEventListener('property-editor-change', this._onPropertyEditorChange as any as EventListener);
|
||||
this.observe(this._propertyContext.label, (label) => {
|
||||
this._label = label;
|
||||
});
|
||||
this.observe(this._propertyContext.label, (description) => {
|
||||
this._description = description;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private _onPropertyEditorChange = (e: CustomEvent) => {
|
||||
const target = e.composedPath()[0] as any;
|
||||
|
||||
this.value = target.value;// Sets value in context.
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
private _observePropertyEditorUI() {
|
||||
this.propertyEditorUIObserver?.destroy();
|
||||
this.propertyEditorUIObserver = this.observe(umbExtensionsRegistry.getByTypeAndAlias('propertyEditorUI', this.propertyEditorUIAlias), (manifest) => {
|
||||
this._gotEditor(manifest);
|
||||
this.propertyEditorUIObserver = this.observe(umbExtensionsRegistry.getByTypeAndAlias('propertyEditorUI', this._propertyEditorUIAlias), (manifest) => {
|
||||
this._gotEditorUI(manifest);
|
||||
});
|
||||
}
|
||||
|
||||
private _gotEditor(propertyEditorUIManifest?: ManifestPropertyEditorUI | null) {
|
||||
if (!propertyEditorUIManifest) {
|
||||
// TODO: if dataTypeKey didn't exist in store, we should do some nice UI.
|
||||
private _gotEditorUI(manifest?: ManifestPropertyEditorUI | null) {
|
||||
if (!manifest) {
|
||||
// TODO: if propertyEditorUIAlias didn't exist in store, we should do some nice fail UI.
|
||||
return;
|
||||
}
|
||||
|
||||
createExtensionElement(propertyEditorUIManifest)
|
||||
createExtensionElement(manifest)
|
||||
.then((el) => {
|
||||
const oldValue = this._element;
|
||||
|
||||
oldValue?.removeEventListener('change', this._onPropertyEditorChange as any as EventListener);
|
||||
|
||||
this._element = el;
|
||||
|
||||
if (this._element) {
|
||||
this._element.value = this.value; // Be aware its duplicated code
|
||||
this._element.config = this.config; // Be aware its duplicated code
|
||||
this._valueObserver?.destroy();
|
||||
this._configObserver?.destroy();
|
||||
|
||||
if(this._element) {
|
||||
this._element.addEventListener('change', this._onPropertyEditorChange as any as EventListener);
|
||||
|
||||
this._valueObserver = this.observe(this._propertyContext.value, (value) => {
|
||||
if(this._element) {
|
||||
this._element.value = value;
|
||||
}
|
||||
});
|
||||
this._configObserver = this.observe(this._propertyContext.config, (config) => {
|
||||
if(this._element) {
|
||||
this._element.config = config;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.requestUpdate('element', oldValue);
|
||||
|
||||
})
|
||||
.catch(() => {
|
||||
// TODO: loading JS failed so we should do some nice UI. (This does only happen if extension has a js prop, otherwise we concluded that no source was needed resolved the load.)
|
||||
});
|
||||
}
|
||||
|
||||
private _onPropertyEditorChange = (e: CustomEvent) => {
|
||||
const target = e.composedPath()[0] as any;
|
||||
this.value = target.value;
|
||||
this.dispatchEvent(new CustomEvent('property-value-change', { bubbles: true, composed: true }));
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
/** Lit does not currently handle dynamic tag names, therefor we are doing some manual rendering */
|
||||
// TODO: Refactor into a base class for dynamic-tag element? we will be using this a lot for extensions.
|
||||
// This could potentially hook into Lit and parse all properties defined in the specific class on to the dynamic-element. (see static elementProperties: PropertyDeclarationMap;)
|
||||
willUpdate(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>) {
|
||||
super.willUpdate(changedProperties);
|
||||
|
||||
if (changedProperties.has('value') && this._element) {
|
||||
this._element.value = this.value; // Be aware its duplicated code
|
||||
}
|
||||
|
||||
if (changedProperties.has('config') && this._element) {
|
||||
this._element.config = this.config; // Be aware its duplicated code
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<umb-workspace-property-layout id="layout" label="${this.label}" description="${this.description}">
|
||||
<umb-workspace-property-layout id="layout" label="${ifDefined(this._label)}" description="${ifDefined(this._description)}">
|
||||
${this._renderPropertyActionMenu()}
|
||||
<div slot="editor">${this._element}</div>
|
||||
</umb-workspace-property-layout>
|
||||
@@ -194,11 +217,11 @@ export class UmbEntityPropertyElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
private _renderPropertyActionMenu() {
|
||||
return html`${this.propertyEditorUIAlias
|
||||
return html`${this._propertyEditorUIAlias
|
||||
? html`<umb-property-action-menu
|
||||
slot="property-action-menu"
|
||||
id="property-action-menu"
|
||||
.propertyEditorUIAlias="${this.propertyEditorUIAlias}"
|
||||
.propertyEditorUIAlias="${this._propertyEditorUIAlias}"
|
||||
.value="${this.value}"></umb-property-action-menu>`
|
||||
: ''}`;
|
||||
}
|
||||
@@ -206,6 +229,6 @@ export class UmbEntityPropertyElement extends UmbLitElement {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-entity-property': UmbEntityPropertyElement;
|
||||
'umb-workspace-property': UmbWorkspacePropertyElement;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Meta, Story } from '@storybook/web-components';
|
||||
import { html } from 'lit-html';
|
||||
|
||||
import type { UmbWorkspacePropertyElement } from './workspace-property.element';
|
||||
import './workspace-property.element';
|
||||
|
||||
export default {
|
||||
title: 'Components/Entity Property',
|
||||
component: 'umb-workspace-property',
|
||||
id: 'umb-workspace-property',
|
||||
} as Meta;
|
||||
|
||||
export const AAAOverview: Story<UmbWorkspacePropertyElement> = () =>
|
||||
html` <umb-workspace-property
|
||||
label="Property"
|
||||
description="Description"
|
||||
alias="textProperty"
|
||||
property-editor-ui-alias="Umb.PropertyEditorUI.TextBox"
|
||||
.value="${'Hello'}"></umb-workspace-property>`;
|
||||
AAAOverview.storyName = 'Overview';
|
||||
@@ -2,6 +2,7 @@ import { css, html } from 'lit';
|
||||
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
import { distinctUntilChanged } from 'rxjs';
|
||||
import { repeat } from 'lit/directives/repeat.js';
|
||||
import type { UmbWorkspaceContentContext } from '../../workspace-content.context';
|
||||
import type { ContentProperty, ContentPropertyData, DocumentDetails, MediaDetails } from '@umbraco-cms/models';
|
||||
|
||||
@@ -40,11 +41,22 @@ export class UmbWorkspaceViewContentEditElement extends UmbLitElement {
|
||||
private _observeContent() {
|
||||
if (!this._workspaceContext) return;
|
||||
|
||||
/*
|
||||
TODO: Property-Context: This observer gets all changes, We need to fix this. it should be simpler.
|
||||
It should look at length and aliases? as long as they are identical nothing should change.
|
||||
As they would update them selfs?
|
||||
|
||||
Should use a Observable for this._workspaceContext.properties
|
||||
*/
|
||||
this.observe(
|
||||
this._workspaceContext.data.pipe(distinctUntilChanged()),
|
||||
(content) => {
|
||||
this._properties = content.properties;
|
||||
this._data = content.data;
|
||||
/*
|
||||
Maybe we should not give the value, but the umb-content-property should get the context and observe its own data.
|
||||
This would become a more specific Observer therefor better performance?.. Note to self: Debate with Mads how he sees this perspective.
|
||||
*/
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -52,12 +64,14 @@ export class UmbWorkspaceViewContentEditElement extends UmbLitElement {
|
||||
render() {
|
||||
return html`
|
||||
<uui-box>
|
||||
${this._properties?.map(
|
||||
(property: ContentProperty) => html`
|
||||
<umb-content-property
|
||||
${repeat(
|
||||
this._properties,
|
||||
(property) => property.alias,
|
||||
(property) =>
|
||||
html`<umb-content-property
|
||||
.property=${property}
|
||||
.value=${this._data.find((data) => data.alias === property.alias)?.value}></umb-content-property>
|
||||
`
|
||||
`
|
||||
)}
|
||||
</uui-box>
|
||||
`;
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { UmbNotificationService } from '../../../../../core/notification';
|
||||
import { UmbNotificationDefaultData } from '../../../../../core/notification/layouts/default';
|
||||
import { UmbWorkspaceContext } from '../workspace-context/workspace.context';
|
||||
import { UmbNodeStoreBase } from '@umbraco-cms/stores/store';
|
||||
import { ContentTreeItem } from '@umbraco-cms/backend-api';
|
||||
import { UmbControllerHostInterface } from 'src/core/controller/controller-host.mixin';
|
||||
import { UmbContextConsumerController } from 'src/core/context-api/consume/context-consumer.controller';
|
||||
import { UmbObserverController } from '@umbraco-cms/observable-api';
|
||||
import { UmbContextProviderController } from 'src/core/context-api/provide/context-provider.controller';
|
||||
import { EntityTreeItem } from '@umbraco-cms/backend-api';
|
||||
|
||||
// TODO: Consider if its right to have this many class-inheritance of WorkspaceContext
|
||||
// TODO: Could we extract this code into a 'Manager' of its own, which will be instantiated by the concrete Workspace Context. This will be more transparent and 'reuseable'
|
||||
export class UmbWorkspaceContentContext<
|
||||
ContentTypeType extends ContentTreeItem = ContentTreeItem,
|
||||
export abstract class UmbWorkspaceContentContext<
|
||||
ContentTypeType extends EntityTreeItem = EntityTreeItem,
|
||||
StoreType extends UmbNodeStoreBase<ContentTypeType> = UmbNodeStoreBase<ContentTypeType>
|
||||
> extends UmbWorkspaceContext<ContentTypeType> {
|
||||
> {
|
||||
|
||||
protected _host: UmbControllerHostInterface;
|
||||
|
||||
// TODO: figure out how fine grained we want to make our observables.
|
||||
// TODO: add interface
|
||||
protected _data!:BehaviorSubject<ContentTypeType>;
|
||||
public readonly data: Observable<ContentTypeType>;
|
||||
|
||||
protected _notificationService?: UmbNotificationService;
|
||||
|
||||
@@ -32,7 +39,14 @@ export class UmbWorkspaceContentContext<
|
||||
storeAlias: string,
|
||||
entityType: string
|
||||
) {
|
||||
super(host, defaultData);
|
||||
|
||||
this._host = host;
|
||||
|
||||
//TODO: Use the UniqueBehaviorSubject, and separate observables for each part?
|
||||
|
||||
this._data = new BehaviorSubject<ContentTypeType>(defaultData);
|
||||
this.data = this._data.asObservable();
|
||||
this.entityType = entityType;
|
||||
|
||||
new UmbContextConsumerController(
|
||||
host,
|
||||
@@ -42,25 +56,31 @@ export class UmbWorkspaceContentContext<
|
||||
}
|
||||
);
|
||||
|
||||
this.entityType = entityType;
|
||||
|
||||
new UmbContextConsumerController(host, storeAlias, (_instance: StoreType) => {
|
||||
this._store = _instance;
|
||||
if (!this._store) {
|
||||
// TODO: make sure to break the application in a good way.
|
||||
return;
|
||||
}
|
||||
this._readyToLoad();
|
||||
this._observeStore();
|
||||
|
||||
// TODO: first provide when we have umbNotificationService as well.
|
||||
new UmbContextProviderController(this._host, 'umbWorkspaceContext', this);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public getData() {
|
||||
return this._data.getValue();
|
||||
}
|
||||
public update(data: Partial<ContentTypeType>) {
|
||||
this._data.next({ ...this.getData(), ...data });
|
||||
}
|
||||
|
||||
load(entityKey: string) {
|
||||
this.#isNew = false;
|
||||
this.entityKey = entityKey;
|
||||
this._readyToLoad();
|
||||
this._observeStore();
|
||||
}
|
||||
|
||||
create(parentKey: string | null) {
|
||||
@@ -69,14 +89,14 @@ export class UmbWorkspaceContentContext<
|
||||
console.log("I'm new, and I will be created under ", parentKey)
|
||||
}
|
||||
|
||||
protected _readyToLoad(): void {
|
||||
protected _observeStore(): void {
|
||||
if(!this._store || !this.entityKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this.#isNew) {
|
||||
this._storeSubscription?.destroy();
|
||||
this._storeSubscription = new UmbObserverController(this._host, this._store.getByKey(this.entityKey),
|
||||
this._storeSubscription = new UmbObserverController(this._host, this._store.getByKey(this.entityKey),
|
||||
(content) => {
|
||||
if (!content) return; // TODO: Handle nicely if there is no content data.
|
||||
this.update(content as any);
|
||||
@@ -88,6 +108,9 @@ export class UmbWorkspaceContentContext<
|
||||
return this._store;
|
||||
}
|
||||
|
||||
abstract setPropertyValue(alias: string, value: unknown):void;
|
||||
|
||||
|
||||
public save(): Promise<void> {
|
||||
if(!this._store) {
|
||||
// TODO: more beautiful error:
|
||||
@@ -104,4 +127,11 @@ export class UmbWorkspaceContentContext<
|
||||
this._notificationService?.peek('danger', { data });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TODO: how can we make sure to call this.
|
||||
public destroy(): void {
|
||||
this._data.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
|
||||
import { css, html } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { distinctUntilChanged } from 'rxjs';
|
||||
import type { UmbWorkspaceContentContext } from './workspace-content.context';
|
||||
import type { DocumentDetails, MediaDetails } from '@umbraco-cms/models';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
|
||||
import '../workspace-layout/workspace-layout.element';
|
||||
import '../../variant-selector/variant-selector.element';
|
||||
@@ -12,11 +9,8 @@ import '../../variant-selector/variant-selector.element';
|
||||
// TODO: Make this dynamic, use load-extensions method to loop over extensions for this node.
|
||||
import './views/edit/workspace-view-content-edit.element';
|
||||
import './views/info/workspace-view-content-info.element';
|
||||
import type { UmbNodeStoreBase } from '@umbraco-cms/stores/store';
|
||||
import { UmbLitElement } from '@umbraco-cms/element';
|
||||
|
||||
type ContentTypeTypes = DocumentDetails | MediaDetails;
|
||||
|
||||
/**
|
||||
* TODO: IMPORTANT TODO: Get rid of the content workspace. Instead we aim to get separate components that can be composed by each workspace.
|
||||
* Example. Document Workspace would use a Variant-component(variant component would talk directly to the workspace-context)
|
||||
@@ -49,52 +43,6 @@ export class UmbWorkspaceContentElement extends UmbLitElement {
|
||||
@property()
|
||||
alias!: string;
|
||||
|
||||
// TODO: use a NodeDetails type here:
|
||||
@state()
|
||||
_content?: ContentTypeTypes;
|
||||
|
||||
private _workspaceContext?: UmbWorkspaceContentContext<ContentTypeTypes, UmbNodeStoreBase<ContentTypeTypes>>;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext('umbWorkspaceContext', (instance) => {
|
||||
this._workspaceContext = instance;
|
||||
this._observeWorkspace();
|
||||
});
|
||||
|
||||
this.addEventListener('property-value-change', this._onPropertyValueChange);
|
||||
}
|
||||
|
||||
private async _observeWorkspace() {
|
||||
if (!this._workspaceContext) return;
|
||||
|
||||
this.observe(this._workspaceContext.data.pipe(distinctUntilChanged()), (data) => {
|
||||
this._content = data;
|
||||
});
|
||||
}
|
||||
|
||||
private _onPropertyValueChange = (e: Event) => {
|
||||
const target = e.composedPath()[0] as any;
|
||||
|
||||
// TODO: Set value.
|
||||
const property = this._content?.properties.find((x) => x.alias === target.alias);
|
||||
if (property) {
|
||||
this._setPropertyValue(property.alias, target.value);
|
||||
} else {
|
||||
console.error('property was not found', target.alias);
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: How do we ensure this is a change of this document and not nested documents? Should the event be stopped at this spot at avoid such.
|
||||
private _setPropertyValue(alias: string, value: unknown) {
|
||||
this._content?.data.forEach((data) => {
|
||||
if (data.alias === alias) {
|
||||
data.value = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<umb-workspace-layout alias=${this.alias}>
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
|
||||
CollectionContext {
|
||||
|
||||
// RxJS store..
|
||||
this._data = new BehaviorSubject<BlockType>(defaultData);
|
||||
this.data = this._data.asObservable();
|
||||
|
||||
getStore();
|
||||
|
||||
}
|
||||
|
||||
|
||||
DocumentCollectionContext extends CollectionContext {
|
||||
|
||||
// RxJS store..
|
||||
this._data = new BehaviorSubject<BlockType>(defaultData);
|
||||
this.data = this._data.asObservable();
|
||||
|
||||
getStore();
|
||||
publish();
|
||||
update();
|
||||
|
||||
}
|
||||
|
||||
|
||||
MediaCollectionContext extends CollectionContext {
|
||||
|
||||
// RxJS store..
|
||||
this._data = new BehaviorSubject<BlockType>(defaultData);
|
||||
this.data = this._data.asObservable();
|
||||
|
||||
getStore();
|
||||
update();
|
||||
save();
|
||||
|
||||
}
|
||||
|
||||
|
||||
VendrCollectionContext extends CollectionContext {
|
||||
|
||||
// RxJS store..
|
||||
this._data = new BehaviorSubject<BlockType>(defaultData);
|
||||
this.data = this._data.asObservable();
|
||||
|
||||
getStore();
|
||||
update();
|
||||
save();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
DocumentContext {
|
||||
|
||||
// Validation?
|
||||
|
||||
// RxJS store..
|
||||
this._data = new BehaviorSubject<BlockType>(defaultData);
|
||||
this.data = this._data.asObservable();
|
||||
|
||||
getStore();
|
||||
|
||||
setPublishDate()
|
||||
|
||||
addVariant(name) {
|
||||
this.data.name = name;
|
||||
}
|
||||
|
||||
save() {
|
||||
this.backendStore.save()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
PropertyContext {
|
||||
|
||||
// Validation?
|
||||
|
||||
}
|
||||
|
||||
|
||||
BlockContext {
|
||||
|
||||
// Validation?
|
||||
|
||||
this._data = new BehaviorSubject<BlockType>(defaultData);
|
||||
this.data = this._data.asObservable();
|
||||
|
||||
this._liveEditing = true;
|
||||
|
||||
setName(name) {
|
||||
this.update({name: name})
|
||||
if(this._liveEditing) {
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
|
||||
save() {
|
||||
//
|
||||
this.parentData.block[123] = this.data.getData();
|
||||
this.parentDatarxJS.update(this.parentData);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
var myBlockContext = new BlockContext(documentData.blocks[1]);
|
||||
|
||||
|
||||
// Property Editor Edit Element Name:
|
||||
|
||||
myBlockContext.data.subscribe((blockData) => {
|
||||
this.input.value = blockData.name;
|
||||
})
|
||||
this.input.addEventListener("change", () => {
|
||||
myBlockContext.setName(this.input.value);
|
||||
// RXJS update?? ^^
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
blockContext.setName('sdaafgdss');
|
||||
// Does does other update?
|
||||
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import { BehaviorSubject, Observable } from "rxjs";
|
||||
import { UmbControllerHostInterface } from "src/core/controller/controller-host.mixin";
|
||||
|
||||
|
||||
export abstract class UmbWorkspaceContext<DataType> {
|
||||
|
||||
protected _host: UmbControllerHostInterface;
|
||||
|
||||
// TODO: figure out how fine grained we want to make our observables.
|
||||
// TODO: add interface
|
||||
protected _data!:BehaviorSubject<DataType>;
|
||||
public readonly data: Observable<DataType>;
|
||||
|
||||
|
||||
constructor(host:UmbControllerHostInterface, defaultData: DataType) {
|
||||
this._host = host;
|
||||
|
||||
this._data = new BehaviorSubject<DataType>(defaultData);
|
||||
this.data = this._data.asObservable();
|
||||
}
|
||||
|
||||
|
||||
public getData() {
|
||||
return this._data.getValue();
|
||||
}
|
||||
|
||||
public update(data: Partial<DataType>) {
|
||||
this._data.next({ ...this.getData(), ...data });
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// TODO: how can we make sure to call this.
|
||||
public destroy(): void {
|
||||
this._data.unsubscribe();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,35 +1,46 @@
|
||||
import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { UmbPropertyActionMenuContext } from '../shared/property-action-menu/property-action-menu.context';
|
||||
//import type { UmbPropertyActionMenuContext } from '../shared/property-action-menu/property-action-menu.context';
|
||||
import { UmbPropertyAction } from '../shared/property-action/property-action.model';
|
||||
import type { UmbWorkspacePropertyContext } from '../../components/workspace-property/workspace-property.context';
|
||||
import { UmbLitElement } from '@umbraco-cms/element';
|
||||
|
||||
@customElement('umb-property-action-clear')
|
||||
export class UmbPropertyActionClearElement extends UmbLitElement implements UmbPropertyAction {
|
||||
|
||||
@property()
|
||||
value = '';
|
||||
|
||||
private _propertyActionMenuContext?: UmbPropertyActionMenuContext;
|
||||
// THESE OUT COMMENTED CODE IS USED FOR THE EXAMPLE BELOW, TODO: Should be transferred to some documentation.
|
||||
//private _propertyActionMenuContext?: UmbPropertyActionMenuContext;
|
||||
private _propertyContext?: UmbWorkspacePropertyContext;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
/*
|
||||
this.consumeContext('umbPropertyActionMenu', (propertyActionsContext: UmbPropertyActionMenuContext) => {
|
||||
this._propertyActionMenuContext = propertyActionsContext;
|
||||
});
|
||||
*/
|
||||
this.consumeContext('umbPropertyContext', (propertyContext: UmbWorkspacePropertyContext) => {
|
||||
this._propertyContext = propertyContext;
|
||||
});
|
||||
}
|
||||
|
||||
private _handleLabelClick() {
|
||||
this._clearValue();
|
||||
// TODO: how do we want to close the menu? Testing an event based approach and context api approach
|
||||
// this.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }));
|
||||
this._propertyActionMenuContext?.close();
|
||||
this.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }));
|
||||
// Or you can do this:
|
||||
//this._propertyActionMenuContext?.close();
|
||||
}
|
||||
|
||||
private _clearValue() {
|
||||
// TODO: how do we want to update the value? Testing an event based approach. We need to test an api based approach too.
|
||||
this.value = '';
|
||||
this.dispatchEvent(new CustomEvent('property-editor-change', { bubbles: true, composed: true }));
|
||||
//this.value = '';// This is though bad as it assumes we are dealing with a string. So wouldn't work as a generalized element.
|
||||
//this.dispatchEvent(new CustomEvent('property-value-change'));
|
||||
// Or you can do this:
|
||||
this._propertyContext?.resetValue();// This resets value to what the property wants.
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
import { Observable, ReplaySubject } from 'rxjs';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { UmbContextProviderController } from 'src/core/context-api/provide/context-provider.controller';
|
||||
import type { UmbControllerHostInterface } from 'src/core/controller/controller-host.mixin';
|
||||
|
||||
export class UmbPropertyActionMenuContext {
|
||||
private _isOpen: ReplaySubject<boolean> = new ReplaySubject(1);
|
||||
public readonly isOpen: Observable<boolean> = this._isOpen.asObservable();
|
||||
|
||||
private _isOpen = new BehaviorSubject(false);
|
||||
public readonly isOpen = this._isOpen.asObservable();
|
||||
|
||||
constructor(host: UmbControllerHostInterface) {
|
||||
new UmbContextProviderController(host, 'umbPropertyActionMenu', this);
|
||||
}
|
||||
|
||||
toggle() {
|
||||
this._isOpen.next(!this._isOpen.getValue());
|
||||
}
|
||||
open() {
|
||||
this._isOpen.next(true);
|
||||
}
|
||||
|
||||
close() {
|
||||
this._isOpen.next(false);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { umbExtensionsRegistry } from '@umbraco-cms/extensions-registry';
|
||||
|
||||
import '../property-action/property-action.element';
|
||||
import { UmbLitElement } from '@umbraco-cms/element';
|
||||
import { UmbObserverController } from '@umbraco-cms/observable-api';
|
||||
|
||||
@customElement('umb-property-action-menu')
|
||||
export class UmbPropertyActionMenuElement extends UmbLitElement {
|
||||
@@ -40,87 +41,91 @@ export class UmbPropertyActionMenuElement extends UmbLitElement {
|
||||
`,
|
||||
];
|
||||
|
||||
@property()
|
||||
public propertyEditorUIAlias = '';
|
||||
|
||||
|
||||
// TODO: we need to investigate context api vs values props and events
|
||||
@property()
|
||||
public value?: string;
|
||||
|
||||
@property()
|
||||
set propertyEditorUIAlias(alias: string) {
|
||||
this._observeActions(alias);
|
||||
}
|
||||
|
||||
private _actionsObserver?: UmbObserverController<ManifestPropertyAction[]>;
|
||||
|
||||
@state()
|
||||
private _actions: Array<ManifestPropertyAction> = [];
|
||||
|
||||
@state()
|
||||
private _open = false;
|
||||
|
||||
private _propertyActionMenuContext = new UmbPropertyActionMenuContext();
|
||||
private _propertyActionMenuContext = new UmbPropertyActionMenuContext(this);
|
||||
|
||||
connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this._observePropertyActions();
|
||||
this._observePropertyActionMenuOpenState();
|
||||
this.observe(this._propertyActionMenuContext.isOpen, (value) => {
|
||||
this._open = value;
|
||||
});
|
||||
|
||||
this.provideContext('umbPropertyActionMenu', this._propertyActionMenuContext);
|
||||
this.addEventListener('close', (e) => {
|
||||
this._propertyActionMenuContext.close();
|
||||
e.stopPropagation();
|
||||
});
|
||||
}
|
||||
|
||||
private _observePropertyActions() {
|
||||
this.observe(
|
||||
private _observeActions(alias: string) {
|
||||
this._actionsObserver?.destroy();
|
||||
this._actionsObserver = this.observe(
|
||||
umbExtensionsRegistry
|
||||
.extensionsOfType('propertyAction')
|
||||
.pipe(
|
||||
map((propertyActions) =>
|
||||
propertyActions.filter((propertyAction) =>
|
||||
propertyAction.meta.propertyEditors.includes(this.propertyEditorUIAlias)
|
||||
map((propertyActions) => {
|
||||
return propertyActions.filter((propertyAction) =>
|
||||
propertyAction.meta.propertyEditors.includes(alias)
|
||||
)
|
||||
}
|
||||
)
|
||||
),
|
||||
(propertyActionManifests) => {
|
||||
this._actions = propertyActionManifests;
|
||||
(manifests) => {
|
||||
this._actions = manifests;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private _observePropertyActionMenuOpenState() {
|
||||
this.observe(this._propertyActionMenuContext.isOpen, (value) => {
|
||||
this._open = value;
|
||||
});
|
||||
}
|
||||
|
||||
private _toggleMenu() {
|
||||
this._open ? this._propertyActionMenuContext.close() : this._propertyActionMenuContext.open();
|
||||
this._propertyActionMenuContext.toggle();
|
||||
}
|
||||
|
||||
private _handleClose(event: CustomEvent) {
|
||||
this._open = false;
|
||||
this._propertyActionMenuContext.close();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${this._actions.length > 0
|
||||
? html`
|
||||
<uui-popover id="popover" placement="bottom-start" .open=${this._open} @close="${this._handleClose}">
|
||||
<uui-button
|
||||
id="popover-trigger"
|
||||
slot="trigger"
|
||||
look="secondary"
|
||||
label="More"
|
||||
@click="${this._toggleMenu}"
|
||||
compact>
|
||||
<uui-symbol-more id="more-symbol"></uui-symbol-more>
|
||||
</uui-button>
|
||||
return (this._actions.length > 0) ?
|
||||
html`
|
||||
<uui-popover id="popover" placement="bottom-start" .open=${this._open} @close="${this._handleClose}">
|
||||
<uui-button
|
||||
id="popover-trigger"
|
||||
slot="trigger"
|
||||
look="secondary"
|
||||
label="More"
|
||||
@click="${this._toggleMenu}"
|
||||
compact>
|
||||
<uui-symbol-more id="more-symbol"></uui-symbol-more>
|
||||
</uui-button>
|
||||
|
||||
<div slot="popover" id="dropdown">
|
||||
${this._actions.map(
|
||||
(action) => html`
|
||||
<umb-property-action .propertyAction=${action} .value="${this.value}"></umb-property-action>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
</uui-popover>
|
||||
`
|
||||
: ''}
|
||||
`;
|
||||
<div slot="popover" id="dropdown">
|
||||
${this._actions.map(
|
||||
(action) => html`
|
||||
<umb-property-action .propertyAction=${action} .value="${this.value}"></umb-property-action>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
</uui-popover>
|
||||
`
|
||||
: '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
|
||||
import type { PropertyEditorConfigDefaultData, PropertyEditorConfigProperty } from '@umbraco-cms/models';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/extensions-registry';
|
||||
|
||||
import '../../../components/entity-property/entity-property.element';
|
||||
import '../../../components/workspace-property/workspace-property.element';
|
||||
import { UmbLitElement } from '@umbraco-cms/element';
|
||||
|
||||
/**
|
||||
@@ -104,12 +104,12 @@ export class UmbPropertyEditorConfigElement extends UmbLitElement {
|
||||
? html`
|
||||
${this._properties?.map(
|
||||
(property) => html`
|
||||
<umb-entity-property
|
||||
<umb-workspace-property
|
||||
label="${property.label}"
|
||||
description="${ifDefined(property.description)}"
|
||||
alias="${property.alias}"
|
||||
property-editor-ui-alias="${property.propertyEditorUI}"
|
||||
.value=${this._getValue(property)}></umb-entity-property>
|
||||
.value=${this._getValue(property)}></umb-workspace-property>
|
||||
`
|
||||
)}
|
||||
`
|
||||
|
||||
@@ -90,7 +90,7 @@ export class UmbPropertyEditorUIContentPickerElement extends UmbLitElement {
|
||||
private _setValue(newValue: Array<string>) {
|
||||
this.value = newValue;
|
||||
this._observePickedDocuments();
|
||||
this.dispatchEvent(new CustomEvent('property-editor-change', { bubbles: true, composed: true }));
|
||||
this.dispatchEvent(new CustomEvent('property-value-change'));
|
||||
}
|
||||
|
||||
private _renderItem(item: FolderTreeItem) {
|
||||
|
||||
@@ -21,7 +21,7 @@ export class UmbPropertyEditorUINumberElement extends LitElement {
|
||||
|
||||
private onInput(e: InputEvent) {
|
||||
this.value = (e.target as HTMLInputElement).value;
|
||||
this.dispatchEvent(new CustomEvent('property-editor-change', { bubbles: true, composed: true }));
|
||||
this.dispatchEvent(new CustomEvent('property-value-change'));
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -21,7 +21,7 @@ export class UmbPropertyEditorUITextBoxElement extends LitElement {
|
||||
|
||||
private onInput(e: InputEvent) {
|
||||
this.value = (e.target as HTMLInputElement).value;
|
||||
this.dispatchEvent(new CustomEvent('property-editor-change', { bubbles: true, composed: true }));
|
||||
this.dispatchEvent(new CustomEvent('property-value-change'));
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { css, html } from 'lit';
|
||||
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { UmbWorkspacePropertyContext } from 'src/backoffice/shared/components/entity-property/workspace-property.context';
|
||||
import type { UmbWorkspacePropertyContext } from 'src/backoffice/shared/components/workspace-property/workspace-property.context';
|
||||
import { UmbLitElement } from '@umbraco-cms/element';
|
||||
import { UUITextareaElement } from '@umbraco-ui/uui';
|
||||
|
||||
@customElement('umb-property-editor-ui-textarea')
|
||||
export class UmbPropertyEditorUITextareaElement extends UmbLitElement {
|
||||
@@ -26,21 +27,19 @@ export class UmbPropertyEditorUITextareaElement extends UmbLitElement {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext('umbPropertyContext', (instance) => {
|
||||
this.consumeContext('umbPropertyContext', (instance: UmbWorkspacePropertyContext<string>) => {
|
||||
this.propertyContext = instance;
|
||||
});
|
||||
}
|
||||
|
||||
private onInput(e: InputEvent) {
|
||||
this.value = (e.target as HTMLInputElement).value;
|
||||
this.dispatchEvent(new CustomEvent('property-editor-change', { bubbles: true, composed: true }));
|
||||
this.value = (e.target as UUITextareaElement).value as string;
|
||||
this.dispatchEvent(new CustomEvent('property-value-change'));
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<uui-textarea .value=${this.value} @input=${this.onInput}></uui-textarea>
|
||||
${this.config?.map((property: any) => html`<div>${property.alias}: ${property.value}</div>`)}
|
||||
<button @click=${() => this.propertyContext?.resetValue()}>Reset</button>`;
|
||||
<uui-textarea .value=${this.value} @input=${this.onInput}></uui-textarea>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,4 +21,9 @@ export class UmbWorkspaceUserGroupContext extends UmbWorkspaceContentContext<
|
||||
constructor(host: UmbControllerHostInterface) {
|
||||
super(host, DefaultDataTypeData, 'umbUserStore', 'userGroup');
|
||||
}
|
||||
|
||||
|
||||
public setPropertyValue(alias: string, value: unknown) {
|
||||
throw new Error("setPropertyValue is not implemented for UmbWorkspaceUserGroupContext")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,4 +24,8 @@ export class UmbWorkspaceUserContext extends UmbWorkspaceContentContext<UmbUserS
|
||||
constructor(host: UmbControllerHostInterface) {
|
||||
super(host, DefaultDataTypeData, 'umbUserStore', 'user');
|
||||
}
|
||||
|
||||
public setPropertyValue(alias: string, value: unknown) {
|
||||
throw new Error("setPropertyValue is not implemented for UmbWorkspaceUserContext")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ export const data: Array<DataTypeDetails> = [
|
||||
parentKey: null,
|
||||
isFolder: false,
|
||||
propertyEditorModelAlias: 'Umbraco.TextArea',
|
||||
propertyEditorUIAlias: 'Umb.PropertyEditorUI.Textarea',
|
||||
propertyEditorUIAlias: 'Umb.PropertyEditorUI.TextArea',
|
||||
data: [
|
||||
{
|
||||
alias: 'maxChars',
|
||||
|
||||
@@ -24,6 +24,13 @@ export interface Entity {
|
||||
parentKey: string | null;
|
||||
}
|
||||
|
||||
export interface ContentDetails extends ContentTreeItem {
|
||||
isTrashed: boolean; // TODO: remove only temp part of refactor
|
||||
properties: Array<ContentProperty>;
|
||||
//data: Array<ContentPropertyData>;
|
||||
//layout?: any; // TODO: define layout type - make it non-optional
|
||||
}
|
||||
|
||||
export interface UserEntity extends Entity {
|
||||
type: 'user';
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
import { BehaviorSubject, distinctUntilChanged, map, Observable, shareReplay } from "rxjs";
|
||||
|
||||
|
||||
function deepFreeze<T>(inObj: T): T {
|
||||
Object.freeze(inObj);
|
||||
|
||||
Object.getOwnPropertyNames(inObj).forEach(function (prop) {
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if ((inObj as any).hasOwnProperty(prop)
|
||||
&& (inObj as any)[prop] != null
|
||||
&& typeof (inObj as any)[prop] === 'object'
|
||||
&& !Object.isFrozen((inObj as any)[prop])) {
|
||||
deepFreeze((inObj as any)[prop]);
|
||||
}
|
||||
});
|
||||
return inObj;
|
||||
}
|
||||
|
||||
|
||||
export function naiveObjectComparison(objOne: any, objTwo: any): boolean {
|
||||
return JSON.stringify(objOne) === JSON.stringify(objTwo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
type MappingFunction<T, R> = (mappable: T) => R;
|
||||
type MemoizationFunction<R> = (previousResult: R, currentResult: R) => boolean;
|
||||
|
||||
function defaultMemoization(previousValue: any, currentValue: any): boolean {
|
||||
if (typeof previousValue === 'object' && typeof currentValue === 'object') {
|
||||
return naiveObjectComparison(previousValue, currentValue);
|
||||
}
|
||||
return previousValue === currentValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @method CreateObservablePart
|
||||
* @param {Observable<T>} source - RxJS Subject to use for this Observable.
|
||||
* @param {(mappable: T) => R} mappingFunction - Method to return the part for this Observable to return.
|
||||
* @param {(previousResult: R, currentResult: R) => boolean} [memoizationFunction] - Method to Compare if the data has changed. Should return true when data is different.
|
||||
* @description - Creates a RxJS Observable from RxJS Subject.
|
||||
* @example <caption>Example create a Observable for part of the data Subject.</caption>
|
||||
* public readonly myPart = CreateObservablePart(this._data, (data) => data.myPart);
|
||||
*/
|
||||
export function CreateObservablePart<T, R> (
|
||||
source$: Observable<T>,
|
||||
mappingFunction: MappingFunction<T, R>,
|
||||
memoizationFunction?: MemoizationFunction<R>
|
||||
): Observable<R> {
|
||||
return source$.pipe(
|
||||
map(mappingFunction),
|
||||
distinctUntilChanged(memoizationFunction || defaultMemoization),
|
||||
shareReplay(1)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @class UniqueBehaviorSubject
|
||||
* @extends {BehaviorSubject<T>}
|
||||
* @description - A RxJS BehaviorSubject which deepFreezes the data to ensure its not manipulated from any implementations.
|
||||
* Additionally the Subject ensures the data is unique, not updating any Observes unless there is an actual change of the content.
|
||||
*/
|
||||
export class UniqueBehaviorSubject<T> extends BehaviorSubject<T> {
|
||||
constructor(initialData: T) {
|
||||
super(deepFreeze(initialData));
|
||||
}
|
||||
|
||||
next(newData: T): void {
|
||||
const frozenData = deepFreeze(newData);
|
||||
// Only update data if its different than current data.
|
||||
if (!naiveObjectComparison(frozenData, this.getValue())) {
|
||||
super.next(frozenData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Partial update data set, only works for Objects.
|
||||
* TODO: consider moving this into a specific class for Objects?
|
||||
* Consider doing similar for Array?
|
||||
*/
|
||||
update(data: Partial<T>) {
|
||||
this.next({ ...this.getValue(), ...data });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user