]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mgr/dashboard: replace usage or progress bar with carbon meter chart
authorNaman Munet <namanmunet@li-ff83bccc-26af-11b2-a85c-a4b04bfb1003.ibm.com>
Mon, 21 Oct 2024 16:55:41 +0000 (22:25 +0530)
committerAbhishek Desai <abhishek.desai1@ibm.com>
Fri, 30 Jan 2026 06:57:09 +0000 (12:27 +0530)
Fixes: https://tracker.ceph.com/issues/68258
Changes affect the following files:
- rbd-list.component.html
- cephfs-detail.component.html
- cephfs-subvolume-group.component.html
- cephfs-subvolume-list.componenet.html
- multi-cluster.component.html
- osd-list.component.html
- service-daemon-list.component.html
- pool-list.component.html
- rgw-bucket-list.component.html
- rgw-user-list.component.html

Signed-off-by: Naman Munet <naman.munet@ibm.com>
(cherry picked from commit 01df0cd84f16eade54fa1448821e5479dfb575c5)

 Conflicts:
src/pybind/mgr/dashboard/frontend/package-lock.json
src/pybind/mgr/dashboard/frontend/package.json
src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts
src/pybind/mgr/dashboard/frontend/src/styles.scss

13 files changed:
src/pybind/mgr/dashboard/frontend/package-lock.json
src/pybind/mgr/dashboard/frontend/package.json
src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-subvolume-group/cephfs-subvolume-group.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-subvolume-list/cephfs-subvolume-list.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/classes/css-helper.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/components/usage-bar/usage-bar.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/components/usage-bar/usage-bar.component.scss
src/pybind/mgr/dashboard/frontend/src/app/shared/components/usage-bar/usage-bar.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/components/usage-bar/usage-bar.component.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/enum/usage-bar-chart.enum.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/jestGlobalMocks.ts
src/pybind/mgr/dashboard/frontend/src/styles.scss

index 1d833ce5b585dc09673d25fc0c305fa135045153..4d67eda3e3771a0e5668e30a3f1b54b4a2d61646 100644 (file)
@@ -18,8 +18,9 @@
         "@angular/platform-browser": "18.2.11",
         "@angular/platform-browser-dynamic": "18.2.11",
         "@angular/router": "18.2.11",
+        "@carbon/charts-angular": "1.23.9",
         "@carbon/icons": "11.63.0",
-        "@carbon/styles": "1.57.0",
+        "@carbon/styles": "1.83.0",
         "@ibm/plex": "6.4.0",
         "@ng-bootstrap/ng-bootstrap": "17.0.1",
         "@ngx-formly/bootstrap": "6.1.1",
@@ -45,7 +46,7 @@
         "rxjs": "6.6.3",
         "simplebar-angular": "3.2.6",
         "stream-browserify": "3.0.0",
-        "swagger-ui": "4.12.0",
+        "swagger-ui": "5.3.1",
         "timers-browserify": "2.0.12",
         "tslib": "2.3.1",
         "xml2js": "0.6.2",
         "ts-node": "9.0.0",
         "typescript": "5.4.5",
         "validator": "13.15.20"
-      },
-      "optionalDependencies": {
-        "@rollup/rollup-linux-arm64-gnu": "4.22.4"
       }
     },
     "node_modules/@aduh95/viz.js": {
       "dev": true
     },
     "node_modules/@braintree/sanitize-url": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.0.tgz",
-      "integrity": "sha512-mgmE7XBYY/21erpzhexk4Cj1cyTQ9LzvnTxtzM17BJ7ERMNE6W72mQRo0I1Ud8eFJ+RVVIcBNhLFZ3GX4XFz5w=="
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.2.tgz",
+      "integrity": "sha512-Tbsj02wXCbqGmzdnXNk0SOF19ChhRU70BsroIi4Pm6Ehp56in6vch94mfbdQ17DozxkL3BAVjbZ4Qc1a0HFRAg=="
+    },
+    "node_modules/@carbon/charts": {
+      "version": "1.23.9",
+      "resolved": "https://registry.npmjs.org/@carbon/charts/-/charts-1.23.9.tgz",
+      "integrity": "sha512-hYd+jN+EuM1OcA/apoHv3fPN0TGnvjKBRBJkDwDBjkrp1YwoMYf3arqL9VDrq+Gl5hy3MPu4j57elVAOCCMG0Q==",
+      "hasInstallScript": true,
+      "dependencies": {
+        "@carbon/colors": "^11.31.0",
+        "@carbon/utils-position": "^1.3.0",
+        "@ibm/telemetry-js": "^1.9.1",
+        "@types/d3": "^7.4.3",
+        "@types/topojson": "^3.2.6",
+        "d3": "^7.9.0",
+        "d3-cloud": "^1.2.7",
+        "d3-sankey": "^0.12.3",
+        "date-fns": "^4.1.0",
+        "dompurify": "^3.2.6",
+        "html-to-image": "1.11.11",
+        "lodash-es": "^4.17.21",
+        "topojson-client": "^3.1.0",
+        "tslib": "^2.8.1"
+      }
+    },
+    "node_modules/@carbon/charts-angular": {
+      "version": "1.23.9",
+      "resolved": "https://registry.npmjs.org/@carbon/charts-angular/-/charts-angular-1.23.9.tgz",
+      "integrity": "sha512-vN+9BIvlv+LqeDT0LrlwbmQR9Qj1C1E9OQaMLHattGrCLInpwQG0YBtzJQ/Jrhp9IrAjeEMvDm6jPWek6EI3Hg==",
+      "dependencies": {
+        "@carbon/charts": "1.23.9",
+        "@ibm/telemetry-js": "^1.9.1",
+        "tslib": "^2.8.1"
+      },
+      "peerDependencies": {
+        "@angular/common": "^19.0.6",
+        "@angular/core": "^19.0.6"
+      }
+    },
+    "node_modules/@carbon/charts-angular/node_modules/tslib": {
+      "version": "2.8.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
+    },
+    "node_modules/@carbon/charts/node_modules/@carbon/utils-position": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@carbon/utils-position/-/utils-position-1.3.0.tgz",
+      "integrity": "sha512-bfar2dV+fQ15syIrH3n9ujY4PXd1Q+AF2VcTLJIC04IDe2f80zOnJlLNPc/RktHcWTZ7WSQm80cQo3abGcsfTA==",
+      "hasInstallScript": true,
+      "dependencies": {
+        "@ibm/telemetry-js": "^1.5.1"
+      }
+    },
+    "node_modules/@carbon/charts/node_modules/dompurify": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz",
+      "integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==",
+      "optionalDependencies": {
+        "@types/trusted-types": "^2.0.7"
+      }
+    },
+    "node_modules/@carbon/charts/node_modules/tslib": {
+      "version": "2.8.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
     },
     "node_modules/@carbon/colors": {
-      "version": "11.22.0",
-      "resolved": "https://registry.npmjs.org/@carbon/colors/-/colors-11.22.0.tgz",
-      "integrity": "sha512-IRbzstMpIhD1ULhfYhZ5ne7kIKdhQhiMeltWRPw+7wlFB5ezFoX+kX3ILqdz20CkcrpLu+TVKLD79Zv/+4RD6w==",
+      "version": "11.46.0",
+      "resolved": "https://registry.npmjs.org/@carbon/colors/-/colors-11.46.0.tgz",
+      "integrity": "sha512-YL4BH2hxHkUT0+wMn8cO3sYN7rb9Nnp7rGttoblM0iTy83n/urwRPcxudifRwJLtASQpravCyLHdIC9WnTtIAA==",
       "hasInstallScript": true,
       "dependencies": {
         "@ibm/telemetry-js": "^1.5.0"
       }
     },
     "node_modules/@carbon/feature-flags": {
-      "version": "0.20.0",
-      "resolved": "https://registry.npmjs.org/@carbon/feature-flags/-/feature-flags-0.20.0.tgz",
-      "integrity": "sha512-OEYrazJa0nEEHbBDyarXIz6kjWgqsJggjbNAcVOxx0Nvma1nZBd+SwXKwdbMkBZagSSC816dV12oZJtr+GIZZg==",
+      "version": "0.27.0",
+      "resolved": "https://registry.npmjs.org/@carbon/feature-flags/-/feature-flags-0.27.0.tgz",
+      "integrity": "sha512-YDV3IcQnSxDHHHguJQ3DJd7Vi5OA9NsRg0CicrNX7fKyjHpNpFuLy1yan47LItXY1atw4GP7agpZgSumlUl9UA==",
       "hasInstallScript": true,
       "dependencies": {
         "@ibm/telemetry-js": "^1.5.0"
       }
     },
     "node_modules/@carbon/grid": {
-      "version": "11.23.0",
-      "resolved": "https://registry.npmjs.org/@carbon/grid/-/grid-11.23.0.tgz",
-      "integrity": "sha512-/8SiXzefUdUeIRzMxKB2+xq65knjkDas2TcZj0NS7dnDIEr5HarWTABh/H5b5BTFEJXos3PfEH6X5OUDuK4qpg==",
+      "version": "11.49.0",
+      "resolved": "https://registry.npmjs.org/@carbon/grid/-/grid-11.49.0.tgz",
+      "integrity": "sha512-zZfj/sbwJpXboduVFNUXUdV6LmsEH39fNQQMye4V+788sdvs+ErO8L3onBZFpsek5gI4ebwjpWJu2g5szu2+kQ==",
       "hasInstallScript": true,
       "dependencies": {
-        "@carbon/layout": "^11.22.0",
+        "@carbon/layout": "^11.47.0",
         "@ibm/telemetry-js": "^1.5.0"
       }
     },
       }
     },
     "node_modules/@carbon/layout": {
-      "version": "11.30.2",
-      "resolved": "https://registry.npmjs.org/@carbon/layout/-/layout-11.30.2.tgz",
-      "integrity": "sha512-jJuhVGiLg8cvRFZT0zfMC3aDxJStS7qEwEimUBahL+pdB5/754hB5ovh1AbwOho92ucJb11tNDBQ1JFixiW3JA==",
+      "version": "11.47.0",
+      "resolved": "https://registry.npmjs.org/@carbon/layout/-/layout-11.47.0.tgz",
+      "integrity": "sha512-2XR4TVp3uf2IB0WdoZuDcBbc9C8EN/JvZAw9BdHJ3njng8FlUAQUkTFvfoUsJl10868rqA6YeClCElBS4BHofg==",
       "hasInstallScript": true,
       "dependencies": {
         "@ibm/telemetry-js": "^1.5.0"
       }
     },
     "node_modules/@carbon/motion": {
-      "version": "11.18.0",
-      "resolved": "https://registry.npmjs.org/@carbon/motion/-/motion-11.18.0.tgz",
-      "integrity": "sha512-hVTmRxhXCA+xznXZSTd6m0kmuIRrR8mxnDHvrVKFvN3ksTYDni5Mtx4XNylI4u/fmzyUcvrvVeTHqJ8LbPsDvA==",
+      "version": "11.40.0",
+      "resolved": "https://registry.npmjs.org/@carbon/motion/-/motion-11.40.0.tgz",
+      "integrity": "sha512-QjvjMcC3G289GKYDvrf5dDuyol7SXm0TYaFltx+AkJdU6fptDCJ/qjUL5SdVrsLse3jFuI8rada9tRAL5xHS1g==",
       "hasInstallScript": true,
       "dependencies": {
         "@ibm/telemetry-js": "^1.5.0"
       }
     },
     "node_modules/@carbon/styles": {
-      "version": "1.57.0",
-      "integrity": "sha512-1GOJi0AAAOJXz411e9hoA3DTrK6SXsseSl7BDjQ5cO4ljlqCIPW5JS213yaF4MoYiLw5coDeGP7n6mgfWjbymA==",
+      "version": "1.83.0",
+      "resolved": "https://registry.npmjs.org/@carbon/styles/-/styles-1.83.0.tgz",
+      "integrity": "sha512-ez8Hhi4yxGyXoUBVdQDdA5a7A5XGtOEHkszdjl8gYLI4LC/8A2Idmed65lgIlemjsFefWqOa04wrynmU5RoFXA==",
       "hasInstallScript": true,
       "dependencies": {
-        "@carbon/colors": "^11.22.0",
-        "@carbon/feature-flags": "^0.20.0",
-        "@carbon/grid": "^11.23.0",
-        "@carbon/layout": "^11.22.0",
-        "@carbon/motion": "^11.18.0",
-        "@carbon/themes": "^11.35.0",
-        "@carbon/type": "^11.27.0",
+        "@carbon/colors": "^11.34.0",
+        "@carbon/feature-flags": "^0.27.0",
+        "@carbon/grid": "^11.37.0",
+        "@carbon/layout": "^11.35.0",
+        "@carbon/motion": "^11.29.0",
+        "@carbon/themes": "^11.54.0",
+        "@carbon/type": "^11.41.0",
         "@ibm/plex": "6.0.0-next.6",
+        "@ibm/plex-mono": "0.0.3-alpha.0",
+        "@ibm/plex-sans": "0.0.3-alpha.0",
+        "@ibm/plex-sans-arabic": "0.0.3-alpha.0",
+        "@ibm/plex-sans-devanagari": "0.0.3-alpha.0",
+        "@ibm/plex-sans-hebrew": "0.0.3-alpha.0",
+        "@ibm/plex-sans-thai": "0.0.3-alpha.0",
+        "@ibm/plex-sans-thai-looped": "0.0.3-alpha.0",
+        "@ibm/plex-serif": "0.0.3-alpha.0",
         "@ibm/telemetry-js": "^1.5.0"
       },
       "peerDependencies": {
       }
     },
     "node_modules/@carbon/themes": {
-      "version": "11.35.0",
-      "resolved": "https://registry.npmjs.org/@carbon/themes/-/themes-11.35.0.tgz",
-      "integrity": "sha512-Sgh8u2JhpOhpfjaj8U2jStmGtLNDGWSLojZdxKl9FnVg1yNe02+IlhnK5bFeCNOGx4dFhrLFIhLtdh9T0Hy8rg==",
+      "version": "11.67.0",
+      "resolved": "https://registry.npmjs.org/@carbon/themes/-/themes-11.67.0.tgz",
+      "integrity": "sha512-sCjmwxvM7nUdsDPef9g2v07Motvd4EYZJJqJyklMfhm9ZJ1oUfwecpW8rLzXylDsOBhrX9s1oCKWG/JqZF3kig==",
       "hasInstallScript": true,
       "dependencies": {
-        "@carbon/colors": "^11.22.0",
-        "@carbon/layout": "^11.22.0",
-        "@carbon/type": "^11.27.0",
+        "@carbon/colors": "^11.46.0",
+        "@carbon/layout": "^11.47.0",
+        "@carbon/type": "^11.53.0",
         "@ibm/telemetry-js": "^1.5.0",
         "color": "^4.0.0"
       }
     },
     "node_modules/@carbon/type": {
-      "version": "11.27.0",
-      "resolved": "https://registry.npmjs.org/@carbon/type/-/type-11.27.0.tgz",
-      "integrity": "sha512-+YsFTKsch8xcdZ7y40K69B+47j86H7u8HEZ9OfymmXfMYAT+73MTfAtwyO3leS9rWGljKIh0h3I+Ga7wxE0Q6w==",
+      "version": "11.53.0",
+      "resolved": "https://registry.npmjs.org/@carbon/type/-/type-11.53.0.tgz",
+      "integrity": "sha512-x3GeJrkvM8wdpBwYbRr6jUsmR2wSRVbIxmPl7kamSFih32+czp7xpt/frG02EAY5xgaEk3N9YCNYspwco42raA==",
       "hasInstallScript": true,
       "dependencies": {
-        "@carbon/grid": "^11.23.0",
-        "@carbon/layout": "^11.22.0",
+        "@carbon/grid": "^11.49.0",
+        "@carbon/layout": "^11.47.0",
         "@ibm/telemetry-js": "^1.5.0"
       }
     },
       "version": "6.4.0",
       "integrity": "sha512-P70hmNoSJhpV6fGG4++JEivoccUVuvkyZoXprsDmPTtv3s6QvL+Q8bK3HFSGmK/VgyLMDptoKPV7b/h/1xaWAw=="
     },
+    "node_modules/@ibm/plex-mono": {
+      "version": "0.0.3-alpha.0",
+      "resolved": "https://registry.npmjs.org/@ibm/plex-mono/-/plex-mono-0.0.3-alpha.0.tgz",
+      "integrity": "sha512-xSa/c1vrzGmMR5xQr/aWP/q62jUD41mKwm2w4kFsvIVyT9fxC3wq81UYMSGBxQZ6+P1AROMSefF22aLXkv6uqw=="
+    },
+    "node_modules/@ibm/plex-sans": {
+      "version": "0.0.3-alpha.0",
+      "resolved": "https://registry.npmjs.org/@ibm/plex-sans/-/plex-sans-0.0.3-alpha.0.tgz",
+      "integrity": "sha512-JU3dmaJiTNL17MO2pTzUJUzYSLZjUmkFUOia9c/2mU4ehqyvw95yQ6G4XRRqEHQdUA7auO4I0GX8mcI8rQk/Tw=="
+    },
+    "node_modules/@ibm/plex-sans-arabic": {
+      "version": "0.0.3-alpha.0",
+      "resolved": "https://registry.npmjs.org/@ibm/plex-sans-arabic/-/plex-sans-arabic-0.0.3-alpha.0.tgz",
+      "integrity": "sha512-tFi6soIKl/A2xWf5/N9kCkMhv+MOcEewWWFM9Bz9U0YO5I4KR0qdUTU7rN4jTjvCJGPExwPFukQKBNz7djuShg=="
+    },
+    "node_modules/@ibm/plex-sans-devanagari": {
+      "version": "0.0.3-alpha.0",
+      "resolved": "https://registry.npmjs.org/@ibm/plex-sans-devanagari/-/plex-sans-devanagari-0.0.3-alpha.0.tgz",
+      "integrity": "sha512-jrhO6KOxwtpw3WaidCNSn+IWqxDyYGSUUP8i4WjmxkBREQNf4fSJwbjzgB79E/Mnhc3b2NZska+41k5owRlIoQ=="
+    },
+    "node_modules/@ibm/plex-sans-hebrew": {
+      "version": "0.0.3-alpha.0",
+      "resolved": "https://registry.npmjs.org/@ibm/plex-sans-hebrew/-/plex-sans-hebrew-0.0.3-alpha.0.tgz",
+      "integrity": "sha512-sMsn1jU8kyYfSlWMfjcbvpGXJIIXGOZD+sxtBcogZz4umnCq5ys+bmsqlzkfGR25DCB49WvseD2IHbejes0/aA=="
+    },
+    "node_modules/@ibm/plex-sans-thai": {
+      "version": "0.0.3-alpha.0",
+      "resolved": "https://registry.npmjs.org/@ibm/plex-sans-thai/-/plex-sans-thai-0.0.3-alpha.0.tgz",
+      "integrity": "sha512-3RteUFhshRTmP5Swq9LYravDXmVvjxtxsZ7qeSqjn31CUgeSuZKprDWb+RzSQrO+Jg7AI4g1lolzTr/jG/LnxA=="
+    },
+    "node_modules/@ibm/plex-sans-thai-looped": {
+      "version": "0.0.3-alpha.0",
+      "resolved": "https://registry.npmjs.org/@ibm/plex-sans-thai-looped/-/plex-sans-thai-looped-0.0.3-alpha.0.tgz",
+      "integrity": "sha512-mcddR5ZcAQx5TjmaxaXd6gTdtOgxlyVaKqjzQAjUbzNQy0cjTGhIJHB5VrFES7yJLRCtQNCNGP+bzupzHOQERw=="
+    },
+    "node_modules/@ibm/plex-serif": {
+      "version": "0.0.3-alpha.0",
+      "resolved": "https://registry.npmjs.org/@ibm/plex-serif/-/plex-serif-0.0.3-alpha.0.tgz",
+      "integrity": "sha512-wuyglvk5dVTiOtRMlGhbRdu9zptl84CHLhjzuWPb2LwU3IiFlVWAirKaRKRv/AFwtAT9RoTtvT7spEyffdCzFw=="
+    },
     "node_modules/@ibm/telemetry-js": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/@ibm/telemetry-js/-/telemetry-js-1.5.1.tgz",
-      "integrity": "sha512-Hu8iJAy9UGvjWjpMmHTNgekr2+b44nvp37RxSdWogpkSO7bPajR3CbDvb0QWAvJ7KnW+VmB3aDi1rlNsIyrZVw==",
+      "version": "1.11.0",
+      "resolved": "https://registry.npmjs.org/@ibm/telemetry-js/-/telemetry-js-1.11.0.tgz",
+      "integrity": "sha512-RO/9j+URJnSfseWg9ZkEX9p+a3Ousd33DBU7rOafoZB08RqdzxFVYJ2/iM50dkBuD0o7WX7GYt1sLbNgCoE+pA==",
       "bin": {
         "ibmtelemetry": "dist/collect.js"
       }
       "integrity": "sha512-sK2/uU5CtmJ51zo0JF2Lc4iSw9Fy3xn9ewfewuooV5Qmeb5O+brAHuoXKMV7UWwRbBmd+txhAXAJoi4S5QLDRQ==",
       "dev": true
     },
+    "node_modules/@types/d3": {
+      "version": "7.4.3",
+      "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz",
+      "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==",
+      "dependencies": {
+        "@types/d3-array": "*",
+        "@types/d3-axis": "*",
+        "@types/d3-brush": "*",
+        "@types/d3-chord": "*",
+        "@types/d3-color": "*",
+        "@types/d3-contour": "*",
+        "@types/d3-delaunay": "*",
+        "@types/d3-dispatch": "*",
+        "@types/d3-drag": "*",
+        "@types/d3-dsv": "*",
+        "@types/d3-ease": "*",
+        "@types/d3-fetch": "*",
+        "@types/d3-force": "*",
+        "@types/d3-format": "*",
+        "@types/d3-geo": "*",
+        "@types/d3-hierarchy": "*",
+        "@types/d3-interpolate": "*",
+        "@types/d3-path": "*",
+        "@types/d3-polygon": "*",
+        "@types/d3-quadtree": "*",
+        "@types/d3-random": "*",
+        "@types/d3-scale": "*",
+        "@types/d3-scale-chromatic": "*",
+        "@types/d3-selection": "*",
+        "@types/d3-shape": "*",
+        "@types/d3-time": "*",
+        "@types/d3-time-format": "*",
+        "@types/d3-timer": "*",
+        "@types/d3-transition": "*",
+        "@types/d3-zoom": "*"
+      }
+    },
+    "node_modules/@types/d3-array": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz",
+      "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="
+    },
+    "node_modules/@types/d3-axis": {
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz",
+      "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==",
+      "dependencies": {
+        "@types/d3-selection": "*"
+      }
+    },
+    "node_modules/@types/d3-brush": {
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz",
+      "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==",
+      "dependencies": {
+        "@types/d3-selection": "*"
+      }
+    },
+    "node_modules/@types/d3-chord": {
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz",
+      "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg=="
+    },
+    "node_modules/@types/d3-color": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz",
+      "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="
+    },
+    "node_modules/@types/d3-contour": {
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz",
+      "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==",
+      "dependencies": {
+        "@types/d3-array": "*",
+        "@types/geojson": "*"
+      }
+    },
+    "node_modules/@types/d3-delaunay": {
+      "version": "6.0.4",
+      "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz",
+      "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw=="
+    },
+    "node_modules/@types/d3-dispatch": {
+      "version": "3.0.7",
+      "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz",
+      "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA=="
+    },
+    "node_modules/@types/d3-drag": {
+      "version": "3.0.7",
+      "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz",
+      "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==",
+      "dependencies": {
+        "@types/d3-selection": "*"
+      }
+    },
+    "node_modules/@types/d3-dsv": {
+      "version": "3.0.7",
+      "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz",
+      "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g=="
+    },
+    "node_modules/@types/d3-ease": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz",
+      "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="
+    },
+    "node_modules/@types/d3-fetch": {
+      "version": "3.0.7",
+      "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz",
+      "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==",
+      "dependencies": {
+        "@types/d3-dsv": "*"
+      }
+    },
+    "node_modules/@types/d3-force": {
+      "version": "3.0.10",
+      "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz",
+      "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw=="
+    },
+    "node_modules/@types/d3-format": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz",
+      "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g=="
+    },
+    "node_modules/@types/d3-geo": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz",
+      "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==",
+      "dependencies": {
+        "@types/geojson": "*"
+      }
+    },
+    "node_modules/@types/d3-hierarchy": {
+      "version": "3.1.7",
+      "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz",
+      "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg=="
+    },
+    "node_modules/@types/d3-interpolate": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz",
+      "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==",
+      "dependencies": {
+        "@types/d3-color": "*"
+      }
+    },
+    "node_modules/@types/d3-path": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz",
+      "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="
+    },
+    "node_modules/@types/d3-polygon": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz",
+      "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA=="
+    },
+    "node_modules/@types/d3-quadtree": {
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz",
+      "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg=="
+    },
+    "node_modules/@types/d3-random": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz",
+      "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ=="
+    },
+    "node_modules/@types/d3-scale": {
+      "version": "4.0.9",
+      "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz",
+      "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==",
+      "dependencies": {
+        "@types/d3-time": "*"
+      }
+    },
+    "node_modules/@types/d3-scale-chromatic": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz",
+      "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ=="
+    },
+    "node_modules/@types/d3-selection": {
+      "version": "3.0.11",
+      "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz",
+      "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w=="
+    },
+    "node_modules/@types/d3-shape": {
+      "version": "3.1.8",
+      "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz",
+      "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==",
+      "dependencies": {
+        "@types/d3-path": "*"
+      }
+    },
+    "node_modules/@types/d3-time": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz",
+      "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="
+    },
+    "node_modules/@types/d3-time-format": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz",
+      "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg=="
+    },
+    "node_modules/@types/d3-timer": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz",
+      "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="
+    },
+    "node_modules/@types/d3-transition": {
+      "version": "3.0.9",
+      "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz",
+      "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==",
+      "dependencies": {
+        "@types/d3-selection": "*"
+      }
+    },
+    "node_modules/@types/d3-zoom": {
+      "version": "3.0.8",
+      "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz",
+      "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==",
+      "dependencies": {
+        "@types/d3-interpolate": "*",
+        "@types/d3-selection": "*"
+      }
+    },
     "node_modules/@types/estree": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
       "version": "2.0.1",
       "integrity": "sha512-g1QUuhYVVAamfCifK7oB7G3aIl4BbOyzDOqVyUfEr4tfBKrXfeH+M+Tg7HKCXSrbzxYdhyCP7z9WbKo0R2hBCw=="
     },
+    "node_modules/@types/geojson": {
+      "version": "7946.0.16",
+      "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
+      "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg=="
+    },
     "node_modules/@types/graceful-fs": {
       "version": "4.1.9",
       "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
       }
     },
     "node_modules/@types/hoist-non-react-statics": {
-      "version": "3.3.6",
-      "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.6.tgz",
-      "integrity": "sha512-lPByRJUer/iN/xa4qpyL0qmL11DqNW81iU/IG1S3uvRUq4oKagz8VCxZjiWkumgt66YT3vOdDgZ0o32sGKtCEw==",
+      "version": "3.3.7",
+      "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.7.tgz",
+      "integrity": "sha512-PQTyIulDkIDro8P+IHbKCsw7U2xxBYflVzW/FgWdCAePD9xGSidgA76/GeJ6lBKoblyhf9pBY763gbrN+1dI8g==",
       "dependencies": {
-        "@types/react": "*",
         "hoist-non-react-statics": "^3.3.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*"
       }
     },
     "node_modules/@types/http-errors": {
       "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
       "dev": true
     },
-    "node_modules/@types/react": {
-      "version": "19.0.12",
-      "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.12.tgz",
-      "integrity": "sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA==",
-      "dependencies": {
-        "csstype": "^3.0.2"
-      }
-    },
-    "node_modules/@types/react-redux": {
-      "version": "7.1.34",
-      "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.34.tgz",
-      "integrity": "sha512-GdFaVjEbYv4Fthm2ZLvj1VSCedV7TqE5y1kNwnjSdBOTXuRSgowux6J8TAct15T3CKBr63UMk+2CO7ilRhyrAQ==",
-      "dependencies": {
-        "@types/hoist-non-react-statics": "^3.3.0",
-        "@types/react": "*",
-        "hoist-non-react-statics": "^3.3.0",
-        "redux": "^4.0.0"
-      }
-    },
     "node_modules/@types/retry": {
       "version": "0.12.2",
       "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz",
       "integrity": "sha512-SlufixEmh+8CLHNgTfAfCT1icNOF7bXboWabhHr1+hIolqlvfwYJGe7HgRcpI3ChE7HWASmEKLkMu34rxseJjQ==",
       "dev": true
     },
+    "node_modules/@types/topojson": {
+      "version": "3.2.6",
+      "resolved": "https://registry.npmjs.org/@types/topojson/-/topojson-3.2.6.tgz",
+      "integrity": "sha512-ppfdlxjxofWJ66XdLgIlER/85RvpGyfOf8jrWf+3kVIjEatFxEZYD/Ea83jO672Xu1HRzd/ghwlbcZIUNHTskw==",
+      "dependencies": {
+        "@types/geojson": "*",
+        "@types/topojson-client": "*",
+        "@types/topojson-server": "*",
+        "@types/topojson-simplify": "*",
+        "@types/topojson-specification": "*"
+      }
+    },
+    "node_modules/@types/topojson-client": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/@types/topojson-client/-/topojson-client-3.1.5.tgz",
+      "integrity": "sha512-C79rySTyPxnQNNguTZNI1Ct4D7IXgvyAs3p9HPecnl6mNrJ5+UhvGNYcZfpROYV2lMHI48kJPxwR+F9C6c7nmw==",
+      "dependencies": {
+        "@types/geojson": "*",
+        "@types/topojson-specification": "*"
+      }
+    },
+    "node_modules/@types/topojson-server": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/@types/topojson-server/-/topojson-server-3.0.4.tgz",
+      "integrity": "sha512-5+ieK8ePfP+K2VH6Vgs1VCt+fO1U8XZHj0UsF+NktaF0DavAo1q3IvCBXgokk/xmtvoPltSUs6vxuR/zMdOE1g==",
+      "dependencies": {
+        "@types/geojson": "*",
+        "@types/topojson-specification": "*"
+      }
+    },
+    "node_modules/@types/topojson-simplify": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@types/topojson-simplify/-/topojson-simplify-3.0.3.tgz",
+      "integrity": "sha512-sBO5UZ0O2dB0bNwo0vut2yLHhj3neUGi9uL7/ROdm8Gs6dtt4jcB9OGDKr+M2isZwQM2RuzVmifnMZpxj4IGNw==",
+      "dependencies": {
+        "@types/geojson": "*",
+        "@types/topojson-specification": "*"
+      }
+    },
+    "node_modules/@types/topojson-specification": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/@types/topojson-specification/-/topojson-specification-1.0.5.tgz",
+      "integrity": "sha512-C7KvcQh+C2nr6Y2Ub4YfgvWvWCgP2nOQMtfhlnwsRL4pYmmwzBS7HclGiS87eQfDOU/DLQpX6GEscviaz4yLIQ==",
+      "dependencies": {
+        "@types/geojson": "*"
+      }
+    },
     "node_modules/@types/tough-cookie": {
       "version": "4.0.5",
       "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
       "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
       "dev": true
     },
+    "node_modules/@types/trusted-types": {
+      "version": "2.0.7",
+      "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
+      "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
+      "optional": true
+    },
     "node_modules/@types/unist": {
       "version": "2.0.10",
       "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz",
       "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="
     },
+    "node_modules/@types/use-sync-external-store": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
+      "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
+    },
     "node_modules/@types/uuid": {
       "version": "3.4.13",
       "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.13.tgz",
     "node_modules/@yarnpkg/lockfile": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz",
-      "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==",
-      "dev": true
+      "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ=="
     },
     "node_modules/abab": {
       "version": "2.0.6",
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
       "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
-      "dev": true,
       "engines": {
         "node": ">= 4.0.0"
       }
       "version": "3.9.0",
       "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
       "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
-      "dev": true,
       "funding": [
         {
           "type": "github",
     "node_modules/commander": {
       "version": "2.20.3",
       "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
-      "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
-      "dev": true
+      "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
     },
     "node_modules/common-path-prefix": {
       "version": "3.0.0",
     "node_modules/concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
-      "dev": true
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
     },
     "node_modules/concat-stream": {
       "version": "1.6.2",
       "version": "7.0.3",
       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
       "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
-      "dev": true,
       "dependencies": {
         "path-key": "^3.1.0",
         "shebang-command": "^2.0.0",
       "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==",
       "dev": true
     },
-    "node_modules/csstype": {
-      "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
-      "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
-    },
     "node_modules/cucumber": {
       "version": "4.2.1",
       "resolved": "https://registry.npmjs.org/cucumber/-/cucumber-4.2.1.tgz",
         "node": ">=0.12"
       }
     },
+    "node_modules/d3": {
+      "version": "7.9.0",
+      "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz",
+      "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==",
+      "dependencies": {
+        "d3-array": "3",
+        "d3-axis": "3",
+        "d3-brush": "3",
+        "d3-chord": "3",
+        "d3-color": "3",
+        "d3-contour": "4",
+        "d3-delaunay": "6",
+        "d3-dispatch": "3",
+        "d3-drag": "3",
+        "d3-dsv": "3",
+        "d3-ease": "3",
+        "d3-fetch": "3",
+        "d3-force": "3",
+        "d3-format": "3",
+        "d3-geo": "3",
+        "d3-hierarchy": "3",
+        "d3-interpolate": "3",
+        "d3-path": "3",
+        "d3-polygon": "3",
+        "d3-quadtree": "3",
+        "d3-random": "3",
+        "d3-scale": "4",
+        "d3-scale-chromatic": "3",
+        "d3-selection": "3",
+        "d3-shape": "3",
+        "d3-time": "3",
+        "d3-time-format": "4",
+        "d3-timer": "3",
+        "d3-transition": "3",
+        "d3-zoom": "3"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "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==",
+      "dependencies": {
+        "internmap": "1 - 2"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-axis": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz",
+      "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-brush": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz",
+      "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==",
+      "dependencies": {
+        "d3-dispatch": "1 - 3",
+        "d3-drag": "2 - 3",
+        "d3-interpolate": "1 - 3",
+        "d3-selection": "3",
+        "d3-transition": "3"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-chord": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz",
+      "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==",
+      "dependencies": {
+        "d3-path": "1 - 3"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-cloud": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/d3-cloud/-/d3-cloud-1.2.8.tgz",
+      "integrity": "sha512-K0qBFkgystNlgFW/ufdwIES5kDiC8cGJxMw4ULzN9UU511v89A6HXs1X8vUPxqurehzqJZS5KzZI4c8McT+4UA==",
+      "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=="
+    },
+    "node_modules/d3-color": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
+      "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-contour": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz",
+      "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==",
+      "dependencies": {
+        "d3-array": "^3.2.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-delaunay": {
+      "version": "6.0.4",
+      "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz",
+      "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==",
+      "dependencies": {
+        "delaunator": "5"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-dispatch": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
+      "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-drag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
+      "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
+      "dependencies": {
+        "d3-dispatch": "1 - 3",
+        "d3-selection": "3"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-dsv": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz",
+      "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==",
+      "dependencies": {
+        "commander": "7",
+        "iconv-lite": "0.6",
+        "rw": "1"
+      },
+      "bin": {
+        "csv2json": "bin/dsv2json.js",
+        "csv2tsv": "bin/dsv2dsv.js",
+        "dsv2dsv": "bin/dsv2dsv.js",
+        "dsv2json": "bin/dsv2json.js",
+        "json2csv": "bin/json2dsv.js",
+        "json2dsv": "bin/json2dsv.js",
+        "json2tsv": "bin/json2dsv.js",
+        "tsv2csv": "bin/dsv2dsv.js",
+        "tsv2json": "bin/dsv2json.js"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-dsv/node_modules/commander": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+      "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/d3-dsv/node_modules/iconv-lite": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+      "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/d3-ease": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
+      "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-fetch": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz",
+      "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==",
+      "dependencies": {
+        "d3-dsv": "1 - 3"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-force": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
+      "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==",
+      "dependencies": {
+        "d3-dispatch": "1 - 3",
+        "d3-quadtree": "1 - 3",
+        "d3-timer": "1 - 3"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-format": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz",
+      "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-geo": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz",
+      "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==",
+      "dependencies": {
+        "d3-array": "2.5.0 - 3"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-hierarchy": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz",
+      "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-interpolate": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
+      "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
+      "dependencies": {
+        "d3-color": "1 - 3"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-path": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
+      "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-polygon": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz",
+      "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-quadtree": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz",
+      "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-random": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz",
+      "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-sankey": {
+      "version": "0.12.3",
+      "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz",
+      "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==",
+      "dependencies": {
+        "d3-array": "1 - 2",
+        "d3-shape": "^1.2.0"
+      }
+    },
+    "node_modules/d3-sankey/node_modules/d3-array": {
+      "version": "2.12.1",
+      "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
+      "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==",
+      "dependencies": {
+        "internmap": "^1.0.0"
+      }
+    },
+    "node_modules/d3-sankey/node_modules/d3-path": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz",
+      "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="
+    },
+    "node_modules/d3-sankey/node_modules/d3-shape": {
+      "version": "1.3.7",
+      "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz",
+      "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==",
+      "dependencies": {
+        "d3-path": "1"
+      }
+    },
+    "node_modules/d3-sankey/node_modules/internmap": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz",
+      "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="
+    },
+    "node_modules/d3-scale": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
+      "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
+      "dependencies": {
+        "d3-array": "2.10.0 - 3",
+        "d3-format": "1 - 3",
+        "d3-interpolate": "1.2.0 - 3",
+        "d3-time": "2.1.1 - 3",
+        "d3-time-format": "2 - 4"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-scale-chromatic": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz",
+      "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==",
+      "dependencies": {
+        "d3-color": "1 - 3",
+        "d3-interpolate": "1 - 3"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-selection": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
+      "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-shape": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
+      "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
+      "dependencies": {
+        "d3-path": "^3.1.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-time": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
+      "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
+      "dependencies": {
+        "d3-array": "2 - 3"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-time-format": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
+      "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
+      "dependencies": {
+        "d3-time": "1 - 3"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-timer": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
+      "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-transition": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
+      "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
+      "dependencies": {
+        "d3-color": "1 - 3",
+        "d3-dispatch": "1 - 3",
+        "d3-ease": "1 - 3",
+        "d3-interpolate": "1 - 3",
+        "d3-timer": "1 - 3"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "peerDependencies": {
+        "d3-selection": "2 - 3"
+      }
+    },
+    "node_modules/d3-zoom": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
+      "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
+      "dependencies": {
+        "d3-dispatch": "1 - 3",
+        "d3-drag": "2 - 3",
+        "d3-interpolate": "1 - 3",
+        "d3-selection": "2 - 3",
+        "d3-transition": "2 - 3"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/dargs": {
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz",
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/date-fns": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
+      "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/kossnocorp"
+      }
+    },
     "node_modules/dateformat": {
       "version": "3.0.3",
       "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/delaunator": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz",
+      "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==",
+      "dependencies": {
+        "robust-predicates": "^3.0.2"
+      }
+    },
     "node_modules/delayed-stream": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
       "dev": true
     },
     "node_modules/dompurify": {
-      "version": "2.3.3",
-      "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.3.tgz",
-      "integrity": "sha512-dqnqRkPMAjOZE0FogZ+ceJNM2dZ3V/yNOuFB7+39qpO93hHhfRpHw3heYQC7DPK9FqbQTfBKUJhiSfz4MvXYwg=="
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.5.tgz",
+      "integrity": "sha512-F9e6wPGtY+8KNMRAVfxeCOHU0/NPWMSENNq4pQctuXRqqdEPW7q3CrLbR5Nse044WwacyjHGOMlvNsBe1y6z9A=="
     },
     "node_modules/domutils": {
       "version": "3.1.0",
         "node": ">=8"
       }
     },
+    "node_modules/find-yarn-workspace-root": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz",
+      "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==",
+      "dependencies": {
+        "micromatch": "^4.0.2"
+      }
+    },
     "node_modules/findit2": {
       "version": "2.2.3",
       "resolved": "https://registry.npmjs.org/findit2/-/findit2-2.2.3.tgz",
       "version": "9.1.0",
       "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
       "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
-      "dev": true,
       "dependencies": {
         "at-least-node": "^1.0.0",
         "graceful-fs": "^4.2.0",
     "node_modules/fs.realpath": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
-      "dev": true
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
     },
     "node_modules/fsevents": {
       "version": "2.3.3",
     "node_modules/graceful-fs": {
       "version": "4.2.11",
       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
-      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
-      "dev": true
+      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
     },
     "node_modules/graphemer": {
       "version": "1.4.0",
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/html-to-image": {
+      "version": "1.11.11",
+      "resolved": "https://registry.npmjs.org/html-to-image/-/html-to-image-1.11.11.tgz",
+      "integrity": "sha512-9gux8QhvjRO/erSnDPv28noDZcPZmYE7e1vFsBLKLlRlKDSqNJYebj6Qz1TGd5lsRV+X+xYyjCKjuZdABinWjA=="
+    },
     "node_modules/htmlescape": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz",
       "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
       "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
       "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
-      "dev": true,
       "dependencies": {
         "once": "^1.3.0",
         "wrappy": "1"
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/internmap": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
+      "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/invariant": {
       "version": "2.2.4",
       "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
       "version": "2.2.1",
       "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
       "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
-      "dev": true,
       "bin": {
         "is-docker": "cli.js"
       },
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/is-dom": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/is-dom/-/is-dom-1.1.0.tgz",
-      "integrity": "sha512-u82f6mvhYxRPKpw8V1N0W8ce1xXwOrQtgGcxl6UCL5zBmZu3is/18K0rR7uFCnMDuAsS/3W54mGL4vsaFUQlEQ==",
-      "dependencies": {
-        "is-object": "^1.0.1",
-        "is-window": "^1.0.2"
-      }
-    },
     "node_modules/is-extendable": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/is-object": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz",
-      "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==",
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
     "node_modules/is-path-inside": {
       "version": "3.0.3",
       "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
       "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==",
       "dev": true
     },
-    "node_modules/is-window": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/is-window/-/is-window-1.0.2.tgz",
-      "integrity": "sha512-uj00kdXyZb9t9RcAUAwMZAnkBUwdYGhYlt7djMXhfyhUCzwNba50tIiBKR7q0l7tdoBtFVw/3JmLY6fI3rmZmg=="
-    },
     "node_modules/is-windows": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
       "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
-      "dev": true,
       "dependencies": {
         "is-docker": "^2.0.0"
       },
     "node_modules/isexe": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
-      "dev": true
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
     },
     "node_modules/isobject": {
       "version": "3.0.1",
       "version": "6.1.0",
       "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
       "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
-      "dev": true,
       "dependencies": {
         "universalify": "^2.0.0"
       },
         "node": ">=0.10.0"
       }
     },
+    "node_modules/klaw-sync": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz",
+      "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==",
+      "dependencies": {
+        "graceful-fs": "^4.1.11"
+      }
+    },
     "node_modules/kleur": {
       "version": "3.0.3",
       "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
       "version": "1.2.8",
       "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
       "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
-      "devOptional": true,
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
       }
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
       "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
-      "devOptional": true,
       "dependencies": {
         "wrappy": "1"
       }
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
       "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
-      "dev": true,
       "engines": {
         "node": ">=0.10.0"
       }
         "node": ">=0.10.0"
       }
     },
+    "node_modules/patch-package": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-7.0.2.tgz",
+      "integrity": "sha512-PMYfL8LXxGIRmxXLqlEaBxzKPu7/SdP13ld6GSfAUJUZRmBDPp8chZs0dpzaAFn9TSPnFiMwkC6PJt6pBiAl8Q==",
+      "dependencies": {
+        "@yarnpkg/lockfile": "^1.1.0",
+        "chalk": "^4.1.2",
+        "ci-info": "^3.7.0",
+        "cross-spawn": "^7.0.3",
+        "find-yarn-workspace-root": "^2.0.0",
+        "fs-extra": "^9.0.0",
+        "klaw-sync": "^6.0.0",
+        "minimist": "^1.2.6",
+        "open": "^7.4.2",
+        "rimraf": "^2.6.3",
+        "semver": "^7.5.3",
+        "slash": "^2.0.0",
+        "tmp": "^0.0.33",
+        "yaml": "^2.2.2"
+      },
+      "bin": {
+        "patch-package": "index.js"
+      },
+      "engines": {
+        "node": ">=14",
+        "npm": ">5"
+      }
+    },
+    "node_modules/patch-package/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/patch-package/node_modules/brace-expansion": {
+      "version": "1.1.12",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+      "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/patch-package/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/patch-package/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/patch-package/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+    },
+    "node_modules/patch-package/node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "deprecated": "Glob versions prior to v9 are no longer supported",
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/patch-package/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/patch-package/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/patch-package/node_modules/open": {
+      "version": "7.4.2",
+      "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz",
+      "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
+      "dependencies": {
+        "is-docker": "^2.0.0",
+        "is-wsl": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/patch-package/node_modules/rimraf": {
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+      "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+      "deprecated": "Rimraf versions prior to v4 are no longer supported",
+      "dependencies": {
+        "glob": "^7.1.3"
+      },
+      "bin": {
+        "rimraf": "bin.js"
+      }
+    },
+    "node_modules/patch-package/node_modules/semver": {
+      "version": "7.7.3",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
+      "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/patch-package/node_modules/slash": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
+      "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/patch-package/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/patch-package/node_modules/yaml": {
+      "version": "2.8.2",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
+      "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
+      "bin": {
+        "yaml": "bin.mjs"
+      },
+      "engines": {
+        "node": ">= 14.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/eemeli"
+      }
+    },
     "node_modules/path-browserify": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
       "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
-      "dev": true,
       "engines": {
         "node": ">=0.10.0"
       }
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
       "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
-      "dev": true,
       "engines": {
         "node": ">=8"
       }
       }
     },
     "node_modules/react-copy-to-clipboard": {
-      "version": "5.0.4",
-      "resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.4.tgz",
-      "integrity": "sha512-IeVAiNVKjSPeGax/Gmkqfa/+PuMTBhutEvFUaMQLwE2tS0EXrAdgOpWDX26bWTXF3HrioorR7lr08NqeYUWQCQ==",
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz",
+      "integrity": "sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==",
       "dependencies": {
-        "copy-to-clipboard": "^3",
-        "prop-types": "^15.5.8"
+        "copy-to-clipboard": "^3.3.1",
+        "prop-types": "^15.8.1"
       },
       "peerDependencies": {
-        "react": "^15.3.0 || ^16.0.0 || ^17.0.0"
+        "react": "^15.3.0 || 16 || 17 || 18"
       }
     },
     "node_modules/react-debounce-input": {
-      "version": "3.2.4",
-      "resolved": "https://registry.npmjs.org/react-debounce-input/-/react-debounce-input-3.2.4.tgz",
-      "integrity": "sha512-fX70bNj0fLEYO2Zcvuh7eh9wOUQ29GIx6r8IxIJlc0i0mpUH++9ax0BhfAYfzndADli3RAMROrZQ014J01owrg==",
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/react-debounce-input/-/react-debounce-input-3.3.0.tgz",
+      "integrity": "sha512-VEqkvs8JvY/IIZvh71Z0TC+mdbxERvYF33RcebnodlsUZ8RSgyKe2VWaHXv4+/8aoOgXLxWrdsYs2hDhcwbUgA==",
       "dependencies": {
         "lodash.debounce": "^4",
-        "prop-types": "^15.7.2"
+        "prop-types": "^15.8.1"
       },
       "peerDependencies": {
-        "react": "^15.3.0 || ^16.0.0 || ^17.0.0"
+        "react": "^15.3.0 || 16 || 17 || 18"
       }
     },
     "node_modules/react-dom": {
       }
     },
     "node_modules/react-inspector": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-5.1.1.tgz",
-      "integrity": "sha512-GURDaYzoLbW8pMGXwYPDBIv6nqei4kK7LPRZ9q9HCZF54wqXz/dnylBp/kfE9XmekBhHvLDdcYeyIwSrvtOiWg==",
-      "dependencies": {
-        "@babel/runtime": "^7.0.0",
-        "is-dom": "^1.0.0",
-        "prop-types": "^15.0.0"
-      },
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-6.0.2.tgz",
+      "integrity": "sha512-x+b7LxhmHXjHoU/VrFAzw5iutsILRoYyDq97EDYdFpPLcvqtEzk4ZSZSQjnFPbr5T57tLXnHcqFYoN1pI6u8uQ==",
       "peerDependencies": {
-        "react": "^16.8.4 || ^17.0.0"
+        "react": "^16.8.4 || ^17.0.0 || ^18.0.0"
       }
     },
     "node_modules/react-is": {
       "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
     },
     "node_modules/react-redux": {
-      "version": "7.2.9",
-      "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz",
-      "integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==",
+      "version": "8.1.3",
+      "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.3.tgz",
+      "integrity": "sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw==",
       "dependencies": {
-        "@babel/runtime": "^7.15.4",
-        "@types/react-redux": "^7.1.20",
+        "@babel/runtime": "^7.12.1",
+        "@types/hoist-non-react-statics": "^3.3.1",
+        "@types/use-sync-external-store": "^0.0.3",
         "hoist-non-react-statics": "^3.3.2",
-        "loose-envify": "^1.4.0",
-        "prop-types": "^15.7.2",
-        "react-is": "^17.0.2"
+        "react-is": "^18.0.0",
+        "use-sync-external-store": "^1.0.0"
       },
       "peerDependencies": {
-        "react": "^16.8.3 || ^17 || ^18"
+        "@types/react": "^16.8 || ^17.0 || ^18.0",
+        "@types/react-dom": "^16.8 || ^17.0 || ^18.0",
+        "react": "^16.8 || ^17.0 || ^18.0",
+        "react-dom": "^16.8 || ^17.0 || ^18.0",
+        "react-native": ">=0.59",
+        "redux": "^4 || ^5.0.0-beta.0"
       },
       "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        },
         "react-dom": {
           "optional": true
         },
         "react-native": {
           "optional": true
+        },
+        "redux": {
+          "optional": true
         }
       }
     },
     "node_modules/react-redux/node_modules/react-is": {
-      "version": "17.0.2",
-      "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
-      "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
+      "version": "18.3.1",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
+      "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
     },
     "node_modules/react-syntax-highlighter": {
       "version": "15.5.0",
         "inherits": "^2.0.1"
       }
     },
+    "node_modules/robust-predicates": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz",
+      "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg=="
+    },
     "node_modules/rollup": {
       "version": "4.22.4",
       "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.4.tgz",
         "queue-microtask": "^1.2.2"
       }
     },
+    "node_modules/rw": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
+      "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="
+    },
     "node_modules/rxjs": {
       "version": "6.6.3",
       "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz",
     "node_modules/safer-buffer": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
-      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
-      "dev": true
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
     },
     "node_modules/sass": {
       "version": "1.77.6",
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
       "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
-      "dev": true,
       "dependencies": {
         "shebang-regex": "^3.0.0"
       },
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
       "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
-      "dev": true,
       "engines": {
         "node": ">=8"
       }
       }
     },
     "node_modules/simple-swizzle": {
-      "version": "0.2.2",
-      "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
-      "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz",
+      "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==",
       "dependencies": {
         "is-arrayish": "^0.3.1"
       }
     },
     "node_modules/simple-swizzle/node_modules/is-arrayish": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
-      "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
+      "version": "0.3.4",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz",
+      "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA=="
     },
     "node_modules/simplebar-angular": {
       "version": "3.2.6",
       }
     },
     "node_modules/swagger-ui": {
-      "version": "4.12.0",
-      "integrity": "sha512-ffNcDTQFWu5dEzJywQ4QEcgQZlBaHaeYCjifuWePds8anzqCZXVpeJSD7RCirUs+8D051YevRSu3ZjqNUNyvrQ==",
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/swagger-ui/-/swagger-ui-5.3.1.tgz",
+      "integrity": "sha512-CT862rtHlHiWoaIpT/VzBTOAdV2cMSkOuQou1oNwXxJujFVaxn54aoOz5NMg00LowAODzPTUQAjI2xPsCYC2wg==",
+      "hasInstallScript": true,
       "dependencies": {
-        "@babel/runtime-corejs3": "^7.16.8",
-        "@braintree/sanitize-url": "=6.0.0",
+        "@babel/runtime-corejs3": "^7.22.6",
+        "@braintree/sanitize-url": "=6.0.2",
         "base64-js": "^1.5.1",
         "classnames": "^2.3.1",
         "css.escape": "1.5.1",
         "deep-extend": "0.6.0",
-        "dompurify": "=2.3.3",
+        "dompurify": "=3.0.5",
         "ieee754": "^1.2.1",
         "immutable": "^3.x.x",
         "js-file-download": "^0.4.12",
         "js-yaml": "=4.1.0",
         "lodash": "^4.17.21",
+        "patch-package": "^7.0.2",
         "prop-types": "^15.8.1",
         "randexp": "^0.5.3",
         "randombytes": "^2.1.0",
         "react": "=17.0.2",
-        "react-copy-to-clipboard": "5.0.4",
-        "react-debounce-input": "=3.2.4",
+        "react-copy-to-clipboard": "5.1.0",
+        "react-debounce-input": "=3.3.0",
         "react-dom": "=17.0.2",
         "react-immutable-proptypes": "2.2.0",
         "react-immutable-pure-component": "^2.2.0",
-        "react-inspector": "^5.1.1",
-        "react-redux": "^7.2.4",
-        "react-syntax-highlighter": "^15.4.5",
+        "react-inspector": "^6.0.1",
+        "react-redux": "^8.1.2",
+        "react-syntax-highlighter": "^15.5.0",
         "redux": "^4.1.2",
         "redux-immutable": "^4.0.0",
         "remarkable": "^2.0.1",
-        "reselect": "^4.1.5",
+        "reselect": "^4.1.8",
         "serialize-error": "^8.1.0",
         "sha.js": "^2.4.11",
-        "swagger-client": "^3.18.5",
-        "url-parse": "^1.5.8",
+        "swagger-client": "^3.20.0",
+        "url-parse": "^1.5.10",
         "xml": "=1.0.1",
         "xml-but-prettier": "^1.0.1",
         "zenscroll": "^4.0.2"
       "version": "0.0.33",
       "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
       "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
-      "dev": true,
       "dependencies": {
         "os-tmpdir": "~1.0.2"
       },
         "node": ">=0.6"
       }
     },
+    "node_modules/topojson-client": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.1.0.tgz",
+      "integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==",
+      "dependencies": {
+        "commander": "2"
+      },
+      "bin": {
+        "topo2geo": "bin/topo2geo",
+        "topomerge": "bin/topomerge",
+        "topoquantize": "bin/topoquantize"
+      }
+    },
     "node_modules/tough-cookie": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz",
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
       "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
-      "dev": true,
       "engines": {
         "node": ">= 10.0.0"
       }
         "node": ">=0.10.0"
       }
     },
+    "node_modules/use-sync-external-store": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
+      "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+      }
+    },
     "node_modules/util": {
       "version": "0.10.4",
       "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
       "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
-      "dev": true,
       "dependencies": {
         "isexe": "^2.0.0"
       },
     "node_modules/wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
-      "devOptional": true
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
     },
     "node_modules/write-file-atomic": {
       "version": "4.0.2",
index b3fc03e2acc7df874ba883a325ee022a8d7213f2..244ffd18bc348f4c99a9b84be09156e7e6631903 100644 (file)
@@ -52,7 +52,8 @@
     "@angular/platform-browser-dynamic": "18.2.11",
     "@angular/router": "18.2.11",
     "@carbon/icons": "11.63.0",
-    "@carbon/styles": "1.57.0",
+    "@carbon/styles": "1.83.0",
+    "@carbon/charts-angular": "1.23.9",
     "@ibm/plex": "6.4.0",
     "@ng-bootstrap/ng-bootstrap": "17.0.1",
     "@ngx-formly/bootstrap": "6.1.1",
@@ -78,7 +79,7 @@
     "rxjs": "6.6.3",
     "simplebar-angular": "3.2.6",
     "stream-browserify": "3.0.0",
-    "swagger-ui": "4.12.0",
+    "swagger-ui": "5.3.1",
     "timers-browserify": "2.0.12",
     "tslib": "2.3.1",
     "xml2js": "0.6.2",
index 256f0df1c0466c83c8bfeeb179cab0301fd49d24..98630293b5ef1e4520439775d5b74d57fe909397 100644 (file)
                 [total]="row.info.bytes_quota"
                 [used]="row.info.bytes_used"
                 [title]="row.name"
-                [showFreeToolTip]="false"
-                customLegend="Quota"
-                [customLegendValue]="row.info.bytes_quota"
                 decimals="2"></cd-usage-bar>
-
   <ng-template #noLimitTpl>
     <span ngbTooltip="Quota limit is not set"
           *ngIf="row.info.bytes_pcent === 'undefined'"
index c5d46bb677012f2f40f017c0d442fde9bb469f4f..5ff07f75eb33c717ae66083c3770f954105281c5 100644 (file)
@@ -33,9 +33,6 @@
                 [total]="row.info.bytes_quota"
                 [used]="row.info.bytes_used"
                 [title]="row.name"
-                [showFreeToolTip]="false"
-                customLegend="Quota"
-                [customLegendValue]="row.info.bytes_quota"
                 decimals="2"></cd-usage-bar>
 
   <ng-template #noLimitTpl>
index e5caef761d46e36cee6728bea7e26c8d4b05fa38..e423834b53ad7bbedf30549018289f9afc802efe 100644 (file)
@@ -1,5 +1,11 @@
 export class CssHelper {
-  propertyValue(propertyName: string): string {
-    return getComputedStyle(document.body).getPropertyValue(`--${propertyName}`);
+  /**
+   * Gets the value of a CSS custom property (CSS variable).
+   * @param propertyName The name of the variable without `--`.
+   * @param element Optional: HTMLElement to scope the variable lookup. Defaults to `document.body`.
+   */
+  propertyValue(propertyName: string, element?: HTMLElement): string {
+    const target = element ?? document.body;
+    return getComputedStyle(target).getPropertyValue(`--${propertyName}`);
   }
 }
index 0d90ff6ee4b9e73fd734a3663b0553c2958d5fff..8b20898dbe8ea0d8915cbfc12cd06aa13d8a5625 100644 (file)
@@ -37,6 +37,7 @@ import {
   ComboBoxModule,
   ProgressIndicatorModule,
   InlineLoadingModule,
+  PanelModule,
   TagModule,
   LinkModule
 } from 'carbon-components-angular';
@@ -89,6 +90,8 @@ import { TearsheetStepComponent } from './tearsheet-step/tearsheet-step.componen
 import InfoIcon from '@carbon/icons/es/information/16';
 import CopyIcon from '@carbon/icons/es/copy/32';
 import { IconComponent } from './icon/icon.component';
+import downloadIcon from '@carbon/icons/es/download/16';
+import { ChartsModule } from '@carbon/charts-angular';
 
 @NgModule({
   imports: [
@@ -129,6 +132,8 @@ import { IconComponent } from './icon/icon.component';
     ProgressIndicatorModule,
     BaseChartDirective,
     InlineLoadingModule,
+    PanelModule,
+    ChartsModule,
     TagModule,
     LinkModule
   ],
@@ -222,6 +227,6 @@ import { IconComponent } from './icon/icon.component';
 })
 export class ComponentsModule {
   constructor(private iconService: IconService) {
-    this.iconService.registerAll([InfoIcon, CopyIcon]);
+    this.iconService.registerAll([InfoIcon, CopyIcon, downloadIcon]);
   }
 }
index e29b0dd8b4be227e2950d0ca39ccb079cb55e3c8..fc9990b7422ac2bb15071ddf5137199055b0e8f9 100644 (file)
@@ -1,45 +1,15 @@
-<ng-template #usageTooltipTpl>
-  <table *ngIf="!showMultisiteTooltip">
-    <tr>
-      <td class="text-left me-1">Used:</td>
-      <td class="text-right"><strong> {{ isBinary ? (used | dimlessBinary) : (used | dimless) }}</strong></td>
-    </tr>
-    <tr *ngIf="calculatePerc && showFreeToolTip">
-      <td class="text-left me-1">Free:</td>
-      <td class="'text-right"><strong>{{ isBinary ? (total - used | dimlessBinary) : (total - used | dimless) }}</strong></td>
-    </tr>
-    <tr *ngIf="customLegend">
-      <td class="text-left me-1">{{ customLegend }}:</td>
-      <td class="text-right"><strong>{{ isBinary ? (customLegendValue | dimlessBinary) : (customLegend[1] | dimless) }}</strong></td>
-    </tr>
-  </table>
-  <table *ngIf="showMultisiteTooltip">
-    <tr>
-      <td class="text-left">Total Shards:&nbsp;</td>
-      <td class="text-right"><strong> {{ total }}</strong></td>
-    </tr>
-    <tr *ngIf="calculatePerc">
-      <td class="text-left">Transferred Shards:&nbsp;</td>
-      <td class="'text-right"><strong>{{ used }}</strong></td>
-    </tr>
-  </table>
+<ng-container *ngIf="customLabel">
+  <ng-container *ngIf="isCustomLabelTemplate; else stringLabel">
+    <ng-container *ngTemplateOutlet="customLabel"></ng-container>
+  </ng-container>
+  <ng-template #stringLabel>
+    <ng-container i18n>{{ customLabel }}</ng-container>
+  </ng-template>
+</ng-container>
+<ibm-meter-chart *ngIf="used >=0 && total > 0; else noDataFound"
+                 [data]="data"
+                 [options]="options">
+</ibm-meter-chart>
+<ng-template #noDataFound>
+  <span i18n>{{noDataText}}</span>
 </ng-template>
-
-<div class="progress"
-     data-placement="left"
-     [ngbTooltip]="usageTooltipTpl">
-  <div class="progress-bar bg-info"
-       [ngClass]="{'bg-warning': warningThreshold && (warningThreshold >= 0) && (usedPercentage/100 >= warningThreshold), 'bg-danger': errorThreshold && (errorThreshold >= 0) && (usedPercentage/100 >= errorThreshold)}"
-       role="progressbar"
-       [attr.aria-label]="{ title }"
-       i18n-aria-label="The title of this usage bar is { title }"
-       [style.width]="usedPercentage + '%'">
-    <span [style.color]="usedPercentage < 60 ? 'black' : 'white'">{{ usedPercentage | number: '1.0-' + decimals }}%</span>
-  </div>
-  <div class="progress-bar bg-freespace"
-       role="progressbar"
-       [attr.aria-label]="{ title }"
-       i18n-aria-label="The title of this usage bar is { title }"
-       [style.width]="freePercentage + '%'">
-  </div>
-</div>
index 3c57015fec799f2421c59c1244f75c6a66e3490e..bba76c558ae82cf6d250c801f68f93134e51e9c7 100644 (file)
@@ -1,35 +1,22 @@
-@use './src/styles/vendor/variables' as vv;
+@use '@carbon/type';
 
-.bg-info {
-  background-color: vv.$primary !important;
-}
-
-.bg-warning {
-  background-color: vv.$warning !important;
-}
-
-.bg-danger {
-  background-color: vv.$danger !important;
-}
+::ng-deep {
+  .cds--cc--chart-wrapper {
+    text {
+      @include type.type-style('heading-01');
 
-.bg-freespace {
-  background-color: vv.$gray-400 !important;
-}
+      font-family: inherit;
+      font-weight: normal;
+    }
+  }
 
-.progress {
-  height: 20px;
-  margin-bottom: 0;
-  position: relative;
+  .meter-tooltip {
+    @include type.type-style('helper-text-01');
 
-  div.progress-bar {
-    position: static;
-  }
+    padding-top: 0.25rem;
 
-  span {
-    color: vv.$white;
-    display: block;
-    font-weight: normal;
-    position: absolute;
-    width: 100%;
+    div {
+      padding-bottom: 0.25rem;
+    }
   }
 }
index 45e6a06b6d37a3d58fcebe17873eca522c338274..a3b6b305feca76f4a54bc28a17345c8c3d398d3c 100644 (file)
@@ -1,10 +1,14 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-
 import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
-
 import { PipesModule } from '~/app/shared/pipes/pipes.module';
 import { configureTestBed } from '~/testing/unit-test-helper';
 import { UsageBarComponent } from './usage-bar.component';
+import { ElementRef } from '@angular/core';
+import { CssHelper } from '../../classes/css-helper';
+
+const mockElementRef = {
+  nativeElement: {}
+};
 
 describe('UsageBarComponent', () => {
   let component: UsageBarComponent;
@@ -12,16 +16,140 @@ describe('UsageBarComponent', () => {
 
   configureTestBed({
     imports: [PipesModule, NgbTooltipModule],
-    declarations: [UsageBarComponent]
+    declarations: [UsageBarComponent],
+    providers: [{ provide: ElementRef, useValue: mockElementRef }, CssHelper]
   });
 
   beforeEach(() => {
     fixture = TestBed.createComponent(UsageBarComponent);
     component = fixture.componentInstance;
+
+    window.getComputedStyle = jest.fn().mockReturnValue({
+      getPropertyValue: (name: string) => {
+        const mockStyles: Record<string, string> = {
+          '--cds-support-info': '#00f',
+          '--cds-support-warning': '#ff0',
+          '--cds-support-danger': '#f00'
+        };
+        return mockStyles[name] || '';
+      }
+    });
+
     fixture.detectChanges();
   });
 
   it('should create', () => {
     expect(component).toBeTruthy();
   });
+
+  it('should get correct CSS variable value', () => {
+    const value = component['getCssVariableValue']('cds-support-info');
+    expect(value.trim()).toBe('#00f');
+  });
+
+  it('should return the correct tooltip string for defaultTooltip', () => {
+    component.total = 100000;
+    component.used = 40000;
+    component.isBinary = false;
+    component.decimals = 2;
+    const normalize = (str: string) => str.replace(/\s+/g, ' ').trim();
+    const tooltip = component['defaultTooltip']();
+    expect(normalize(tooltip)).toContain(
+      normalize(`<div class="meter-tooltip">
+    <div><strong>Used:</strong> 40 k</div>
+    <div><strong>Available:</strong> 60 k</div>
+    <div><strong>Total:</strong> 100 k</div>
+  </div>`)
+    );
+  });
+  it('should return custom breakdown format when customBreakdownFormatter is provided', () => {
+    component.customBreakdownFormatter = jest.fn().mockReturnValue('Custom breakdown format');
+    const breakdownFormatted = component['getBreakdownFormatter']();
+    expect(breakdownFormatted).toBe('Custom breakdown format');
+    expect(component.customBreakdownFormatter).toHaveBeenCalledWith({
+      used: component.used,
+      total: component.total
+    });
+  });
+
+  it('should return custom total format when customTotalFormatter is provided', () => {
+    component.customTotalFormatter = jest.fn().mockReturnValue('Custom total format');
+    const totalFormatted = component['getTotalFormatter']();
+    expect(totalFormatted).toBe('Custom total format');
+    expect(component.customTotalFormatter).toHaveBeenCalledWith(component.total);
+  });
+
+  describe('when enablePercentageLabel is true', () => {
+    beforeEach(() => {
+      component.total = 200;
+      component.used = 50;
+      component.decimals = 2;
+      component.enablePercentageLabel = true;
+    });
+
+    it('should return empty total formatter', () => {
+      const result = component['getTotalFormatter']();
+      expect(result).toBe('');
+    });
+
+    it('should return percentage breakdown formatter', () => {
+      const result = component['getBreakdownFormatter']();
+      expect(result).toBe('25.00%');
+    });
+
+    it('should return "0%" when used is 0', () => {
+      component.used = 0;
+      component.total = 100;
+      expect(component['getBreakdownFormatter']()).toBe('0%');
+    });
+
+    it('should clamp small percentage to 0% if less than 0.01%, otherwise format normally', () => {
+      component.total = 100000000;
+
+      component.used = 5; // 0.000005 => 0.0005%
+      expect(component['getBreakdownFormatter']()).toBe('0%');
+
+      component.used = 10000; // 10000 / 100000000 = 0.01%
+      expect(component['getBreakdownFormatter']()).toBe('0.01%');
+
+      component.used = 500000; // 0.5%
+      expect(component['getBreakdownFormatter']()).toBe('0.50%');
+    });
+  });
+
+  describe('when enablePercentageLabel is false', () => {
+    beforeEach(() => {
+      component.total = 10242424;
+      component.used = 5122424;
+      component.enablePercentageLabel = false;
+      component.decimals = 2;
+      component.isBinary = true;
+    });
+
+    it('should return total with formatted binary value', () => {
+      const result = component['getTotalFormatter']();
+      expect(result).toContain('9.77 MiB total');
+    });
+
+    it('should return used with formatted binary value in breakdown', () => {
+      const result = component['getBreakdownFormatter']();
+      expect(result).toContain('used');
+      expect(result).toContain('4.89 MiB used');
+    });
+
+    it('should return default total format when customTotalFormatter is not provided', () => {
+      component.total = 100000;
+      component.customTotalFormatter = undefined;
+      const totalFormatted = component['getTotalFormatter']();
+      expect(totalFormatted).toContain('97.66 KiB total');
+    });
+
+    it('should return default breakdown format when customBreakdownFormatter is not provided', () => {
+      component.used = 30000;
+      component.total = 100000;
+      component.customBreakdownFormatter = undefined;
+      const breakdownFormatted = component['getBreakdownFormatter']();
+      expect(breakdownFormatted).toContain('29.3 KiB used');
+    });
+  });
 });
index f147227eb1bc5415aac73890cca22c47412b1ac6..15177f1b1322e2be6a764f5fa7a08e2d5656ae82 100644 (file)
-import { Component, Input, OnChanges } from '@angular/core';
+import { Component, Input, ElementRef, OnInit, TemplateRef } from '@angular/core';
+import { ChartTabularData, MeterChartOptions, Statuses } from '@carbon/charts-angular';
+import { StatusToCssMap } from '../../enum/usage-bar-chart.enum';
+import { CssHelper } from '../../classes/css-helper';
+import { DimlessBinaryPipe } from '../../pipes/dimless-binary.pipe';
+import { DimlessPipe } from '../../pipes/dimless.pipe';
 
-import _ from 'lodash';
+const PRIMARY_COLOR = 'primary'; // Default theme primary color variable
 
 @Component({
   selector: 'cd-usage-bar',
   templateUrl: './usage-bar.component.html',
   styleUrls: ['./usage-bar.component.scss']
 })
-export class UsageBarComponent implements OnChanges {
-  @Input()
-  total: number;
-  @Input()
-  used: any;
-  @Input()
-  warningThreshold?: number;
-  @Input()
-  errorThreshold?: number;
-  @Input()
-  isBinary = true;
-  @Input()
-  decimals = 0;
-  @Input()
-  calculatePerc = true;
-  @Input()
-  title = $localize`usage`;
-  @Input()
-  customLegend?: string;
-  @Input()
-  customLegendValue?: string;
-  @Input()
-  showFreeToolTip = true;
-  @Input()
-  showMultisiteTooltip = false;
-
-  usedPercentage: number;
-  freePercentage: number;
-
-  ngOnChanges() {
-    if (this.calculatePerc) {
-      this.usedPercentage = this.total > 0 ? (this.used / this.total) * 100 : 0;
-      this.freePercentage = 100 - this.usedPercentage;
-    } else {
-      if (this.used) {
-        this.used = this.used.slice(0, -1);
-        this.usedPercentage = Number(this.used);
-        this.freePercentage = 100 - this.usedPercentage;
-      } else {
-        this.usedPercentage = 0;
+export class UsageBarComponent implements OnInit {
+  // Total amount of resource (e.g., disk, memory) available, in bytes.
+  @Input({ required: true }) total: number = 0;
+
+  // Amount of resource currently used, in bytes.
+  @Input({ required: true }) used: number = 0;
+
+  // Optional label or title for the chart, used in legends and tooltips.
+  @Input() title: string = '';
+
+  // Threshold (0–1) to mark the start of the "warning" zone (e.g., 0.5 = 50%).
+  @Input() warningThreshold: number;
+
+  // Threshold (0–1) to mark the start of the "danger" zone (e.g., 0.8 = 80%).
+  @Input() errorThreshold: number;
+
+  /**
+   * If true, values are formatted using binary units (e.g., KiB, MiB).
+   * If false, decimal units are used (e.g., kB, MB).
+   */
+  @Input() isBinary: boolean = true;
+
+  // Number of decimal places to show in formatted numbers.
+  @Input() decimals: number = 2;
+
+  // Height of the chart component (CSS units like `rem`, `px`, `%`).
+  @Input() height: string = '2rem';
+
+  // Width of the chart component (CSS units like `rem`, `px`, `%`).
+  @Input() width: string = '15rem';
+
+  // Custom unit label for the total value (e.g., "B", "kB", "requests").
+  @Input() totalUnit: string = 'B';
+
+  // Whether chart animations are enabled (e.g., grow bars on change).
+  @Input() animations: boolean = false;
+
+  // Enables the legend section (useful for grouped charts).
+  @Input() legendEnabled: boolean = false;
+
+  // Enables the toolbar (for exporting, toggling datasets, etc., depending on chart lib).
+  @Input() toolbarEnabled: boolean = false;
+
+  // Text to display when `total` is zero or there’s no data.
+  @Input() noDataText: string = '-';
+
+  /**
+   * If true, breakdown is shown as a percentage (e.g., "75% used").
+   * When false, raw values like "750 MB used" are shown instead.
+   */
+  @Input() enablePercentageLabel: boolean = true;
+
+  // Optional custom label (e.g., <ng-template><div>Capacity</div></<ng-template>) (overrides default label).
+  @Input() customLabel: TemplateRef<any> | string = '';
+
+  // Custom tooltip options passed directly to the chart library.
+  @Input() tooltipOptions?: MeterChartOptions['tooltip'] = {};
+
+  // Optional override for the default color scale (e.g., { Memory: "#ff0000" }).
+  @Input() customColorScale?: { [key: string]: string };
+
+  /**
+   * Optional custom formatter for the total value (overrides default formatter).
+   * Example usage: (total) => `${total} requests`
+   */
+  @Input() customTotalFormatter?: (total: number) => string;
+
+  /**
+   * Optional custom formatter for the breakdown section (overrides default formatter).
+   * Example usage: ({ used, total }) => `${used} of ${total} used`
+   */
+  @Input() customBreakdownFormatter?: (x: { used: number; total: number }) => string;
+
+  data: ChartTabularData = [];
+  options: MeterChartOptions = {};
+
+  constructor(
+    private elementRef: ElementRef,
+    private cssHelper: CssHelper,
+    private dimlessPipe: DimlessPipe,
+    private dimlessBinaryPipe: DimlessBinaryPipe
+  ) {}
+
+  get isCustomLabelTemplate(): boolean {
+    return this.customLabel instanceof TemplateRef;
+  }
+
+  ngOnInit(): void {
+    const chartData: ChartTabularData = [{ group: this.title || '', value: this.used }];
+    let thresholds: MeterChartOptions['meter']['status']['ranges'] = [];
+    if (this.warningThreshold && this.errorThreshold) {
+      thresholds = [
+        {
+          range: [this.total * this.warningThreshold, this.total * this.errorThreshold],
+          status: Statuses.WARNING
+        },
+        { range: [this.total * this.errorThreshold, this.total], status: Statuses.DANGER }
+      ];
+    }
+    const colorScale = this.customColorScale || {
+      [this.title || '']: this.getStatusFromThresholds(this.used, thresholds)
+    };
+
+    const chartOptions: MeterChartOptions = {
+      legend: { enabled: this.legendEnabled },
+      toolbar: { enabled: this.toolbarEnabled },
+      tooltip: {
+        enabled: true,
+        ...this.tooltipOptions,
+        customHTML: this.tooltipOptions?.customHTML || (() => this.defaultTooltip())
+      },
+      animations: this.animations,
+      height: this.height,
+      width: this.width,
+      color: { scale: colorScale },
+      meter: {
+        showLabels: !this.customLabel,
+        proportional: {
+          total: this.total,
+          unit: this.totalUnit,
+          totalFormatter: () => this.getTotalFormatter(),
+          breakdownFormatter: () => this.getBreakdownFormatter()
+        }
+      }
+    };
+    if (thresholds.length > 0) {
+      chartOptions.meter = {
+        ...chartOptions.meter,
+        status: {
+          ranges: thresholds
+        }
+      };
+    }
+    this.data = chartData;
+    this.options = chartOptions;
+  }
+
+  private getStatusFromThresholds(
+    value: number,
+    thresholds: MeterChartOptions['meter']['status']['ranges']
+  ): string {
+    for (const threshold of thresholds) {
+      const [min, max] = threshold.range;
+      if (value >= min && value < max) {
+        return this.getCssVariableValue(
+          StatusToCssMap[threshold.status as keyof typeof StatusToCssMap]
+        );
+      }
+    }
+    return this.getCssVariableValue(PRIMARY_COLOR);
+  }
+
+  private getCssVariableValue(variableName: string): string {
+    return this.cssHelper.propertyValue(variableName, this.elementRef.nativeElement);
+  }
+
+  private formatValue(value: number): string {
+    return this.isBinary
+      ? this.dimlessBinaryPipe.transform(value, this.decimals)
+      : this.dimlessPipe.transform(value, this.decimals);
+  }
+
+  private defaultTooltip(): string {
+    const used = this.formatValue(this.used);
+    const available = this.formatValue(this.total - this.used);
+    const total = this.formatValue(this.total);
+    return `<div class="meter-tooltip">
+      <div><strong>Used:</strong> ${used}</div>
+      <div><strong>Available:</strong> ${available}</div>
+      <div><strong>Total:</strong> ${total}</div>
+    </div>`;
+  }
+
+  private getTotalFormatter(): string {
+    if (this.customTotalFormatter) {
+      return this.customTotalFormatter!(this.total);
+    }
+    if (this.enablePercentageLabel && this.total > 0) {
+      return '';
+    }
+
+    return $localize`${this.formatValue(this.total)} total`;
+  }
+
+  private getBreakdownFormatter(): string {
+    if (this.customBreakdownFormatter) {
+      return this.customBreakdownFormatter!({ used: this.used, total: this.total });
+    }
+
+    if (this.enablePercentageLabel && this.total > 0) {
+      const percentage = (this.used / this.total) * 100;
+      if (percentage < 0.01) {
+        return '0%';
       }
+
+      const formatted = percentage.toFixed(this.decimals);
+      return `${formatted}%`;
     }
+
+    return $localize`${this.formatValue(this.used)} used`;
   }
 }
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/enum/usage-bar-chart.enum.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/enum/usage-bar-chart.enum.ts
new file mode 100644 (file)
index 0000000..16a388a
--- /dev/null
@@ -0,0 +1,7 @@
+import { Statuses } from '@carbon/charts-angular';
+
+export const StatusToCssMap: Record<Statuses, string> = {
+  [Statuses.SUCCESS]: 'cds-support-success',
+  [Statuses.WARNING]: 'cds-support-warning',
+  [Statuses.DANGER]: 'cds-support-error'
+};
index cb2d8c64fe8de1b3fb2fb7ce8fc4b9240bc88d5f..f971cf529f36d04630f240bcc17a9c9bbcc094da 100644 (file)
@@ -5,3 +5,22 @@ Object.defineProperty(window, 'getComputedStyle', {
     }
   })
 });
+
+/* Carbon Charts (via @carbon/charts or @carbon/charts-angular) uses ResizeObserver
+  to automatically adjust chart size on container resize, and it expects it to be
+  available globally — which isn’t the case in unit tests.
+*/
+Object.defineProperty(window, 'ResizeObserver', {
+  writable: true,
+  configurable: true,
+  value: class {
+    observe() {}
+    unobserve() {}
+    disconnect() {}
+  }
+});
+
+Object.defineProperty(SVGElement.prototype, 'getComputedTextLength', {
+  configurable: true,
+  value: () => 100 // or any realistic number
+});
index 5f4055d939b9c04c95c0ba7fea12bc28cada5e20..ac64fd717f7388b0484a319c3685808f9ba0fa2c 100644 (file)
@@ -1,6 +1,8 @@
 /* You can add global styles to this file, and also import other style files */
 @use './src/styles/defaults' as *;
 @use '@carbon/colors';
+@use '@carbon/charts/styles.css' as *;
+
 @import './src/styles/carbon-defaults.scss';
 
 // Fork-Awesome