diff --git a/package-lock.json b/package-lock.json index 2fb83a9e47..d230efc90c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -130,6 +130,7 @@ "react-use-size": "^3.0.3", "react-windowed-select": "^5.2.0", "reactflow": "^11.11.3", + "reaviz": "^16.1.2", "recharts": "^2.15.4", "shiki": "^3.20.0", "streamdown": "^1.6.10", @@ -3302,27 +3303,24 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.0.tgz", - "integrity": "sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.1.3" + "@floating-ui/utils": "^0.2.11" } }, "node_modules/@floating-ui/dom": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz", - "integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==", + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.0.0", - "@floating-ui/utils": "^0.2.0" + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" } }, - "node_modules/@floating-ui/dom/node_modules/@floating-ui/utils": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", - "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" - }, "node_modules/@floating-ui/react": { "version": "0.26.22", "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.22.tgz", @@ -3338,26 +3336,23 @@ } }, "node_modules/@floating-ui/react-dom": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", - "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", + "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", + "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.0.0" + "@floating-ui/dom": "^1.7.6" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, - "node_modules/@floating-ui/react/node_modules/@floating-ui/utils": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.7.tgz", - "integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==" - }, "node_modules/@floating-ui/utils": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz", - "integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==" + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "license": "MIT" }, "node_modules/@headlessui/react": { "version": "2.1.2", @@ -8500,6 +8495,16 @@ "react-dom": ">=17" } }, + "node_modules/@reaviz/react-use-fuzzy": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@reaviz/react-use-fuzzy/-/react-use-fuzzy-1.0.3.tgz", + "integrity": "sha512-ON5RxiI0r9zNpEKHvxqT8zz3iI4kzc37NzB4t8lfXSWwCEkpzxWY9TB2JAdYp9LC3UW2tN9zxdMnaNBLz4atTw==", + "license": "MIT", + "peerDependencies": { + "fuse.js": "^6.6.2", + "react": ">= 16" + } + }, "node_modules/@remix-run/router": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.13.0.tgz", @@ -8508,6 +8513,19 @@ "node": ">=14.0.0" } }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz", + "integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rushstack/eslint-patch": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.6.0.tgz", @@ -15439,6 +15457,21 @@ "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==" }, + "node_modules/@types/d3-cloud": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@types/d3-cloud/-/d3-cloud-1.2.9.tgz", + "integrity": "sha512-5EWJvnlCrqTThGp8lYHx+DL00sOjx2HTlXH1WRe93k5pfOIhPQaL63NttaKYIbT7bTXp/USiunjNS/N4ipttIQ==", + "license": "MIT", + "dependencies": { + "@types/d3": "^3" + } + }, + "node_modules/@types/d3-cloud/node_modules/@types/d3": { + "version": "3.5.53", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-3.5.53.tgz", + "integrity": "sha512-8yKQA9cAS6+wGsJpBysmnhlaaxlN42Qizqkw+h2nILSlS+MAG2z4JdO6p+PJrJ+ACvimkmLJL281h157e52psQ==", + "license": "MIT" + }, "node_modules/@types/d3-color": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", @@ -16474,6 +16507,16 @@ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" }, + "node_modules/@upsetjs/venn.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@upsetjs/venn.js/-/venn.js-2.0.0.tgz", + "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==", + "license": "MIT", + "optionalDependencies": { + "d3-selection": "^3.0.0", + "d3-transition": "^3.0.1" + } + }, "node_modules/@valibot/to-json-schema": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@valibot/to-json-schema/-/to-json-schema-1.5.0.tgz", @@ -18022,7 +18065,6 @@ "version": "1.6.52", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", - "dev": true, "engines": { "node": ">=0.6" } @@ -18173,6 +18215,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/body-scroll-lock-upgrade": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/body-scroll-lock-upgrade/-/body-scroll-lock-upgrade-1.1.0.tgz", + "integrity": "sha512-nnfVAS+tB7CS9RaksuHVTpgHWHF7fE/ptIBJnwZrMqImIvWJF1OGcLnMpBhC6qhkx9oelvyxmWXwmIJXCV98Sw==", + "license": "MIT" + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -18892,6 +18940,12 @@ "node": ">=10" } }, + "node_modules/chroma-js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-3.2.0.tgz", + "integrity": "sha512-os/OippSlX1RlWWr+QDPcGUZs0uoqr32urfxESG9U93lhUfbnlyckte84Q8P1UQY/qth983AS1JONKmLS4T0nw==", + "license": "(BSD-3-Clause AND Apache-2.0)" + }, "node_modules/chromatic": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/chromatic/-/chromatic-6.24.1.tgz", @@ -18958,9 +19012,10 @@ "integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==" }, "node_modules/classnames": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", - "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" }, "node_modules/clean-css": { "version": "5.3.2", @@ -19767,6 +19822,13 @@ "node": ">= 6" } }, + "node_modules/coverup": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/coverup/-/coverup-0.1.1.tgz", + "integrity": "sha512-Q2Fs0v3M4eMNfj0TGaFb4Oh0yuaQj9EhQbEKtFhD3Tm4HZt1Zn7TrBKX14gVEO9aeWP8KnF2/qrh7fr/rvbcXw==", + "deprecated": "No longer maintained", + "license": "MIT" + }, "node_modules/create-ecdh": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", @@ -19783,6 +19845,12 @@ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "dev": true }, + "node_modules/create-global-state-hook": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/create-global-state-hook/-/create-global-state-hook-0.0.2.tgz", + "integrity": "sha512-+1gRNwtuSQIC9lQQngfcY1VARKs6R32KJjI1bFrsp0W5MbauupRW/uQF0f+ElXx8xMmuEK9wl5zqAslzj6GvCA==", + "license": "MIT" + }, "node_modules/create-hash": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", @@ -20094,6 +20162,15 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" }, + "node_modules/ctrl-keys": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/ctrl-keys/-/ctrl-keys-1.0.6.tgz", + "integrity": "sha512-fENSKrbIfvX83uHxruP3S/9GizirvgT66vHhgKHOCTVHK+22Xpud/vttg5c5IifRl+6Gom/GjE+ZSXJKf0DMTA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/cytoscape": { "version": "3.33.1", "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", @@ -20228,6 +20305,21 @@ "node": ">=12" } }, + "node_modules/d3-cloud": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/d3-cloud/-/d3-cloud-1.2.9.tgz", + "integrity": "sha512-leL1GLneC9ZQtnV+6TGWrNlGfI1WX7S2arcTv2vae12DaXo5wjm6GBCkskXbrDlyOymd/A75Pyj1H37MW4BZ/Q==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-dispatch": "^1.0.3" + } + }, + "node_modules/d3-cloud/node_modules/d3-dispatch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", + "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==", + "license": "BSD-3-Clause" + }, "node_modules/d3-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", @@ -21372,6 +21464,12 @@ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.25.tgz", "integrity": "sha512-kMb204zvK3PsSlgvvwzI3wBIcAw15tRkYk+NQdsjdDtcQWTp2RABbMQ9rUBy8KNEOM+/E6ep+XC3AykiWZld4g==" }, + "node_modules/ellipsize": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/ellipsize/-/ellipsize-0.6.2.tgz", + "integrity": "sha512-zB4m5iEETalVrrP8RzcF0Qzqyw3MkUQ4R43NiczRAp0Hpp0+0bRdwKnoaFXyJoVJCipm2/3xc7Hkg0OOAorUPw==", + "license": "MIT" + }, "node_modules/elliptic": { "version": "6.5.4", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", @@ -23479,6 +23577,30 @@ "node": ">=0.4.0" } }, + "node_modules/focus-trap": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.8.0.tgz", + "integrity": "sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==", + "license": "MIT", + "dependencies": { + "tabbable": "^6.4.0" + } + }, + "node_modules/focus-trap-react": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/focus-trap-react/-/focus-trap-react-10.3.1.tgz", + "integrity": "sha512-PN4Ya9xf9nyj/Nd9VxBNMuD7IrlRbmaG6POAQ8VLqgtc6IY/Ln1tYakow+UIq4fihYYYFM70/2oyidE6bbiPgw==", + "license": "MIT", + "dependencies": { + "focus-trap": "^7.6.1", + "tabbable": "^6.2.0" + }, + "peerDependencies": { + "prop-types": "^15.8.1", + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + } + }, "node_modules/follow-redirects": { "version": "1.15.3", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", @@ -23913,6 +24035,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/fuse.js": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-6.6.2.tgz", + "integrity": "sha512-cJaJkxCCxC8qIIcPBF9yGxY0W/tVZS3uEISDxhYIdtk8OL93pe+6Zj7LjCqVV4dzbqcriOZ+kQ/NE4RXZHsIGA==", + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -24871,6 +25002,12 @@ "dev": true, "license": "MIT" }, + "node_modules/highlight-words-core": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/highlight-words-core/-/highlight-words-core-1.2.3.tgz", + "integrity": "sha512-m1O9HW3/GNHxzSIXWw1wCNXXsgLlxrP0OI6+ycGUhiUHkikqW3OrwVHz+lxeNBe5yqLESdIcj8PowHQ2zLvUvQ==", + "license": "MIT" + }, "node_modules/hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -25154,6 +25291,15 @@ "node": ">= 14" } }, + "node_modules/human-format": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/human-format/-/human-format-1.2.1.tgz", + "integrity": "sha512-o5Ldz62VWR5lYUZ8aVQaLKiN37NsHnmk3xjMoUjza3mGkk8MvMofgZT0T6HKSCKSJIir+AWk9Dx8KhxvZAUgCg==", + "license": "ISC", + "engines": { + "node": ">=4" + } + }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -25475,6 +25621,12 @@ "loose-envify": "^1.0.0" } }, + "node_modules/invert-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-color/-/invert-color-2.0.0.tgz", + "integrity": "sha512-9s6IATlhOAr0/0MPUpLdMpk81ixIu8IqwPwORssXBauFT/4ff/iyEOcojd0UYuPwkDbJvL1+blIZGhqVIaAm5Q==", + "license": "MIT" + }, "node_modules/ip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", @@ -31346,6 +31498,12 @@ "thenify-all": "^1.0.0" } }, + "node_modules/name-initials": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/name-initials/-/name-initials-0.1.3.tgz", + "integrity": "sha512-UJcpCmyftGuZ7I46dqOw776VvH3VqHhAM7ma4eyY0t52FahFv/VhmDqSeekwSZFXyK9HLg9MXmb9udeOJ3YtCA==", + "license": "MIT" + }, "node_modules/nanoclone": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz", @@ -35901,6 +36059,15 @@ "pathe": "^2.0.1" } }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/pnp-webpack-plugin": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.7.0.tgz", @@ -36995,6 +37162,90 @@ "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/reablocks": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/reablocks/-/reablocks-9.4.1.tgz", + "integrity": "sha512-WiicdjqkgZeJZGQop9fWLafEeaYVaVOse3o7Z+Y3YGDuMcxkmkBS3qQvCDVGNW6DZvSGN3cQuaTE8Wa4G9BTcQ==", + "license": "Apache-2.0", + "dependencies": { + "@floating-ui/react": "^0.27.16", + "@reaviz/react-use-fuzzy": "^1.0.3", + "body-scroll-lock-upgrade": "^1.1.0", + "chroma-js": "^3.1.2", + "classnames": "^2.5.1", + "coverup": "^0.1.1", + "create-global-state-hook": "^0.0.2", + "ctrl-keys": "^1.0.6", + "date-fns": "^4.1.0", + "ellipsize": "^0.6.2", + "focus-trap-react": "^10.3.1", + "fuse.js": "^6.6.2", + "human-format": "^1.2.1", + "motion": "^12.23.12", + "name-initials": "^0.1.3", + "pluralize": "^8.0.0", + "react-fast-compare": "^3.2.2", + "react-highlight-words": "^0.21.0", + "react-textarea-autosize": "^8.5.9", + "tailwind-merge": "^2.6.0" + }, + "engines": { + "node": ">=22", + "npm": ">=10.8.2" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, + "node_modules/reablocks/node_modules/@floating-ui/react": { + "version": "0.27.19", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.19.tgz", + "integrity": "sha512-31B8h5mm8YxotlE7/AU/PhNAl8eWxAmjL/v2QOxroDNkTFLk3Uu82u63N3b6TXa4EGJeeZLVcd/9AlNlVqzeog==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.8", + "@floating-ui/utils": "^0.2.11", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=17.0.0", + "react-dom": ">=17.0.0" + } + }, + "node_modules/reablocks/node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==", + "license": "MIT" + }, + "node_modules/reablocks/node_modules/react-textarea-autosize": { + "version": "8.5.9", + "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.5.9.tgz", + "integrity": "sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.13", + "use-composed-ref": "^1.3.0", + "use-latest": "^1.2.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/reablocks/node_modules/tailwind-merge": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.1.tgz", + "integrity": "sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, "node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", @@ -37189,6 +37440,25 @@ "react-dom": "^16.8.2 || ^17.0 || ^18.x || ^19.x" } }, + "node_modules/react-highlight-words": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/react-highlight-words/-/react-highlight-words-0.21.0.tgz", + "integrity": "sha512-SdWEeU9fIINArEPO1rO5OxPyuhdEKZQhHzZZP1ie6UeXQf+CjycT1kWaB+9bwGcVbR0NowuHK3RqgqNg6bgBDQ==", + "license": "MIT", + "dependencies": { + "highlight-words-core": "^1.2.0", + "memoize-one": "^4.0.0" + }, + "peerDependencies": { + "react": "^0.14.0 || ^15.0.0 || ^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" + } + }, + "node_modules/react-highlight-words/node_modules/memoize-one": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-4.0.3.tgz", + "integrity": "sha512-QmpUu4KqDmX0plH4u+tf0riMc1KHE1+lw95cMrLlXQAFOx/xnBtwhZ52XJxd9X2O6kwKBqX32kmhbhlobD0cuw==", + "license": "MIT" + }, "node_modules/react-hook-form": { "version": "7.48.2", "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.48.2.tgz", @@ -37708,6 +37978,103 @@ "node": ">=8.10.0" } }, + "node_modules/reaviz": { + "version": "16.1.2", + "resolved": "https://registry.npmjs.org/reaviz/-/reaviz-16.1.2.tgz", + "integrity": "sha512-w79c7e1jYKZgY1MQ9RDkF/r5lzAX51nIpX+j926m0G0Gs+v8FkE3HWbN2CqhGF4vBZdbPkmc1tLhg5jqcJcpBw==", + "license": "Apache-2.0", + "dependencies": { + "@floating-ui/dom": "^1.7.4", + "@types/d3-cloud": "^1.2.9", + "@upsetjs/venn.js": "^2.0.0", + "big-integer": "^1.6.52", + "chroma-js": "^3.1.2", + "classnames": "^2.5.1", + "d3-array": "^3.2.4", + "d3-cloud": "^1.2.7", + "d3-format": "^3.1.0", + "d3-geo": "^3.1.1", + "d3-hierarchy": "^3.1.2", + "d3-interpolate": "^3.0.1", + "d3-sankey": "^0.12.3", + "d3-scale": "^4.0.2", + "d3-shape": "^3.2.0", + "d3-time": "^3.1.0", + "ellipsize": "^0.6.2", + "human-format": "^1.2.1", + "invert-color": "^2.0.0", + "motion": "^12.23.12", + "reablocks": "^9.2.2", + "react-fast-compare": "^3.2.2", + "reaviz-data-utils": "^1.0.0", + "safe-identifier": "^0.4.2", + "transformation-matrix": "^3.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, + "node_modules/reaviz-data-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/reaviz-data-utils/-/reaviz-data-utils-1.0.0.tgz", + "integrity": "sha512-I1sUNF8E1fuV4XZwEnh5M9vEUlbyM5rWW3EO53hLUWHTzc43ScTVWbs9LncSTvL93GmwW+sVeotLzDq1WRz0Rw==", + "license": "ISC", + "dependencies": { + "big-integer": "^1.6.52", + "d3-array": "^3.2.4", + "date-fns": "^3.6.0" + }, + "optionalDependencies": { + "@rollup/rollup-linux-x64-gnu": "4.18.0" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/reaviz-data-utils/node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/reaviz-data-utils/node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/reaviz/node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/reaviz/node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==", + "license": "MIT" + }, "node_modules/recast": { "version": "0.23.4", "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.4.tgz", @@ -38657,6 +39024,12 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/safe-identifier": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/safe-identifier/-/safe-identifier-0.4.2.tgz", + "integrity": "sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==", + "license": "ISC" + }, "node_modules/safe-regex-test": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", @@ -41282,9 +41655,10 @@ "integrity": "sha512-AsS729u2RHUfEra9xJrE39peJcc2stq2+poBXX8bcM08Y6g9j/i/PUzwNQqkaJde7Ntg1TO7bSREbR5sdosQ+g==" }, "node_modules/tabbable": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", - "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz", + "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==", + "license": "MIT" }, "node_modules/tagged-tag": { "version": "1.0.0", @@ -42041,6 +42415,15 @@ "node": ">=12" } }, + "node_modules/transformation-matrix": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/transformation-matrix/-/transformation-matrix-3.1.0.tgz", + "integrity": "sha512-oYubRWTi2tYFHAL2J8DLvPIqIYcYZ0fSOi2vmSy042Ho4jBW2ce6VP7QfD44t65WQz6bw5w1Pk22J7lcUpaTKA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/chrvadala" + } + }, "node_modules/traverse": { "version": "0.6.8", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.8.tgz", diff --git a/package.json b/package.json index 66adff1a18..39829e9883 100644 --- a/package.json +++ b/package.json @@ -130,6 +130,7 @@ "react-use-size": "^3.0.3", "react-windowed-select": "^5.2.0", "reactflow": "^11.11.3", + "reaviz": "^16.1.2", "recharts": "^2.15.4", "shiki": "^3.20.0", "streamdown": "^1.6.10", diff --git a/src/components/Configs/Changes/ConfigChangesFilters/ConfigChangeSeverity.tsx b/src/components/Configs/Changes/ConfigChangesFilters/ConfigChangeSeverity.tsx index 0d37f9b9d6..debf986395 100644 --- a/src/components/Configs/Changes/ConfigChangesFilters/ConfigChangeSeverity.tsx +++ b/src/components/Configs/Changes/ConfigChangesFilters/ConfigChangeSeverity.tsx @@ -57,7 +57,7 @@ export const configChangeSeverity = { icon: , name: "Info", description: "Info", - value: "Info", + value: "info", colorClass: "text-gray-500 fill-gray-500" } } as const; diff --git a/src/components/Configs/Changes/ConfigChangesFilters/ConfigChangesFilters.tsx b/src/components/Configs/Changes/ConfigChangesFilters/ConfigChangesFilters.tsx index ee0e455c18..253721f473 100644 --- a/src/components/Configs/Changes/ConfigChangesFilters/ConfigChangesFilters.tsx +++ b/src/components/Configs/Changes/ConfigChangesFilters/ConfigChangesFilters.tsx @@ -11,6 +11,7 @@ import { ConfigChangeSeverity } from "./ConfigChangeSeverity"; import ConfigChangesDateRangeFilter from "./ConfigChangesDateRangeFIlter"; import { ConfigTagsDropdown } from "./ConfigTagsDropdown"; import ShowDeletedConfigs from "../../ConfigsListFilters/ShowDeletedConfigs"; +import ConfigChangesViewToggle from "../ConfigChangesViewToggle"; import ConfigTypesTristateDropdown from "./ConfigTypesTristateDropdown"; type FilterBadgeProps = { @@ -102,6 +103,8 @@ export function ConfigChangeFilters({ + + {extra} diff --git a/src/components/Configs/Changes/ConfigChangesGraph.tsx b/src/components/Configs/Changes/ConfigChangesGraph.tsx new file mode 100644 index 0000000000..1c3dc9aa0b --- /dev/null +++ b/src/components/Configs/Changes/ConfigChangesGraph.tsx @@ -0,0 +1,132 @@ +import { ConfigChange } from "@flanksource-ui/api/types/configs"; +import { Age } from "@flanksource-ui/ui/Age"; +import { ChangeIcon } from "@flanksource-ui/ui/Icons/ChangeIcon"; +import { relativeDateTime } from "@flanksource-ui/utils/date"; +import dayjs from "dayjs"; +import { useMemo } from "react"; +import { + ChartShallowDataShape, + ChartTooltip, + ChartZoomPan, + LinearXAxis, + LinearXAxisTickLabel, + LinearXAxisTickLine, + LinearXAxisTickSeries, + LinearYAxis, + LinearYAxisTickLabel, + LinearYAxisTickSeries, + ScatterPlot, + ScatterPoint, + ScatterSeries +} from "reaviz"; +import ConfigsTypeIcon from "../ConfigsTypeIcon"; + +type ConfigChangesGraphProps = { + changes: ConfigChange[]; + onItemClicked?: (change: ConfigChange) => void; +}; + +export default function ConfigChangesGraph({ + changes, + onItemClicked = () => {} +}: ConfigChangesGraphProps) { + const data: ChartShallowDataShape[] = useMemo(() => { + return changes + .filter((change) => change.first_observed && change.config?.name) + .map((change) => ({ + key: dayjs(change.first_observed).toDate(), + data: change.config!.name!, + metadata: change + })); + }, [changes]); + + return ( +
+ } + yAxis={ + v} + /> + } + /> + } + /> + } + xAxis={ + } + label={ + relativeDateTime(v)} + /> + } + /> + } + /> + } + series={ + { + const change = data.metadata as ConfigChange; + return ( +
+ + {change.config?.name} + +
+
+ + + {change.change_type} + + + + {(change.count || 1) > 1 && + change.first_observed && ( + + (x{change.count} over{" "} + ) + + )} + +
+

{change.summary}

+
+
+ ); + }} + /> + } + className={"bg-gray-500"} + size={20} + symbol={(data) => } + onClick={(data) => { + onItemClicked(data.metadata as ConfigChange); + }} + /> + } + /> + } + /> +
+ ); +} diff --git a/src/components/Configs/Changes/ConfigChangesViewToggle.tsx b/src/components/Configs/Changes/ConfigChangesViewToggle.tsx new file mode 100644 index 0000000000..510dad424f --- /dev/null +++ b/src/components/Configs/Changes/ConfigChangesViewToggle.tsx @@ -0,0 +1,34 @@ +import { Switch } from "@flanksource-ui/ui/FormControls/Switch"; +import { useAtom } from "jotai"; +import { atomWithStorage } from "jotai/utils"; + +export type GraphType = "Table" | "Graph"; +export const configChangesViewToggle = atomWithStorage( + "configChangesViewToggleState", + "Table", + undefined, + { + getOnInit: true + } +); + +export function useConfigChangesViewToggleState() { + const [view] = useAtom(configChangesViewToggle); + return view; +} + +export default function ConfigChangesViewToggle() { + const [toggleValue, setToggleValue] = useAtom(configChangesViewToggle); + + return ( +
+ { + setToggleValue(v as GraphType); + }} + value={toggleValue} + /> +
+ ); +} diff --git a/src/components/Configs/Changes/ConfigDetailsChanges/ConfigDetailsChanges.tsx b/src/components/Configs/Changes/ConfigDetailsChanges/ConfigDetailsChanges.tsx index 3e164ddc4b..3e8c69d709 100644 --- a/src/components/Configs/Changes/ConfigDetailsChanges/ConfigDetailsChanges.tsx +++ b/src/components/Configs/Changes/ConfigDetailsChanges/ConfigDetailsChanges.tsx @@ -68,7 +68,7 @@ export function ConfigDetailsChanges({ } + value={} /> -
+
@@ -37,6 +43,8 @@ export function ConfigRelatedChangesFilters({ + + {extra}
diff --git a/src/pages/config/ConfigChangesPage.tsx b/src/pages/config/ConfigChangesPage.tsx index 32ac2fd272..15d56c5674 100644 --- a/src/pages/config/ConfigChangesPage.tsx +++ b/src/pages/config/ConfigChangesPage.tsx @@ -1,7 +1,10 @@ import { useGetAllConfigsChangesQuery } from "@flanksource-ui/api/query-hooks/useConfigChangesHooks"; +import { useGetConfigChangesById } from "@flanksource-ui/api/query-hooks/useGetConfigChangesByConfigChangeIdQuery"; import { ConfigChange } from "@flanksource-ui/api/types/configs"; import { ConfigChangeTable } from "@flanksource-ui/components/Configs/Changes/ConfigChangeTable"; import { ConfigChangeFilters } from "@flanksource-ui/components/Configs/Changes/ConfigChangesFilters/ConfigChangesFilters"; +import { useConfigChangesViewToggleState } from "@flanksource-ui/components/Configs/Changes/ConfigChangesViewToggle"; +import { ConfigDetailChangeModal } from "@flanksource-ui/components/Configs/Changes/ConfigDetailsChanges/ConfigDetailsChanges"; import ConfigPageTabs from "@flanksource-ui/components/Configs/ConfigPageTabs"; import ConfigsTypeIcon from "@flanksource-ui/components/Configs/ConfigsTypeIcon"; import { InfoMessage } from "@flanksource-ui/components/InfoMessage"; @@ -15,7 +18,7 @@ import { SearchLayout } from "@flanksource-ui/ui/Layout/SearchLayout"; import { refreshButtonClickedTrigger } from "@flanksource-ui/ui/SlidingSideBar/SlidingSideBar"; import { Toggle } from "@flanksource-ui/ui/FormControls/Toggle"; import { useAtom } from "jotai"; -import { useEffect, useState } from "react"; +import { Suspense, lazy, useEffect, useState } from "react"; import { useSearchParams } from "react-router-dom"; function getNewestInsertedAt(changes: ConfigChange[]): string | undefined { @@ -29,7 +32,12 @@ function getNewestInsertedAt(changes: ConfigChange[]): string | undefined { return latest; } +const ConfigChangesGraph = lazy( + () => import("@flanksource-ui/components/Configs/Changes/ConfigChangesGraph") +); + export function ConfigChangesPage() { + const view = useConfigChangesViewToggleState(); const [, setRefreshButtonClickedTrigger] = useAtom( refreshButtonClickedTrigger ); @@ -125,6 +133,17 @@ export function ConfigChangesPage() { const totalChanges = (data?.total ?? 0) + newTailedCount; const totalChangesPages = Math.ceil(totalChanges / parseInt(pageSize)); + const [selectedChange, setSelectedChange] = useState(); + + useEffect(() => { + if (view !== "Graph") setSelectedChange(undefined); + }, [view]); + + const { data: changeDetails, isLoading: changeLoading } = + useGetConfigChangesById(selectedChange?.id ?? "", { + enabled: view === "Graph" && !!selectedChange + }); + const errorMessage = typeof error === "string" ? error @@ -185,13 +204,40 @@ export function ConfigChangesPage() { /> } /> - + {view === "Graph" ? ( + <> + + Loading graph... +
+ } + > + setSelectedChange(change)} + /> + + {selectedChange && ( + { + if (!open) setSelectedChange(undefined); + }} + changeDetails={changeDetails ?? selectedChange} + /> + )} + + ) : ( + + )} )} diff --git a/src/pages/config/details/ConfigDetailsChangesPage.tsx b/src/pages/config/details/ConfigDetailsChangesPage.tsx index 28aef9e85c..26985082cc 100644 --- a/src/pages/config/details/ConfigDetailsChangesPage.tsx +++ b/src/pages/config/details/ConfigDetailsChangesPage.tsx @@ -1,11 +1,14 @@ +import { useGetConfigChangesById } from "@flanksource-ui/api/query-hooks/useGetConfigChangesByConfigChangeIdQuery"; import { useGetConfigChangesByIDQuery } from "@flanksource-ui/api/query-hooks/useConfigChangesHooks"; import { ConfigChange } from "@flanksource-ui/api/types/configs"; import { ConfigChangeTable } from "@flanksource-ui/components/Configs/Changes/ConfigChangeTable"; +import { useConfigChangesViewToggleState } from "@flanksource-ui/components/Configs/Changes/ConfigChangesViewToggle"; +import { ConfigDetailChangeModal } from "@flanksource-ui/components/Configs/Changes/ConfigDetailsChanges/ConfigDetailsChanges"; import { ConfigRelatedChangesFilters } from "@flanksource-ui/components/Configs/Changes/ConfigsRelatedChanges/FilterBar/ConfigRelatedChangesFilters"; import { ConfigDetailsTabs } from "@flanksource-ui/components/Configs/ConfigDetailsTabs"; import { InfoMessage } from "@flanksource-ui/components/InfoMessage"; import { Toggle } from "@flanksource-ui/ui/FormControls/Toggle"; -import { useEffect, useState } from "react"; +import { Suspense, lazy, useEffect, useState } from "react"; import { useParams, useSearchParams } from "react-router-dom"; function getNewestInsertedAt(changes: ConfigChange[]): string | undefined { @@ -18,9 +21,13 @@ function getNewestInsertedAt(changes: ConfigChange[]): string | undefined { } return latest; } +const ConfigChangesGraph = lazy( + () => import("@flanksource-ui/components/Configs/Changes/ConfigChangesGraph") +); export function ConfigDetailsChangesPage() { const { id } = useParams(); + const view = useConfigChangesViewToggleState(); const [params] = useSearchParams({ sortBy: "created_at", @@ -78,21 +85,21 @@ export function ConfigDetailsChangesPage() { }); }, [pollData]); - const baseChanges = (data?.changes ?? []).map((change) => ({ - ...change, + const baseChanges = (data?.changes ?? []).map((c) => ({ + ...c, config: { - id: change.config_id!, - type: change.type!, - name: change.name! + id: c.config_id ?? "", + type: c.type ?? c.config?.type ?? "", + name: c.name ?? c.config?.name ?? "" } })); - const tailedWithConfig = tailedChanges.map((change) => ({ - ...change, + const tailedWithConfig = tailedChanges.map((c) => ({ + ...c, config: { - id: change.config_id!, - type: change.type!, - name: change.name! + id: c.config_id ?? "", + type: c.type ?? c.config?.type ?? "", + name: c.name ?? c.config?.name ?? "" } })); @@ -107,6 +114,17 @@ export function ConfigDetailsChangesPage() { const totalChanges = (data?.total ?? 0) + newTailedCount; const totalChangesPages = Math.ceil(totalChanges / parseInt(pageSize)); + const [selectedChange, setSelectedChange] = useState(); + + useEffect(() => { + if (view !== "Graph") setSelectedChange(undefined); + }, [view]); + + const { data: changeDetails, isLoading: changeLoading } = + useGetConfigChangesById(selectedChange?.id ?? "", { + enabled: view === "Graph" && !!selectedChange + }); + if (error) { const errorMessage = typeof error === "symbol" @@ -132,12 +150,39 @@ export function ConfigDetailsChangesPage() { } />
- + {view === "Graph" ? ( + <> + + Loading graph... +
+ } + > + setSelectedChange(change)} + /> + + {selectedChange && ( + { + if (!open) setSelectedChange(undefined); + }} + changeDetails={changeDetails ?? selectedChange} + /> + )} + + ) : ( + + )} diff --git a/src/ui/Icons/ChangeIcon.tsx b/src/ui/Icons/ChangeIcon.tsx index 5c1f034057..d46f6eb174 100644 --- a/src/ui/Icons/ChangeIcon.tsx +++ b/src/ui/Icons/ChangeIcon.tsx @@ -16,8 +16,16 @@ export function ChangeIcon({ change }: ChangeIconProps) { const colorClass = useMemo(() => { + const normalized = change?.severity?.toLowerCase(); + const aliases: Record = { + failure: "critical", + blocker: "critical", + warning: "medium", + success: "low" + }; + const mapped = aliases[normalized ?? ""] ?? normalized; const items = Object.values(configChangeSeverity).find( - (item) => item.value === change?.severity + (item) => item.value === mapped ); return items?.colorClass ?? ""; }, [change?.severity]);