diff --git a/package-lock.json b/package-lock.json
index 9812f9f7..e4c5a855 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,6 +11,8 @@
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.28.6",
+ "@carbon/react": "^1.100.0",
+ "@carbon/styles": "^1.99.0",
"@date-io/core": "^3.2.0",
"@date-io/date-fns": "^3.2.1",
"@emotion/react": "^11.14.0",
@@ -546,6 +548,173 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@carbon/colors": {
+ "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.32.0",
+ "resolved": "https://registry.npmjs.org/@carbon/feature-flags/-/feature-flags-0.32.0.tgz",
+ "integrity": "sha512-a1rFplSEFPwJ4ZsuwvOaKHgoLqPNhjCJdWY6VTgCoytRZqtgYWqwYFEqQkm9/f1mX1lHr6oK/eBpAcmi0Izuvg==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@ibm/telemetry-js": "^1.5.0"
+ }
+ },
+ "node_modules/@carbon/grid": {
+ "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.47.0",
+ "@ibm/telemetry-js": "^1.5.0"
+ }
+ },
+ "node_modules/@carbon/icon-helpers": {
+ "version": "10.71.0",
+ "resolved": "https://registry.npmjs.org/@carbon/icon-helpers/-/icon-helpers-10.71.0.tgz",
+ "integrity": "sha512-T6KcxkNIa609jPC+8A7u5husSY+mH60lCNNa3ivcOyuREoVYHwnieM7GIECigF/oaGaF5eBzrxYFx2+8mLRk1A==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@ibm/telemetry-js": "^1.5.0"
+ }
+ },
+ "node_modules/@carbon/icons-react": {
+ "version": "11.74.0",
+ "resolved": "https://registry.npmjs.org/@carbon/icons-react/-/icons-react-11.74.0.tgz",
+ "integrity": "sha512-tP/ZwM3e86zDm/8mup1NoObdaBl2xqZlroWP/Z1PQ9bCYOOFelR6r34aObWiDBJVpKb5YwwZWYUrl+/98fmDRQ==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@carbon/icon-helpers": "^10.71.0",
+ "@ibm/telemetry-js": "^1.5.0",
+ "prop-types": "^15.8.1"
+ },
+ "peerDependencies": {
+ "react": ">=16"
+ }
+ },
+ "node_modules/@carbon/layout": {
+ "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.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/react": {
+ "version": "1.100.0",
+ "resolved": "https://registry.npmjs.org/@carbon/react/-/react-1.100.0.tgz",
+ "integrity": "sha512-QlJ/bqiQn3fF3EX1YfVN3+zYvbqiGuMULtsI+wtuMaoEOJcR9FBwUYSP4w7lXTCxQ7WkB/wTLrekVcGgRoNquQ==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@babel/runtime": "^7.27.3",
+ "@carbon/feature-flags": ">=0.32.0",
+ "@carbon/icons-react": "^11.74.0",
+ "@carbon/layout": "^11.47.0",
+ "@carbon/styles": "^1.99.0",
+ "@carbon/utilities": "^0.15.0",
+ "@floating-ui/react": "^0.27.4",
+ "@ibm/telemetry-js": "^1.5.0",
+ "classnames": "2.5.1",
+ "copy-to-clipboard": "^3.3.1",
+ "downshift": "9.0.10",
+ "es-toolkit": "^1.27.0",
+ "flatpickr": "4.6.13",
+ "invariant": "^2.2.3",
+ "prop-types": "^15.8.1",
+ "react-fast-compare": "^3.2.2",
+ "tabbable": "^6.2.0"
+ },
+ "peerDependencies": {
+ "react": "^16.8.6 || ^17.0.1 || ^18.2.0 || ^19.0.0",
+ "react-dom": "^16.8.6 || ^17.0.1 || ^18.2.0 || ^19.0.0",
+ "react-is": "^16.13.1 || ^17.0.2 || ^18.3.1 || ^19.0.0",
+ "sass": "^1.33.0"
+ }
+ },
+ "node_modules/@carbon/styles": {
+ "version": "1.99.0",
+ "resolved": "https://registry.npmjs.org/@carbon/styles/-/styles-1.99.0.tgz",
+ "integrity": "sha512-71iypyzR97h6Z94XRZyel3IEo4+n9TRylKdsYUJASNs7GNIjsIBlwKRn+upUktsyWVNTV1iQ9uzo3UkFcRiEFQ==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@carbon/colors": "^11.46.0",
+ "@carbon/feature-flags": ">=0.32.0",
+ "@carbon/grid": "^11.49.0",
+ "@carbon/layout": "^11.47.0",
+ "@carbon/motion": "^11.40.0",
+ "@carbon/themes": "^11.67.0",
+ "@carbon/type": "^11.53.0",
+ "@ibm/plex": "6.0.0-next.6",
+ "@ibm/plex-mono": "1.1.0",
+ "@ibm/plex-sans": "1.1.0",
+ "@ibm/plex-sans-arabic": "1.1.0",
+ "@ibm/plex-sans-devanagari": "1.1.0",
+ "@ibm/plex-sans-hebrew": "1.1.0",
+ "@ibm/plex-sans-thai": "1.1.0",
+ "@ibm/plex-sans-thai-looped": "1.1.0",
+ "@ibm/plex-serif": "1.1.0",
+ "@ibm/telemetry-js": "^1.5.0"
+ },
+ "peerDependencies": {
+ "sass": "^1.33.0"
+ },
+ "peerDependenciesMeta": {
+ "sass": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@carbon/themes": {
+ "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.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.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.49.0",
+ "@carbon/layout": "^11.47.0",
+ "@ibm/telemetry-js": "^1.5.0"
+ }
+ },
+ "node_modules/@carbon/utilities": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/@carbon/utilities/-/utilities-0.15.0.tgz",
+ "integrity": "sha512-bwneNtLk8khoSIsilr6fBl115BMBrCMqxo/LjwAYiA+GiHes4URC4QYUihg+Ida5bCDpMixDx3RI9IW1UodXLQ==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@ibm/telemetry-js": "^1.6.1",
+ "@internationalized/number": "^3.6.1"
+ }
+ },
"node_modules/@date-io/core": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@date-io/core/-/core-3.2.0.tgz",
@@ -721,6 +890,150 @@
"integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
"license": "MIT"
},
+ "node_modules/@floating-ui/core": {
+ "version": "1.7.4",
+ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.4.tgz",
+ "integrity": "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==",
+ "dependencies": {
+ "@floating-ui/utils": "^0.2.10"
+ }
+ },
+ "node_modules/@floating-ui/dom": {
+ "version": "1.7.5",
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.5.tgz",
+ "integrity": "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==",
+ "dependencies": {
+ "@floating-ui/core": "^1.7.4",
+ "@floating-ui/utils": "^0.2.10"
+ }
+ },
+ "node_modules/@floating-ui/react": {
+ "version": "0.27.17",
+ "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.17.tgz",
+ "integrity": "sha512-LGVZKHwmWGg6MRHjLLgsfyaX2y2aCNgnD1zT/E6B+/h+vxg+nIJUqHPAlTzsHDyqdgEpJ1Np5kxWuFEErXzoGg==",
+ "dependencies": {
+ "@floating-ui/react-dom": "^2.1.7",
+ "@floating-ui/utils": "^0.2.10",
+ "tabbable": "^6.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=17.0.0",
+ "react-dom": ">=17.0.0"
+ }
+ },
+ "node_modules/@floating-ui/react-dom": {
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.7.tgz",
+ "integrity": "sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==",
+ "dependencies": {
+ "@floating-ui/dom": "^1.7.5"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@floating-ui/utils": {
+ "version": "0.2.10",
+ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz",
+ "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="
+ },
+ "node_modules/@ibm/plex": {
+ "version": "6.0.0-next.6",
+ "resolved": "https://registry.npmjs.org/@ibm/plex/-/plex-6.0.0-next.6.tgz",
+ "integrity": "sha512-B3uGruTn2rS5gweynLmfSe7yCawSRsJguJJQHVQiqf4rh2RNgJFu8YLE2Zd/JHV0ZXoVMOslcXP2k3hMkxKEyA==",
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@ibm/plex-mono": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@ibm/plex-mono/-/plex-mono-1.1.0.tgz",
+ "integrity": "sha512-hpsdRxR3BRJkC6wGM4MZcUFD6C8M+mmK76RtAy/hlsfPro9FzpXVdIWC+G3jeQOXof109dxlUvmeKxpeKUG68A==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@ibm/telemetry-js": "^1.6.1"
+ }
+ },
+ "node_modules/@ibm/plex-sans": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@ibm/plex-sans/-/plex-sans-1.1.0.tgz",
+ "integrity": "sha512-WPgvO6Yfj2w5YbhyAr1tv95RUz4LRJlqN+CmYvBglabXteufP1D1E9BABMde+ZIKdRbFJDoKF5eQzfhpnbgZcQ==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@ibm/telemetry-js": "^1.6.1"
+ }
+ },
+ "node_modules/@ibm/plex-sans-arabic": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@ibm/plex-sans-arabic/-/plex-sans-arabic-1.1.0.tgz",
+ "integrity": "sha512-u8wIS6szLAOFvlBjCFZmtpKIqbhuIuniG2N0J+sio8vV6INH58hP0t0QNYrSl9SZtCv2Fwb4oQGuZJY3kJ4+QA==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@ibm/telemetry-js": "^1.6.1"
+ }
+ },
+ "node_modules/@ibm/plex-sans-devanagari": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@ibm/plex-sans-devanagari/-/plex-sans-devanagari-1.1.0.tgz",
+ "integrity": "sha512-IVNV9NxXZDzcGZRao/xj+kiFwkdLkcw5vNiKwY8wEzzkpjApXJnPhJ0a7mIKNAh8oIadTIF68+iGtzRKK3nXAQ==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@ibm/telemetry-js": "^1.6.1"
+ }
+ },
+ "node_modules/@ibm/plex-sans-hebrew": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@ibm/plex-sans-hebrew/-/plex-sans-hebrew-1.1.0.tgz",
+ "integrity": "sha512-iix0rLpUD0E8dE8q+/t3B7u1or7h6gEzoy6TK9NwP41AN31WE55f2cFwQAXomBDwr0Ozc9sHYy97NutEukZXzQ==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@ibm/telemetry-js": "^1.6.1"
+ }
+ },
+ "node_modules/@ibm/plex-sans-thai": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@ibm/plex-sans-thai/-/plex-sans-thai-1.1.0.tgz",
+ "integrity": "sha512-vk7IrjdO69eEElJpFBppCha/wvU48DFyVuDewcfIf5L6Z11s0vbROANCvKipVPRUz1LE4ron8KoitWGcl3AlfA==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@ibm/telemetry-js": "^1.6.1"
+ }
+ },
+ "node_modules/@ibm/plex-sans-thai-looped": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@ibm/plex-sans-thai-looped/-/plex-sans-thai-looped-1.1.0.tgz",
+ "integrity": "sha512-9zbDGzmtscHgBRTF88y3/92zQx6lmKjz5ZxhgcljilwOpj08BAytDc3mzUl9XGUh+DmOMl0Ql1lk6ecsEYYg2w==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@ibm/telemetry-js": "^1.6.1"
+ }
+ },
+ "node_modules/@ibm/plex-serif": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@ibm/plex-serif/-/plex-serif-1.1.0.tgz",
+ "integrity": "sha512-ORIyWlK8t8mvpFI7AAfhVFH+sacink2l9AjLiKZscmAzLVSa2dqFckrPOXqx4dK/cax567gWwCpJNEYk7xWxBQ==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@ibm/telemetry-js": "^1.6.1"
+ }
+ },
+ "node_modules/@ibm/telemetry-js": {
+ "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"
+ }
+ },
+ "node_modules/@internationalized/number": {
+ "version": "3.6.5",
+ "resolved": "https://registry.npmjs.org/@internationalized/number/-/number-3.6.5.tgz",
+ "integrity": "sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g==",
+ "dependencies": {
+ "@swc/helpers": "^0.5.0"
+ }
+ },
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
@@ -2709,7 +3022,7 @@
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz",
"integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
- "dev": true,
+ "devOptional": true,
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -3307,7 +3620,6 @@
"version": "0.5.17",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz",
"integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==",
- "dev": true,
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.8.0"
@@ -3558,7 +3870,7 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"fill-range": "^7.1.1"
@@ -3686,6 +3998,21 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
+ "node_modules/chokidar": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+ "peer": true,
+ "dependencies": {
+ "readdirp": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 14.16.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
"node_modules/chrome-trace-event": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
@@ -3696,6 +4023,11 @@
"node": ">=6.0"
}
},
+ "node_modules/classnames": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
+ "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="
+ },
"node_modules/clone": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
@@ -3715,11 +4047,22 @@
"node": ">=6"
}
},
+ "node_modules/color": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
+ "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
+ "dependencies": {
+ "color-convert": "^2.0.1",
+ "color-string": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=12.5.0"
+ }
+ },
"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==",
- "dev": true,
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
@@ -3732,9 +4075,17 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true,
"license": "MIT"
},
+ "node_modules/color-string": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+ "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -3757,6 +4108,11 @@
"node": ">=18"
}
},
+ "node_modules/compute-scroll-into-view": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.1.tgz",
+ "integrity": "sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw=="
+ },
"node_modules/convert-source-map": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
@@ -3773,6 +4129,14 @@
"node": ">=18"
}
},
+ "node_modules/copy-to-clipboard": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz",
+ "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==",
+ "dependencies": {
+ "toggle-selection": "^1.0.6"
+ }
+ },
"node_modules/core-js-compat": {
"version": "3.46.0",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.46.0.tgz",
@@ -3976,7 +4340,7 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
- "dev": true,
+ "devOptional": true,
"license": "Apache-2.0",
"bin": {
"detect-libc": "bin/detect-libc.js"
@@ -4079,6 +4443,26 @@
"url": "https://dotenvx.com"
}
},
+ "node_modules/downshift": {
+ "version": "9.0.10",
+ "resolved": "https://registry.npmjs.org/downshift/-/downshift-9.0.10.tgz",
+ "integrity": "sha512-TP/iqV6bBok6eGD5tZ8boM8Xt7/+DZvnVNr8cNIhbAm2oUBd79Tudiccs2hbcV9p7xAgS/ozE7Hxy3a9QqS6Mw==",
+ "dependencies": {
+ "@babel/runtime": "^7.24.5",
+ "compute-scroll-into-view": "^3.1.0",
+ "prop-types": "^15.8.1",
+ "react-is": "18.2.0",
+ "tslib": "^2.6.2"
+ },
+ "peerDependencies": {
+ "react": ">=16.12.0"
+ }
+ },
+ "node_modules/downshift/node_modules/react-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+ },
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
@@ -4208,7 +4592,7 @@
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
@@ -4223,6 +4607,11 @@
"integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
"license": "MIT"
},
+ "node_modules/flatpickr": {
+ "version": "4.6.13",
+ "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.13.tgz",
+ "integrity": "sha512-97PMG/aywoYpB4IvbvUJi0RQi8vearvU0oov1WW3k0WZPBMrTQVqekSX5CjSG/M4Q3i6A/0FKXC7RyAoAUUSPw=="
+ },
"node_modules/follow-redirects": {
"version": "1.15.11",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
@@ -4481,6 +4870,12 @@
"url": "https://opencollective.com/immer"
}
},
+ "node_modules/immutable": {
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz",
+ "integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==",
+ "peer": true
+ },
"node_modules/import-fresh": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
@@ -4506,6 +4901,14 @@
"node": ">=12"
}
},
+ "node_modules/invariant": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+ "dependencies": {
+ "loose-envify": "^1.0.0"
+ }
+ },
"node_modules/is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
@@ -4531,7 +4934,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -4541,7 +4944,7 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
@@ -4554,7 +4957,7 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=0.12.0"
@@ -5000,7 +5403,7 @@
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"braces": "^3.0.3",
@@ -5101,7 +5504,7 @@
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT"
},
"node_modules/node-gyp-build-optional-packages": {
@@ -5248,7 +5651,7 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=8.6"
@@ -5334,6 +5737,11 @@
"react": "^19.2.3"
}
},
+ "node_modules/react-fast-compare": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
+ "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="
+ },
"node_modules/react-is": {
"version": "19.2.3",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.3.tgz",
@@ -5411,6 +5819,19 @@
"react-dom": ">=16.6.0"
}
},
+ "node_modules/readdirp": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+ "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+ "peer": true,
+ "engines": {
+ "node": ">= 14.18.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
"node_modules/recharts": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/recharts/-/recharts-3.6.0.tgz",
@@ -5519,6 +5940,26 @@
],
"license": "MIT"
},
+ "node_modules/sass": {
+ "version": "1.97.3",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.3.tgz",
+ "integrity": "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==",
+ "peer": true,
+ "dependencies": {
+ "chokidar": "^4.0.0",
+ "immutable": "^5.0.2",
+ "source-map-js": ">=0.6.2 <2.0.0"
+ },
+ "bin": {
+ "sass": "sass.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "optionalDependencies": {
+ "@parcel/watcher": "^2.4.1"
+ }
+ },
"node_modules/scheduler": {
"version": "0.27.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
@@ -5560,6 +6001,19 @@
"node": ">=11.0"
}
},
+ "node_modules/simple-swizzle": {
+ "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.4",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz",
+ "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA=="
+ },
"node_modules/source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@@ -5569,6 +6023,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "peer": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/stylis": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
@@ -5600,6 +6063,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/tabbable": {
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz",
+ "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg=="
+ },
"node_modules/term-size": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz",
@@ -5623,7 +6091,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
@@ -5632,11 +6100,15 @@
"node": ">=8.0"
}
},
+ "node_modules/toggle-selection": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
+ "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ=="
+ },
"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==",
- "dev": true,
"license": "0BSD"
},
"node_modules/type-fest": {
diff --git a/package.json b/package.json
index a2853f42..d8dbb12b 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,8 @@
],
"dependencies": {
"@babel/runtime": "^7.28.6",
+ "@carbon/react": "^1.100.0",
+ "@carbon/styles": "^1.99.0",
"@date-io/core": "^3.2.0",
"@date-io/date-fns": "^3.2.1",
"@emotion/react": "^11.14.0",
diff --git a/src/app.js b/src/app.js
index acaca9ad..ac9f7c0b 100644
--- a/src/app.js
+++ b/src/app.js
@@ -1,5 +1,6 @@
import { createRoot } from "react-dom/client";
import Routes from "./route";
+import "@carbon/styles/css/styles.css";
const root = createRoot(document.getElementById("app"));
root.render( );
diff --git a/src/components/AssetsCosts/Charts/assetByTypeTabs.js b/src/components/AssetsCosts/Charts/assetByTypeTabs.js
new file mode 100644
index 00000000..53e56f24
--- /dev/null
+++ b/src/components/AssetsCosts/Charts/assetByTypeTabs.js
@@ -0,0 +1,53 @@
+import { Tabs, TabList, Tab, TabPanels, TabPanel } from "@carbon/react";
+
+function AssetsByTypeTabs({ data, aggregationOptions }) {
+ if (!Array.isArray(data) || data.length === 0) {
+ return null;
+ }
+function formatDate(iso) {
+ if (!iso) return "-";
+ return iso.split("T")[0]; // YYYY-MM-DD
+ }
+ function filterByType(data, type) {
+ if (!Array.isArray(data)) return [];
+
+ return data.filter(item => item.type?.toLowerCase() === type);
+}
+ return (
+
+
+ {aggregationOptions.map(opt => (
+ {opt.name}
+ ))}
+
+
+
+ {aggregationOptions.map(opt => {
+ const items = filterByType(data, opt.value);
+
+ return (
+
+ {items.length === 0 ? (
+
+ No {opt.name} assets for selected window
+
+ ) : (
+
+ {items.map((item, idx) => (
+
+ {item.properties?.name || "Unnamed asset"}
+ {" — "}
+ {formatDate(item.start)}
+
+ ))}
+
+ )}
+
+ );
+ })}
+
+
+ );
+}
+
+export default AssetsByTypeTabs;
diff --git a/src/components/AssetsCosts/Charts/assetsTable.js b/src/components/AssetsCosts/Charts/assetsTable.js
new file mode 100644
index 00000000..b246d22e
--- /dev/null
+++ b/src/components/AssetsCosts/Charts/assetsTable.js
@@ -0,0 +1,108 @@
+import {
+ DataTable,
+ Table,
+ TableHead,
+ TableRow,
+ TableHeader,
+ TableBody,
+ TableCell,
+ TableContainer,
+ TableToolbar,
+ TableToolbarContent,
+ TableToolbarSearch,
+ Pagination,
+} from "@carbon/react";
+
+function AssetsCostsTable({ rows }) {
+
+ // Column definitions
+ const headers = [
+ { key: "date", header: "Date" },
+ { key: "type", header: "Type" },
+ { key: "category", header: "Category" },
+ { key: "name", header: "Name" },
+ { key: "service", header: "Service" },
+ { key: "provider", header: "Provider" },
+ { key: "totalCost", header: "Total Cost ($)" },
+ ];
+
+ return (
+
+ {({
+ rows,
+ headers,
+ getHeaderProps,
+ getRowProps,
+ getTableProps,
+ onInputChange,
+ }) => (
+
+
+
+ {/* Search Bar */}
+
+
+
+
+
+
+ {/* Table */}
+
+
+
+
+ {headers.map(header => {
+ const { key, ...rest } = getHeaderProps({ header });
+
+ return (
+
+ {header.header}
+
+ );
+})}
+
+
+
+
+ {rows.map(row => {
+ const { key, ...rest } = getRowProps({ row });
+
+ return (
+
+
+ {row.cells.map(cell => (
+
+ {cell.value}
+
+ ))}
+
+
+ );
+ })}
+
+
+
+
+
+ {/* Pagination */}
+
+
+
+ )}
+
+ );
+}
+
+export default AssetsCostsTable;
\ No newline at end of file
diff --git a/src/components/AssetsCosts/Charts/main.js b/src/components/AssetsCosts/Charts/main.js
new file mode 100644
index 00000000..0bd566cb
--- /dev/null
+++ b/src/components/AssetsCosts/Charts/main.js
@@ -0,0 +1,187 @@
+import {
+ LineChart,
+ Line,
+ XAxis,
+ YAxis,
+ Tooltip,
+ CartesianGrid,
+ ResponsiveContainer,
+} from "recharts";
+import React, { useEffect, useMemo, useState } from "react";
+import PieChartMain from "./pieChart-part1";
+import PieChartMain2 from "./pieChart-part2";
+import { Button } from "@carbon/react";
+import AssetsCostsTable from "./assetsTable";
+import { Padding } from "@mui/icons-material";
+import AssetsByTypeTabs from "./assetByTypeTabs"
+//based on what you want to group
+const aggregationOptions = [
+ { name: "Cloud", value: "cloud" },
+ { name: "Disk", value: "disk" },
+ { name: "Loadbalancer", value: "loadbalancer" },
+ { name: "Network", value: "network" },
+ { name: "Node", value: "node" },
+ { name: "Shared", value: "shared" },
+ { name: "ClusterManagement", value: "clustermanagement" },
+];
+
+
+//tables built using the carbon-react needs this format of data
+function buildTableRows(data) {
+ if (!Array.isArray(data)) return [];
+
+ return data.map((item, index) => ({
+ id: String(index), // required by Carbon
+
+ date: item.start
+ ? item.start.split("T")[0]
+ : "-",
+
+ type: item.type || "-",
+
+ category:
+ item.properties?.category || "-",
+
+ name:
+ item.properties?.name ||
+ item.properties?.providerID ||
+ "Unknown",
+
+ service:
+ item.properties?.service || "-",
+
+ provider:
+ item.properties?.provider || "-",
+
+ totalCost: item.totalCost
+ ? item.totalCost.toFixed(4)
+ : "0.0000",
+ }));
+}
+
+
+function ChartsMain({ finalData }) {
+ const [selectedDate, setSelectedDate] = React.useState(null);
+ const [selectedType, setSelectedType] = React.useState(null);
+ if (!Array.isArray(finalData)) {
+ console.log("data should be in the format of arrays for charts")
+ }
+ //1.convert our data into the chart format
+ var arr = finalData
+ function aggregateByDate(data) {
+ const map = {};
+
+ data.forEach(item => {
+ const date = item.start?.split("T")[0];
+ const cost = item.totalCost || 0;
+
+ if (!date) return;
+
+ if (!map[date]) {
+ map[date] = 0;
+ }
+
+ map[date] += cost;
+ });
+
+ // Convert to array
+ return Object.entries(map).map(([date, cost]) => ({
+ date,
+ cost: Number(cost.toFixed(4)), // clean decimals
+ }));
+}
+ const chartData = aggregateByDate(arr)
+ const sortedChartsData = chartData.sort(
+ (a, b) => new Date(a.date) - new Date(b.date)
+ );
+
+
+ const tableRows = buildTableRows(finalData);
+
+ useEffect(() => {
+ if (sortedChartsData.length > 0 && !selectedDate) {
+ setSelectedDate(sortedChartsData[0].date);
+ }
+}, [sortedChartsData]);
+
+ // console.log("Selected Day:", selectedDate);
+
+ return (
+ <>
+
+
+ Click points(dates) on the line chart to view the cost breakdown
+
+
+
+ {
+ if (e && e.activeLabel) {
+ setSelectedDate(e.activeLabel);
+ }
+ }}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Pie 1 */}
+
+
+ {/* Pie 2 */}
+
+
+ {finalData && finalData.length > 0 && (
+
+
+)}
+ {finalData && finalData.length > 0 && (
+
+)}
+
+ >
+ );
+}
+
+export default ChartsMain
\ No newline at end of file
diff --git a/src/components/AssetsCosts/Charts/pieChart-part1.js b/src/components/AssetsCosts/Charts/pieChart-part1.js
new file mode 100644
index 00000000..ed0bc6ef
--- /dev/null
+++ b/src/components/AssetsCosts/Charts/pieChart-part1.js
@@ -0,0 +1,101 @@
+import {
+ PieChart,
+ Pie,
+ Cell,
+ Tooltip,
+ Legend,
+ ResponsiveContainer,
+} from "recharts";
+
+const COLORS = [
+ "#1976d2",
+ "#2e7d32",
+ "#ed6c02",
+ "#9c27b0",
+ "#d32f2f",
+ "#0288d1",
+];
+
+function PieChartMain({ data, date , onTypeSelect}) {
+ if (!date || !data || data.length === 0) {
+ return Select a day to see breakdown
;
+ }
+
+ // Filter only selected day
+ const dayData = data.filter(
+ item => item.start?.startsWith(date)
+ );
+
+ // Group by asset type
+ const map = {};
+
+ dayData.forEach(item => {
+ const type = item.type || "Other";
+ const cost = item.totalCost || 0;
+
+ if (!map[type]) {
+ map[type] = 0;
+ }
+
+ map[type] += cost;
+ });
+
+ // Convert to chart format
+ const pieData = Object.entries(map).map(
+ ([name, value]) => ({
+ name,
+ value: Number(value.toFixed(3)),
+ })
+ );
+
+ if (pieData.length === 0) {
+ return No data for {date}
;
+ }
+
+ return (
+
+
+
+ Cost Breakdown — {date}
+
+
+
+
+
+
+ {
+ if (entry?.name) {
+ onTypeSelect(entry.name); // 🔥 send type
+ }
+ }}
+ >
+
+ {pieData.map((_, index) => (
+ |
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default PieChartMain;
diff --git a/src/components/AssetsCosts/Charts/pieChart-part2.js b/src/components/AssetsCosts/Charts/pieChart-part2.js
new file mode 100644
index 00000000..4a7e5be0
--- /dev/null
+++ b/src/components/AssetsCosts/Charts/pieChart-part2.js
@@ -0,0 +1,98 @@
+import {
+ PieChart,
+ Pie,
+ Cell,
+ Tooltip,
+ Legend,
+ ResponsiveContainer,
+} from "recharts";
+
+const COLORS = [
+ "#1565c0",
+ "#2e7d32",
+ "#f57c00",
+ "#7b1fa2",
+ "#c62828",
+];
+
+function PieChartMain2({ data, date, type }) {
+
+ if (!date || !type || !data) {
+ return Click on asset from cost breakdown
;
+ }
+
+ // Filter by day + type
+ const filtered = data.filter(item =>
+ item.start?.startsWith(date) &&
+ item.type === type
+ );
+
+ // Group by asset name
+ const map = {};
+
+ filtered.forEach(item => {
+ const name =
+ item.properties?.name ||
+ item.properties?.providerID ||
+ "Unknown";
+
+ const cost = item.totalCost || 0;
+
+ if (!map[name]) {
+ map[name] = 0;
+ }
+
+ map[name] += cost;
+ });
+
+ const pieData = Object.entries(map).map(
+ ([name, value]) => ({
+ name,
+ value: Number(value.toFixed(3)),
+ })
+ );
+
+ if (pieData.length === 0) {
+ return No assets for {type}
;
+ }
+
+ return (
+
+
+
+ {type} Details — {date}
+
+
+
+
+
+
+
+
+ {pieData.map((_, i) => (
+ |
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default PieChartMain2;
\ No newline at end of file
diff --git a/src/components/AssetsCosts/Controls/edit.js b/src/components/AssetsCosts/Controls/edit.js
new file mode 100644
index 00000000..cf763932
--- /dev/null
+++ b/src/components/AssetsCosts/Controls/edit.js
@@ -0,0 +1,20 @@
+import React from "react";
+import SelectWindow from "../../SelectWindow";
+
+function EditControl({windowOptions,window,setWindow,useSample}) {
+ return <>
+
+
+
+
+ >
+
+
+}
+
+export default EditControl
\ No newline at end of file
diff --git a/src/components/AssetsCosts/Controls/index.js b/src/components/AssetsCosts/Controls/index.js
new file mode 100644
index 00000000..ba95d7d1
--- /dev/null
+++ b/src/components/AssetsCosts/Controls/index.js
@@ -0,0 +1,15 @@
+import React from "react";
+import EditControl from "../../AssetsCosts/Controls/edit";
+
+function Controls({ windowOptions , window, setWindow , useSample}) {
+ return (
+
+ )
+}
+
+export default Controls
\ No newline at end of file
diff --git a/src/components/Nav/SidebarNav.js b/src/components/Nav/SidebarNav.js
index 781184d7..5244be89 100644
--- a/src/components/Nav/SidebarNav.js
+++ b/src/components/Nav/SidebarNav.js
@@ -2,7 +2,7 @@ import * as React from "react";
import { Drawer, List } from "@mui/material";
import { NavItem } from "./NavItem";
-import { BarChart, Cloud } from "@mui/icons-material";
+import { BarChart, Cloud , DeviceHub} from "@mui/icons-material";
const logo = new URL("../../images/logo.png", import.meta.url).href;
@@ -25,6 +25,7 @@ const SidebarNav = ({ active }) => {
},
{ name: "Cloud Costs", href: "/cloud", icon: },
{ name: "External Costs", href: "/external-costs", icon: },
+ { name: "Assets", href: "/assets", icon: },
];
return (
diff --git a/src/components/SelectWindow.js b/src/components/SelectWindow.js
index 15e44e2d..f99c7ff3 100644
--- a/src/components/SelectWindow.js
+++ b/src/components/SelectWindow.js
@@ -9,7 +9,7 @@ import Typography from "@mui/material/Typography";
import { isValid } from "date-fns";
import { find, get } from "lodash";
-const SelectWindow = ({ windowOptions, window, setWindow }) => {
+const SelectWindow = ({ windowOptions, window, setWindow ,useSample}) => {
const [anchorEl, setAnchorEl] = useState(null);
const [startDate, setStartDate] = useState(null);
@@ -117,7 +117,7 @@ const SelectWindow = ({ windowOptions, window, setWindow }) => {
flexFlow: "row",
}}
>
-
+ {!useSample &&
{
Apply
-
+ }
+
{
+ if (!item.start) return false;
+
+ const start = new Date(item.start);
+
+ return start >= from && start <= to;
+ });
+}
+
+export default function AssetsCosts() {
+ // data
+ const [assetCostData, setAssetCostData] = React.useState(null);
+ //the below state is used for keep track whether to use sample data or not
+ const [useSample , setUseSample] = React.useState(false)
+ //page and settings state
+ const [errors, setErrors] = React.useState([]);
+ const [loading, setLoading] = React.useState(true);
+ const [init, setInit] = React.useState(false);
+ const [fetch, setFetch] = React.useState(false);
+ //we are using the below state to check we are working with the network data or the sample data
+ const [check2, setCheck2] = React.useState(false);
+
+
+ //this below function is used to make everything ready before fetching up the data
+ async function initialize() {
+ setInit(true);
+ }
+
+
+ //this below function is going to assetCost.js file , where we are going to make the client request
+
+ async function fetchChartData() {
+ //when the user wants to work on the sample data dont even touch anything like going into the network
+ if (useSample) {
+ var calculatedSampleData = calculatingWindow(SampleAssetsData, win)
+ // console.log(calculatedSampleData)
+ setLoading(false);
+ setAssetCostData(calculatedSampleData)
+
+ return
+ }
+ try {
+ // console.log("hello i am inside the request")
+ setLoading(true)
+ const resp = await AssetsCostsService.fetchAssetsGraphCosts(
+ );
+ if (resp) {
+ setCheck2(true)
+ setAssetCostData(Object.values(resp.data));
+ // console.log(Object.values(resp.data)) //returns an object
+ } else {
+ if (resp.message && resp.message.indexOf("boundary error") >= 0) {
+ let match = resp.message.match(/(ETL is \d+\.\d+% complete)/);
+ let secondary = "Try again after ETL build is complete";
+ if (match.length > 0) {
+ secondary = `${match[1]}. ${secondary}`;
+ }
+ setErrors([
+ {
+ primary: "Data unavailable while ETL is building",
+ secondary: secondary,
+ },
+ ]);
+ }
+ setAssetCostData([]);
+ }
+ } catch (err) {
+ console.log(err);
+ if (err.message.indexOf("404") === 0) {
+ setErrors([
+ {
+ primary: "Failed to load report data",
+ secondary:
+ "Please update OpenCost to the latest version, and open an Issue if problems persist.",
+ },
+ ]);
+ } else {
+ let secondary =
+ "Please open an Issue with OpenCost if problems persist.";
+ if (err.message.length > 0) {
+ secondary = err.message;
+ }
+ setErrors([
+ {
+ primary: "Failed to load report data",
+ secondary: secondary,
+ },
+ ]);
+ }
+ setAssetCostData([]);
+ } finally {
+ setLoading(false); // always stop loader
+ }
+ }
+
+ //this is where we are goona call the fetchChartData(parent function)
+
+ async function fetchData() {
+ setLoading(true);
+ setErrors([]);
+ // todo: come back and have inidividual loading
+ await fetchChartData();
+
+ setLoading(false);
+ }
+
+
+ /*
+ 1.Buttons, dropdows , filters etc get there value from the url
+ 2.when the user changes something on the page we update the url
+ 3.if url does not have something we use a default value
+ */
+ //the below line does give me the current page URL info
+ const routerLocation = useLocation();
+ //take the part that is after ? and make it something into like an object that i can read (URLSear....-> built in browser tool)
+ const searchParams = new URLSearchParams(routerLocation.search);
+ const navigate = useNavigate();
+ const win = searchParams.get("window") || "7d";
+ const aggregateBy = searchParams.get("agg") || "";
+ const title =
+ searchParams.get("title") ||
+ generateTitle({ window: win, aggregateBy });
+
+ var finalData = null
+ //the below logic is used for showing the right things ,when we get the data , or when we want to use the sample data
+ var check = false
+
+ if (!loading && errors.length == 0 && assetCostData != null && !useSample) {
+ finalData = assetCostData
+ // we dont want error appearing on our page even if we are working on the real network that is why the below line exist
+ check = check2 ? false : true;
+
+ // console.log(finalData)
+ } else if (!loading && useSample) {
+ finalData = calculatingWindow(SampleAssetsData, win)
+ check = true
+
+ console.log(finalData)
+ } else if (!loading && !useSample) {
+ finalData = null
+ }
+ //the below useEffect is used to run 2 request trading between safe/slow
+ React.useEffect(() => {
+ //the below condition is there to avoid the loop
+ if (!init) {
+ initialize();
+ }
+ if (init || fetch) {
+ fetchData();
+ }
+ }, [init, fetch]);
+
+ React.useEffect(() => {
+ setFetch(!fetch);
+ }, [win]);
+ React.useEffect(() => {
+ if (!useSample) {
+ setAssetCostData(null); // 🔥 Clear old sample data
+ setCheck2(false);
+ }
+}, [useSample]);
+
+ return (
+
+
+ {!useSample && fetchData()}
+ style={{ padding: 12 }}
+ >
+
+ }
+
+
+ {/* the below block is only going to execute when we can't get the real data from backend */}
+ {!loading && (errors.length > 0 || check || useSample) && (
+
+
+
+
+
+ {
+ setUseSample(e.target.checked)}
+ />
+ {!useSample ? "Use sample data or (refresh again for the connection)" : "use sample data"}
+ }
+
+
+
+
+ )}
+
+ {finalData &&
+
+
+
+ {title}
+
+
+ {/* we have Controls beautifully controlling the data system irrespective of whether sample or real data */}
+
{
+ searchParams.set("window", win);
+ navigate({
+ search: `?${searchParams.toString()}`,
+ });
+ }}
+ useSample={useSample}
+ >
+
+
+ {/* at this point we have all the data based on the window time */}
+ {loading && (
+
+ )}
+ {
+ finalData && finalData.length > 0 ? (
+
+ ) : (
+ "no data to show here"
+ )
+}
+
+
+
+ }
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/route.js b/src/route.js
index 919717b2..70c3c045 100644
--- a/src/route.js
+++ b/src/route.js
@@ -6,6 +6,7 @@ import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns";
import Allocations from "./pages/Allocations.js";
import CloudCosts from "./pages/CloudCosts.js";
import ExternalCosts from "./pages/ExternalCosts.js";
+import AssetsCosts from "./pages/AssetsCosts.js";
const basename = (process.env.UI_PATH || "").replace(/\/+$/, "");
@@ -18,6 +19,7 @@ const RouteSet = () => {
} />
} />
} />
+
}>
diff --git a/src/services/api_client.js b/src/services/api_client.js
index 77021eeb..1fabe52b 100644
--- a/src/services/api_client.js
+++ b/src/services/api_client.js
@@ -6,6 +6,7 @@
import axios from "axios";
let baseURL = process.env.BASE_URL || "{PLACEHOLDER_BASE_URL}";
+
if (baseURL.includes("PLACEHOLDER_BASE_URL")) {
baseURL = "http://localhost:9090";
}
diff --git a/src/services/assets.mock.js b/src/services/assets.mock.js
new file mode 100644
index 00000000..3f8b9828
--- /dev/null
+++ b/src/services/assets.mock.js
@@ -0,0 +1,712 @@
+
+export const SampleAssetsData = {
+ //2 node data from today
+ "Oracle/__undefined__/__undefined__/Compute/default-cluster/Node/Kubernetes/ocid1.instance.oc1.iad.anuwcljru4az63qc3kz63cx64xj5elyk23vljy5g6rv3ztofnre3nhwqfbpa/10.0.154.178": {
+ "type": "Node",
+ "properties": {
+ "category": "Compute",
+ "provider": "Oracle",
+ "service": "Kubernetes",
+ "cluster": "default-cluster",
+ "name": "10.0.154.17",
+ "providerID": "ocid1.instance.oc1.iad.anuwcljru4az63qc3kz63cx64xj5elyk23vljy5g6rv3ztofnre3nhwqfbpa"
+ },
+ "labels": {
+ "beta_kubernetes_io_arch": "amd64",
+ "beta_kubernetes_io_instance_type": "VM.Optimized3.Flex",
+ "beta_kubernetes_io_os": "linux",
+ "displayName": "oke-cggb7sjbcpa-nmnpcydddta-sfr367dugkq-0",
+ "failure_domain_beta_kubernetes_io_region": "iad",
+ "failure_domain_beta_kubernetes_io_zone": "US-ASHBURN-AD-1",
+ "hostname": "oke-cggb7sjbcpa-nmnpcydddta-sfr367dugkq-0",
+ "internal_addr": "10.0.154.17",
+ "kubernetes_io_arch": "amd64",
+ "kubernetes_io_hostname": "10.0.154.17",
+ "kubernetes_io_os": "linux",
+ "last_migration_failure": "get_kubesvc_failure",
+ "node_info_compartment_id": "aaaaaaaaazsr3zf5iw2c4wu4of4rglbva7vx3ybf4ifbsyaj2iq4dpdc4gpa",
+ "node_info_compartment_name": "opencost",
+ "node_info_ds_proxymux_client": "true",
+ "node_info_kubeletVersion": "v1.31",
+ "node_kubernetes_io_instance_type": "VM.Optimized3.Flex",
+ "oci_oraclecloud_com_fault_domain": "FAULT-DOMAIN-1",
+ "oci_oraclecloud_com_host_id": "425f852926e",
+ "oci_oraclecloud_com_host_network_block_id": "643bbe2114c",
+ "oci_oraclecloud_com_host_rack_id": "85d8c1e6046",
+ "oci_oraclecloud_com_ip_family_ipv4": "true",
+ "oci_oraclecloud_com_ip_family_preferred": "ipv4",
+ "oci_oraclecloud_com_node_info_managed": "true",
+ "oci_oraclecloud_com_oke_is_preemptible": "true",
+ "oci_oraclecloud_com_vcn_native_ip_cni": "false",
+ "oke_oraclecloud_com_cluster_autoscaler": "disabled",
+ "oke_oraclecloud_com_node_info_private_subnet": "true",
+ "oke_oraclecloud_com_node_info_private_worker": "true",
+ "oke_oraclecloud_com_pool_mode": "node-pool",
+ "oke_oraclecloud_com_pool_name": "np-spot",
+ "oke_oraclecloud_com_tf_module": "terraform-oci-oke",
+ "oke_oraclecloud_com_tf_state_id": "ksmyvm",
+ "providerID": "ocid1.instance.oc1.iad.anuwcljru4az63qc3kz63cx64xj5elyk23vljy5g6rv3ztofnre3nhwqfbpa",
+ "topology_kubernetes_io_region": "iad",
+ "topology_kubernetes_io_zone": "US-ASHBURN-AD-1"
+ },
+ "window": {
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-05T00:00:00Z"
+ },
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-04T05:10:00Z",
+ "minutes": 310,
+ "nodeType": "VM.Optimized3.Flex",
+ "cpuCores": 4,
+ "ramBytes": 33347035136,
+ "cpuCoreHours": 20.666667,
+ "ramByteHours": 172293014869.333,
+ "GPUHours": 0,
+ "cpuBreakdown": {
+ "idle": 1,
+ "other": 0,
+ "system": 0,
+ "user": 0
+ },
+ "ramBreakdown": {
+ "idle": 1,
+ "other": 0,
+ "system": 0,
+ "user": 0
+ },
+ "preemptible": 1,
+ "discount": 0,
+ "cpuCost": 0.558,
+ "gpuCost": 0,
+ "gpuCount": 0,
+ "ramCost": 0.240691,
+ "adjustment": 0,
+ "overhead": {
+ "CpuOverheadFraction": 0.04625,
+ "RamOverheadFraction": 0.102885928479324,
+ "OverheadCostFraction": 0.0633176029938702
+ },
+ "totalCost": 0.798691
+ },
+ "Oracle/__undefined__/__undefined__/Compute/default-cluster/Node/Kubernetes/ocid1.instance.oc1.iad.anuwcljru4az63qc7pq7a2sk4kjwcdk6nm4kp7hgkfhnvcav6rdlkmk4jdna/10.0.144.51": {
+ "type": "Node",
+ "properties": {
+ "category": "Compute",
+ "provider": "Oracle",
+ "service": "Kubernetes",
+ "cluster": "default-cluster",
+ "name": "10.0.144.51",
+ "providerID": "ocid1.instance.oc1.iad.anuwcljru4az63qc7pq7a2sk4kjwcdk6nm4kp7hgkfhnvcav6rdlkmk4jdna"
+ },
+ "labels": {
+ "beta_kubernetes_io_arch": "amd64",
+ "beta_kubernetes_io_instance_type": "VM.Optimized3.Flex",
+ "beta_kubernetes_io_os": "linux",
+ "displayName": "oke-cggb7sjbcpa-nwacqdcqrwa-sfr367dugkq-1",
+ "failure_domain_beta_kubernetes_io_region": "iad",
+ "failure_domain_beta_kubernetes_io_zone": "US-ASHBURN-AD-1",
+ "hostname": "oke-cggb7sjbcpa-nwacqdcqrwa-sfr367dugkq-1",
+ "internal_addr": "10.0.144.51",
+ "kubernetes_io_arch": "amd64",
+ "kubernetes_io_hostname": "10.0.144.51",
+ "kubernetes_io_os": "linux",
+ "last_migration_failure": "get_kubesvc_failure",
+ "node_info_compartment_id": "aaaaaaaaazsr3zf5iw2c4wu4of4rglbva7vx3ybf4ifbsyaj2iq4dpdc4gpa",
+ "node_info_compartment_name": "opencost",
+ "node_info_ds_proxymux_client": "true",
+ "node_info_kubeletVersion": "v1.31",
+ "node_kubernetes_io_instance_type": "VM.Optimized3.Flex",
+ "oci_oraclecloud_com_fault_domain": "FAULT-DOMAIN-1",
+ "oci_oraclecloud_com_host_id": "f589eb8254a",
+ "oci_oraclecloud_com_host_rack_id": "1b31d02bc4e",
+ "oci_oraclecloud_com_ip_family_ipv4": "true",
+ "oci_oraclecloud_com_ip_family_preferred": "ipv4",
+ "oci_oraclecloud_com_node_info_managed": "true",
+ "oci_oraclecloud_com_oke_is_preemptible": "true",
+ "oci_oraclecloud_com_vcn_native_ip_cni": "false",
+ "oke_oraclecloud_com_cluster_autoscaler": "disabled",
+ "oke_oraclecloud_com_node_info_private_subnet": "true",
+ "oke_oraclecloud_com_node_info_private_worker": "true",
+ "oke_oraclecloud_com_pool_mode": "node-pool",
+ "oke_oraclecloud_com_pool_name": "np-spot",
+ "oke_oraclecloud_com_tf_module": "terraform-oci-oke",
+ "oke_oraclecloud_com_tf_state_id": "ksmyvm",
+ "providerID": "ocid1.instance.oc1.iad.anuwcljru4az63qc7pq7a2sk4kjwcdk6nm4kp7hgkfhnvcav6rdlkmk4jdna",
+ "topology_kubernetes_io_region": "iad",
+ "topology_kubernetes_io_zone": "US-ASHBURN-AD-1"
+ },
+ "window": {
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-05T00:00:00Z"
+ },
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-04T13:05:12Z",
+ "minutes": 785.209354,
+ "nodeType": "VM.Optimized3.Flex",
+ "cpuCores": 4,
+ "ramBytes": 33347035136,
+ "cpuCoreHours": 52.34729,
+ "ramByteHours": 436406732210.94,
+ "GPUHours": 0,
+ "cpuBreakdown": {
+ "idle": 1,
+ "other": 0,
+ "system": 0,
+ "user": 0
+ },
+ "ramBreakdown": {
+ "idle": 1,
+ "other": 0,
+ "system": 0,
+ "user": 0
+ },
+ "preemptible": 1,
+ "discount": 0,
+ "cpuCost": 1.413377,
+ "gpuCost": 0,
+ "gpuCount": 0,
+ "ramCost": 0.609653,
+ "adjustment": 0,
+ "overhead": {
+ "CpuOverheadFraction": 0.04625,
+ "RamOverheadFraction": 0.102885928479324,
+ "OverheadCostFraction": 0.0633176029938702
+ },
+ "totalCost": 2.02303
+ },
+ //1 from managment for today
+ "Oracle/__undefined__/__undefined__/Management/default-cluster/ClusterManagement/Kubernetes/__undefined__/__undefined__": {
+ "type": "ClusterManagement",
+ "properties": {
+ "category": "Management",
+ "provider": "Oracle",
+ "service": "Kubernetes",
+ "cluster": "default-cluster"
+ },
+ "labels": {
+
+ },
+ "window": {
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-05T00:00:00Z"
+ },
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-05T00:00:00Z",
+ "minutes": 1440,
+ "totalCost": 1.308683
+ },
+ // 3 disk and 1 lb for today
+ "Oracle/__undefined__/__undefined__/Network/default-cluster/LoadBalancer/Kubernetes/129.213.15.26/ingress-nginx/ingress-nginx-demo-controller": {
+ "type": "LoadBalancer",
+ "properties": {
+ "category": "Network",
+ "provider": "Oracle",
+ "service": "Kubernetes",
+ "cluster": "default-cluster",
+ "name": "ingress-nginx/ingress-nginx-demo-controller",
+ "providerID": "129.213.15.26"
+ },
+ "labels": {
+
+ },
+ "window": {
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-05T00:00:00Z"
+ },
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-04T13:05:12Z",
+ "minutes": 785.209403,
+ "adjustment": 0,
+ "totalCost": 0.147881,
+ "private": false,
+ "ip": "129.213.15.26"
+ },
+ "Oracle/__undefined__/__undefined__/Storage/default-cluster/Disk/Kubernetes/ocid1.volume.oc1.iad.abuwcljriemqfhkjnrqj6in7yffin6g35zvuoxk4o7vo57ze7mzueov62nua/csi-bb8858a8-d03b-4b2e-ae29-ccd2486aac42": {
+ "type": "Disk",
+ "properties": {
+ "category": "Storage",
+ "provider": "Oracle",
+ "service": "Kubernetes",
+ "cluster": "default-cluster",
+ "name": "csi-bb8858a8-d03b-4b2e-ae29-ccd2486aac42",
+ "providerID": "ocid1.volume.oc1.iad.abuwcljriemqfhkjnrqj6in7yffin6g35zvuoxk4o7vo57ze7mzueov62nua"
+ },
+ "labels": {
+
+ },
+ "window": {
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-05T00:00:00Z"
+ },
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-04T13:05:12Z",
+ "minutes": 785.209846,
+ "byteHours": 1405187753227.41,
+ "bytes": 107374182400,
+ "byteHoursUsed": 491498390.937002,
+ "byteUsageMax": 37752832,
+ "breakdown": {
+ "idle": 1,
+ "other": 0,
+ "system": 0,
+ "user": 0
+ },
+ "adjustment": 0,
+ "totalCost": 0.044495,
+ "storageClass": "oci-bv",
+ "volumeName": "csi-bb8858a8-d03b-4b2e-ae29-ccd2486aac42",
+ "claimName": "test-install-speedtest-tracker-cnpg-main-2",
+ "local": 0,
+ "claimNamespace": "network-load-gen"
+ },
+ "Oracle/__undefined__/__undefined__/Storage/default-cluster/Disk/Kubernetes/ocid1.volume.oc1.iad.abuwcljrwqxpdxoqmn7bjmgayfsvfvnixntomcnilkujiw45vdg4bv2pucva/csi-3e493950-a8bb-48fc-8c6e-2a6c46be335e": {
+ "type": "Disk",
+ "properties": {
+ "category": "Storage",
+ "provider": "Oracle",
+ "service": "Kubernetes",
+ "cluster": "default-cluster",
+ "name": "csi-3e493950-a8bb-48fc-8c6e-2a6c46be335e",
+ "providerID": "ocid1.volume.oc1.iad.abuwcljrwqxpdxoqmn7bjmgayfsvfvnixntomcnilkujiw45vdg4bv2pucva"
+ },
+ "labels": {
+
+ },
+ "window": {
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-05T00:00:00Z"
+ },
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-04T13:05:12Z",
+ "minutes": 785.209846,
+ "byteHours": 1405187753135.99,
+ "bytes": 107374182400,
+ "byteHoursUsed": 9870702828.70701,
+ "byteUsageMax": 812138496,
+ "breakdown": {
+ "idle": 1,
+ "other": 0,
+ "system": 0,
+ "user": 0
+ },
+ "adjustment": 0,
+ "totalCost": 0.044495,
+ "storageClass": "oci-bv",
+ "volumeName": "csi-3e493950-a8bb-48fc-8c6e-2a6c46be335e",
+ "claimName": "test-install-speedtest-tracker-cnpg-main-2-wal",
+ "local": 0,
+ "claimNamespace": "network-load-gen"
+ },
+ "Oracle/__undefined__/__undefined__/Storage/default-cluster/Disk/Kubernetes/ocid1.volume.oc1.iad.abuwcljrzp57sacypolzcgdftatho3mpiliyz5lblzvvhuztckfdazfx37ma/csi-398733a4-9c59-4d71-92e0-2ec69ab99a9c": {
+ "type": "Disk",
+ "properties": {
+ "category": "Storage",
+ "provider": "Oracle",
+ "service": "Kubernetes",
+ "cluster": "default-cluster",
+ "name": "csi-398733a4-9c59-4d71-92e0-2ec69ab99a9c",
+ "providerID": "ocid1.volume.oc1.iad.abuwcljrzp57sacypolzcgdftatho3mpiliyz5lblzvvhuztckfdazfx37ma"
+ },
+ "labels": {
+
+ },
+ "window": {
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-05T00:00:00Z"
+ },
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-04T13:05:12Z",
+ "minutes": 785.209846,
+ "byteHours": 1405187753102.11,
+ "bytes": 107374182400,
+ "byteHoursUsed": 226168884.311569,
+ "byteUsageMax": 17653760,
+ "breakdown": {
+ "idle": 1,
+ "other": 0,
+ "system": 0,
+ "user": 0
+ },
+ "adjustment": 0,
+ "totalCost": 0.044495,
+ "storageClass": "oci-bv",
+ "volumeName": "csi-398733a4-9c59-4d71-92e0-2ec69ab99a9c",
+ "claimName": "test-install-speedtest-tracker-config",
+ "local": 0,
+ "claimNamespace": "network-load-gen"
+ },
+ "Oracle/__undefined__/__undefined__/Storage/default-cluster/Disk/Kubernetes/ocid1.volume.oc1.iad.abuwcljrzp57sacypolzcgdftatho3mpiliyz5lblzvvhuztckfdazfx37ma/csi-398733a4-9c59-4d71-92e0-2ec69ab99a9c": {
+ "type": "Disk",
+ "properties": {
+ "category": "Storage",
+ "provider": "Oracle",
+ "service": "Kubernetes",
+ "cluster": "default-cluster",
+ "name": "csi-398733a4-9c59-4d71-92e0-2ec69ab99a9c",
+ "providerID": "ocid1.volume.oc1.iad.abuwcljrzp57sacypolzcgdftatho3mpiliyz5lblzvvhuztckfdazfx37ma"
+ },
+ "labels": {
+
+ },
+ "window": {
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-05T00:00:00Z"
+ },
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-04T13:05:12Z",
+ "minutes": 785.209846,
+ "byteHours": 1405187753102.11,
+ "bytes": 107374182400,
+ "byteHoursUsed": 226168884.311569,
+ "byteUsageMax": 17653760,
+ "breakdown": {
+ "idle": 1,
+ "other": 0,
+ "system": 0,
+ "user": 0
+ },
+ "adjustment": 0,
+ "totalCost": 0.044495,
+ "storageClass": "oci-bv",
+ "volumeName": "csi-398733a4-9c59-4d71-92e0-2ec69ab99a9c",
+ "claimName": "test-install-speedtest-tracker-config",
+ "local": 0,
+ "claimNamespace": "network-load-gen"
+ },
+ //8 days dack back
+ "Oracle/__undefined__/__undefined__/Compute/default-cluster/Node/Kubernetes/ocid1.instance.oc1.iad.anuwcljru4az63qc3kz63cx64xj5elyk23vljy5g6rv3ztofnre3nhwqfbpa/101.0.154.1723": {
+ "type": "Node",
+ "properties": {
+ "category": "Compute",
+ "provider": "Oracle",
+ "service": "Kubernetes",
+ "cluster": "default-cluster",
+ "name": "10.0.154.17",
+ "providerID": "ocid1.instance.oc1.iad.anuwcljru4az63qc3kz63cx64xj5elyk23vljy5g6rv3ztofnre3nhwqfbpa"
+ },
+ "labels": {
+ "beta_kubernetes_io_arch": "amd64",
+ "beta_kubernetes_io_instance_type": "VM.Optimized3.Flex",
+ "beta_kubernetes_io_os": "linux",
+ "displayName": "oke-cggb7sjbcpa-nmnpcydddta-sfr367dugkq-0",
+ "failure_domain_beta_kubernetes_io_region": "iad",
+ "failure_domain_beta_kubernetes_io_zone": "US-ASHBURN-AD-1",
+ "hostname": "oke-cggb7sjbcpa-nmnpcydddta-sfr367dugkq-0",
+ "internal_addr": "10.0.154.17",
+ "kubernetes_io_arch": "amd64",
+ "kubernetes_io_hostname": "10.0.154.17",
+ "kubernetes_io_os": "linux",
+ "last_migration_failure": "get_kubesvc_failure",
+ "node_info_compartment_id": "aaaaaaaaazsr3zf5iw2c4wu4of4rglbva7vx3ybf4ifbsyaj2iq4dpdc4gpa",
+ "node_info_compartment_name": "opencost",
+ "node_info_ds_proxymux_client": "true",
+ "node_info_kubeletVersion": "v1.31",
+ "node_kubernetes_io_instance_type": "VM.Optimized3.Flex",
+ "oci_oraclecloud_com_fault_domain": "FAULT-DOMAIN-1",
+ "oci_oraclecloud_com_host_id": "425f852926e",
+ "oci_oraclecloud_com_host_network_block_id": "643bbe2114c",
+ "oci_oraclecloud_com_host_rack_id": "85d8c1e6046",
+ "oci_oraclecloud_com_ip_family_ipv4": "true",
+ "oci_oraclecloud_com_ip_family_preferred": "ipv4",
+ "oci_oraclecloud_com_node_info_managed": "true",
+ "oci_oraclecloud_com_oke_is_preemptible": "true",
+ "oci_oraclecloud_com_vcn_native_ip_cni": "false",
+ "oke_oraclecloud_com_cluster_autoscaler": "disabled",
+ "oke_oraclecloud_com_node_info_private_subnet": "true",
+ "oke_oraclecloud_com_node_info_private_worker": "true",
+ "oke_oraclecloud_com_pool_mode": "node-pool",
+ "oke_oraclecloud_com_pool_name": "np-spot",
+ "oke_oraclecloud_com_tf_module": "terraform-oci-oke",
+ "oke_oraclecloud_com_tf_state_id": "ksmyvm",
+ "providerID": "ocid1.instance.oc1.iad.anuwcljru4az63qc3kz63cx64xj5elyk23vljy5g6rv3ztofnre3nhwqfbpa",
+ "topology_kubernetes_io_region": "iad",
+ "topology_kubernetes_io_zone": "US-ASHBURN-AD-1"
+ },
+ "window": {
+ "start": "2026-02-03T00:00:00Z",
+ "end": "2026-02-05T00:00:00Z"
+ },
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-04T05:10:00Z",
+ "minutes": 310,
+ "nodeType": "VM.Optimized3.Flex",
+ "cpuCores": 4,
+ "ramBytes": 33347035136,
+ "cpuCoreHours": 20.666667,
+ "ramByteHours": 172293014869.333,
+ "GPUHours": 0,
+ "cpuBreakdown": {
+ "idle": 1,
+ "other": 0,
+ "system": 0,
+ "user": 0
+ },
+ "ramBreakdown": {
+ "idle": 1,
+ "other": 0,
+ "system": 0,
+ "user": 0
+ },
+ "preemptible": 1,
+ "discount": 0,
+ "cpuCost": 0.558,
+ "gpuCost": 0,
+ "gpuCount": 0,
+ "ramCost": 0.240691,
+ "adjustment": 0,
+ "overhead": {
+ "CpuOverheadFraction": 0.04625,
+ "RamOverheadFraction": 0.102885928479324,
+ "OverheadCostFraction": 0.0633176029938702
+ },
+ "totalCost": 0.798691
+ },
+ "apache/__undefined__/__undefined__/Compute/default-cluster/Node/Kubernetes/ocid1.instance.oc1.iad.anuwcljru4az63qc7pq7a2sk4kjwcdk6nm4kp7hgkfhnvcav6rdlkmk4jdna/10.0.144.5123": {
+ "type": "Node",
+ "properties": {
+ "category": "Compute",
+ "provider": "Oracle",
+ "service": "Kubernetes",
+ "cluster": "default-cluster",
+ "name": "10.0.144.51",
+ "providerID": "ocid1.instance.oc1.iad.anuwcljru4az63qc7pq7a2sk4kjwcdk6nm4kp7hgkfhnvcav6rdlkmk4jdna"
+ },
+ "labels": {
+ "beta_kubernetes_io_arch": "amd64",
+ "beta_kubernetes_io_instance_type": "VM.Optimized3.Flex",
+ "beta_kubernetes_io_os": "linux",
+ "displayName": "oke-cggb7sjbcpa-nwacqdcqrwa-sfr367dugkq-1",
+ "failure_domain_beta_kubernetes_io_region": "iad",
+ "failure_domain_beta_kubernetes_io_zone": "US-ASHBURN-AD-1",
+ "hostname": "oke-cggb7sjbcpa-nwacqdcqrwa-sfr367dugkq-1",
+ "internal_addr": "10.0.144.51",
+ "kubernetes_io_arch": "amd64",
+ "kubernetes_io_hostname": "10.0.144.51",
+ "kubernetes_io_os": "linux",
+ "last_migration_failure": "get_kubesvc_failure",
+ "node_info_compartment_id": "aaaaaaaaazsr3zf5iw2c4wu4of4rglbva7vx3ybf4ifbsyaj2iq4dpdc4gpa",
+ "node_info_compartment_name": "opencost",
+ "node_info_ds_proxymux_client": "true",
+ "node_info_kubeletVersion": "v1.31",
+ "node_kubernetes_io_instance_type": "VM.Optimized3.Flex",
+ "oci_oraclecloud_com_fault_domain": "FAULT-DOMAIN-1",
+ "oci_oraclecloud_com_host_id": "f589eb8254a",
+ "oci_oraclecloud_com_host_rack_id": "1b31d02bc4e",
+ "oci_oraclecloud_com_ip_family_ipv4": "true",
+ "oci_oraclecloud_com_ip_family_preferred": "ipv4",
+ "oci_oraclecloud_com_node_info_managed": "true",
+ "oci_oraclecloud_com_oke_is_preemptible": "true",
+ "oci_oraclecloud_com_vcn_native_ip_cni": "false",
+ "oke_oraclecloud_com_cluster_autoscaler": "disabled",
+ "oke_oraclecloud_com_node_info_private_subnet": "true",
+ "oke_oraclecloud_com_node_info_private_worker": "true",
+ "oke_oraclecloud_com_pool_mode": "node-pool",
+ "oke_oraclecloud_com_pool_name": "np-spot",
+ "oke_oraclecloud_com_tf_module": "terraform-oci-oke",
+ "oke_oraclecloud_com_tf_state_id": "ksmyvm",
+ "providerID": "ocid1.instance.oc1.iad.anuwcljru4az63qc7pq7a2sk4kjwcdk6nm4kp7hgkfhnvcav6rdlkmk4jdna",
+ "topology_kubernetes_io_region": "iad",
+ "topology_kubernetes_io_zone": "US-ASHBURN-AD-1"
+ },
+ "window": {
+ "start": "2026-01-28T00:00:00Z",
+ "end": "2026-02-05T00:00:00Z"
+ },
+ "start": "2026-02-05T00:00:00Z",
+ "end": "2026-02-06T13:05:12Z",
+ "minutes": 785.209354,
+ "nodeType": "VM.Optimized3.Flex",
+ "cpuCores": 4,
+ "ramBytes": 33347035136,
+ "cpuCoreHours": 52.34729,
+ "ramByteHours": 436406732210.94,
+ "GPUHours": 0,
+ "cpuBreakdown": {
+ "idle": 1,
+ "other": 0,
+ "system": 0,
+ "user": 0
+ },
+ "ramBreakdown": {
+ "idle": 1,
+ "other": 0,
+ "system": 0,
+ "user": 0
+ },
+ "preemptible": 1,
+ "discount": 0,
+ "cpuCost": 1.413377,
+ "gpuCost": 0,
+ "gpuCount": 0,
+ "ramCost": 0.609653,
+ "adjustment": 0,
+ "overhead": {
+ "CpuOverheadFraction": 0.04625,
+ "RamOverheadFraction": 0.102885928479324,
+ "OverheadCostFraction": 0.0633176029938702
+ },
+ "totalCost": 2.02303
+ },
+ //1 from managment for (8days back)
+ "sample/__undefined__/__undefined__/Management/default-cluster/ClusterManagement/Kubernetes/__undefined__/__undefined__": {
+ "type": "ClusterManagement",
+ "properties": {
+ "category": "Management",
+ "provider": "Oracle",
+ "service": "Kubernetes",
+ "cluster": "default-cluster"
+ },
+ "labels": {
+
+ },
+ "window": {
+ "start": "2026-01-28T00:00:00Z",
+ "end": "2026-02-05T00:00:00Z"
+ },
+ "start": "2026-01-28T00:00:00Z",
+ "end": "2026-02-05T00:00:00Z",
+ "minutes": 1440,
+ "totalCost": 1.308683
+ },
+ // 3 disk and 1 lb for (8days back)
+ "Oracle/__undefined__/__undefined__/Network/default-cluster/LoadBalancer/Kubernetes/129.213.15.26/ingress-nginx/ingress-nginx-demo-controller": {
+ "type": "LoadBalancer",
+ "properties": {
+ "category": "Network",
+ "provider": "Oracle",
+ "service": "Kubernetes",
+ "cluster": "default-cluster",
+ "name": "ingress-nginx/ingress-nginx-demo-controller",
+ "providerID": "129.213.15.26"
+ },
+ "labels": {
+
+ },
+ "window": {
+ "start": "2026-01-28T00:00:00Z",
+ "end": "2026-02-05T00:00:00Z"
+ },
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-04T13:05:12Z",
+ "minutes": 785.209403,
+ "adjustment": 0,
+ "totalCost": 0.147881,
+ "private": false,
+ "ip": "129.213.15.26"
+ },
+ "Oracle/__undefined__/__undefined__/Storage/default-cluster/Disk/Kubernetes/ocid1.volume.oc1.iad.abuwcljriemqfhkjnrqj6in7yffin6g35zvuoxk4o7vo57ze7mzueov62nua/csi-bb8858a8-d03b-4b2e-ae29-ccd2486aac42": {
+ "type": "Disk",
+ "properties": {
+ "category": "Storage",
+ "provider": "Oracle",
+ "service": "Kubernetes",
+ "cluster": "default-cluster",
+ "name": "csi-bb8858a8-d03b-4b2e-ae29-ccd2486aac42",
+ "providerID": "ocid1.volume.oc1.iad.abuwcljriemqfhkjnrqj6in7yffin6g35zvuoxk4o7vo57ze7mzueov62nua"
+ },
+ "labels": {
+
+ },
+ "window": {
+ "start": "2026-01-28T00:00:00Z",
+ "end": "2026-02-05T00:00:00Z"
+ },
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-04T13:05:12Z",
+ "minutes": 785.209846,
+ "byteHours": 1405187753227.41,
+ "bytes": 107374182400,
+ "byteHoursUsed": 491498390.937002,
+ "byteUsageMax": 37752832,
+ "breakdown": {
+ "idle": 1,
+ "other": 0,
+ "system": 0,
+ "user": 0
+ },
+ "adjustment": 0,
+ "totalCost": 0.044495,
+ "storageClass": "oci-bv",
+ "volumeName": "csi-bb8858a8-d03b-4b2e-ae29-ccd2486aac42",
+ "claimName": "test-install-speedtest-tracker-cnpg-main-2",
+ "local": 0,
+ "claimNamespace": "network-load-gen"
+ },
+ "Oracle/__undefined__/__undefined__/Storage/default-cluster/Disk/Kubernetes/ocid1.volume.oc1.iad.abuwcljrwqxpdxoqmn7bjmgayfsvfvnixntomcnilkujiw45vdg4bv2pucva/csi-3e493950-a8bb-48fc-8c6e-2a6c46be335e": {
+ "type": "Disk",
+ "properties": {
+ "category": "Storage",
+ "provider": "Oracle",
+ "service": "Kubernetes",
+ "cluster": "default-cluster",
+ "name": "csi-3e493950-a8bb-48fc-8c6e-2a6c46be335e",
+ "providerID": "ocid1.volume.oc1.iad.abuwcljrwqxpdxoqmn7bjmgayfsvfvnixntomcnilkujiw45vdg4bv2pucva"
+ },
+ "labels": {
+
+ },
+ "window": {
+ "start": "2026-01-28T00:00:00Z",
+ "end": "2026-02-05T00:00:00Z"
+ },
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-04T13:05:12Z",
+ "minutes": 785.209846,
+ "byteHours": 1405187753135.99,
+ "bytes": 107374182400,
+ "byteHoursUsed": 9870702828.70701,
+ "byteUsageMax": 812138496,
+ "breakdown": {
+ "idle": 1,
+ "other": 0,
+ "system": 0,
+ "user": 0
+ },
+ "adjustment": 0,
+ "totalCost": 0.044495,
+ "storageClass": "oci-bv",
+ "volumeName": "csi-3e493950-a8bb-48fc-8c6e-2a6c46be335e",
+ "claimName": "test-install-speedtest-tracker-cnpg-main-2-wal",
+ "local": 0,
+ "claimNamespace": "network-load-gen"
+ },
+ // (8days back)
+ "Oracle/__undefined__/__undefined__/Storage/default-cluster/Disk/Kubernetes/ocid1.volume.oc1.iad.abuwcljrzp57sacypolzcgdftatho3mpiliyz5lblzvvhuztckfdazfx37ma/csi-398733a4-9c59-4d71-92e0-2ec69ab99a9c": {
+ "type": "Disk",
+ "properties": {
+ "category": "Storage",
+ "provider": "Oracle",
+ "service": "Kubernetes",
+ "cluster": "default-cluster",
+ "name": "csi-398733a4-9c59-4d71-92e0-2ec69ab99a9c",
+ "providerID": "ocid1.volume.oc1.iad.abuwcljrzp57sacypolzcgdftatho3mpiliyz5lblzvvhuztckfdazfx37ma"
+ },
+ "labels": {
+
+ },
+ "window": {
+ "start": "2026-01-28T00:00:00Z",
+ "end": "2026-02-05T00:00:00Z"
+ },
+ "start": "2026-02-04T00:00:00Z",
+ "end": "2026-02-04T13:05:12Z",
+ "minutes": 785.209846,
+ "byteHours": 1405187753102.11,
+ "bytes": 107374182400,
+ "byteHoursUsed": 226168884.311569,
+ "byteUsageMax": 17653760,
+ "breakdown": {
+ "idle": 1,
+ "other": 0,
+ "system": 0,
+ "user": 0
+ },
+ "adjustment": 0,
+ "totalCost": 0.044495,
+ "storageClass": "oci-bv",
+ "volumeName": "csi-398733a4-9c59-4d71-92e0-2ec69ab99a9c",
+ "claimName": "test-install-speedtest-tracker-config",
+ "local": 0,
+ "claimNamespace": "network-load-gen"
+ },
+}
diff --git a/src/services/assetsCosts.js b/src/services/assetsCosts.js
new file mode 100644
index 00000000..063a79e7
--- /dev/null
+++ b/src/services/assetsCosts.js
@@ -0,0 +1,23 @@
+import client from "./api_client";
+
+class AssetsCostsService {
+ async fetchAssetsGraphCosts( ) {
+ const params = {
+ window: "7d",
+ filters:""//empty for now
+ };
+ // console.log("FETCH ASSETS FUNCTION CALLED");
+ const result = await client.get(`/assets`, {
+ params,
+ });
+ // console.log(result)
+ // console.log("result.data" + result.data)
+ // console.log("result.data.data" + result.data.data)
+ // let temp = Object.values(result.data)
+ // const returnData = Object.values(result.data.data)
+ // console.log("return data" + returnData)
+
+ return result.data;
+ }
+}
+export default new AssetsCostsService();
\ No newline at end of file