diff --git a/package-lock.json b/package-lock.json index 778641767..2dc88988b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34247,25 +34247,25 @@ "version": "0.29.2", "license": "Apache-2.0", "dependencies": { - "@deephaven/chart": "^0.109.0", - "@deephaven/components": "^0.109.0", - "@deephaven/console": "^0.109.0", - "@deephaven/dashboard": "^0.109.0", - "@deephaven/dashboard-core-plugins": "^0.109.0", - "@deephaven/golden-layout": "^0.109.0", - "@deephaven/grid": "^0.109.0", - "@deephaven/icons": "^0.109.0", - "@deephaven/iris-grid": "^0.109.0", - "@deephaven/jsapi-bootstrap": "^0.109.0", - "@deephaven/jsapi-components": "^0.109.0", + "@deephaven/chart": "^1.0.0", + "@deephaven/components": "^1.0.0", + "@deephaven/console": "^1.0.0", + "@deephaven/dashboard": "^1.0.0", + "@deephaven/dashboard-core-plugins": "^1.0.0", + "@deephaven/golden-layout": "^1.0.0", + "@deephaven/grid": "^1.0.0", + "@deephaven/icons": "^1.0.0", + "@deephaven/iris-grid": "^1.0.0", + "@deephaven/jsapi-bootstrap": "^1.0.0", + "@deephaven/jsapi-components": "^1.0.0", "@deephaven/jsapi-types": "^1.0.0-dev0.35.0", - "@deephaven/jsapi-utils": "^0.109.0", - "@deephaven/log": "^0.109.0", - "@deephaven/plugin": "^0.109.0", - "@deephaven/react-hooks": "^0.109.0", - "@deephaven/redux": "^0.109.0", - "@deephaven/test-utils": "^0.109.0", - "@deephaven/utils": "^0.109.0", + "@deephaven/jsapi-utils": "^1.0.0", + "@deephaven/log": "^1.0.0", + "@deephaven/plugin": "^1.0.0", + "@deephaven/react-hooks": "^1.0.0", + "@deephaven/redux": "^1.0.0", + "@deephaven/test-utils": "^1.0.0", + "@deephaven/utils": "^1.0.0", "@fortawesome/react-fontawesome": "^0.2.0", "@internationalized/date": "^3.5.5", "classnames": "^2.5.1", @@ -34291,17 +34291,17 @@ } }, "plugins/ui/src/js/node_modules/@deephaven/chart": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/chart/-/chart-0.109.0.tgz", - "integrity": "sha512-nMec+kuSLB9upYI70qT9TNY0gE36hjChQ24eJpY0dDCJdZCdnbQfqIztRQGpfefSQZBsIAOcwbn+v+IiwLjgug==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/chart/-/chart-1.0.0.tgz", + "integrity": "sha512-rcYgMUKKL/DksUeXo5k2vLzJ0v1V9VDuX+RgMasvW0GLwx+pF/A59TrLXFIQCvK0VnzLpvLcQw/7TAVspBfs8w==", "dependencies": { - "@deephaven/components": "^0.109.0", - "@deephaven/icons": "^0.109.0", + "@deephaven/components": "^1.0.0", + "@deephaven/icons": "^1.0.0", "@deephaven/jsapi-types": "^1.0.0-dev0.37.2", - "@deephaven/jsapi-utils": "^0.109.0", - "@deephaven/log": "^0.109.0", - "@deephaven/react-hooks": "^0.109.0", - "@deephaven/utils": "^0.109.0", + "@deephaven/jsapi-utils": "^1.0.0", + "@deephaven/log": "^1.0.0", + "@deephaven/react-hooks": "^1.0.0", + "@deephaven/utils": "^1.0.0", "buffer": "^6.0.3", "fast-deep-equal": "^3.1.3", "lodash.debounce": "^4.0.8", @@ -34320,15 +34320,15 @@ } }, "plugins/ui/src/js/node_modules/@deephaven/components": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/components/-/components-0.109.0.tgz", - "integrity": "sha512-LQ5U9IsN1Se7PbOCwF2vsvpP7JHLhWM8X0dVo1FMwXuEtHNSmkzLzIf37aAtGpYiwXLGjeruUYprtemmT5u/GA==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/components/-/components-1.0.0.tgz", + "integrity": "sha512-bvApNMPNdzV3grHJYfwb+yL62sFLMNnRX8OfTHpvez3xIRdOfQ5ARj0ClplDnVLTMkXsTVm2QAcjLTPEpyAfOg==", "dependencies": { "@adobe/react-spectrum": "3.38.0", - "@deephaven/icons": "^0.109.0", - "@deephaven/log": "^0.109.0", - "@deephaven/react-hooks": "^0.109.0", - "@deephaven/utils": "^0.109.0", + "@deephaven/icons": "^1.0.0", + "@deephaven/log": "^1.0.0", + "@deephaven/react-hooks": "^1.0.0", + "@deephaven/utils": "^1.0.0", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/react-fontawesome": "^0.2.0", "@internationalized/date": "^3.5.5", @@ -34455,21 +34455,21 @@ } }, "plugins/ui/src/js/node_modules/@deephaven/console": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/console/-/console-0.109.0.tgz", - "integrity": "sha512-dnqLxfQky7qB8j6cXV4zifraMMkxCpKaLG/jDW+EpEmlviNwNb3wmIVlyuGE7OL38t/JXLwgeFh9U1pWk04nbg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/console/-/console-1.0.0.tgz", + "integrity": "sha512-Mzna9+ivR61u4R18miB6PSHBp4wMd/Qj7uZr6zYFnLBV07S18PYLpKwN94ndGJ3+GE1YO5frZuqwOKCto0xevQ==", "dependencies": { "@astral-sh/ruff-wasm-web": "0.6.4", - "@deephaven/chart": "^0.109.0", - "@deephaven/components": "^0.109.0", - "@deephaven/icons": "^0.109.0", - "@deephaven/jsapi-bootstrap": "^0.109.0", + "@deephaven/chart": "^1.0.0", + "@deephaven/components": "^1.0.0", + "@deephaven/icons": "^1.0.0", + "@deephaven/jsapi-bootstrap": "^1.0.0", "@deephaven/jsapi-types": "^1.0.0-dev0.37.2", - "@deephaven/jsapi-utils": "^0.109.0", - "@deephaven/log": "^0.109.0", - "@deephaven/react-hooks": "^0.109.0", - "@deephaven/storage": "^0.109.0", - "@deephaven/utils": "^0.109.0", + "@deephaven/jsapi-utils": "^1.0.0", + "@deephaven/log": "^1.0.0", + "@deephaven/react-hooks": "^1.0.0", + "@deephaven/storage": "^1.0.0", + "@deephaven/utils": "^1.0.0", "@fortawesome/react-fontawesome": "^0.2.0", "classnames": "^2.3.1", "linkifyjs": "^4.1.0", @@ -34493,12 +34493,12 @@ } }, "plugins/ui/src/js/node_modules/@deephaven/console/node_modules/@deephaven/storage": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/storage/-/storage-0.109.0.tgz", - "integrity": "sha512-cUkX/VY5UvmmB3Nbgvdmvcoo+mqWpL+997C9ovFsNw0TPxIGtJQWPTEDR7iPWKwKXXkznrIFfGIuDU32weuTJw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/storage/-/storage-1.0.0.tgz", + "integrity": "sha512-7ddXJWvr/bHpI/4PoAKVBbfBbvwfVouJ1I2gzn89pgDyH4rTVBwxo9zw/cnKB16wTkPcWOdhFB33xGHSHaGCOg==", "dependencies": { - "@deephaven/filters": "^0.109.0", - "@deephaven/log": "^0.109.0", + "@deephaven/filters": "^1.0.0", + "@deephaven/log": "^1.0.0", "lodash.throttle": "^4.1.1" }, "engines": { @@ -34509,19 +34509,21 @@ } }, "plugins/ui/src/js/node_modules/@deephaven/dashboard": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/dashboard/-/dashboard-0.109.0.tgz", - "integrity": "sha512-mCbfVUJXy8TTcuWPr30mmZP3KUYQon13cn5nIBhZ3ZyLrAaRtrb+lOswvbEbzUM8XHcSdtUflqs2hTyLt961Sw==", - "dependencies": { - "@deephaven/components": "^0.109.0", - "@deephaven/golden-layout": "^0.109.0", - "@deephaven/log": "^0.109.0", - "@deephaven/react-hooks": "^0.109.0", - "@deephaven/redux": "^0.109.0", - "@deephaven/utils": "^0.109.0", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/dashboard/-/dashboard-1.0.0.tgz", + "integrity": "sha512-E+cCnNiY6rwFfWQVwygvJgNpkfbUoPYU5g/FzZjUyoMCVq4jUOfw3tJROAZydjwL4KFUVvqX4SDgAhBp/qkANw==", + "dependencies": { + "@deephaven/components": "^1.0.0", + "@deephaven/golden-layout": "^1.0.0", + "@deephaven/log": "^1.0.0", + "@deephaven/react-hooks": "^1.0.0", + "@deephaven/redux": "^1.0.0", + "@deephaven/utils": "^1.0.0", + "classnames": "^2.3.1", "fast-deep-equal": "^3.1.3", "lodash.ismatch": "^4.1.1", "lodash.throttle": "^4.1.1", + "memoize-one": "^5.1.1", "nanoid": "^5.0.7", "prop-types": "^15.7.2" }, @@ -34535,30 +34537,30 @@ } }, "plugins/ui/src/js/node_modules/@deephaven/dashboard-core-plugins": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/dashboard-core-plugins/-/dashboard-core-plugins-0.109.0.tgz", - "integrity": "sha512-D8PqAX+/X4EsjHCRMHF0jNOLW8IZzbpbTB33415puuixi0sW75jVY9eF9zeIgKyH47cGcwnt2GqcwaZA729ftA==", - "dependencies": { - "@deephaven/chart": "^0.109.0", - "@deephaven/components": "^0.109.0", - "@deephaven/console": "^0.109.0", - "@deephaven/dashboard": "^0.109.0", - "@deephaven/file-explorer": "^0.109.0", - "@deephaven/filters": "^0.109.0", - "@deephaven/golden-layout": "^0.109.0", - "@deephaven/grid": "^0.109.0", - "@deephaven/icons": "^0.109.0", - "@deephaven/iris-grid": "^0.109.0", - "@deephaven/jsapi-bootstrap": "^0.109.0", - "@deephaven/jsapi-components": "^0.109.0", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/dashboard-core-plugins/-/dashboard-core-plugins-1.0.0.tgz", + "integrity": "sha512-hfjYnSFE+Yoq4aH9odFebCi3vgJyvT+nq6vwUmQ513vTZO6Q01Y6wcuqFWohFVD5nXwXnNd5iLjfakCTTtXS2w==", + "dependencies": { + "@deephaven/chart": "^1.0.0", + "@deephaven/components": "^1.0.0", + "@deephaven/console": "^1.0.0", + "@deephaven/dashboard": "^1.0.0", + "@deephaven/file-explorer": "^1.0.0", + "@deephaven/filters": "^1.0.0", + "@deephaven/golden-layout": "^1.0.0", + "@deephaven/grid": "^1.0.0", + "@deephaven/icons": "^1.0.0", + "@deephaven/iris-grid": "^1.0.0", + "@deephaven/jsapi-bootstrap": "^1.0.0", + "@deephaven/jsapi-components": "^1.0.0", "@deephaven/jsapi-types": "^1.0.0-dev0.37.2", - "@deephaven/jsapi-utils": "^0.109.0", - "@deephaven/log": "^0.109.0", - "@deephaven/plugin": "^0.109.0", - "@deephaven/react-hooks": "^0.109.0", - "@deephaven/redux": "^0.109.0", - "@deephaven/storage": "^0.109.0", - "@deephaven/utils": "^0.109.0", + "@deephaven/jsapi-utils": "^1.0.0", + "@deephaven/log": "^1.0.0", + "@deephaven/plugin": "^1.0.0", + "@deephaven/react-hooks": "^1.0.0", + "@deephaven/redux": "^1.0.0", + "@deephaven/storage": "^1.0.0", + "@deephaven/utils": "^1.0.0", "@fortawesome/react-fontawesome": "^0.2.0", "classnames": "^2.3.1", "fast-deep-equal": "^3.1.3", @@ -34586,15 +34588,15 @@ } }, "plugins/ui/src/js/node_modules/@deephaven/dashboard-core-plugins/node_modules/@deephaven/file-explorer": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/file-explorer/-/file-explorer-0.109.0.tgz", - "integrity": "sha512-9A5dpPy2SuEqkk5ZaN6H+9VDEbBS70ctqaHxR+8eyAfFhuYXWOC8mgSWE3avqOXW4+In6RTbKdJihbnMOdhohw==", - "dependencies": { - "@deephaven/components": "^0.109.0", - "@deephaven/icons": "^0.109.0", - "@deephaven/log": "^0.109.0", - "@deephaven/storage": "^0.109.0", - "@deephaven/utils": "^0.109.0", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/file-explorer/-/file-explorer-1.0.0.tgz", + "integrity": "sha512-FFE0ZORVW2b9E0wVMoBsw1nbhts4icnGMn2oMgi7Mx7mkgISHYIiYgUbqgidRd6+GK9jVKAOcp6usQvPumixPg==", + "dependencies": { + "@deephaven/components": "^1.0.0", + "@deephaven/icons": "^1.0.0", + "@deephaven/log": "^1.0.0", + "@deephaven/storage": "^1.0.0", + "@deephaven/utils": "^1.0.0", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/react-fontawesome": "^0.2.0", "classnames": "^2.3.1", @@ -34609,12 +34611,12 @@ } }, "plugins/ui/src/js/node_modules/@deephaven/dashboard-core-plugins/node_modules/@deephaven/storage": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/storage/-/storage-0.109.0.tgz", - "integrity": "sha512-cUkX/VY5UvmmB3Nbgvdmvcoo+mqWpL+997C9ovFsNw0TPxIGtJQWPTEDR7iPWKwKXXkznrIFfGIuDU32weuTJw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/storage/-/storage-1.0.0.tgz", + "integrity": "sha512-7ddXJWvr/bHpI/4PoAKVBbfBbvwfVouJ1I2gzn89pgDyH4rTVBwxo9zw/cnKB16wTkPcWOdhFB33xGHSHaGCOg==", "dependencies": { - "@deephaven/filters": "^0.109.0", - "@deephaven/log": "^0.109.0", + "@deephaven/filters": "^1.0.0", + "@deephaven/log": "^1.0.0", "lodash.throttle": "^4.1.1" }, "engines": { @@ -34643,19 +34645,19 @@ } }, "plugins/ui/src/js/node_modules/@deephaven/filters": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/filters/-/filters-0.109.0.tgz", - "integrity": "sha512-Iir/Hn+Xa1VcaGHYDqaZr5hp13wM/ztgTpNqpaqxVNPbvVhv6JvJTQBovsgJpBUKa52B0cbOwhdMwRRSzELSrA==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/filters/-/filters-1.0.0.tgz", + "integrity": "sha512-JMEFu3/SyNDH8cXiohrL4AFaQOR1hq9SkpnP2aj/uZfRLxswDj6qzt0WO7LC5z2youaYF9xg9TwJAF34ZAWF5Q==", "engines": { "node": ">=16" } }, "plugins/ui/src/js/node_modules/@deephaven/golden-layout": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/golden-layout/-/golden-layout-0.109.0.tgz", - "integrity": "sha512-moBmfkIc5O6zxBZytfOBr9ywRdIq49WfG/IEjjGKlJ43ay8UEq4HYMg0yGSBs2qPqUqZWgLKYxxdbV1K5Yj3cg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/golden-layout/-/golden-layout-1.0.0.tgz", + "integrity": "sha512-LUVevia25ibA37LEYk2T4ivL6MgfiT8Fa4BDncDN5Z8xCvDWxweKgcnkUNg4xBMQczxtk++a4niF6scfk8lECg==", "dependencies": { - "@deephaven/components": "^0.109.0", + "@deephaven/components": "^1.0.0", "jquery": "^3.6.0", "nanoid": "^5.0.7" }, @@ -34665,11 +34667,11 @@ } }, "plugins/ui/src/js/node_modules/@deephaven/grid": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/grid/-/grid-0.109.0.tgz", - "integrity": "sha512-tcATgtsHl6AzNyEwaOn6+3HepsBMZWweoHiDxKpt+LdTN1cuQO+E5ppb+e2LOZxneCadrWXY48lbfpzUo97VBg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/grid/-/grid-1.0.0.tgz", + "integrity": "sha512-QlW8M2kYaInubMMST4T/iBh5kb40444t+V675rc+PyuBu7VHBUci2Wq4GIuwKlshU/Bwj4HcjDNe2rw5Y+5Gcg==", "dependencies": { - "@deephaven/utils": "^0.109.0", + "@deephaven/utils": "^1.0.0", "classnames": "^2.3.1", "color-convert": "^2.0.1", "event-target-shim": "^6.0.2", @@ -34687,9 +34689,9 @@ } }, "plugins/ui/src/js/node_modules/@deephaven/icons": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/icons/-/icons-0.109.0.tgz", - "integrity": "sha512-fvTeHUSMU5duAsPvvCYjtWgwcIQF4KhMo8jBeOWngrG+P6Ddl1cx3tYr1UJEnKDCEyXnHbohNHIw0ejyfQcZ6A==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/icons/-/icons-1.0.0.tgz", + "integrity": "sha512-1z1nBz3TFK9OC/1gYHPCfsmgHFHMNmqj1byEKGxwQdhQbwTZ4vz0gvsim3z7EsNxc9ucooFcgv/xH43VUVx40A==", "dependencies": { "@fortawesome/fontawesome-common-types": "^6.1.1" }, @@ -34699,22 +34701,22 @@ } }, "plugins/ui/src/js/node_modules/@deephaven/iris-grid": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/iris-grid/-/iris-grid-0.109.0.tgz", - "integrity": "sha512-9X2TR160OG5DvRuKm67RmRmoTWVEmSYHSnS2wcw2T3vaDGzv+cen2BgK7marG4iglbJOvDkFFA6eXYj/3erMjg==", - "dependencies": { - "@deephaven/components": "^0.109.0", - "@deephaven/console": "^0.109.0", - "@deephaven/filters": "^0.109.0", - "@deephaven/grid": "^0.109.0", - "@deephaven/icons": "^0.109.0", - "@deephaven/jsapi-components": "^0.109.0", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/iris-grid/-/iris-grid-1.0.0.tgz", + "integrity": "sha512-2Vk++97JT4ISFh31QsTsP6egJ0XWLX1Y+cdiSQih3EXlPkqZBr1X9c5Bu/4ncnK1I2Ljj1emXgSHBFkQtMyZhg==", + "dependencies": { + "@deephaven/components": "^1.0.0", + "@deephaven/console": "^1.0.0", + "@deephaven/filters": "^1.0.0", + "@deephaven/grid": "^1.0.0", + "@deephaven/icons": "^1.0.0", + "@deephaven/jsapi-components": "^1.0.0", "@deephaven/jsapi-types": "^1.0.0-dev0.37.2", - "@deephaven/jsapi-utils": "^0.109.0", - "@deephaven/log": "^0.109.0", - "@deephaven/react-hooks": "^0.109.0", - "@deephaven/storage": "^0.109.0", - "@deephaven/utils": "^0.109.0", + "@deephaven/jsapi-utils": "^1.0.0", + "@deephaven/log": "^1.0.0", + "@deephaven/react-hooks": "^1.0.0", + "@deephaven/storage": "^1.0.0", + "@deephaven/utils": "^1.0.0", "@dnd-kit/core": "^6.1.0", "@dnd-kit/sortable": "^7.0.2", "@dnd-kit/utilities": "^3.2.2", @@ -34741,12 +34743,12 @@ } }, "plugins/ui/src/js/node_modules/@deephaven/iris-grid/node_modules/@deephaven/storage": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/storage/-/storage-0.109.0.tgz", - "integrity": "sha512-cUkX/VY5UvmmB3Nbgvdmvcoo+mqWpL+997C9ovFsNw0TPxIGtJQWPTEDR7iPWKwKXXkznrIFfGIuDU32weuTJw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/storage/-/storage-1.0.0.tgz", + "integrity": "sha512-7ddXJWvr/bHpI/4PoAKVBbfBbvwfVouJ1I2gzn89pgDyH4rTVBwxo9zw/cnKB16wTkPcWOdhFB33xGHSHaGCOg==", "dependencies": { - "@deephaven/filters": "^0.109.0", - "@deephaven/log": "^0.109.0", + "@deephaven/filters": "^1.0.0", + "@deephaven/log": "^1.0.0", "lodash.throttle": "^4.1.1" }, "engines": { @@ -34757,15 +34759,15 @@ } }, "plugins/ui/src/js/node_modules/@deephaven/jsapi-bootstrap": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/jsapi-bootstrap/-/jsapi-bootstrap-0.109.0.tgz", - "integrity": "sha512-KOar6Or2KgWx/a+vmKsBJGvkA7N/K04SkE76C05io9/1YZv+SMiDMa19mWBlHJcTZ78LIbhETUGH6cwo0e9HDw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-bootstrap/-/jsapi-bootstrap-1.0.0.tgz", + "integrity": "sha512-TVJ+5+/qzK/hm9QGi+A3D6Zj3oTt8I5HL1ajN1FtxS6Ov1vlPAnnvukHZwx5slsAjYkHswL/KIzB4r6Hc/hrEw==", "dependencies": { - "@deephaven/components": "^0.109.0", + "@deephaven/components": "^1.0.0", "@deephaven/jsapi-types": "^1.0.0-dev0.37.2", - "@deephaven/log": "^0.109.0", - "@deephaven/react-hooks": "^0.109.0", - "@deephaven/utils": "^0.109.0" + "@deephaven/log": "^1.0.0", + "@deephaven/react-hooks": "^1.0.0", + "@deephaven/utils": "^1.0.0" }, "engines": { "node": ">=16" @@ -34775,17 +34777,17 @@ } }, "plugins/ui/src/js/node_modules/@deephaven/jsapi-components": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/jsapi-components/-/jsapi-components-0.109.0.tgz", - "integrity": "sha512-H409txhFlEumti0d9JQFHNi1StQT96eN1OmDOgVcOKkF3KtuJXB4noAy4pQsaKowbDW1DMMnsC/TeofOl9iLpg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-components/-/jsapi-components-1.0.0.tgz", + "integrity": "sha512-HZ/qc6bsOunmjCAeSfQLhoV0qCSa7fwyDE81ou7tktXoF0HSvvzJ1+bPzy5z7ANY6sG6l8DUvpy3S7qX265QyQ==", "dependencies": { - "@deephaven/components": "^0.109.0", - "@deephaven/jsapi-bootstrap": "^0.109.0", + "@deephaven/components": "^1.0.0", + "@deephaven/jsapi-bootstrap": "^1.0.0", "@deephaven/jsapi-types": "^1.0.0-dev0.37.2", - "@deephaven/jsapi-utils": "^0.109.0", - "@deephaven/log": "^0.109.0", - "@deephaven/react-hooks": "^0.109.0", - "@deephaven/utils": "^0.109.0", + "@deephaven/jsapi-utils": "^1.0.0", + "@deephaven/log": "^1.0.0", + "@deephaven/react-hooks": "^1.0.0", + "@deephaven/utils": "^1.0.0", "@types/js-cookie": "^3.0.3", "classnames": "^2.3.2", "js-cookie": "^3.0.5", @@ -34804,14 +34806,14 @@ "license": "Apache-2.0" }, "plugins/ui/src/js/node_modules/@deephaven/jsapi-utils": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/jsapi-utils/-/jsapi-utils-0.109.0.tgz", - "integrity": "sha512-ON1Qeztu34DYNlDVhLOQUrBNHdTh5Rflnq9u1B4NaVo/vvV0cutLlTW56v5GSYNXgoOWDPURdTyjep072TFmGg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-utils/-/jsapi-utils-1.0.0.tgz", + "integrity": "sha512-NBJOSzaaSp/1j7RSiyx2gtDIk9FQ/ZkHTuMO1QUs/+b1AimrILsWzZAhMugxHIJgXS3vNVo//oS29SkYBbewTw==", "dependencies": { - "@deephaven/filters": "^0.109.0", + "@deephaven/filters": "^1.0.0", "@deephaven/jsapi-types": "^1.0.0-dev0.37.2", - "@deephaven/log": "^0.109.0", - "@deephaven/utils": "^0.109.0", + "@deephaven/log": "^1.0.0", + "@deephaven/utils": "^1.0.0", "lodash.clamp": "^4.0.3", "nanoid": "^5.0.7" }, @@ -34820,9 +34822,9 @@ } }, "plugins/ui/src/js/node_modules/@deephaven/log": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/log/-/log-0.109.0.tgz", - "integrity": "sha512-8Yv2UTr67aIS+2Na/1JXnNdEkm+tEhssrxDTySay3vywm3N3+5ghEsFY8PzL7rkLOyPZi1WAZejTOQ9omR+u7g==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/log/-/log-1.0.0.tgz", + "integrity": "sha512-8YMLtGhomekpXTZrkNJOlz+dAPRfENRpExiuz8pzq9qyncVv29CXwrQw8Fs4olG/z3YWcHKv6Rf7z/082H7n/Q==", "dependencies": { "event-target-shim": "^6.0.2", "jszip": "^3.10.1" @@ -34832,18 +34834,18 @@ } }, "plugins/ui/src/js/node_modules/@deephaven/plugin": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/plugin/-/plugin-0.109.0.tgz", - "integrity": "sha512-D2zoQ8qd52t+CkxXqYo1UIujAKM/7URoifnYHtNbhsnJT2Teb4EgayKtHIuRcqc+J/sFJLTbY27b26GupJ8/fA==", - "dependencies": { - "@deephaven/components": "^0.109.0", - "@deephaven/golden-layout": "^0.109.0", - "@deephaven/grid": "^0.109.0", - "@deephaven/icons": "^0.109.0", - "@deephaven/iris-grid": "^0.109.0", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/plugin/-/plugin-1.0.0.tgz", + "integrity": "sha512-jNssATvJmHwr8iMgudWEapeft7m3pfDLD/hUoNS5DMcZVDmJjfco8K/rQoE/+wyhI2Q1QfIyZKcmPNIPAYlljQ==", + "dependencies": { + "@deephaven/components": "^1.0.0", + "@deephaven/golden-layout": "^1.0.0", + "@deephaven/grid": "^1.0.0", + "@deephaven/icons": "^1.0.0", + "@deephaven/iris-grid": "^1.0.0", "@deephaven/jsapi-types": "^1.0.0-dev0.37.2", - "@deephaven/log": "^0.109.0", - "@deephaven/react-hooks": "^0.109.0", + "@deephaven/log": "^1.0.0", + "@deephaven/react-hooks": "^1.0.0", "@fortawesome/fontawesome-common-types": "^6.1.1", "@fortawesome/react-fontawesome": "^0.2.0", "nanoid": "^5.0.7" @@ -34856,13 +34858,13 @@ } }, "plugins/ui/src/js/node_modules/@deephaven/react-hooks": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/react-hooks/-/react-hooks-0.109.0.tgz", - "integrity": "sha512-twVsLG3x7HhopxDYbVkOWt7z/Cs+RiHSxJVKAGlwUk9BR+xc7aonNytNiXU8iKhw+zKOo8nAUrd79Hi6jcnGPw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/react-hooks/-/react-hooks-1.0.0.tgz", + "integrity": "sha512-s/6yzIgcD+duCzJY5t8s99Ew5GYu4yABXwd62i1xcRSxqgSZPwaZu7QV7mGY6C1HJeJtbq8gsSfs7tMcBg5m0Q==", "dependencies": { "@adobe/react-spectrum": "3.38.0", - "@deephaven/log": "^0.109.0", - "@deephaven/utils": "^0.109.0", + "@deephaven/log": "^1.0.0", + "@deephaven/utils": "^1.0.0", "lodash.debounce": "^4.0.8", "lodash.throttle": "^4.1.1", "nanoid": "^5.0.7" @@ -34947,14 +34949,14 @@ } }, "plugins/ui/src/js/node_modules/@deephaven/redux": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/redux/-/redux-0.109.0.tgz", - "integrity": "sha512-yb1eJ4c+3zeY2X1mI9arYHJ/GzX+jSB2Cf0aZZCnbfPt8ObyaaTmgoEfh8RR5tn7DQakpC09//rzqi3CsG68zA==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/redux/-/redux-1.0.0.tgz", + "integrity": "sha512-+R6sqj2gd/8ji3z84hAcvu0CwG0l4YLW/+nn2K7e4pdYPUCeYxJSoyzUfI5NenZp3+4z0TwXEJzGGWZr8QAkqA==", "dependencies": { "@deephaven/jsapi-types": "^1.0.0-dev0.37.2", - "@deephaven/jsapi-utils": "^0.109.0", - "@deephaven/log": "^0.109.0", - "@deephaven/plugin": "^0.109.0", + "@deephaven/jsapi-utils": "^1.0.0", + "@deephaven/log": "^1.0.0", + "@deephaven/plugin": "^1.0.0", "fast-deep-equal": "^3.1.3", "proxy-memoize": "^3.0.0", "redux-thunk": "2.4.1" @@ -34967,19 +34969,19 @@ } }, "plugins/ui/src/js/node_modules/@deephaven/test-utils": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/test-utils/-/test-utils-0.109.0.tgz", - "integrity": "sha512-eEHVCXLkXwbsRQZL+bu+tQjM+jHrgaS/iog82zppsiVtKazy8+aGsTqPUZ2HwAOr3VfrVTWTrbUlgN/VEOBR2w==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/test-utils/-/test-utils-1.0.0.tgz", + "integrity": "sha512-a6MIfCrLlncfbsKAcIGsxDVP/LixzkfVjbomu2Nbvj9roLYgLu5TvKF+YpvnHNsqI3kLLL38C4bxY8fylvJwzQ==", "engines": { "node": ">=16" } }, "plugins/ui/src/js/node_modules/@deephaven/utils": { - "version": "0.109.0", - "resolved": "https://registry.npmjs.org/@deephaven/utils/-/utils-0.109.0.tgz", - "integrity": "sha512-LsqrLrxgcICYQMv9U7mfXiNulXxrB8z+DciAZNcdLf2VfDvkaClAo86tHsaPbe/cKO7zBbYnlCuLNXUuuwsVMg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deephaven/utils/-/utils-1.0.0.tgz", + "integrity": "sha512-lGrhWxKs/NTmOqVroR8tBbz6IaXjoQwKm9//tknJYHh1u88PFUm1DU2sfoUEN1ivpUhihDdswbZ3PrLkicG7Ow==", "dependencies": { - "@deephaven/log": "^0.109.0", + "@deephaven/log": "^1.0.0", "nanoid": "^5.0.7" }, "engines": { diff --git a/plugins/ui/src/js/package.json b/plugins/ui/src/js/package.json index dda8e6ff0..7155c4331 100644 --- a/plugins/ui/src/js/package.json +++ b/plugins/ui/src/js/package.json @@ -40,25 +40,25 @@ "react-dom": "^17.0.2" }, "dependencies": { - "@deephaven/chart": "^0.109.0", - "@deephaven/components": "^0.109.0", - "@deephaven/console": "^0.109.0", - "@deephaven/dashboard": "^0.109.0", - "@deephaven/dashboard-core-plugins": "^0.109.0", - "@deephaven/golden-layout": "^0.109.0", - "@deephaven/grid": "^0.109.0", - "@deephaven/icons": "^0.109.0", - "@deephaven/iris-grid": "^0.109.0", - "@deephaven/jsapi-bootstrap": "^0.109.0", - "@deephaven/jsapi-components": "^0.109.0", + "@deephaven/chart": "^1.0.0", + "@deephaven/components": "^1.0.0", + "@deephaven/console": "^1.0.0", + "@deephaven/dashboard": "^1.0.0", + "@deephaven/dashboard-core-plugins": "^1.0.0", + "@deephaven/golden-layout": "^1.0.0", + "@deephaven/grid": "^1.0.0", + "@deephaven/icons": "^1.0.0", + "@deephaven/iris-grid": "^1.0.0", + "@deephaven/jsapi-bootstrap": "^1.0.0", + "@deephaven/jsapi-components": "^1.0.0", "@deephaven/jsapi-types": "^1.0.0-dev0.35.0", - "@deephaven/jsapi-utils": "^0.109.0", - "@deephaven/log": "^0.109.0", - "@deephaven/plugin": "^0.109.0", - "@deephaven/react-hooks": "^0.109.0", - "@deephaven/redux": "^0.109.0", - "@deephaven/test-utils": "^0.109.0", - "@deephaven/utils": "^0.109.0", + "@deephaven/jsapi-utils": "^1.0.0", + "@deephaven/log": "^1.0.0", + "@deephaven/plugin": "^1.0.0", + "@deephaven/react-hooks": "^1.0.0", + "@deephaven/redux": "^1.0.0", + "@deephaven/test-utils": "^1.0.0", + "@deephaven/utils": "^1.0.0", "@fortawesome/react-fontawesome": "^0.2.0", "@internationalized/date": "^3.5.5", "classnames": "^2.5.1", diff --git a/plugins/ui/src/js/src/elements/ObjectView.tsx b/plugins/ui/src/js/src/elements/ObjectView.tsx index 8f8b32f1f..6cb3024da 100644 --- a/plugins/ui/src/js/src/elements/ObjectView.tsx +++ b/plugins/ui/src/js/src/elements/ObjectView.tsx @@ -5,9 +5,13 @@ import type { dh } from '@deephaven/jsapi-types'; const log = Log.module('@deephaven/js-plugin-ui/ObjectView'); -export type ObjectViewProps = { object: dh.WidgetExportedObject }; +export type ObjectViewProps = { + object: dh.WidgetExportedObject; + __dhId?: string; +}; + function ObjectView(props: ObjectViewProps): JSX.Element { - const { object } = props; + const { object, __dhId } = props; log.info('Object is', object); const { type } = object; @@ -32,7 +36,7 @@ function ObjectView(props: ObjectViewProps): JSX.Element { if (plugin != null) { const Component = plugin.component; // eslint-disable-next-line react/jsx-props-no-spreading - return ; + return ; } log.warn('Unknown object type', object.type); diff --git a/plugins/ui/src/js/src/elements/UITable/UITable.tsx b/plugins/ui/src/js/src/elements/UITable/UITable.tsx index 23ba95492..87f4706fc 100644 --- a/plugins/ui/src/js/src/elements/UITable/UITable.tsx +++ b/plugins/ui/src/js/src/elements/UITable/UITable.tsx @@ -27,6 +27,11 @@ import { useTheme, viewStyleProps, } from '@deephaven/components'; +import { + InputFilterEvent, + useDashboardColumnFilters, +} from '@deephaven/dashboard-core-plugins'; +import { useLayoutManager, useListener } from '@deephaven/dashboard'; import { useApi } from '@deephaven/jsapi-bootstrap'; import type { dh as DhType } from '@deephaven/jsapi-types'; import Log from '@deephaven/log'; @@ -213,6 +218,7 @@ export function UITable({ ); const dh = useApi(); + const { eventHub } = useLayoutManager(); const theme = useTheme(); const [irisGrid, setIrisGrid] = useState(null); const utils = useMemo(() => new IrisGridUtils(dh), [dh]); @@ -527,6 +533,24 @@ export function UITable({ }; }, [irisGridServerProps, initialHydratedState]); + const inputFilters = useDashboardColumnFilters( + model?.columns ?? EMPTY_ARRAY, + model?.table + ); + + const handleClearAllFilters = useCallback(() => { + if (irisGrid == null) { + return; + } + irisGrid.clearAllFilters(); + }, [irisGrid]); + + useListener( + eventHub, + InputFilterEvent.CLEAR_ALL_FILTERS, + handleClearAllFilters + ); + return model ? (
) : null; diff --git a/plugins/ui/src/js/src/elements/utils/ElementUtils.test.tsx b/plugins/ui/src/js/src/elements/utils/ElementUtils.test.tsx index bb120bd56..4b7f16256 100644 --- a/plugins/ui/src/js/src/elements/utils/ElementUtils.test.tsx +++ b/plugins/ui/src/js/src/elements/utils/ElementUtils.test.tsx @@ -68,32 +68,41 @@ describe('wrapElementChildren', () => { it.each([ [ + 'single', mock.exportedA1, - , + , ], [ + 'multiple', [mock.exportedA1, mock.exportedA2, mock.exportedB1], [ , , , ], ], ])( - 'should wrap exported object children in ObjectView: %s, %s', - (children, expectedChildren) => { + 'should wrap exported object children in ObjectView: %s', + (testName, children, expectedChildren) => { const actual = wrapElementChildren({ [ELEMENT_KEY]: 'mock.element', - props: { children }, + props: { children, __dhId: 'test-root' }, }); expect(actual.props?.children).toEqual(expectedChildren); @@ -119,7 +128,7 @@ describe('wrapElementChildren', () => { ], ], ])( - 'should wrap primitive item element children in Text elements: %s, %s', + 'should wrap primitive item element children in Text elements: %s', (children, expectedChildren) => { const givenProps: Record = { children }; if (textValue != null) { diff --git a/plugins/ui/src/js/src/elements/utils/ElementUtils.tsx b/plugins/ui/src/js/src/elements/utils/ElementUtils.tsx index 9e8b05f38..e0258a88b 100644 --- a/plugins/ui/src/js/src/elements/utils/ElementUtils.tsx +++ b/plugins/ui/src/js/src/elements/utils/ElementUtils.tsx @@ -191,7 +191,15 @@ export function wrapElementChildren(element: ElementNode): ElementNode { const wrappedChildren = children.map(child => { // Exported objects need to be converted to `ObjectView` to be rendered if (isExportedObject(child)) { - return ; + const key = getChildKey(child.type); + return ( + + ); } // Auto wrap primitive children of `Item` elements in `Text` elements diff --git a/plugins/ui/src/js/src/layout/ReactPanel.tsx b/plugins/ui/src/js/src/layout/ReactPanel.tsx index c78c8ffe8..b3d1ae221 100644 --- a/plugins/ui/src/js/src/layout/ReactPanel.tsx +++ b/plugins/ui/src/js/src/layout/ReactPanel.tsx @@ -10,6 +10,7 @@ import { nanoid } from 'nanoid'; import { LayoutUtils, PanelEvent, + PanelIdContext, useLayoutManager, useListener, } from '@deephaven/dashboard'; @@ -218,52 +219,52 @@ function ReactPanel({ return portal ? ReactDOM.createPortal( - - + - - {/** - * Don't render the children if there's an error with the widget. If there's an error with the widget, we can assume the children won't render properly, - * but we still want the panels to appear so things don't disappear/jump around. - */} - - {React.Children.map(renderedChildren, child => - React.cloneElement(child as React.ReactElement) - )} - - - - + + + {/** + * Don't render the children if there's an error with the widget. If there's an error with the widget, we can assume the children won't render properly, + * but we still want the panels to appear so things don't disappear/jump around. + */} + + {renderedChildren ?? null} + + + + + , portal, contentKey diff --git a/plugins/ui/src/js/src/widget/DashboardWidgetHandler.tsx b/plugins/ui/src/js/src/widget/DashboardWidgetHandler.tsx index d7136c5bb..e4620e603 100644 --- a/plugins/ui/src/js/src/widget/DashboardWidgetHandler.tsx +++ b/plugins/ui/src/js/src/widget/DashboardWidgetHandler.tsx @@ -41,6 +41,7 @@ function DashboardWidgetHandler({ return ( = {}) { return ( { - // Need to re-hydrate any objects that are defined - if (isCallableNode(value)) { - const callableId = value[CALLABLE_KEY]; - deadCallableMap.delete(callableId); - if (renderedCallableMap.current.has(callableId)) { - log.debug2('Reusing callableId', callableId); - return renderedCallableMap.current.get(callableId); + const hydratedDocument = transformNode( + doc, + (key, value) => { + // Need to re-hydrate any objects that are defined + if (isCallableNode(value)) { + const callableId = value[CALLABLE_KEY]; + deadCallableMap.delete(callableId); + if (renderedCallableMap.current.has(callableId)) { + log.debug2('Reusing callableId', callableId); + return renderedCallableMap.current.get(callableId); + } + log.debug2('Registering callableId', callableId); + const callable = wrapCallable( + jsonClient, + callableId, + callableFinalizationRegistry, + false + ); + renderedCallableMap.current.set(callableId, callable); + return callable; } - log.debug2('Registering callableId', callableId); - const callable = wrapCallable( - jsonClient, - callableId, - callableFinalizationRegistry, - false - ); - renderedCallableMap.current.set(callableId, callable); - return callable; - } - if (isObjectNode(value)) { - // Replace this node with the exported object - const objectKey = value[OBJECT_KEY]; - const exportedObject = exportedObjectMap.current.get(objectKey); - if (exportedObject === undefined) { - // The map should always have the exported object for a key, otherwise the protocol is broken - throw new Error(`Invalid exported object key ${objectKey}`); + if (isObjectNode(value)) { + // Replace this node with the exported object + const objectKey = value[OBJECT_KEY]; + const exportedObject = exportedObjectMap.current.get(objectKey); + if (exportedObject === undefined) { + // The map should always have the exported object for a key, otherwise the protocol is broken + throw new Error(`Invalid exported object key ${objectKey}`); + } + deadObjectMap.delete(objectKey); + return exportedObject; } - deadObjectMap.delete(objectKey); - return exportedObject; - } - if (isElementNode(value)) { - // Replace the elements node with the Component it maps to - try { - return getComponentForElement(value); - } catch (e) { - log.warn('Error getting component for element', e); - return value; + if (isElementNode(value)) { + // Replace the elements node with the Component it maps to + try { + return getComponentForElement(value); + } catch (e) { + log.warn('Error getting component for element', e); + return value; + } } - } - return value; - }); + return value; + }, + id + ); // Close any objects that are no longer referenced deadObjectMap.forEach((deadObject, objectKey) => { @@ -275,7 +283,13 @@ function WidgetHandler({ ); return hydratedDocument; }, - [callableFinalizationRegistry, document, jsonClient, renderEmptyDocument] + [ + callableFinalizationRegistry, + document, + jsonClient, + renderEmptyDocument, + id, + ] ); const updateExportedObjects = useCallback( diff --git a/plugins/ui/src/js/src/widget/WidgetUtils.test.tsx b/plugins/ui/src/js/src/widget/WidgetUtils.test.tsx index 04b519038..3429e88f4 100644 --- a/plugins/ui/src/js/src/widget/WidgetUtils.test.tsx +++ b/plugins/ui/src/js/src/widget/WidgetUtils.test.tsx @@ -253,7 +253,7 @@ describe('transformNode', () => { 'should handle primitive values: %s', value => { const transform = jest.fn((k, v) => v); - expect(transformNode(value, transform)).toBe(value); + expect(transformNode(value, transform, '')).toBe(value); expect(transform).toHaveBeenCalledWith('', value); } ); @@ -263,7 +263,7 @@ describe('transformNode', () => { const transform = jest.fn((k, v) => v); const value = ['test', 'test2']; const valueCopy = [...value]; - const result = transformNode(value, transform); + const result = transformNode(value, transform, ''); expect(result).toBe(value); expect(result).toEqual(valueCopy); expect(transform).toHaveBeenCalledTimes(3); @@ -276,7 +276,7 @@ describe('transformNode', () => { const transform = jest.fn((k, v) => (k === '0' ? 'modified' : v)); const value = ['test', 'test2']; const expected = ['modified', 'test2']; - const result = transformNode(value, transform); + const result = transformNode(value, transform, ''); expect(result).toEqual(expected); expect(result).not.toBe(value); }); @@ -284,7 +284,7 @@ describe('transformNode', () => { it('handles the empty array', () => { const transform = jest.fn((k, v) => v); const value: unknown[] = []; - const result = transformNode(value, transform); + const result = transformNode(value, transform, ''); expect(result).toEqual([]); expect(result).toBe(value); }); @@ -295,7 +295,7 @@ describe('transformNode', () => { const transform = jest.fn((k, v) => v); const value = { a: 'test', b: 'test2' }; const valueCopy = { ...value }; - const result = transformNode(value, transform); + const result = transformNode(value, transform, ''); expect(result).toBe(value); expect(result).toStrictEqual(valueCopy); expect(transform).toHaveBeenCalledTimes(3); @@ -308,7 +308,7 @@ describe('transformNode', () => { const transform = jest.fn((k, v) => (k === 'a' ? 'modified' : v)); const value = { a: 'test', b: 'test2' }; const expected = { a: 'modified', b: 'test2' }; - const result = transformNode(value, transform); + const result = transformNode(value, transform, ''); expect(result).toEqual(expected); expect(result).not.toBe(value); }); @@ -316,7 +316,7 @@ describe('transformNode', () => { it('handles the empty object', () => { const transform = jest.fn((k, v) => v); const value: Record = {}; - const result = transformNode(value, transform); + const result = transformNode(value, transform, ''); expect(result).toStrictEqual({}); expect(result).toBe(value); }); @@ -326,7 +326,7 @@ describe('transformNode', () => { const transform = jest.fn((k, v) => (k === 'a' ? 'modified' : v)); const value = { a: 'test', b: { c: 'test2' } }; const expected = { a: 'modified', b: { c: 'test2' } }; - const result = transformNode(value, transform); + const result = transformNode(value, transform, ''); expect(result).toStrictEqual(expected); expect(result).not.toBe(value); // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -337,10 +337,177 @@ describe('transformNode', () => { const transform = jest.fn((k, v) => (k === 'a' ? 'modified' : v)); const value = { a: 'test', b: ['test2'] }; const expected = { a: 'modified', b: ['test2'] }; - const result = transformNode(value, transform); + const result = transformNode(value, transform, ''); expect(result).toStrictEqual(expected); expect(result).not.toBe(value); // eslint-disable-next-line @typescript-eslint/no-explicit-any expect((result as any).b).toBe(value.b); }); + + it('adds dhId to root and nested child elements', () => { + const transform = jest.fn((k, v) => v); + const value = { + [ELEMENT_KEY]: ELEMENT_NAME.flex, + props: { + children: { + [ELEMENT_KEY]: ELEMENT_NAME.button, + props: { + children: { + [ELEMENT_KEY]: ELEMENT_NAME.text, + props: { textValue: 'Click me' }, + }, + }, + }, + }, + }; + const result = transformNode(value, transform, 'testRoot'); + expect(result).toEqual({ + [ELEMENT_KEY]: ELEMENT_NAME.flex, + props: { + __dhId: `testRoot/${ELEMENT_NAME.flex}`, + children: { + [ELEMENT_KEY]: ELEMENT_NAME.button, + props: { + __dhId: `testRoot/${ELEMENT_NAME.flex}/${ELEMENT_NAME.button}`, + children: { + [ELEMENT_KEY]: ELEMENT_NAME.text, + props: { + textValue: 'Click me', + __dhId: `testRoot/${ELEMENT_NAME.flex}/${ELEMENT_NAME.button}/${ELEMENT_NAME.text}`, + }, + }, + }, + }, + }, + }); + }); + + it('adds key or array index to dhId for array elements', () => { + const transform = jest.fn((k, v) => v); + const value = { + [ELEMENT_KEY]: ELEMENT_NAME.flex, + props: { + children: [ + { + [ELEMENT_KEY]: ELEMENT_NAME.button, + props: { + key: 'buttonKey', + children: { + [ELEMENT_KEY]: ELEMENT_NAME.text, + props: { textValue: 'button' }, + }, + }, + }, + { + [ELEMENT_KEY]: ELEMENT_NAME.actionButton, + props: { textValue: 'actionButton' }, + }, + 'string child', + ], + }, + }; + const result = transformNode(value, transform, 'testRoot'); + expect(result).toEqual({ + [ELEMENT_KEY]: ELEMENT_NAME.flex, + props: { + __dhId: `testRoot/${ELEMENT_NAME.flex}`, + children: [ + { + [ELEMENT_KEY]: ELEMENT_NAME.button, + props: { + key: 'buttonKey', + __dhId: `testRoot/${ELEMENT_NAME.flex}/${ELEMENT_NAME.button}:buttonKey`, + children: { + [ELEMENT_KEY]: ELEMENT_NAME.text, + props: { + textValue: 'button', + __dhId: `testRoot/${ELEMENT_NAME.flex}/${ELEMENT_NAME.button}:buttonKey/${ELEMENT_NAME.text}`, + }, + }, + }, + }, + { + [ELEMENT_KEY]: ELEMENT_NAME.actionButton, + props: { + textValue: 'actionButton', + __dhId: `testRoot/${ELEMENT_NAME.flex}/${ELEMENT_NAME.actionButton}:1`, + }, + }, + 'string child', + ], + }, + }); + }); + + it('adds dhId to elements in props other than children', () => { + const transform = jest.fn((k, v) => v); + const value = { + [ELEMENT_KEY]: ELEMENT_NAME.flex, + props: { + other: [ + { + [ELEMENT_KEY]: ELEMENT_NAME.button, + props: { + key: 'buttonKey', + children: { + [ELEMENT_KEY]: ELEMENT_NAME.text, + props: { textValue: 'button' }, + }, + }, + }, + { + [ELEMENT_KEY]: ELEMENT_NAME.actionButton, + props: { textValue: 'actionButton' }, + }, + 'string child', + [ + { + [ELEMENT_KEY]: ELEMENT_NAME.text, + props: { textValue: 'text child' }, + }, + ], + ], + }, + }; + const result = transformNode(value, transform, 'testRoot'); + expect(result).toEqual({ + [ELEMENT_KEY]: ELEMENT_NAME.flex, + props: { + __dhId: `testRoot/${ELEMENT_NAME.flex}`, + other: [ + { + [ELEMENT_KEY]: ELEMENT_NAME.button, + props: { + key: 'buttonKey', + __dhId: `testRoot/${ELEMENT_NAME.flex}/props/other/${ELEMENT_NAME.button}:buttonKey`, + children: { + [ELEMENT_KEY]: ELEMENT_NAME.text, + props: { + textValue: 'button', + __dhId: `testRoot/${ELEMENT_NAME.flex}/props/other/${ELEMENT_NAME.button}:buttonKey/${ELEMENT_NAME.text}`, + }, + }, + }, + }, + { + [ELEMENT_KEY]: ELEMENT_NAME.actionButton, + props: { + textValue: 'actionButton', + __dhId: `testRoot/${ELEMENT_NAME.flex}/props/other/${ELEMENT_NAME.actionButton}:1`, + }, + }, + 'string child', + [ + { + [ELEMENT_KEY]: ELEMENT_NAME.text, + props: { + textValue: 'text child', + __dhId: `testRoot/${ELEMENT_NAME.flex}/props/other/3/${ELEMENT_NAME.text}:0`, + }, + }, + ], + ], + }, + }); + }); }); diff --git a/plugins/ui/src/js/src/widget/WidgetUtils.tsx b/plugins/ui/src/js/src/widget/WidgetUtils.tsx index 78a14d802..8cb285936 100644 --- a/plugins/ui/src/js/src/widget/WidgetUtils.tsx +++ b/plugins/ui/src/js/src/widget/WidgetUtils.tsx @@ -44,6 +44,7 @@ import { CALLABLE_KEY, wrapTextChildren, isPrimitive, + getElementKey, } from '../elements/utils/ElementUtils'; import HTMLElementView from '../elements/HTMLElementView'; import { isHTMLElementNode } from '../elements/utils/HTMLElementUtils'; @@ -248,24 +249,51 @@ export function getComponentForElement(element: ElementNode): React.ReactNode { /** * Deeply transform a given object depth-first and return a new object given a transform function. * Useful for iterating through an object and converting values. + * Also adds __dhId prop to any element nodes to uniquely identify them. * * @param value The object to transform. * @param transform Function to be called for each key-value pair in the object, allowing for the value to be transformed. + * @param id The dhId of the current object. Used as a unique ID for elements. * @param key The key of the current object. * @returns A new object with the same keys as the original object, but with the values replaced by the return value of the callback. If there were no changes, returns the same object. */ export function transformNode( value: unknown, transform: (key: string, value: unknown) => unknown, + id: string, key = '' ): unknown { // We initialize the result to the same value, but if any of the children values change, we'll shallow copy it let result = value; + + let nextId = id; + + // The component names will be added instead of props/children + if (key === 'children' && id.endsWith('/props')) { + nextId = nextId.slice(0, -1 * '/props'.length); + } + + if (isElementNode(result)) { + // Don't fallback to key if it's children, only fallback should be an array or object index + const elementKey = getElementKey(result, key === 'children' ? '' : key); + nextId += `/${result[ELEMENT_KEY]}${elementKey ? `:${elementKey}` : ''}`; + result = { ...result, props: { ...result.props, __dhId: nextId } }; + } else if (key !== 'children') { + // We have already removed trailing /props if we are at /props/children, so don't add /children + // The next item (children) must be either a child element or an array of children + nextId += `/${key}`; + } + // First check if it's an object or an array - if it is then we need to encode the children first if (Array.isArray(result)) { let arrayResult: unknown[] = result; arrayResult.forEach((childValue, i) => { - const newChildValue = transformNode(childValue, transform, `${i}`); + const newChildValue = transformNode( + childValue, + transform, + nextId, + `${i}` + ); if (newChildValue !== childValue) { if (arrayResult === value) { arrayResult = [...arrayResult]; @@ -277,7 +305,12 @@ export function transformNode( } else if (typeof result === 'object' && result != null) { let objResult = result as Record; Object.entries(result).forEach(([childKey, childValue]) => { - const newChildValue = transformNode(childValue, transform, childKey); + const newChildValue = transformNode( + childValue, + transform, + nextId, + childKey + ); if (newChildValue !== childValue) { if (objResult === value) { objResult = { ...objResult }; diff --git a/plugins/ui/src/js/vite.config.ts b/plugins/ui/src/js/vite.config.ts index f8637b5a0..d09148acc 100644 --- a/plugins/ui/src/js/vite.config.ts +++ b/plugins/ui/src/js/vite.config.ts @@ -21,6 +21,7 @@ export default defineConfig(({ mode }) => ({ '@deephaven/components', '@deephaven/console', '@deephaven/dashboard', + '@deephaven/dashboard-core-plugins', '@deephaven/icons', '@deephaven/iris-grid', '@deephaven/jsapi-bootstrap',