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) && ( +
+
+ +
+
+ { } +
+ +
+ + )} + + {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