From e1d525878a91d251b59656c07e45a6d5277a77c4 Mon Sep 17 00:00:00 2001 From: Gordon Smith Date: Thu, 18 Jul 2024 18:44:12 +0100 Subject: [PATCH 1/3] HPCC-32279 Timeline selection issues Url contains "undefined" for selection Restoring selection in scopesTable fails on pushUrl Disable timeline toggle, make click only Signed-off-by: Gordon Smith --- esp/src/package-lock.json | 301 +++++++++++------------ esp/src/package.json | 31 +-- esp/src/src-react/components/Metrics.tsx | 43 ++-- 3 files changed, 181 insertions(+), 194 deletions(-) diff --git a/esp/src/package-lock.json b/esp/src/package-lock.json index bb858aa4279..f31d2188ec8 100644 --- a/esp/src/package-lock.json +++ b/esp/src/package-lock.json @@ -15,22 +15,23 @@ "@fluentui/react-hooks": "8.8.10", "@fluentui/react-icons-mdl2": "1.3.72", "@fluentui/react-migration-v8-v9": "9.6.22", - "@hpcc-js/chart": "2.83.4", - "@hpcc-js/codemirror": "2.62.1", - "@hpcc-js/common": "2.71.18", - "@hpcc-js/comms": "2.94.0", + "@hpcc-js/chart": "2.84.1", + "@hpcc-js/codemirror": "2.63.0", + "@hpcc-js/common": "2.72.0", + "@hpcc-js/comms": "2.95.0", "@hpcc-js/dataflow": "8.1.7", - "@hpcc-js/eclwatch": "2.74.8", - "@hpcc-js/graph": "2.85.16", - "@hpcc-js/html": "2.42.21", - "@hpcc-js/layout": "2.49.23", - "@hpcc-js/map": "2.77.22", - "@hpcc-js/other": "2.15.23", - "@hpcc-js/phosphor": "2.18.9", - "@hpcc-js/react": "2.53.17", - "@hpcc-js/tree": "2.40.18", - "@hpcc-js/util": "2.51.1", - "@hpcc-js/wasm": "2.18.0", + "@hpcc-js/eclwatch": "2.75.3", + "@hpcc-js/graph": "2.86.0", + "@hpcc-js/html": "2.43.0", + "@hpcc-js/layout": "2.50.1", + "@hpcc-js/map": "2.78.1", + "@hpcc-js/other": "2.16.1", + "@hpcc-js/phosphor": "2.19.1", + "@hpcc-js/react": "2.54.0", + "@hpcc-js/timeline": "2.53.0", + "@hpcc-js/tree": "2.41.0", + "@hpcc-js/util": "2.52.0", + "@hpcc-js/wasm": "2.18.1", "@kubernetes/client-node": "0.20.0", "clipboard": "2.0.11", "d3-dsv": "3.0.1", @@ -2026,41 +2027,41 @@ } }, "node_modules/@hpcc-js/api": { - "version": "2.12.18", - "resolved": "https://registry.npmjs.org/@hpcc-js/api/-/api-2.12.18.tgz", - "integrity": "sha512-Iq00B6q9DGGoLe+PTm4mJjaopfHRQbd6A3rNW968vZDmtgBh3Vcn2ie/Ym/Dbcf3UjSuWjaldaLKksqvgIbmtw==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/@hpcc-js/api/-/api-2.13.0.tgz", + "integrity": "sha512-bqMLQ/jlCSqBe3CfC2f2vaWZt12FBPW/5LfzW0I0Z30L+FRmjvBpEPMgr3Jd9JIv/igpq49F3xEAKiCxeMYaeA==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/common": "^2.71.18" + "@hpcc-js/common": "^2.72.0" } }, "node_modules/@hpcc-js/chart": { - "version": "2.83.4", - "resolved": "https://registry.npmjs.org/@hpcc-js/chart/-/chart-2.83.4.tgz", - "integrity": "sha512-rIE6OSEbh9Z75l0fkP0rDjZuBi60lXDMsBlaG42YBgnZpWKIQHydkGDOnq7q7jC3PedvSgOnr3ZRJL8ZBA1iXg==", + "version": "2.84.1", + "resolved": "https://registry.npmjs.org/@hpcc-js/chart/-/chart-2.84.1.tgz", + "integrity": "sha512-ddqZh6rnp93FIRLtcfE3bKpV+o194aOnSyYwW2pCkKYoAiGtFPfZAiOY2AaYsqqhQ96Pqk+6bOEfi4Asr6cj5A==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/api": "^2.12.18", - "@hpcc-js/common": "^2.71.18", - "@hpcc-js/util": "^2.51.1" + "@hpcc-js/api": "^2.13.0", + "@hpcc-js/common": "^2.72.0", + "@hpcc-js/util": "^2.52.0" } }, "node_modules/@hpcc-js/codemirror": { - "version": "2.62.1", - "resolved": "https://registry.npmjs.org/@hpcc-js/codemirror/-/codemirror-2.62.1.tgz", - "integrity": "sha512-p/sG+En3UG5grGx00maZ8wjUuuUGb/6flzlq+bSIDNldwqaheWZscGPaJdxLa+aSvcFbXXrDgcV4dhhd70xEyA==", + "version": "2.63.0", + "resolved": "https://registry.npmjs.org/@hpcc-js/codemirror/-/codemirror-2.63.0.tgz", + "integrity": "sha512-Vx/EJWOhSzAqdg5RqA9w/wOjtIuBBNYAWjvvz+mqwHtzWN9bK9ciwRFeL+LyrunT66W49qV0sSt8sgQ4fa7n+Q==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/common": "^2.71.18" + "@hpcc-js/common": "^2.72.0" } }, "node_modules/@hpcc-js/common": { - "version": "2.71.18", - "resolved": "https://registry.npmjs.org/@hpcc-js/common/-/common-2.71.18.tgz", - "integrity": "sha512-9hsDYXsjB2ltmomAAPQUfNUv/FPrHDkE4e7t62nNH7HCN3ZrkgOgbNjdrfPPHwtcz5+j4kH6hjV0hbhVgocs5Q==", + "version": "2.72.0", + "resolved": "https://registry.npmjs.org/@hpcc-js/common/-/common-2.72.0.tgz", + "integrity": "sha512-5GxU2RmNrB/Bq1gG9Ng+NjojxBLDQhPnDxo5l3PhiMLdBe9HCOsAWSkGg55AQvlOQu4o9RLZ78Gtwkjw5BYiHw==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/util": "^2.51.1", + "@hpcc-js/util": "^2.52.0", "@types/d3-array": "1.2.12", "@types/d3-brush": "1.1.8", "@types/d3-collection": "1.0.13", @@ -2079,9 +2080,10 @@ } }, "node_modules/@hpcc-js/comms": { - "version": "2.94.0", - "resolved": "https://registry.npmjs.org/@hpcc-js/comms/-/comms-2.94.0.tgz", - "integrity": "sha512-+AfJsqj648638hTUeLYd0Thvu1QMHX9zLflrep2xVtz7Wo1OmOiI/mrjClMqK8A8drMa3AduKuQS1R2rL15wZw==", + "version": "2.95.0", + "resolved": "https://registry.npmjs.org/@hpcc-js/comms/-/comms-2.95.0.tgz", + "integrity": "sha512-kzEyDxf1Msus5rhU0yO826JxgIl2kh/bI7yNTxHAlCfLKp4SU//zrj/MK5SuEDs2lUHvmTkfx1jbfGUAK3RGFg==", + "license": "Apache-2.0", "dependencies": { "@hpcc-js/ddl-shim": "^2.21.0", "@hpcc-js/util": "^2.52.0", @@ -2093,14 +2095,6 @@ "undici": "5.28.4" } }, - "node_modules/@hpcc-js/comms/node_modules/@hpcc-js/util": { - "version": "2.52.0", - "resolved": "https://registry.npmjs.org/@hpcc-js/util/-/util-2.52.0.tgz", - "integrity": "sha512-WHm/0ApEdWktpPCUG+AFuMnnrDHOTqKXK2oVgyRUAAQJhSWMFxTJxbqIQG7SM9myK58tXzNJrKsP8huzt8X2dg==", - "dependencies": { - "tslib": "2.6.3" - } - }, "node_modules/@hpcc-js/comms/node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -2120,11 +2114,6 @@ } ] }, - "node_modules/@hpcc-js/comms/node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" - }, "node_modules/@hpcc-js/dataflow": { "version": "8.1.7", "resolved": "https://registry.npmjs.org/@hpcc-js/dataflow/-/dataflow-8.1.7.tgz", @@ -2144,92 +2133,92 @@ } }, "node_modules/@hpcc-js/dgrid": { - "version": "2.32.23", - "resolved": "https://registry.npmjs.org/@hpcc-js/dgrid/-/dgrid-2.32.23.tgz", - "integrity": "sha512-wWMJ+YJNeuW+aXdWjDIEfLfcnfSf2TydsZ6weTbJxFAydvn7dkito2qWwPfXYSlMQ8iZztXng8M/ddJ0P2M7zg==", + "version": "2.33.0", + "resolved": "https://registry.npmjs.org/@hpcc-js/dgrid/-/dgrid-2.33.0.tgz", + "integrity": "sha512-MyTybKnc1a83AsYLb/hpwARa9REfT2UbDEzowhqvcSwASPUwdv7di1Gb3iZkws1yvByinfWOPSprWHqAKEDwmw==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/common": "^2.71.18", - "@hpcc-js/ddl-shim": "^2.20.7", - "@hpcc-js/dgrid-shim": "^2.24.11", - "@hpcc-js/util": "^2.51.1" + "@hpcc-js/common": "^2.72.0", + "@hpcc-js/ddl-shim": "^2.21.0", + "@hpcc-js/dgrid-shim": "^2.25.0", + "@hpcc-js/util": "^2.52.0" } }, "node_modules/@hpcc-js/dgrid-shim": { - "version": "2.24.11", - "resolved": "https://registry.npmjs.org/@hpcc-js/dgrid-shim/-/dgrid-shim-2.24.11.tgz", - "integrity": "sha512-rWKAKrlO0GA5FwktWmVBEw0TxmRQp+x2fw+MHL0ksYjMGMcRgaV4sD4DKH5GlLlMQwrmIsmbWdOgz7mV5dPOtA==", + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/@hpcc-js/dgrid-shim/-/dgrid-shim-2.25.0.tgz", + "integrity": "sha512-QYYivb9NKq33OZ8RBCwcr2AYvNLVWgURPAdxvZznRt1qdIdUCaDRxUi0D1RLi+8eBWQx9EHkTWw5lqERNU1/1w==", "license": "Apache-2.0" }, "node_modules/@hpcc-js/dgrid2": { - "version": "2.3.20", - "resolved": "https://registry.npmjs.org/@hpcc-js/dgrid2/-/dgrid2-2.3.20.tgz", - "integrity": "sha512-+9e0LBFKELADY2UhZ6Pj15EGfoW1OVzMiUli2xprebpTtzrJaFESQ6c+8OfqiSuFGvACxlVABq4GvlB8ohHkKw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@hpcc-js/dgrid2/-/dgrid2-2.4.0.tgz", + "integrity": "sha512-92uYB7Cqh7ZGAWeCtZOClKZJJjOVnFRKDgWuHVCexSZ/o54RUXc5WYWqpSp3gas/6K1zAZVFaJA+Yqh6E4aM6g==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/common": "^2.71.18", - "@hpcc-js/preact-shim": "^2.16.11", - "@hpcc-js/util": "^2.51.1" + "@hpcc-js/common": "^2.72.0", + "@hpcc-js/preact-shim": "^2.17.0", + "@hpcc-js/util": "^2.52.0" } }, "node_modules/@hpcc-js/eclwatch": { - "version": "2.74.8", - "resolved": "https://registry.npmjs.org/@hpcc-js/eclwatch/-/eclwatch-2.74.8.tgz", - "integrity": "sha512-kcszxO1eAKYirVTpgzvUKjn9W6hnOdOOSrC9L+bu8fGf8j62C2D0aFOrNsXg3ZV3BnQRxjZt+1z2K3TwttB+hg==", + "version": "2.75.3", + "resolved": "https://registry.npmjs.org/@hpcc-js/eclwatch/-/eclwatch-2.75.3.tgz", + "integrity": "sha512-PFvk0LFeo+kf679J5oMEr/nwL0B/tSPMqFm8g/ZKQRhxNz6KhfTQMZnUXRqHf+M+ppYetFTkfcJJq0ujvqA+Fw==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/codemirror": "^2.62.1", - "@hpcc-js/common": "^2.71.18", - "@hpcc-js/comms": "^2.93.0", - "@hpcc-js/dgrid": "^2.32.23", - "@hpcc-js/graph": "^2.85.16", - "@hpcc-js/layout": "^2.49.23", - "@hpcc-js/phosphor": "^2.18.9", - "@hpcc-js/timeline": "^2.51.26", - "@hpcc-js/tree": "^2.40.18", - "@hpcc-js/util": "^2.51.1" + "@hpcc-js/codemirror": "^2.63.0", + "@hpcc-js/common": "^2.72.0", + "@hpcc-js/comms": "^2.95.0", + "@hpcc-js/dgrid": "^2.33.0", + "@hpcc-js/graph": "^2.86.0", + "@hpcc-js/layout": "^2.50.1", + "@hpcc-js/phosphor": "^2.19.1", + "@hpcc-js/timeline": "^2.53.0", + "@hpcc-js/tree": "^2.41.0", + "@hpcc-js/util": "^2.52.0" } }, "node_modules/@hpcc-js/graph": { - "version": "2.85.16", - "resolved": "https://registry.npmjs.org/@hpcc-js/graph/-/graph-2.85.16.tgz", - "integrity": "sha512-egJdVtAv8PPGVMj1ZColHYROZvXO/KZq/Y/+1aEuXmS8WIXoJo8fCV2SRHo9LmPUrh57ffT/DYhg3xpvcWw+VQ==", + "version": "2.86.0", + "resolved": "https://registry.npmjs.org/@hpcc-js/graph/-/graph-2.86.0.tgz", + "integrity": "sha512-b8yAULHxhMGTSDbhJg4hzx64WdcF5wEAtDD6AerxS4NhgOWS1GpWnZE8ToQWCckdZFFWyKSV7N10d3xB57cVHg==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/api": "^2.12.18", - "@hpcc-js/common": "^2.71.18", - "@hpcc-js/html": "^2.42.21", - "@hpcc-js/react": "^2.53.17", - "@hpcc-js/util": "^2.51.1" + "@hpcc-js/api": "^2.13.0", + "@hpcc-js/common": "^2.72.0", + "@hpcc-js/html": "^2.43.0", + "@hpcc-js/react": "^2.54.0", + "@hpcc-js/util": "^2.52.0" } }, "node_modules/@hpcc-js/html": { - "version": "2.42.21", - "resolved": "https://registry.npmjs.org/@hpcc-js/html/-/html-2.42.21.tgz", - "integrity": "sha512-acNRDb2jnHzEue1irdGut2zSxaxvOVd3uFPdTCJjJpOpqNqQ2jphGYU2EdOiyO/uApVGmmvONeGLfnWtqeGPig==", + "version": "2.43.0", + "resolved": "https://registry.npmjs.org/@hpcc-js/html/-/html-2.43.0.tgz", + "integrity": "sha512-464r3luThDbp72CPhfcirZyqWC+EDhTBXdS76+bxFK5CEsiTzE6sFpx4hCwLE9JFvjDsu0pS0dbFGIHQkJ1Fmw==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/common": "^2.71.18", - "@hpcc-js/preact-shim": "^2.16.11", - "@hpcc-js/util": "^2.51.1" + "@hpcc-js/common": "^2.72.0", + "@hpcc-js/preact-shim": "^2.17.0", + "@hpcc-js/util": "^2.52.0" } }, "node_modules/@hpcc-js/layout": { - "version": "2.49.23", - "resolved": "https://registry.npmjs.org/@hpcc-js/layout/-/layout-2.49.23.tgz", - "integrity": "sha512-JhKf9UqzRt0H9PlRnghRfAiKPucvbsHwuLzjR3w965VKSMgX2M+bqZDbG0ch45kLq81sNcpmn6UupEq/8E4Wpw==", + "version": "2.50.1", + "resolved": "https://registry.npmjs.org/@hpcc-js/layout/-/layout-2.50.1.tgz", + "integrity": "sha512-0OoLv+kOwuzCqGPUviUDtty4yeaRBZONMIUyV+qZNIZGVPvmrMTqlYV6rj8LSTnX8cylz4aqGUfs6llI0UDq4g==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/api": "^2.12.18", - "@hpcc-js/chart": "^2.83.4", - "@hpcc-js/common": "^2.71.18", - "@hpcc-js/dgrid2": "^2.3.20" + "@hpcc-js/api": "^2.13.0", + "@hpcc-js/chart": "^2.84.1", + "@hpcc-js/common": "^2.72.0", + "@hpcc-js/dgrid2": "^2.4.0" } }, "node_modules/@hpcc-js/leaflet-shim": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/@hpcc-js/leaflet-shim/-/leaflet-shim-2.3.6.tgz", - "integrity": "sha512-7eXs0/8gika93i3hb2oaxXiQJxQuV5tO8tQm7PpzzwyzjGI+t622/msrFR1NnAGnywso8YGGBqnQkqxsS1sE3Q==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@hpcc-js/leaflet-shim/-/leaflet-shim-2.4.0.tgz", + "integrity": "sha512-ue3UmHYA9hKOxDc7XFP63+k5OKU6/da8QHr5ElBX5XHDrYDw+TY7/ZknAyFUTS9fv8Sp1YiecPiTI0+DEdMcbA==", "license": "Apache-2.0", "dependencies": { "@types/leaflet": "1.9.8", @@ -2237,47 +2226,47 @@ } }, "node_modules/@hpcc-js/map": { - "version": "2.77.22", - "resolved": "https://registry.npmjs.org/@hpcc-js/map/-/map-2.77.22.tgz", - "integrity": "sha512-znQ6UioWkkJJkuOPoPndk/OHDmcPSOu07EqQVr+GtEacJqmI6B/z9Ltdl920A/2Mr2SDYLaZAgvvR6wjvlInPw==", + "version": "2.78.1", + "resolved": "https://registry.npmjs.org/@hpcc-js/map/-/map-2.78.1.tgz", + "integrity": "sha512-R/FGKO4p3hfplhja4CeEjrCsZAqucdDvnakS9ec2V9UK9SlODM6o0FbOjA9l54vJ0wjQf6luPNV1/9LGQBUUtQ==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/api": "^2.12.18", - "@hpcc-js/common": "^2.71.18", - "@hpcc-js/graph": "^2.85.16", - "@hpcc-js/layout": "^2.49.23", - "@hpcc-js/leaflet-shim": "^2.3.6", - "@hpcc-js/other": "^2.15.23", - "@hpcc-js/util": "^2.51.1" + "@hpcc-js/api": "^2.13.0", + "@hpcc-js/common": "^2.72.0", + "@hpcc-js/graph": "^2.86.0", + "@hpcc-js/layout": "^2.50.1", + "@hpcc-js/leaflet-shim": "^2.4.0", + "@hpcc-js/other": "^2.16.1", + "@hpcc-js/util": "^2.52.0" } }, "node_modules/@hpcc-js/other": { - "version": "2.15.23", - "resolved": "https://registry.npmjs.org/@hpcc-js/other/-/other-2.15.23.tgz", - "integrity": "sha512-79oV6+lEyKUwxqtMRje2Dh32N6g0Qdcu2+YRUo351A6rU0KWwPTnMl3+u24IfxjVUC6b39PNKoU9c70JjohYOQ==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@hpcc-js/other/-/other-2.16.1.tgz", + "integrity": "sha512-S78frHoqjcIJw+A3GK3g+OoCsQ3N3m9o1d3fZmKoldkbw74hzPbcFgBa9+Y5h9jYfEAFOvwMx1nPQsq7EEFg4g==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/api": "^2.12.18", - "@hpcc-js/common": "^2.71.18", - "@hpcc-js/layout": "^2.49.23" + "@hpcc-js/api": "^2.13.0", + "@hpcc-js/common": "^2.72.0", + "@hpcc-js/layout": "^2.50.1" } }, "node_modules/@hpcc-js/phosphor": { - "version": "2.18.9", - "resolved": "https://registry.npmjs.org/@hpcc-js/phosphor/-/phosphor-2.18.9.tgz", - "integrity": "sha512-xhJMgMvrWVkzmzOEFKPLltf9jV8eEN8cZ3nkcm6GXEQte84RsHLbKHeUfUH2iZZjJeSA/xNTivdp7aDZaC+Xhw==", + "version": "2.19.1", + "resolved": "https://registry.npmjs.org/@hpcc-js/phosphor/-/phosphor-2.19.1.tgz", + "integrity": "sha512-hR6ngzFY6GydqjiCMLgp+stqZZhKaemgzrr1axFi1U+JEzZSz2rY9Gt0rJ7IeLwcj8+hc07jZzsN9/GtZbu6BQ==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/common": "^2.71.18", - "@hpcc-js/other": "^2.15.23", - "@hpcc-js/phosphor-shim": "^2.14.7", - "@hpcc-js/util": "^2.51.1" + "@hpcc-js/common": "^2.72.0", + "@hpcc-js/other": "^2.16.1", + "@hpcc-js/phosphor-shim": "^2.15.0", + "@hpcc-js/util": "^2.52.0" } }, "node_modules/@hpcc-js/phosphor-shim": { - "version": "2.14.7", - "resolved": "https://registry.npmjs.org/@hpcc-js/phosphor-shim/-/phosphor-shim-2.14.7.tgz", - "integrity": "sha512-Xu/kSr1kqs//4yGAkiX08Kq7VaGAPRU2Cbvj47NDMdwEtmzT8qm9npTomKvaK0yYYjcLZNwC5liRb74z1HKdIg==", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/@hpcc-js/phosphor-shim/-/phosphor-shim-2.15.0.tgz", + "integrity": "sha512-WyRhZou8IgP3kwvsZ41VtNUlnuVwtddBp9qd3mY7W59sYerTT1GIIpyRVSs/Jbyy8/piKOogthJPrDptn6k1Zg==", "license": "Apache-2.0", "dependencies": { "@lumino/algorithm": "1.9.2", @@ -2287,52 +2276,52 @@ } }, "node_modules/@hpcc-js/preact-shim": { - "version": "2.16.11", - "resolved": "https://registry.npmjs.org/@hpcc-js/preact-shim/-/preact-shim-2.16.11.tgz", - "integrity": "sha512-pYaRMTpNXEam3qUoCZPoKJvvePVMMhZ9rBbQ6q0z7Ri4Lsq6chXCGTKVrTImafPbNWoMOZVPQE6L8+0Iu1PYzw==", + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/@hpcc-js/preact-shim/-/preact-shim-2.17.0.tgz", + "integrity": "sha512-Thbyu1zycHef+6M/MYT4VE72Sjem3ZZ9jS81T67Ixnd84rHKPMU1na0kBnLfk7jzyiKBnjXOH0Vl2RIXrtesKQ==", "license": "Apache-2.0", "dependencies": { "preact": "10.22.0" } }, "node_modules/@hpcc-js/react": { - "version": "2.53.17", - "resolved": "https://registry.npmjs.org/@hpcc-js/react/-/react-2.53.17.tgz", - "integrity": "sha512-r2K+LqjPQ0VgCUxF+fOOhmCuBHQw2nr+SL4DL9MNrkqUDjFMNWG6YkiLEqb6dx6b/mVvWM1P+IWMrD4zIYLsfA==", + "version": "2.54.0", + "resolved": "https://registry.npmjs.org/@hpcc-js/react/-/react-2.54.0.tgz", + "integrity": "sha512-ciWvp77WyiXZeg+uA5L+a7S8X8nglrdHLj7D+lSiz7n3ApRhGxNvuFpU3pE9AWmkDp5O5r+0Oxd0IO1cipvoew==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/common": "^2.71.18", - "@hpcc-js/preact-shim": "^2.16.11" + "@hpcc-js/common": "^2.72.0", + "@hpcc-js/preact-shim": "^2.17.0" } }, "node_modules/@hpcc-js/timeline": { - "version": "2.51.26", - "resolved": "https://registry.npmjs.org/@hpcc-js/timeline/-/timeline-2.51.26.tgz", - "integrity": "sha512-CS73qPo7dVru/0M00IzJnL2YDxlhYMq7VNWDzBpNjLxRhUvvmKAUS4O7/dkuskBpT5SrpPcQc6gkOKvY4qjJbQ==", + "version": "2.53.0", + "resolved": "https://registry.npmjs.org/@hpcc-js/timeline/-/timeline-2.53.0.tgz", + "integrity": "sha512-HgZiPLLaDcQexEH9XPpvJzF1103+CeomwJ9sRulyO3hjctw3yDVHKblIkdQbxBcXvjCNIWCiHcs53tJ3yBcrXw==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/api": "^2.12.18", - "@hpcc-js/chart": "^2.83.4", - "@hpcc-js/common": "^2.71.18", - "@hpcc-js/html": "^2.42.21", - "@hpcc-js/layout": "^2.49.23", - "@hpcc-js/react": "^2.53.17" + "@hpcc-js/api": "^2.13.0", + "@hpcc-js/chart": "^2.84.1", + "@hpcc-js/common": "^2.72.0", + "@hpcc-js/html": "^2.43.0", + "@hpcc-js/layout": "^2.50.1", + "@hpcc-js/react": "^2.54.0" } }, "node_modules/@hpcc-js/tree": { - "version": "2.40.18", - "resolved": "https://registry.npmjs.org/@hpcc-js/tree/-/tree-2.40.18.tgz", - "integrity": "sha512-SWXgKs1JCSL1S1Xx0zBrbUd35fcDxhum573w4JiZzV5S8L0M7zhNTWvPn7joW5Q8Ox3jn1Hk/IQzcyBtVDyp0Q==", + "version": "2.41.0", + "resolved": "https://registry.npmjs.org/@hpcc-js/tree/-/tree-2.41.0.tgz", + "integrity": "sha512-IairckImHOibB1LlnzvpCpfUk6VWTk82aLaG2sDK9M53qWAJPjxb2ftxND1nzeDvWZz4VxpR7F14tgJlRzaEqw==", "license": "Apache-2.0", "dependencies": { - "@hpcc-js/api": "^2.12.18", - "@hpcc-js/common": "^2.71.18" + "@hpcc-js/api": "^2.13.0", + "@hpcc-js/common": "^2.72.0" } }, "node_modules/@hpcc-js/util": { - "version": "2.51.1", - "resolved": "https://registry.npmjs.org/@hpcc-js/util/-/util-2.51.1.tgz", - "integrity": "sha512-BJuqg6FGqcV4RR8/BU5e7fASDtkl0Na7dWY+Th7r5ciWKI5AXsO0GtlgwDBt2uLUOlcGOMpYozmdbGSCoSHAvQ==", + "version": "2.52.0", + "resolved": "https://registry.npmjs.org/@hpcc-js/util/-/util-2.52.0.tgz", + "integrity": "sha512-WHm/0ApEdWktpPCUG+AFuMnnrDHOTqKXK2oVgyRUAAQJhSWMFxTJxbqIQG7SM9myK58tXzNJrKsP8huzt8X2dg==", "license": "Apache-2.0", "dependencies": { "tslib": "2.6.3" @@ -2345,9 +2334,9 @@ "license": "0BSD" }, "node_modules/@hpcc-js/wasm": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/@hpcc-js/wasm/-/wasm-2.18.0.tgz", - "integrity": "sha512-M9XVIvAXGH4Xcyb5UoiohWcn6fil89pcos/gClNdBZG2v+W48xSf2bjcA8BW131X/AFHUerVY28n1P1Jw81/9A==", + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/@hpcc-js/wasm/-/wasm-2.18.1.tgz", + "integrity": "sha512-fT8NCOTaF0NDnT+ZwWpV2VQ6ywFEqw+fG87GSPNQemEmg7FFqUaKRQOW9MBICrkZcXaJBb7VHo1t5UF6bi/JgQ==", "license": "Apache-2.0", "dependencies": { "yargs": "17.7.2" diff --git a/esp/src/package.json b/esp/src/package.json index a30728c2cf2..c1ec1651488 100644 --- a/esp/src/package.json +++ b/esp/src/package.json @@ -41,22 +41,23 @@ "@fluentui/react-hooks": "8.8.10", "@fluentui/react-icons-mdl2": "1.3.72", "@fluentui/react-migration-v8-v9": "9.6.22", - "@hpcc-js/chart": "2.83.4", - "@hpcc-js/codemirror": "2.62.1", - "@hpcc-js/common": "2.71.18", - "@hpcc-js/comms": "2.94.0", + "@hpcc-js/chart": "2.84.1", + "@hpcc-js/codemirror": "2.63.0", + "@hpcc-js/common": "2.72.0", + "@hpcc-js/comms": "2.95.0", "@hpcc-js/dataflow": "8.1.7", - "@hpcc-js/eclwatch": "2.74.8", - "@hpcc-js/graph": "2.85.16", - "@hpcc-js/html": "2.42.21", - "@hpcc-js/layout": "2.49.23", - "@hpcc-js/map": "2.77.22", - "@hpcc-js/other": "2.15.23", - "@hpcc-js/phosphor": "2.18.9", - "@hpcc-js/react": "2.53.17", - "@hpcc-js/tree": "2.40.18", - "@hpcc-js/util": "2.51.1", - "@hpcc-js/wasm": "2.18.0", + "@hpcc-js/eclwatch": "2.75.3", + "@hpcc-js/graph": "2.86.0", + "@hpcc-js/html": "2.43.0", + "@hpcc-js/layout": "2.50.1", + "@hpcc-js/map": "2.78.1", + "@hpcc-js/other": "2.16.1", + "@hpcc-js/phosphor": "2.19.1", + "@hpcc-js/react": "2.54.0", + "@hpcc-js/timeline": "2.53.0", + "@hpcc-js/tree": "2.41.0", + "@hpcc-js/util": "2.52.0", + "@hpcc-js/wasm": "2.18.1", "@kubernetes/client-node": "0.20.0", "clipboard": "2.0.11", "d3-dsv": "3.0.1", diff --git a/esp/src/src-react/components/Metrics.tsx b/esp/src/src-react/components/Metrics.tsx index 798d7843a79..f0df3a94f6a 100644 --- a/esp/src/src-react/components/Metrics.tsx +++ b/esp/src/src-react/components/Metrics.tsx @@ -7,7 +7,7 @@ import { bundleIcon, Folder20Filled, Folder20Regular, FolderOpen20Filled, Folder import { Database } from "@hpcc-js/common"; import { WorkunitsServiceEx, IScope, splitMetric } from "@hpcc-js/comms"; import { CellFormatter, ColumnFormat, ColumnType, DBStore, RowType, Table } from "@hpcc-js/dgrid"; -import { compare, scopedLogger } from "@hpcc-js/util"; +import { scopedLogger } from "@hpcc-js/util"; import nlsHPCC from "src/nlsHPCC"; import { WUTimelineNoFetch } from "src/Timings"; import * as Utility from "src/Utility"; @@ -89,7 +89,7 @@ class TableEx extends Table { } _rawDataMap: { [id: number]: string } = {}; - metrics(metrics: any[], options: MetricsOptionsT, timelineFilter: string, scopeFilter: string, matchCase: boolean): this { + metrics(metrics: any[], options: MetricsOptionsT, scopeFilter: string, matchCase: boolean): this { this .columns(["##"]) // Reset hash to force recalculation of default widths .columns(["##", nlsHPCC.Type, "StdDevs", nlsHPCC.Scope, ...options.properties, "__StdDevs"]) @@ -106,8 +106,7 @@ class TableEx extends Table { .data(metrics .filter(m => this.scopeFilterFunc(m, scopeFilter, matchCase)) .filter(row => { - return (timelineFilter === "" || row.name?.indexOf(timelineFilter) === 0) && - (options.scopeTypes.indexOf(row.type) >= 0); + return options.scopeTypes.indexOf(row.type) >= 0; }).map((row, idx) => { if (idx === 0) { this._rawDataMap = { @@ -175,7 +174,6 @@ export const Metrics: React.FunctionComponent = ({ selection }) => { const [_uiState, _setUIState] = React.useState({ ...defaultUIState }); - const [timelineFilter, setTimelineFilter] = React.useState(""); const [selectedMetricsSource, setSelectedMetricsSource] = React.useState(""); const [selectedMetrics, setSelectedMetrics] = React.useState([]); const [selectedMetricsPtr, setSelectedMetricsPtr] = React.useState(-1); @@ -227,13 +225,15 @@ export const Metrics: React.FunctionComponent = ({ .maxZoom(Number.MAX_SAFE_INTEGER) ); + const [scopeFilter, setScopeFilter] = React.useState(""); React.useEffect(() => { timeline .on("click", (row, col, sel) => { - setTimelineFilter(sel ? row[7].__hpcc_id : ""); if (sel) { + timeline.selection([]); setSelectedMetricsSource("scopesTable"); - pushUrl(`${parentUrl}/${row[7].Id}`); + setScopeFilter(`name:${row[7].__hpcc_id}`); + pushUrl(`${parentUrl}/${row[7].id}`); } }, true) ; @@ -247,7 +247,6 @@ export const Metrics: React.FunctionComponent = ({ }, [metrics, timeline]); // Scopes Table --- - const [scopeFilter, setScopeFilter] = React.useState(""); const onChangeScopeFilter = React.useCallback((event: React.FormEvent, newValue?: string) => { setScopeFilter(newValue || ""); }, []); @@ -259,7 +258,7 @@ export const Metrics: React.FunctionComponent = ({ const scopesTable = useConst(() => new TableEx() .multiSelect(true) - .metrics([], options, timelineFilter, scopeFilter, matchCase) + .metrics([], options, scopeFilter, matchCase) .sortable(true) ); @@ -274,24 +273,22 @@ export const Metrics: React.FunctionComponent = ({ }, [scopesSelectionChanged, scopesTable]); React.useEffect(() => { - if (!scopeFilter || scopeFilter.indexOf("name:") === 0) { - setScopeFilter(timelineFilter ? `name:${timelineFilter}` : ""); - } scopesTable - .metrics(metrics, options, timelineFilter, scopeFilter, matchCase) + .metrics(metrics, options, scopeFilter, matchCase) .lazyRender() ; - }, [matchCase, metrics, options, scopeFilter, scopesTable, timelineFilter]); + }, [matchCase, metrics, options, scopeFilter, scopesTable]); const updateScopesTable = React.useCallback((selection: IScope[]) => { if (scopesTable?.renderCount() > 0) { - const prevSelection = scopesTable.selection().map(row => row.__lparam.id); - const newSelection = selection.map(row => row.id); - const diffs = compare(prevSelection, newSelection); - if (diffs.enter.length || diffs.exit.length) { - scopesTable.selection(scopesTable.data().filter(row => { + scopesTable.selection([]); + if (selection.length) { + const selRows = scopesTable.data().filter(row => { return selection.indexOf(row[row.length - 1]) >= 0; - })); + }); + scopesTable.render(() => { + scopesTable.selection(selRows); + }); } } }, [scopesTable]); @@ -508,7 +505,7 @@ export const Metrics: React.FunctionComponent = ({ } } setIsLayoutComplete(true); - }); + }).catch(err => logger.error(err)); } return () => { cancelled = true; @@ -622,13 +619,13 @@ export const Metrics: React.FunctionComponent = ({ const setShowMetricOptionsHook = React.useCallback((show: boolean) => { setShowMetricOptions(show); scopesTable - .metrics(metrics, options, timelineFilter, scopeFilter, matchCase) + .metrics(metrics, options, scopeFilter, matchCase) .render(() => { updateScopesTable(selectedMetrics); }) ; - }, [matchCase, metrics, options, scopeFilter, scopesTable, selectedMetrics, timelineFilter, updateScopesTable]); + }, [matchCase, metrics, options, scopeFilter, scopesTable, selectedMetrics, updateScopesTable]); return From f4aae261ec70b7138a9e709900ea38674d505b12 Mon Sep 17 00:00:00 2001 From: Gordon Smith Date: Fri, 2 Aug 2024 16:32:52 +0100 Subject: [PATCH 2/3] HPCC-32406 Add ECL Watch "reset settings" option Signed-off-by: Gordon Smith --- esp/src/src-react/components/Frame.tsx | 11 ++- esp/src/src-react/components/Reset.tsx | 87 ++++++++++++++++++++++ esp/src/src-react/components/Title.tsx | 6 ++ esp/src/src-react/components/Workunits.tsx | 10 ++- esp/src/src-react/hooks/favorite.ts | 5 ++ esp/src/src-react/hooks/metrics.ts | 12 ++- esp/src/src-react/hooks/store.ts | 6 +- esp/src/src-react/hooks/theme.ts | 10 ++- esp/src/src-react/routes.tsx | 7 +- esp/src/src-react/util/history.ts | 5 ++ esp/src/src/KeyValStore.ts | 7 ++ esp/src/src/Session.ts | 9 +++ esp/src/src/nls/hpcc.ts | 11 +++ 13 files changed, 176 insertions(+), 10 deletions(-) create mode 100644 esp/src/src-react/components/Reset.tsx diff --git a/esp/src/src-react/components/Frame.tsx b/esp/src/src-react/components/Frame.tsx index ad77d0b45c1..b2c36a65966 100644 --- a/esp/src/src-react/components/Frame.tsx +++ b/esp/src/src-react/components/Frame.tsx @@ -20,6 +20,13 @@ import { useUserSession } from "../hooks/user"; const logger = scopedLogger("../components/Frame.tsx"); const envLogger = scopedLogger("environment"); +const USER_COOKIE_CONSENT = "user_cookie_consent"; + +export function resetCookieConsent() { + const store = userKeyValStore(); + return store.delete(USER_COOKIE_CONSENT); +} + interface FrameProps { } @@ -111,8 +118,10 @@ export const Frame: React.FunctionComponent = () => { />} /> { - userKeyValStore().set("user_cookie_consent", n ? "1" : "0"); + userKeyValStore().set(USER_COOKIE_CONSENT, n ? "1" : "0"); }} /> ; }; + + diff --git a/esp/src/src-react/components/Reset.tsx b/esp/src/src-react/components/Reset.tsx new file mode 100644 index 00000000000..5954d6fe990 --- /dev/null +++ b/esp/src/src-react/components/Reset.tsx @@ -0,0 +1,87 @@ +import * as React from "react"; +import { PrimaryButton, DefaultButton, mergeStyleSets, Checkbox, Stack } from "@fluentui/react"; +import { resetCookies, resetModernMode } from "src/Session"; +import nlsHPCC from "src/nlsHPCC"; +import { pushUrl, replaceUrl } from "../util/history"; +import { resetMetricsViews } from "../hooks/metrics"; +import { resetHistory } from "../util/history"; +import { MessageBox } from "../layouts/MessageBox"; +import { resetTheme, useUserTheme } from "../hooks/theme"; +import { resetFavorites } from "../hooks/favorite"; +import { resetCookieConsent } from "./Frame"; +import { resetWorkunitOptions } from "./Workunits"; + +export interface ResetDialogProps { +} + +export const ResetDialog: React.FunctionComponent = ({ +}) => { + + const [show, setShow] = React.useState(true); + const [checkMetricOptions, setCheckMetricOptions] = React.useState(true); + const [checkWorkunitOptions, setCheckWorkunitOptions] = React.useState(true); + const [checkHistory, setCheckHistoryCheckbox] = React.useState(true); + const [checkFavorites, setCheckFavorites] = React.useState(true); + const [checkEclWatchVersion, setCheckEclWatchVersion] = React.useState(true); + const [checkTheme, setCheckTheme] = React.useState(true); + const [checkCookies, setCheckCookies] = React.useState(false); + const { theme } = useUserTheme(); + + const styles = React.useMemo(() => mergeStyleSets({ + root: { + height: "100%", + backgroundColor: theme.semanticColors.bodyBackground + }, + }), [theme.semanticColors.bodyBackground]); + + return
+ + { + if (checkMetricOptions) { + await resetMetricsViews(); + } + if (checkWorkunitOptions) { + await resetWorkunitOptions(); + } + if (checkHistory) { + await resetHistory(); + } + if (checkFavorites) { + await resetFavorites(); + } + if (checkHistory) { + await resetHistory(); + } + if (checkEclWatchVersion) { + await resetModernMode(); + } + if (checkTheme) { + await resetTheme(); + } + if (checkCookies) { + await resetCookies(); + await resetCookieConsent(); + } + setShow(false); + replaceUrl("/"); + window.location.reload(); + }} /> + { + setShow(false); + pushUrl("/"); + }} /> + + }> + + setCheckMetricOptions(checked)} /> + setCheckWorkunitOptions(checked)} /> + setCheckHistoryCheckbox(checked)} /> + setCheckFavorites(checked)} /> + setCheckEclWatchVersion(checked)} /> + setCheckTheme(checked)} /> + setCheckCookies(checked)} /> + + +
; +}; diff --git a/esp/src/src-react/components/Title.tsx b/esp/src/src-react/components/Title.tsx index 5257ba34747..e4910f7ec42 100644 --- a/esp/src/src-react/components/Title.tsx +++ b/esp/src/src-react/components/Title.tsx @@ -182,6 +182,12 @@ export const DevTitle: React.FunctionComponent = ({ isChecked: true, onClick: onTechPreviewClick }, + { key: "divider_4", itemType: ContextualMenuItemType.Divider }, + { + key: "reset", + href: "/esp/files/index.html#/reset", + text: nlsHPCC.ResetUserSettings + }, { key: "about", text: nlsHPCC.About, onClick: () => setShowAbout(true) } ], directionalHintFixed: true diff --git a/esp/src/src-react/components/Workunits.tsx b/esp/src/src-react/components/Workunits.tsx index b4ff6a3a291..0fce3d69f16 100644 --- a/esp/src/src-react/components/Workunits.tsx +++ b/esp/src/src-react/components/Workunits.tsx @@ -5,6 +5,7 @@ import { SizeMe } from "react-sizeme"; import { CreateWUQueryStore, defaultSort, emptyFilter, Get, WUQueryStore, formatQuery } from "src/ESPWorkunit"; import * as WsWorkunits from "src/WsWorkunits"; import { formatCost } from "src/Session"; +import { userKeyValStore } from "src/KeyValStore"; import nlsHPCC from "src/nlsHPCC"; import { useConfirm } from "../hooks/confirm"; import { useMyAccount } from "../hooks/user"; @@ -45,6 +46,13 @@ const defaultUIState = { hasNotCompleted: false }; +const WORKUNITS_SHOWTIMELINE = "workunits_showTimeline"; + +export function resetWorkunitOptions() { + const store = userKeyValStore(); + return store?.delete(WORKUNITS_SHOWTIMELINE); +} + interface WorkunitsProps { filter?: { [id: string]: any }; sort?: QuerySortItem; @@ -64,7 +72,7 @@ export const Workunits: React.FunctionComponent = ({ const [showFilter, setShowFilter] = React.useState(false); const { currentUser } = useMyAccount(); const [uiState, setUIState] = React.useState({ ...defaultUIState }); - const [showTimeline, setShowTimeline] = useUserStore("workunits_showTimeline", true); + const [showTimeline, setShowTimeline] = useUserStore(WORKUNITS_SHOWTIMELINE, true); const { selection, setSelection, pageNum, setPageNum, diff --git a/esp/src/src-react/hooks/favorite.ts b/esp/src/src-react/hooks/favorite.ts index 183d547c3ca..114282fee9d 100644 --- a/esp/src/src-react/hooks/favorite.ts +++ b/esp/src/src-react/hooks/favorite.ts @@ -7,6 +7,11 @@ import { hashHistory } from "../util/history"; const STORE_FAVORITES_ID = "favorites"; const STORE_CACHE_TIMEOUT = 10000; +export function resetFavorites() { + const store = userKeyValStore(); + return store?.delete(STORE_FAVORITES_ID); +} + interface Payload { // TODO: Will be used for labels and extra info... } diff --git a/esp/src/src-react/hooks/metrics.ts b/esp/src/src-react/hooks/metrics.ts index 24d4a5341e4..72f78b279f1 100644 --- a/esp/src/src-react/hooks/metrics.ts +++ b/esp/src/src-react/hooks/metrics.ts @@ -9,7 +9,13 @@ import { useCounter } from "./util"; const logger = scopedLogger("src-react/hooks/metrics.ts"); -const MetricOptionsVersion = 2; +const METRIC_OPTIONS_VERSION = 2; +const METRIC_OPTIONS_KEY = `MetricOptions-${METRIC_OPTIONS_VERSION}`; + +export function resetMetricsViews() { + const store = userKeyValStore(); + return store?.delete(METRIC_OPTIONS_KEY); +} export interface MetricsOptions { scopeTypes: string[]; @@ -58,7 +64,7 @@ export function useMetricsOptions(): [MetricsOptions, (opts: MetricsOptions) => const save = React.useCallback(() => { if (checkLayout(options)) { - store?.set(`MetricOptions-${MetricOptionsVersion}`, JSON.stringify(options), true); + store?.set(METRIC_OPTIONS_KEY, JSON.stringify(options), true); } }, [store]); @@ -66,7 +72,7 @@ export function useMetricsOptions(): [MetricsOptions, (opts: MetricsOptions) => if (toDefaults) { setOptions({ ...defaults }); } else { - store?.get(`MetricOptions-${MetricOptionsVersion}`).then(opts => { + store?.get(METRIC_OPTIONS_KEY).then(opts => { const options = JSON.parse(opts); checkLayout(options); setOptions({ ...defaults, ...options }); diff --git a/esp/src/src-react/hooks/store.ts b/esp/src/src-react/hooks/store.ts index 95f48517129..58af4736634 100644 --- a/esp/src/src-react/hooks/store.ts +++ b/esp/src/src-react/hooks/store.ts @@ -38,7 +38,7 @@ function fromString(value: string, defaultValue: T): T { } } -function useStore(store: IKeyValStore, key: string, defaultValue: T, monitor: boolean = false): [value: T, setValue: (value: T) => void, reset: () => void] { +function useStore(store: IKeyValStore, key: string, defaultValue: T, monitor: boolean = false): [value: T, setValue: (value: T) => Promise, reset: () => Promise] { const [value, setValue] = React.useState(); @@ -66,13 +66,13 @@ function useStore(store: IKeyValStore, key: string, defaultValue: T, monitor: }, [defaultValue, key, monitor, store]); const extSetValue = React.useCallback((value: T) => { - store.set(key, toString(value, defaultValue), monitor).then(() => { + return store.set(key, toString(value, defaultValue), monitor).then(() => { setValue(value); }); }, [defaultValue, key, monitor, store]); const reset = React.useCallback(() => { - store.delete(key, monitor).then(() => { + return store.delete(key, monitor).then(() => { setValue(defaultValue); }); }, [defaultValue, key, monitor, store]); diff --git a/esp/src/src-react/hooks/theme.ts b/esp/src/src-react/hooks/theme.ts index e1f909a456a..85b50d163da 100644 --- a/esp/src/src-react/hooks/theme.ts +++ b/esp/src/src-react/hooks/theme.ts @@ -1,11 +1,19 @@ import { Theme } from "@fluentui/react"; import { Theme as ThemeV9 } from "@fluentui/react-components"; +import { userKeyValStore } from "src/KeyValStore"; import { darkTheme, lightTheme, darkThemeV9, lightThemeV9 } from "../themes"; import { useUserStore } from "./store"; +const THEME = "theme"; + +export function resetTheme() { + const store = userKeyValStore(); + return store?.delete(THEME); +} + export function useUserTheme(): { theme: Theme, themeV9: ThemeV9, setTheme: (value: "light" | "dark") => void, isDark: boolean } { - const [theme, setTheme] = useUserStore("theme", "light", true); + const [theme, setTheme] = useUserStore(THEME, "light", true); return { theme: theme === "dark" ? darkTheme : lightTheme, diff --git a/esp/src/src-react/routes.tsx b/esp/src/src-react/routes.tsx index 666ef71e6b0..39b52b822bc 100644 --- a/esp/src/src-react/routes.tsx +++ b/esp/src/src-react/routes.tsx @@ -45,12 +45,17 @@ export const routes: RoutesEx = [ path: "/login", action: (ctx) => import("./components/forms/Login").then(_ => <_.Login />) }, + { + mainNav: [], + name: "reset", + path: "/reset", + action: (ctx) => import("./components/Reset").then(_ => <_.ResetDialog />) + }, // Main --- { mainNav: ["activities"], path: "", action: (context) => pushUrl("/activities") - }, { mainNav: ["activities"], diff --git a/esp/src/src-react/util/history.ts b/esp/src/src-react/util/history.ts index 5fe0bc2c1aa..d4420fc4d7e 100644 --- a/esp/src/src-react/util/history.ts +++ b/esp/src/src-react/util/history.ts @@ -92,6 +92,11 @@ const globalHistory = globalThis.history; const STORE_HISTORY_ID = "history"; +export function resetHistory() { + const store = userKeyValStore(); + return store?.delete(STORE_HISTORY_ID); +} + class History { location: HistoryLocation = { diff --git a/esp/src/src/KeyValStore.ts b/esp/src/src/KeyValStore.ts index 6dbb01ef0cf..ede424f2561 100644 --- a/esp/src/src/KeyValStore.ts +++ b/esp/src/src/KeyValStore.ts @@ -250,6 +250,13 @@ class CookieStorage implements IKeyValStore { }); } + async deleteAll(broadcast?: boolean): Promise { + const cookies = Utility.parseCookies(); + for (const cookie in cookies) { + await this.delete(cookie, broadcast); + } + } + monitor(callback: (messages: ValueChangedMessage[]) => void): IObserverHandle { return this._dispatch.attach(callback); } diff --git a/esp/src/src/Session.ts b/esp/src/src/Session.ts index f7a43044e3d..10c6fe5e186 100644 --- a/esp/src/src/Session.ts +++ b/esp/src/src/Session.ts @@ -35,6 +35,15 @@ export async function fetchModernMode(): Promise { }); } +export async function resetModernMode() { + await sessionStore.delete(ModernMode); + await userStore.delete(ModernMode); +} + +export async function resetCookies() { + await cookieStore.deleteAll(true); +} + const isV5DirectURL = () => !!parseSearch(window.location.search)?.["Widget"]; const isV9DirectURL = () => window.location.hash && window.location.hash.indexOf("#/stub/") !== 0; diff --git a/esp/src/src/nls/hpcc.ts b/esp/src/src/nls/hpcc.ts index a46da16dfbe..300feb3aaec 100644 --- a/esp/src/src/nls/hpcc.ts +++ b/esp/src/src/nls/hpcc.ts @@ -147,6 +147,7 @@ export = { Content: "Content", Contents: "Contents", ContentType: "Content Type", + Cookies: "Cookies", CookiesNoticeLinkText: "Our Cookie Notice", CookiesAcceptButtonText: "Allow Cookies", Copy: "Copy", @@ -195,6 +196,7 @@ export = { Deactivate: "Deactivate", Debug: "Debug", DEF: "DEF", + Default: "Default", Defaults: "Defaults", Definition: "Definition", DefinitionID: "Definition ID", @@ -267,6 +269,7 @@ export = { ECL: "ECL", ECLWatchRequiresCookies: "ECL Watch requires cookies enabled to continue.", ECLWatchSessionManagement: "ECL Watch session management", + ECLWatchVersion: "ECL Watch Version", ECLWorkunit: "ECL Workunit", EdgeLabel: "Edge Label", Edges: "Edges", @@ -313,6 +316,7 @@ export = { ExcludeIndexes: "Exclude Indexes", ExpireDays: "Expire in (days)", ExpirationDate: "Expiration Date", + FactoryReset: "Factory Reset", FailIfNoSourceFile: "Fail If No Source File", Fatal: "Fatal", Favorites: "Favorites", @@ -548,6 +552,7 @@ export = { Message: "Message", Methods: "Methods", Metrics: "Metrics", + MetricOptions: "Metric Options", MetricsGraph: "Metrics/Graph", MetricsSQL: "Metrics (SQL)", Min: "Min", @@ -796,6 +801,7 @@ export = { RequiredForXML: "Required for spraying XML", Reschedule: "Reschedule", Reset: "Reset", + ResetUserSettings: "Reset User Settings", ResetThisQuery: "Reset This Query?", ResetViewToSelection: "Reset View to Selection", Resource: "Resource", @@ -826,7 +832,10 @@ export = { SampleRequest: "Sample Request", SampleResponse: "Sample Response", Save: "Save", + SaveAs: "Save As", Scope: "Scope", + ScopeColumns: "Scope Columns", + ScopeTypes: "Scope Types", SearchResults: "Search Results", Seconds: "Seconds", SecondsRemaining: "Seconds Remaining", @@ -943,6 +952,7 @@ export = { TechPreview: "Tech Preview", Terminators: "Terminators", TestPages: "Test Pages", + Theme: "Theme", TheReturnedResults: "The returned results", ThorNetworkAddress: "Thor Network Address", ThorMasterAddress: "Thor Master Address", @@ -1123,6 +1133,7 @@ export = { Workflows: "Workflows", Workunit: "Workunit", WorkunitNotFound: "Workunit not found", + WorkunitOptions: "Workunit Options", Workunits: "Workunits", WorkUnitScopeDefaultPermissions: "Workunit Scope Default Permissions", Wrap: "Wrap", From b0dccf417bbc757afa7e05b4ee3b2ec74d651716 Mon Sep 17 00:00:00 2001 From: Gordon Smith Date: Thu, 18 Jul 2024 18:44:12 +0100 Subject: [PATCH 3/3] WIP WIP WIP WIP WIP WIP WIP _selectionHandler WIP WIP HPCC-32279 Timeline selection issues Url contains "undefined" for selection Restoring selection in scopesTable fails on pushUrl Disable timeline toggle, make click only Signed-off-by: Gordon Smith --- esp/src/package-lock.json | 33 +- esp/src/package.json | 1 + esp/src/src-react/components/ECLArchive.tsx | 2 +- esp/src/src-react/components/Frame.tsx | 4 +- esp/src/src-react/components/Metrics.tsx | 86 +++-- .../src-react/components/MetricsOptions.tsx | 337 +++++++++++++----- esp/src/src-react/components/SourceEditor.tsx | 4 +- .../src-react/components/controls/Grid.tsx | 59 ++- esp/src/src-react/hooks/metrics.ts | 213 ++++++++--- esp/src/src-react/layouts/DockPanel.tsx | 45 ++- esp/src/src-react/util/metricGraph.ts | 14 +- 11 files changed, 581 insertions(+), 217 deletions(-) diff --git a/esp/src/package-lock.json b/esp/src/package-lock.json index f31d2188ec8..74033cbe976 100644 --- a/esp/src/package-lock.json +++ b/esp/src/package-lock.json @@ -51,6 +51,7 @@ "react-hook-form": "7.51.2", "react-hot-toast": "2.4.1", "react-reflex": "4.2.6", + "react-singleton-hook": "3.4.0", "react-sizeme": "3.0.2", "universal-router": "9.2.0", "xstyle": "0.3.3" @@ -89,12 +90,13 @@ "dev": true }, "node_modules/@75lb/deep-merge": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@75lb/deep-merge/-/deep-merge-1.1.1.tgz", - "integrity": "sha512-xvgv6pkMGBA6GwdyJbNAnDmfAIR/DfWhrj9jgWh3TY7gRm3KO46x/GPjRg6wJ0nOepwqrNxFfojebh0Df4h4Tw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@75lb/deep-merge/-/deep-merge-1.1.2.tgz", + "integrity": "sha512-08K9ou5VNbheZFxM5tDWoqjA3ImC50DiuuJ2tj1yEPRfkp8lLLg6XAaJ4On+a0yAXor/8ay5gHnAIshRM44Kpw==", "dev": true, + "license": "MIT", "dependencies": { - "lodash.assignwith": "^4.2.0", + "lodash": "^4.17.21", "typical": "^7.1.1" }, "engines": { @@ -8065,12 +8067,6 @@ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" }, - "node_modules/lodash.assignwith": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assignwith/-/lodash.assignwith-4.2.0.tgz", - "integrity": "sha512-ZznplvbvtjK2gMvnQ1BR/zqPFZmS6jbK4p+6Up4xcRYA7yMIwxHCfbTcrYxXKzzqLsQ05eJPVznEW3tuwV7k1g==", - "dev": true - }, "node_modules/lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -9782,6 +9778,23 @@ "react-dom": ">0.13.0" } }, + "node_modules/react-singleton-hook": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/react-singleton-hook/-/react-singleton-hook-3.4.0.tgz", + "integrity": "sha512-eQEpyacGAaRejmWUizUdNNQFn5AO0iaKRSl1jxgC0FQadVY/I1WFuPrYiutglPzO9s8yEbIh95UXVJQel4d7HQ==", + "license": "MIT", + "peerDependencies": { + "react": "15 - 18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/react-sizeme": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/react-sizeme/-/react-sizeme-3.0.2.tgz", diff --git a/esp/src/package.json b/esp/src/package.json index c1ec1651488..5948eedd174 100644 --- a/esp/src/package.json +++ b/esp/src/package.json @@ -77,6 +77,7 @@ "react-hook-form": "7.51.2", "react-hot-toast": "2.4.1", "react-reflex": "4.2.6", + "react-singleton-hook": "3.4.0", "react-sizeme": "3.0.2", "universal-router": "9.2.0", "xstyle": "0.3.3" diff --git a/esp/src/src-react/components/ECLArchive.tsx b/esp/src/src-react/components/ECLArchive.tsx index 8d63d3ae8f5..a84ceaae3ac 100644 --- a/esp/src/src-react/components/ECLArchive.tsx +++ b/esp/src/src-react/components/ECLArchive.tsx @@ -111,7 +111,7 @@ export const ECLArchive: React.FunctionComponent = ({ return } main={ - + { // Only render after archive is loaded (to ensure it "defaults to open") --- archive?.modAttrs.length && diff --git a/esp/src/src-react/components/Frame.tsx b/esp/src/src-react/components/Frame.tsx index b2c36a65966..d48473f5eca 100644 --- a/esp/src/src-react/components/Frame.tsx +++ b/esp/src/src-react/components/Frame.tsx @@ -27,6 +27,8 @@ export function resetCookieConsent() { return store.delete(USER_COOKIE_CONSENT); } +const USER_COOKIE_CONSENT = "user_cookie_consent"; + interface FrameProps { } @@ -123,5 +125,3 @@ export const Frame: React.FunctionComponent = () => { ; }; - - diff --git a/esp/src/src-react/components/Metrics.tsx b/esp/src/src-react/components/Metrics.tsx index f0df3a94f6a..b1687415a1c 100644 --- a/esp/src/src-react/components/Metrics.tsx +++ b/esp/src/src-react/components/Metrics.tsx @@ -11,7 +11,7 @@ import { scopedLogger } from "@hpcc-js/util"; import nlsHPCC from "src/nlsHPCC"; import { WUTimelineNoFetch } from "src/Timings"; import * as Utility from "src/Utility"; -import { FetchStatus, useMetricsOptions, useWUQueryMetrics, MetricsOptions as MetricsOptionsT } from "../hooks/metrics"; +import { FetchStatus, useMetricsViews, useWUQueryMetrics } from "../hooks/metrics"; import { HolyGrail } from "../layouts/HolyGrail"; import { AutosizeComponent, AutosizeHpccJSComponent } from "../layouts/HpccJSAdapter"; import { DockPanel, DockPanelItem, ResetableDockPanel } from "../layouts/DockPanel"; @@ -89,10 +89,10 @@ class TableEx extends Table { } _rawDataMap: { [id: number]: string } = {}; - metrics(metrics: any[], options: MetricsOptionsT, scopeFilter: string, matchCase: boolean): this { + metrics(metrics: any[], scopeTypes: string[], properties: string[], scopeFilter: string, matchCase: boolean): this { this .columns(["##"]) // Reset hash to force recalculation of default widths - .columns(["##", nlsHPCC.Type, "StdDevs", nlsHPCC.Scope, ...options.properties, "__StdDevs"]) + .columns(["##", nlsHPCC.Type, "StdDevs", nlsHPCC.Scope, ...properties, "__StdDevs"]) .columnFormats([ new ColumnFormatEx() .column("StdDevs") @@ -106,18 +106,18 @@ class TableEx extends Table { .data(metrics .filter(m => this.scopeFilterFunc(m, scopeFilter, matchCase)) .filter(row => { - return options.scopeTypes.indexOf(row.type) >= 0; + return scopeTypes.indexOf(row.type) >= 0; }).map((row, idx) => { if (idx === 0) { this._rawDataMap = { 0: "##", 1: "type", 2: "__StdDevs", 3: "name" }; - options.properties.forEach((p, idx2) => { + properties.forEach((p, idx2) => { this._rawDataMap[4 + idx2] = p; }); } row.__hpcc_id = row.name; - return [idx, row.type, row.__StdDevs === 0 ? undefined : row.__StdDevs, row.name, ...options.properties.map(p => { + return [idx, row.type, row.__StdDevs === 0 ? undefined : row.__StdDevs, row.name, ...properties.map(p => { return row.__groupedProps[p]?.Value ?? row.__groupedProps[p]?.Max ?? row.__groupedProps[p]?.Avg ?? @@ -157,6 +157,7 @@ class TableEx extends Table { } type SelectedMetricsSource = "" | "scopesTable" | "scopesSqlTable" | "metricGraphWidget" | "hotspot" | "reset"; +const TIMELINE_FIXEDHEIGHT = 152; interface MetricsProps { wuid: string; @@ -178,10 +179,9 @@ export const Metrics: React.FunctionComponent = ({ const [selectedMetrics, setSelectedMetrics] = React.useState([]); const [selectedMetricsPtr, setSelectedMetricsPtr] = React.useState(-1); const [metrics, columns, _activities, _properties, _measures, _scopeTypes, fetchStatus, refresh] = useWUQueryMetrics(wuid, querySet, queryId); + const { viewIds, viewId, setViewId, view, updateView } = useMetricsViews(); const [showMetricOptions, setShowMetricOptions] = React.useState(false); - const [options, setOptions, saveOptions] = useMetricsOptions(); const [dockpanel, setDockpanel] = React.useState(); - const [showTimeline, setShowTimeline] = React.useState(true); const [trackSelection, setTrackSelection] = React.useState(true); const [fullscreen, setFullscreen] = React.useState(false); const [hotspots, setHotspots] = React.useState(""); @@ -240,11 +240,14 @@ export const Metrics: React.FunctionComponent = ({ }, [parentUrl, timeline]); React.useEffect(() => { - timeline - .scopes(metrics) - .lazyRender() - ; - }, [metrics, timeline]); + if (view.showTimeline) { + timeline + .scopes(metrics) + .height(TIMELINE_FIXEDHEIGHT) + .lazyRender() + ; + } + }, [metrics, timeline, view.showTimeline]); // Scopes Table --- const onChangeScopeFilter = React.useCallback((event: React.FormEvent, newValue?: string) => { @@ -258,7 +261,7 @@ export const Metrics: React.FunctionComponent = ({ const scopesTable = useConst(() => new TableEx() .multiSelect(true) - .metrics([], options, scopeFilter, matchCase) + .metrics([], view.scopeTypes, view.properties, scopeFilter, matchCase) .sortable(true) ); @@ -274,10 +277,10 @@ export const Metrics: React.FunctionComponent = ({ React.useEffect(() => { scopesTable - .metrics(metrics, options, scopeFilter, matchCase) + .metrics(metrics, view.scopeTypes, view.properties, scopeFilter, matchCase) .lazyRender() ; - }, [matchCase, metrics, options, scopeFilter, scopesTable]); + }, [matchCase, metrics, scopeFilter, scopesTable, view.properties, view.scopeTypes]); const updateScopesTable = React.useCallback((selection: IScope[]) => { if (scopesTable?.renderCount() > 0) { @@ -490,9 +493,9 @@ export const Metrics: React.FunctionComponent = ({ }, [crossTabTable]); React.useEffect(() => { - const dot = metricGraph.graphTpl(selectedLineage ? [selectedLineage] : [], options); + const dot = metricGraph.graphTpl(selectedLineage ? [selectedLineage] : [], view); setDot(dot); - }, [metricGraph, options, selectedLineage]); + }, [metricGraph, view, selectedLineage]); React.useEffect(() => { let cancelled = false; @@ -530,13 +533,14 @@ export const Metrics: React.FunctionComponent = ({ React.useEffect(() => { // Update layout prior to unmount --- - if (dockpanel && options && saveOptions && setOptions) { + if (dockpanel && updateView) { return () => { - setOptions({ ...options, layout: dockpanel.getLayout() }); - saveOptions(); + if (dockpanel && updateView) { + updateView({ layout: dockpanel.getLayout() }); + } }; } - }, [dockpanel, options, saveOptions, setOptions]); + }, [dockpanel, updateView]); // Command Bar --- const buttons = React.useMemo((): ICommandBarItemProps[] => [ @@ -556,19 +560,30 @@ export const Metrics: React.FunctionComponent = ({ }, { key: "divider_1", itemType: ContextualMenuItemType.Divider, onRender: () => }, { - key: "timeline", text: nlsHPCC.Timeline, canCheck: true, checked: showTimeline, iconProps: { iconName: "TimelineProgress" }, + key: "views", text: viewId, iconProps: { iconName: "View" }, + subMenuProps: { + items: viewIds.map(v => ({ + key: v, text: v, onClick: () => { + updateView({ layout: dockpanel.getLayout() }); + setViewId(v); + } + })) + }, + }, + { + key: "timeline", text: nlsHPCC.Timeline, canCheck: true, checked: view.showTimeline, iconProps: { iconName: "TimelineProgress" }, onClick: () => { - setShowTimeline(!showTimeline); + updateView({ showTimeline: !view.showTimeline }, true); } }, { key: "options", text: nlsHPCC.Options, iconProps: { iconName: "Settings" }, onClick: () => { - setOptions({ ...options, layout: dockpanel.layout() }); + updateView({ layout: dockpanel.getLayout() }); setShowMetricOptions(true); } } - ], [dockpanel, hotspots, onHotspot, options, refresh, setOptions, showTimeline, timeline]); + ], [dockpanel, hotspots, onHotspot, refresh, setViewId, timeline, updateView, view.showTimeline, viewId, viewIds]); const formatColumns = React.useMemo((): Utility.ColumnMap => { const copyColumns: Utility.ColumnMap = {}; @@ -610,7 +625,9 @@ export const Metrics: React.FunctionComponent = ({ } }] } - }, { + }, + { key: "divider_2", itemType: ContextualMenuItemType.Divider, onRender: () => }, + { key: "fullscreen", title: nlsHPCC.MaximizeRestore, iconProps: { iconName: fullscreen ? "ChromeRestore" : "FullScreen" }, onClick: () => setFullscreen(!fullscreen) } @@ -618,23 +635,18 @@ export const Metrics: React.FunctionComponent = ({ const setShowMetricOptionsHook = React.useCallback((show: boolean) => { setShowMetricOptions(show); - scopesTable - .metrics(metrics, options, scopeFilter, matchCase) - .render(() => { - updateScopesTable(selectedMetrics); - }) - ; + }, []); - }, [matchCase, metrics, options, scopeFilter, scopesTable, selectedMetrics, updateScopesTable]); + console.log("View ID", viewId, view.scopeTypes); return -