From 225eea086154ea7b2b9ce152f36da8af6ec622b4 Mon Sep 17 00:00:00 2001 From: Leo dev Date: Fri, 26 Dec 2025 20:59:52 +0100 Subject: [PATCH] Made the ui more mobile friendly --- package-lock.json | 298 +++++++++++++-------------- package.json | 2 +- src/app/applications/page.tsx | 36 ++-- src/app/containers/page.tsx | 230 +++++++++++++-------- src/app/deployments/page.tsx | 231 +++++++++++++-------- src/app/environment/page.tsx | 93 +++++---- src/app/logs/page.tsx | 51 +++-- src/app/monitoring/page.tsx | 43 ++-- src/app/nodes/page.tsx | 41 ++-- src/app/overview/page.tsx | 55 +++-- src/components/RadialChart.tsx | 78 +++++++ src/components/ui/chart.tsx | 357 +++++++++++++++++++++++++++++++++ 12 files changed, 1039 insertions(+), 476 deletions(-) create mode 100644 src/components/RadialChart.tsx create mode 100644 src/components/ui/chart.tsx diff --git a/package-lock.json b/package-lock.json index a1d7782..eb5fb8f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "next": "16.1.1", "react": "19.2.3", "react-dom": "19.2.3", - "recharts": "^3.6.0", + "recharts": "^2.15.4", "tailwind-merge": "^3.4.0" }, "devDependencies": { @@ -47,6 +47,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@balena/dockerignore": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@balena/dockerignore/-/dockerignore-1.0.2.tgz", @@ -1779,54 +1788,6 @@ "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", "license": "MIT" }, - "node_modules/@reduxjs/toolkit": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.2.tgz", - "integrity": "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==", - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.0.0", - "@standard-schema/utils": "^0.3.0", - "immer": "^11.0.0", - "redux": "^5.0.1", - "redux-thunk": "^3.1.0", - "reselect": "^5.1.0" - }, - "peerDependencies": { - "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", - "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-redux": { - "optional": true - } - } - }, - "node_modules/@reduxjs/toolkit/node_modules/immer": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.0.tgz", - "integrity": "sha512-dlzb07f5LDY+tzs+iLCSXV2yuhaYfezqyZQc+n6baLECWkOMEWxkECAOnXL0ba7lsA25fM9b2jtzpu/uxo1a7g==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "license": "MIT" - }, - "node_modules/@standard-schema/utils": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", - "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", - "license": "MIT" - }, "node_modules/@swc/helpers": { "version": "0.5.15", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", @@ -2244,12 +2205,6 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "license": "MIT" }, - "node_modules/@types/use-sync-external-store": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", - "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", - "license": "MIT" - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -2480,7 +2435,6 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "devOptional": true, "license": "MIT" }, "node_modules/d3-array": { @@ -2676,6 +2630,16 @@ "node": ">= 8.0" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -2705,16 +2669,6 @@ "node": ">=10.13.0" } }, - "node_modules/es-toolkit": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.43.0.tgz", - "integrity": "sha512-SKCT8AsWvYzBBuUqMk4NPwFlSdqLpJwmy6AP322ERn8W2YLIB6JBXnwMI2Qsh2gfphT3q7EKAxKb23cvFHFwKA==", - "license": "MIT", - "workspaces": [ - "docs", - "benchmarks" - ] - }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -2725,11 +2679,20 @@ } }, "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "license": "MIT" }, + "node_modules/fast-equals": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz", + "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -2781,16 +2744,6 @@ ], "license": "BSD-3-Clause" }, - "node_modules/immer": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", - "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -2825,6 +2778,12 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, "node_modules/lightningcss": { "version": "1.30.2", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", @@ -3086,6 +3045,12 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, "node_modules/lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -3098,6 +3063,18 @@ "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", "license": "Apache-2.0" }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/lucide-react": { "version": "0.562.0", "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.562.0.tgz", @@ -3235,6 +3212,15 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3279,6 +3265,23 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/protobufjs": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", @@ -3335,34 +3338,10 @@ } }, "node_modules/react-is": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.3.tgz", - "integrity": "sha512-qJNJfu81ByyabuG7hPFEbXqNcWSU3+eVus+KJs+0ncpGfMyYdvSmxiJxbWR65lYi1I+/0HBcliO029gc4F+PnA==", - "license": "MIT", - "peer": true - }, - "node_modules/react-redux": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", - "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", - "license": "MIT", - "dependencies": { - "@types/use-sync-external-store": "^0.0.6", - "use-sync-external-store": "^1.4.0" - }, - "peerDependencies": { - "@types/react": "^18.2.25 || ^19", - "react": "^18.0 || ^19", - "redux": "^5.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "redux": { - "optional": true - } - } + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" }, "node_modules/react-remove-scroll": { "version": "2.7.2", @@ -3411,6 +3390,21 @@ } } }, + "node_modules/react-smooth": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz", + "integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==", + "license": "MIT", + "dependencies": { + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/react-style-singleton": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", @@ -3433,6 +3427,22 @@ } } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -3448,48 +3458,35 @@ } }, "node_modules/recharts": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.6.0.tgz", - "integrity": "sha512-L5bjxvQRAe26RlToBAziKUB7whaGKEwD3znoM6fz3DrTowCIC/FnJYnuq1GEzB8Zv2kdTfaxQfi5GoH0tBinyg==", + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.4.tgz", + "integrity": "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==", "license": "MIT", - "workspaces": [ - "www" - ], "dependencies": { - "@reduxjs/toolkit": "1.x.x || 2.x.x", - "clsx": "^2.1.1", - "decimal.js-light": "^2.5.1", - "es-toolkit": "^1.39.3", - "eventemitter3": "^5.0.1", - "immer": "^10.1.1", - "react-redux": "8.x.x || 9.x.x", - "reselect": "5.1.1", - "tiny-invariant": "^1.3.3", - "use-sync-external-store": "^1.2.2", - "victory-vendor": "^37.0.2" + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.21", + "react-is": "^18.3.1", + "react-smooth": "^4.0.4", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" }, "engines": { - "node": ">=18" + "node": ">=14" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/redux": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", - "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT" - }, - "node_modules/redux-thunk": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", - "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", "license": "MIT", - "peerDependencies": { - "redux": "^5.0.0" + "dependencies": { + "decimal.js-light": "^2.4.1" } }, "node_modules/require-directory": { @@ -3501,12 +3498,6 @@ "node": ">=0.10.0" } }, - "node_modules/reselect": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", - "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", - "license": "MIT" - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -3837,15 +3828,6 @@ } } }, - "node_modules/use-sync-external-store": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", - "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -3866,9 +3848,9 @@ } }, "node_modules/victory-vendor": { - "version": "37.3.6", - "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", - "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", "license": "MIT AND ISC", "dependencies": { "@types/d3-array": "^3.0.3", diff --git a/package.json b/package.json index 42af77d..dbeb7df 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "next": "16.1.1", "react": "19.2.3", "react-dom": "19.2.3", - "recharts": "^3.6.0", + "recharts": "^2.15.4", "tailwind-merge": "^3.4.0" }, "devDependencies": { diff --git a/src/app/applications/page.tsx b/src/app/applications/page.tsx index db70541..d983248 100644 --- a/src/app/applications/page.tsx +++ b/src/app/applications/page.tsx @@ -89,14 +89,16 @@ export default function ApplicationsPage() { title="Applications" subtitle="Manage deployed applications" > -
-
+ {/* Header */} +
+
{applications.length} apps {applications.filter((a) => a.status === "running").length} running
- @@ -106,28 +108,30 @@ export default function ApplicationsPage() { {applications.map((app) => ( -
+
{/* Status & Name */} -
+
-
+
{app.name}
-
+
{app.image}
{/* Replicas */} -
-
Replicas
+
+ + Replicas +
{app.replicas}
{/* CPU */} -
+
CPU
@@ -136,7 +140,7 @@ export default function ApplicationsPage() {
{/* Memory */} -
+
Memory
@@ -147,13 +151,15 @@ export default function ApplicationsPage() {
{/* Network */} -
-
Network
+
+ + Network +
{app.network}
{/* Ports */} -
+
Ports
@@ -171,7 +177,7 @@ export default function ApplicationsPage() {
{/* Actions */} -
+
{app.status === "running" ? ( + ) : ( + + )} + + +
+
+ ))} +
diff --git a/src/app/deployments/page.tsx b/src/app/deployments/page.tsx index 2ed7558..311fe46 100644 --- a/src/app/deployments/page.tsx +++ b/src/app/deployments/page.tsx @@ -95,101 +95,156 @@ export default function DeploymentsPage() { title="Deployments" subtitle="Deployment history and management" > -
-
- {deployments.length} deployments -
-
- - - - - - - - - - - - - - - {deployments.map((dep) => ( - - - - - - - - - + {/* Desktop table */} +
+
- Application - - Version - - Status - - Replicas - - Deployed - - Duration - - Deployed By - - Actions -
-
- - {dep.app} -
-
-
- - {dep.version} - - ← {dep.previousVersion} - -
-
- - - {dep.replicas} - - - {dep.deployedAt} - - - {dep.duration} - - - {dep.deployedBy} - - -
- - - -
-
+ + + {[ + "Application", + "Version", + "Status", + "Replicas", + "Deployed", + "Duration", + "Deployed By", + "Actions", + ].map((h) => ( + + ))} - ))} - -
+ {h} +
+ + + {deployments.map((dep) => ( + + +
+ + {dep.app} +
+ + + +
+ + {dep.version} + + ← {dep.previousVersion} + +
+ + + + + + + + {dep.replicas} + + + + {dep.deployedAt} + + + + {dep.duration} + + + + {dep.deployedBy} + + + +
+ + + +
+ + + ))} + + +
+ + {/* Mobile cards */} +
+ {deployments.map((dep) => ( +
+
+
+ + {dep.app} +
+ +
+ +
+ + {dep.version} + + ← {dep.previousVersion} + +
+ +
+
+ Replicas +
{dep.replicas}
+
+
+ Duration +
{dep.duration}
+
+
+ Deployed +
{dep.deployedAt}
+
+
+ By +
{dep.deployedBy}
+
+
+ +
+ + + +
+
+ ))} +
diff --git a/src/app/environment/page.tsx b/src/app/environment/page.tsx index 65672a6..15f00a3 100644 --- a/src/app/environment/page.tsx +++ b/src/app/environment/page.tsx @@ -60,25 +60,28 @@ export default function EnvironmentPage() { title="Environment" subtitle="Manage environment variables" > -
+
{/* Sidebar */} -
+
Applications - + {envGroups.map((group) => (
- {/* Main Content */} + {/* Main */}
- +
{selectedApp}

@@ -102,54 +105,66 @@ export default function EnvironmentPage() { secrets

-
+ +
+ -
-
-
Key
-
Value
-
Actions
-
+ {/* Table header (desktop only) */} +
+
Key
+
Value
+
Actions
+
+ + {/* Rows */} +
{currentGroup?.variables.map((variable) => (
-
+ {/* Key */} +
{variable.secret && ( )} {variable.key}
-
-
- -
+ + {/* Value */} +
+
-
+ + {/* Actions */} +
{variable.secret && (
-
+ + {/* Actions */} +
-
+ +
+
+ {/* Log Card */} @@ -240,25 +246,38 @@ export default function LogsPage() { )}
+ -
+
{filteredLogs.map((log, index) => ( -
- +
+ {/* Timestamp */} + {log.timestamp} + + {/* Level */} [{log.level}] - + + {/* Source */} + {log.source} - {log.message} + + {/* Message */} + + {log.message} +
))}
diff --git a/src/app/monitoring/page.tsx b/src/app/monitoring/page.tsx index 8426b43..bb18e13 100644 --- a/src/app/monitoring/page.tsx +++ b/src/app/monitoring/page.tsx @@ -14,6 +14,8 @@ import { Area, } from "recharts"; import { Progress } from "@/components/ui/progress"; +import RadialChart from "@/components/RadialChart"; +import { ArrowDownLeft, ArrowUpRight, Cpu, MemoryStick } from "lucide-react"; const cpuData = [ { time: "00:00", value: 45 }, @@ -81,7 +83,7 @@ export default function MonitoringPage() { subtitle="Resource utilization and metrics" > {/* Summary Stats */} -
+
@@ -123,16 +125,15 @@ export default function MonitoringPage() {
{/* Charts */} -
+
- - CPU Usage - Last 12 hours + + CPU Usage Last 12 hours -
+
@@ -169,8 +170,8 @@ export default function MonitoringPage() { /> - - Memory Usage - Last 12 hours + + Memory Usage Last 12 hours -
+
@@ -233,8 +233,8 @@ export default function MonitoringPage() { /> - - Network I/O - Last 12 hours + + Network I/O Last 12 hours -
+
-
+
Inbound @@ -322,7 +321,7 @@ export default function MonitoringPage() { Container Metrics -
+
{containerMetrics.map((container) => (
-
-
+
+
{nodes.length} nodes - - {nodes.filter((n) => n.status === "running").length} online - + {nodes.filter((n) => n.status === "running").length} online
-
+
{nodes.map((node) => ( - -
+ +
-
+
{node.name}
@@ -87,7 +84,7 @@ export default function NodesPage() {
-
+
{node.labels.map((label) => ( {label} @@ -102,12 +99,10 @@ export default function NodesPage() {
-
+
{/* System Info */} -
-
- System -
+
+
System
OS @@ -135,12 +130,8 @@ export default function NodesPage() { {/* Memory */}
-
- Memory -
-
- {node.memory.percentage}% -
+
Memory
+
{node.memory.percentage}%
{node.memory.used} / {node.memory.total} @@ -159,9 +150,7 @@ export default function NodesPage() { {/* Quick Actions */}
-
- Quick Actions -
+
Quick Actions
- -
+ +
Name
Containers
@@ -167,27 +168,23 @@ export default function OverviewPage() { {applications.map((app) => (
{app.name}
{app.containers}
-
-
- - - {app.cpu}% - -
+
+ + + {app.cpu}% +
-
-
- - - {app.memory}% - -
+
+ + + {app.memory}% +
@@ -213,7 +210,7 @@ export default function OverviewPage() { {recentDeployments.map((dep) => (
@@ -224,9 +221,8 @@ export default function OverviewPage() {
-
- - {dep.time} +
+ {dep.time}
))} @@ -241,14 +237,14 @@ export default function OverviewPage() { Cluster Nodes {nodes.length} nodes - -
+ +
{nodes.map((node) => (
-
+
{node.name} @@ -267,7 +263,10 @@ export default function OverviewPage() { Memory {node.memory}%
- +
Containers {node.containers} diff --git a/src/components/RadialChart.tsx b/src/components/RadialChart.tsx new file mode 100644 index 0000000..95d8361 --- /dev/null +++ b/src/components/RadialChart.tsx @@ -0,0 +1,78 @@ +"use client"; + +import { + Label, + PolarGrid, + PolarRadiusAxis, + RadialBar, + RadialBarChart, +} from "recharts"; +import { ChartContainer, type ChartConfig } from "@/components/ui/chart"; + +const chartConfig = { + value: { + label: "Value", + }, +} satisfies ChartConfig; + +export default function RadialChart({ + value, + children, +}: { + value: number; + children?: React.ReactNode; +}) { + const chartData = [{ value, fill: "var(--color-chart-1)" }]; + + return ( + + + + + + + + + ); +} diff --git a/src/components/ui/chart.tsx b/src/components/ui/chart.tsx new file mode 100644 index 0000000..8b42f21 --- /dev/null +++ b/src/components/ui/chart.tsx @@ -0,0 +1,357 @@ +"use client" + +import * as React from "react" +import * as RechartsPrimitive from "recharts" + +import { cn } from "@/lib/utils" + +// Format: { THEME_NAME: CSS_SELECTOR } +const THEMES = { light: "", dark: ".dark" } as const + +export type ChartConfig = { + [k in string]: { + label?: React.ReactNode + icon?: React.ComponentType + } & ( + | { color?: string; theme?: never } + | { color?: never; theme: Record } + ) +} + +type ChartContextProps = { + config: ChartConfig +} + +const ChartContext = React.createContext(null) + +function useChart() { + const context = React.useContext(ChartContext) + + if (!context) { + throw new Error("useChart must be used within a ") + } + + return context +} + +function ChartContainer({ + id, + className, + children, + config, + ...props +}: React.ComponentProps<"div"> & { + config: ChartConfig + children: React.ComponentProps< + typeof RechartsPrimitive.ResponsiveContainer + >["children"] +}) { + const uniqueId = React.useId() + const chartId = `chart-${id || uniqueId.replace(/:/g, "")}` + + return ( + +
+ + + {children} + +
+
+ ) +} + +const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => { + const colorConfig = Object.entries(config).filter( + ([, config]) => config.theme || config.color + ) + + if (!colorConfig.length) { + return null + } + + return ( +