diff --git a/package-lock.json b/package-lock.json index a02a7fba..69ddc805 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,8 @@ "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.28.6", + "@carbon/icons-react": "^11.74.0", + "@carbon/react": "^1.100.0", "@date-io/core": "^3.2.0", "@date-io/date-fns": "^3.2.1", "@emotion/react": "^11.14.0", @@ -19,6 +21,7 @@ "@mui/material": "^7.3.6", "@mui/x-date-pickers": "^8.25.0", "axios": "^1.13.3", + "carbon-components": "^10.59.2", "date-fns": "^4.1.0", "html-to-react": "^1.7.0", "lodash": "^4.17.23", @@ -34,11 +37,14 @@ "@babel/plugin-proposal-class-properties": "^7.18.6", "@babel/plugin-transform-runtime": "^7.28.5", "@babel/preset-react": "^7.28.5", + "@types/react": "^19.2.13", + "@types/react-dom": "^19.2.3", "buffer": "^6.0.3", "parcel": "^2.16.3", "prettier": "^3.8.0", "process": "^0.11.10", - "set-value": "4.1.0" + "set-value": "4.1.0", + "typescript": "^5.9.3" } }, "node_modules/@babel/code-frame": { @@ -546,6 +552,194 @@ "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, + "license": "Apache-2.0", + "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, + "license": "Apache-2.0", + "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, + "license": "Apache-2.0", + "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, + "license": "Apache-2.0", + "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, + "license": "Apache-2.0", + "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, + "license": "Apache-2.0", + "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, + "license": "Apache-2.0", + "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, + "license": "Apache-2.0", + "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, + "license": "Apache-2.0", + "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/telemetry": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@carbon/telemetry/-/telemetry-0.1.0.tgz", + "integrity": "sha512-kNWt0bkgPwGW0i5h7HFuljbKRXPvIhsKbB+1tEURAYLXoJg9iJLF1eGvWN5iVoFCS2zje4GR3OGOsvvKVe7Hlg==", + "license": "Apache-2.0", + "bin": { + "carbon-telemetry": "bin/carbon-telemetry.js" + } + }, + "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, + "license": "Apache-2.0", + "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, + "license": "Apache-2.0", + "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, + "license": "Apache-2.0", + "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 +915,166 @@ "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==", + "license": "MIT", + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "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==", + "license": "MIT" + }, + "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==", + "license": "OFL-1.1", + "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, + "license": "OFL-1.1", + "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, + "license": "OFL-1.1", + "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, + "license": "OFL-1.1", + "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, + "license": "OFL-1.1", + "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, + "license": "OFL-1.1", + "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, + "license": "OFL-1.1", + "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, + "license": "OFL-1.1", + "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, + "license": "OFL-1.1", + "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==", + "license": "Apache-2.0", + "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==", + "license": "Apache-2.0", + "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", @@ -3307,7 +3661,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" @@ -3399,13 +3752,23 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "19.2.2", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", - "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", + "version": "19.2.13", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.13.tgz", + "integrity": "sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "csstype": "^3.0.2" + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" } }, "node_modules/@types/react-transition-group": { @@ -3669,6 +4032,25 @@ ], "license": "CC-BY-4.0" }, + "node_modules/carbon-components": { + "version": "10.59.2", + "resolved": "https://registry.npmjs.org/carbon-components/-/carbon-components-10.59.2.tgz", + "integrity": "sha512-apaSI8ce+0IV6BrMSH51yBO/CaeDLjQkBckH/l11X7euNvl58falGcw1S715T4jW5qjpxYcrXAjKVtZHagx2SA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@carbon/telemetry": "0.1.0", + "flatpickr": "4.6.1", + "lodash.debounce": "^4.0.8", + "warning": "^3.0.0" + } + }, + "node_modules/carbon-components/node_modules/flatpickr": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.1.tgz", + "integrity": "sha512-3ULSxbXmcMIRzer/2jLNweoqHpwDvsjEawO2FUd9UFR8uPwLM+LruZcPDpuZStcEgbQKhuFOfXo4nYdGladSNw==", + "license": "MIT" + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -3696,6 +4078,12 @@ "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==", + "license": "MIT" + }, "node_modules/clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", @@ -3715,11 +4103,23 @@ "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==", + "license": "MIT", + "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 +4132,18 @@ "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==", + "license": "MIT", + "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 +4166,12 @@ "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==", + "license": "MIT" + }, "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 +4188,15 @@ "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==", + "license": "MIT", + "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", @@ -4079,6 +4503,28 @@ "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==", + "license": "MIT", + "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==", + "license": "MIT" + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -4223,6 +4669,12 @@ "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==", + "license": "MIT" + }, "node_modules/follow-redirects": { "version": "1.15.11", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", @@ -4506,6 +4958,15 @@ "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==", + "license": "MIT", + "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", @@ -4956,7 +5417,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true, "license": "MIT" }, "node_modules/loose-envify": { @@ -5334,6 +5794,12 @@ "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==", + "license": "MIT" + }, "node_modules/react-is": { "version": "19.2.3", "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.3.tgz", @@ -5560,6 +6026,21 @@ "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==", + "license": "MIT", + "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==", + "license": "MIT" + }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -5600,6 +6081,12 @@ "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==", + "license": "MIT" + }, "node_modules/term-size": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", @@ -5632,11 +6119,16 @@ "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==", + "license": "MIT" + }, "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": { @@ -5652,6 +6144,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/update-browserslist-db": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", @@ -5724,6 +6230,15 @@ "d3-timer": "^3.0.1" } }, + "node_modules/warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", + "integrity": "sha512-jMBt6pUrKn5I+OGgtQ4YZLdhIeJmObddh6CsibPxyQ5yPZm1XExSyzC1LCNX7BzhxWgiHmizBWJTHJIjMjTQYQ==", + "license": "BSD-3-Clause", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/weak-lru-cache": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", diff --git a/package.json b/package.json index c1856034..cb500002 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,8 @@ ], "dependencies": { "@babel/runtime": "^7.28.6", + "@carbon/icons-react": "^11.74.0", + "@carbon/react": "^1.100.0", "@date-io/core": "^3.2.0", "@date-io/date-fns": "^3.2.1", "@emotion/react": "^11.14.0", @@ -23,6 +25,7 @@ "@mui/material": "^7.3.6", "@mui/x-date-pickers": "^8.25.0", "axios": "^1.13.3", + "carbon-components": "^10.59.2", "date-fns": "^4.1.0", "html-to-react": "^1.7.0", "lodash": "^4.17.23", @@ -38,11 +41,14 @@ "@babel/plugin-proposal-class-properties": "^7.18.6", "@babel/plugin-transform-runtime": "^7.28.5", "@babel/preset-react": "^7.28.5", + "@types/react": "^19.2.13", + "@types/react-dom": "^19.2.3", "buffer": "^6.0.3", "parcel": "^2.16.3", "prettier": "^3.8.0", "process": "^0.11.10", - "set-value": "4.1.0" + "set-value": "4.1.0", + "typescript": "^5.9.3" }, "resolutions": { "set-value": "4.1.0" diff --git a/src/components/Nav/SidebarNav.js b/src/components/Nav/SidebarNav.js index 781184d7..33842622 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, FactCheck } 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/css/assets.css b/src/css/assets.css new file mode 100644 index 00000000..8d859759 --- /dev/null +++ b/src/css/assets.css @@ -0,0 +1,95 @@ +/* assets.css - Premium Overrides and Enhancements */ + +.assets-container { + padding: 2rem; + max-width: 1400px; + margin: 0 auto; +} + +.assets-summary-grid { + margin-bottom: 2rem; +} + +.assets-viz-card { + background: #ffffff; + padding: 1.5rem; + border: 1px solid #e0e0e0; + border-radius: 4px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); +} + +.viz-heading { + font-size: 1.125rem; + font-weight: 600; + margin-bottom: 1.5rem; + color: #161616; +} + +.summary-tile-mini { + height: 142px; + /* Calculated to match viz card height in grid ideally */ + background: #ffffff; + transition: all 0.2s cubic-bezier(0.2, 0, 0.38, 0.9); +} + +.summary-tile-mini:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); +} + +.summary-label { + color: #525252; + font-size: 0.875rem; +} + +.summary-value { + font-size: 1.75rem; + font-weight: 600; + color: #161616; +} + +.assets-accordion { + margin-top: 1rem; + background: #ffffff; + border: 1px solid #e0e0e0; +} + +.accordion-title-wrapper { + display: flex; + align-items: center; + gap: 1rem; + padding: 0.5rem 0; +} + +.type-title { + font-weight: 600; + font-size: 1rem; +} + +.cost-cell { + font-weight: 600; + color: #0f62fe; +} + +.assets-error-wrapper { + color: #da1e28; + padding: 2rem; + border: 1px solid #da1e28; + background: #fff1f1; + text-align: center; + border-radius: 4px; +} + +/* Fix Carbon Table Search width */ +.cds--table-toolbar-content .cds--search { + max-width: 400px !important; +} + +.cds--table-container { + padding: 0 !important; +} + +.count-tag { + margin-left: auto; + margin-right: 2rem; +} \ No newline at end of file diff --git a/src/css/index.css b/src/css/index.css index 8ace1e31..b5564541 100644 --- a/src/css/index.css +++ b/src/css/index.css @@ -1,4 +1,6 @@ @import "../../node_modules/material-design-icons-iconfont/dist/material-design-icons.css"; +@import "../../node_modules/@carbon/styles/css/styles.min.css"; +@import "./assets.css"; body { background-color: #f3f3f3; @@ -17,4 +19,4 @@ body .page-container { .recharts-tooltip-wrapper { z-index: 1000; -} +} \ No newline at end of file diff --git a/src/pages/Assets.tsx b/src/pages/Assets.tsx new file mode 100644 index 00000000..2a880a5a --- /dev/null +++ b/src/pages/Assets.tsx @@ -0,0 +1,287 @@ +import React, { useEffect, useState } from "react"; +import { + Loading, + DataTable, + TableContainer, + Table, + TableHead, + TableRow, + TableHeader, + TableBody, + TableCell, + Accordion, + AccordionItem, + ClickableTile, + Column, + Grid, + Stack, + Theme, + Layer, + Heading, + Tag, + TableToolbar, + TableToolbarContent, + TableToolbarSearch, + Toggle +} from "@carbon/react"; +import { Information, Cube, Cloud, Network_4 } from "@carbon/icons-react"; +import { PieChart, Pie, Cell, Tooltip, ResponsiveContainer, Legend } from "recharts"; +import Page from "../components/Page"; +import Header from "../components/Header"; +import AssetsService from "../services/assets"; +import { toCurrency } from "../util"; + +interface Asset { + id: string; + type: string; + totalCost: number; + monthlyCost: number; + name: string; + providerID: string; + [key: string]: any; +} + +const COLORS = ['#0062ff', '#24a148', '#a2191f', '#6929c4', '#1192e8', '#b28600']; + +const Assets: React.FC = () => { + const [loading, setLoading] = useState(true); + const [allAssets, setAllAssets] = useState([]); // Store full dataset + const [assets, setAssets] = useState([]); // Store displayed dataset + const [summary, setSummary] = useState({ total: 0, count: 0, topType: "" }); + const [chartData, setChartData] = useState([]); + const [error, setError] = useState(null); + const [showHighCost, setShowHighCost] = useState(false); + + useEffect(() => { + const fetchAssets = async () => { + setLoading(true); + try { + const response = await AssetsService.fetchAssets("7d", "type", { accumulate: true }); + // Normalize data: sometimes it's wrapped in { data: [...] }, sometimes it's just [...] + const rawData = response?.data || (Array.isArray(response) ? response : null); + + if (rawData && Array.isArray(rawData)) { + const flattened: Asset[] = rawData.flatMap((set: any) => { + if (!set || typeof set !== 'object') return []; + return Object.entries(set).map(([id, val]: [string, any]) => { + const tc = Number(val?.totalCost) || 0; + return { + id, + ...(val && typeof val === 'object' ? val : {}), + totalCost: tc, + monthlyCost: (tc / 7) * 30 + }; + }); + }); + + // Defensive data processing + const validAssets = flattened.filter(a => a && a.type && a.id); + setAllAssets(validAssets); + setError(null); + } else { + throw new Error("Invalid data structure received from Assets API"); + } + } catch (err) { + setError("Failed to fetch assets data. Please ensure the backend is reachable."); + console.error("Assets Load Error:", err); + } finally { + setLoading(false); + } + }; + fetchAssets(); + }, []); + + // Filter Effect + useEffect(() => { + let filtered = allAssets; + if (showHighCost) { + filtered = allAssets.filter(a => (a.totalCost / 7) > 10); // > $10/day + } + setAssets(filtered); + + // Recalculate Summary & Charts based on FILTERED view + const totalCostValue = filtered.reduce((acc, curr) => acc + (Number(curr.totalCost) || 0), 0); + const types = filtered.reduce((acc: Record, curr) => { + const t = curr.type || "Other"; + acc[t] = (acc[t] || 0) + (Number(curr.totalCost) || 0); + return acc; + }, {}); + + const chartRaw = Object.entries(types).map(([name, value]) => ({ name, value })); + setChartData(chartRaw); + + const sortedTypes = Object.entries(types).sort((a, b) => b[1] - a[1]); + const topTypeValue = sortedTypes[0]?.[0] || "None"; + setSummary({ total: totalCostValue, count: filtered.length, topType: topTypeValue }); + + }, [allAssets, showHighCost]); + + const headers = [ + { key: "name", header: "Name" }, + { key: "providerID", header: "Provider ID" }, + { key: "totalCost", header: "7d Cost" }, + { key: "monthlyCost", header: "Est. Monthly" }, + ]; + + const getTypeIcon = (type: string) => { + const t = type.toLowerCase(); + if (t === 'node') return ; + if (t === 'disk') return ; + if (t === 'network') return ; + return ; + }; + + const groupedAssets = assets.reduce((acc: Record, curr) => { + acc[curr.type] = acc[curr.type] || []; + acc[curr.type].push(curr); + return acc; + }, {}); + + return ( + + +
+
+ +
+ {loading ? ( + + ) : error ? ( +
{error}
+ ) : ( + + + +
+
+ Cost Distribution by Asset Type + setShowHighCost(!showHighCost)} + /> +
+
+ + + + {chartData.map((_entry, index) => ( + + ))} + + toCurrency(value, "USD")} /> + + + +
+
+
+ + + + +

Total Ecosystem Cost

+ {toCurrency(summary.total, "USD")} + 7D Accumulate +
+
+ + +

Primary Driver

+ {summary.topType} + Action Recommended +
+
+
+
+
+ + + + {Object.entries(groupedAssets).map(([type, list]) => ( + + {getTypeIcon(type)} + {type} Assets + {list.length} Items +
+ } + key={type} + > + + {({ + rows, + headers, + getTableProps, + getHeaderProps, + getRowProps, + getTableContainerProps, + onInputChange, + }) => ( + + + + + + + + + + {headers.map((header) => ( + + {header.header} + + ))} + + + + {rows.map((row) => ( + + {row.cells.map((cell) => ( + + {cell.info.header === "totalCost" || cell.info.header === "monthlyCost" + ? {toCurrency(cell.value as number, "USD")} + : (cell.value || "N/A")} + + ))} + + ))} + {rows.length === 0 && ( + + No matching assets found. + + )} + +
+
+ )} +
+ + ))} + + + + )} +
+ +
+
+ ); +}; + +export default Assets; diff --git a/src/route.js b/src/route.js index 919717b2..18fd8529 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 Assets from "./pages/Assets"; const basename = (process.env.UI_PATH || "").replace(/\/+$/, ""); @@ -18,6 +19,7 @@ const RouteSet = () => { } /> } /> } /> + } /> diff --git a/src/services/assets.js b/src/services/assets.js new file mode 100644 index 00000000..5cd24751 --- /dev/null +++ b/src/services/assets.js @@ -0,0 +1,45 @@ +import { parseFilters } from "../util"; +import client from "./api_client"; +import { getMockAssetsData } from "./assets.mock"; + +const USE_MOCK_DATA = process.env.REACT_APP_USE_MOCK_DATA === "true" || true; // Default to true for development + +class AssetsService { + async fetchAssets(win, aggregate, options) { + // Defensive check for hostname to force mock on preview sites + const isPreview = window.location.hostname.includes('netlify') || window.location.hostname.includes('github.io'); + + if (isPreview) { + console.log("Preview environment detected, using mock assets data."); + return getMockAssetsData(); + } + + const { accumulate = true, filters } = options; + const params = { + window: win, + aggregate: aggregate, + accumulate: accumulate, + }; + + if (filters && filters.length > 0) { + params.filter = parseFilters(filters); + } + + try { + const result = await client.get("/assets", { + params, + }); + // Handle both { data: [...] } and just [...] response formats + const responseData = result.data; + if (responseData && (responseData.data || Array.isArray(responseData))) { + return responseData; + } + throw new Error("Unexpected API response format"); + } catch (error) { + console.warn("Assets API unreachable or invalid response, falling back to mock data.", error); + return getMockAssetsData(); + } + } +} + +export default new AssetsService(); diff --git a/src/services/assets.mock.js b/src/services/assets.mock.js new file mode 100644 index 00000000..99a40d0b --- /dev/null +++ b/src/services/assets.mock.js @@ -0,0 +1,74 @@ +export const getMockAssetsData = () => { + return { + data: [ + { + "Cluster/Node/oc-demo-node-1": { + name: "oc-demo-node-1", + type: "Node", + totalCost: 125.50, + providerID: "i-0abc123456789def0", + labels: { + "topology.kubernetes.io/region": "us-east-1", + "node.kubernetes.io/instance-type": "m5.large" + } + }, + "Cluster/Node/oc-demo-node-2": { + name: "oc-demo-node-2", + type: "Node", + totalCost: 110.20, + providerID: "i-0abc123456789def1", + labels: { + "topology.kubernetes.io/region": "us-east-1", + "node.kubernetes.io/instance-type": "m5.large" + } + }, + "Cluster/Node/oc-demo-node-3": { + name: "oc-demo-node-3", + type: "Node", + totalCost: 155.00, + providerID: "i-0abc123456789def2", + labels: { + "topology.kubernetes.io/region": "us-west-2", + "node.kubernetes.io/instance-type": "c5.xlarge" + } + }, + "Cluster/Disk/vol-0123456789abcdef0": { + name: "vol-0123456789abcdef0", + type: "Disk", + totalCost: 15.00, + providerID: "vol-0123456789abcdef0", + labels: { + "kubernetes.io/cluster/demo": "owned" + } + }, + "Cluster/Disk/vol-0123456789abcdef1": { + name: "vol-0123456789abcdef1", + type: "Disk", + totalCost: 12.50, + providerID: "vol-0123456789abcdef1", + labels: { + "kubernetes.io/cluster/demo": "owned" + } + }, + "Cluster/Network/LoadBalancer-1": { + name: "LoadBalancer/frontend-lb", + type: "Network", + totalCost: 45.00, + providerID: "arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/frontend/1", + labels: { + "service": "frontend" + } + }, + "Cluster/Network/LoadBalancer-2": { + name: "LoadBalancer/backend-lb", + type: "Network", + totalCost: 35.00, + providerID: "arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/backend/2", + labels: { + "service": "api" + } + } + } + ] + }; +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..0d4cfe41 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "node", + "lib": [ + "DOM", + "DOM.Iterable", + "ESNext" + ], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": false, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "jsx": "react-jsx" + }, + "include": [ + "src" + ] +} \ No newline at end of file