diff --git a/internal/graph/schema.resolvers.go b/internal/graph/schema.resolvers.go index 1e02aba8..244f087f 100644 --- a/internal/graph/schema.resolvers.go +++ b/internal/graph/schema.resolvers.go @@ -31,7 +31,8 @@ func (r *clusterResolver) Partitions(ctx context.Context, obj *schema.Cluster) ( // StartTime is the resolver for the startTime field. func (r *jobResolver) StartTime(ctx context.Context, obj *schema.Job) (*time.Time, error) { - panic(fmt.Errorf("not implemented: StartTime - startTime")) + timestamp := time.Unix(obj.StartTime, 0) + return ×tamp, nil } // Tags is the resolver for the tags field. diff --git a/internal/metricdata/cc-metric-store.go b/internal/metricdata/cc-metric-store.go index 557e1d25..b76ed5b4 100644 --- a/internal/metricdata/cc-metric-store.go +++ b/internal/metricdata/cc-metric-store.go @@ -850,7 +850,7 @@ func (ccms *CCMetricStore) LoadNodeListData( if len(nodes) > page.ItemsPerPage { start := (page.Page - 1) * page.ItemsPerPage end := start + page.ItemsPerPage - if end > len(nodes) { + if end >= len(nodes) { end = len(nodes) hasNextPage = false } else { diff --git a/internal/metricdata/prometheus.go b/internal/metricdata/prometheus.go index fa497649..e0add3a7 100644 --- a/internal/metricdata/prometheus.go +++ b/internal/metricdata/prometheus.go @@ -539,7 +539,7 @@ func (pdb *PrometheusDataRepository) LoadNodeListData( if len(nodes) > page.ItemsPerPage { start := (page.Page - 1) * page.ItemsPerPage end := start + page.ItemsPerPage - if end > len(nodes) { + if end >= len(nodes) { end = len(nodes) hasNextPage = false } else { diff --git a/web/frontend/package-lock.json b/web/frontend/package-lock.json index 0b31f401..51e358d9 100644 --- a/web/frontend/package-lock.json +++ b/web/frontend/package-lock.json @@ -9,32 +9,31 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "@rollup/plugin-replace": "^5.0.7", - "@sveltestrap/sveltestrap": "^6.2.7", - "@urql/svelte": "^4.2.2", - "chart.js": "^4.4.6", - "date-fns": "^2.30.0", - "graphql": "^16.9.0", - "mathjs": "^12.4.3", - "svelte-chartjs": "^3.1.5", - "uplot": "^1.6.31", - "wonka": "^6.3.4" + "@rollup/plugin-replace": "^6.0.2", + "@sveltestrap/sveltestrap": "^7.1.0", + "@urql/svelte": "^4.2.3", + "chart.js": "^4.4.9", + "date-fns": "^4.1.0", + "graphql": "^16.11.0", + "mathjs": "^14.5.2", + "uplot": "^1.6.32", + "wonka": "^6.3.5" }, "devDependencies": { - "@rollup/plugin-commonjs": "^25.0.8", - "@rollup/plugin-node-resolve": "^15.3.0", + "@rollup/plugin-commonjs": "^28.0.3", + "@rollup/plugin-node-resolve": "^16.0.1", "@rollup/plugin-terser": "^0.4.4", "@timohausmann/quadtree-js": "^1.2.6", - "rollup": "^4.27.4", + "rollup": "^4.41.1", "rollup-plugin-css-only": "^4.5.2", "rollup-plugin-svelte": "^7.2.2", - "svelte": "^4.2.19" + "svelte": "^5.33.14" } }, "node_modules/@0no-co/graphql.web": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.0.11.tgz", - "integrity": "sha512-xuSJ9WXwTmtngWkbdEoopMo6F8NLtjy84UNAMsAr5C3/2SgAL/dEU10TMqTIsipqPQ8HA/7WzeqQ9DEQxSvPPA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.1.2.tgz", + "integrity": "sha512-N2NGsU5FLBhT8NZ+3l2YrzZSHITjNXNuDhC4iDiikv0IujaJ0Xc6xIxQZ/Ek3Cb+rgPjnLHYyJm11tInuJn+cw==", "license": "MIT", "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0" @@ -59,21 +58,18 @@ } }, "node_modules/@babel/runtime": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", - "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz", + "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==", "license": "MIT", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, "engines": { "node": ">=6.9.0" } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", @@ -146,21 +142,22 @@ } }, "node_modules/@rollup/plugin-commonjs": { - "version": "25.0.8", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.8.tgz", - "integrity": "sha512-ZEZWTK5n6Qde0to4vS9Mr5x/0UZoqCxPVR9KRUjU4kA2sO7GEUn1fop0DAwpO6z0Nw/kJON9bDmSxdWxO/TT1A==", + "version": "28.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.3.tgz", + "integrity": "sha512-pyltgilam1QPdn+Zd9gaCfOLcnjMEJ9gV+bTw6/r73INdvzf1ah9zLIJBm+kW7R6IUFIQ1YO+VqZtYxZNWFPEQ==", "dev": true, "license": "MIT", "dependencies": { "@rollup/pluginutils": "^5.0.1", "commondir": "^1.0.1", "estree-walker": "^2.0.2", - "glob": "^8.0.3", + "fdir": "^6.2.0", "is-reference": "1.2.1", - "magic-string": "^0.30.3" + "magic-string": "^0.30.3", + "picomatch": "^4.0.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0 || 14 >= 14.17" }, "peerDependencies": { "rollup": "^2.68.0||^3.0.0||^4.0.0" @@ -172,9 +169,9 @@ } }, "node_modules/@rollup/plugin-node-resolve": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.0.tgz", - "integrity": "sha512-9eO5McEICxMzJpDW9OnMYSv4Sta3hmt7VtBFz5zR9273suNOydOyq/FrGeGy+KsTRFm8w0SLVhzig2ILFT63Ag==", + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.1.tgz", + "integrity": "sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==", "dev": true, "license": "MIT", "dependencies": { @@ -197,9 +194,9 @@ } }, "node_modules/@rollup/plugin-replace": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.7.tgz", - "integrity": "sha512-PqxSfuorkHz/SPpyngLyg5GCEkOcee9M1bkxiVDr41Pd61mqP1PLOoDPbpl44SB2mQGKwV/In74gqQmGITOhEQ==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.2.tgz", + "integrity": "sha512-7QaYCf8bqF04dOy7w/eHmJeNExxTYwvKAmlSAH/EaWWUzbT0h5sbF6bktFoX/0F/0qwng5/dWFMyf3gzaM8DsQ==", "license": "MIT", "dependencies": { "@rollup/pluginutils": "^5.0.1", @@ -241,9 +238,9 @@ } }, "node_modules/@rollup/pluginutils": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.3.tgz", - "integrity": "sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", + "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", @@ -263,9 +260,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.4.tgz", - "integrity": "sha512-2Y3JT6f5MrQkICUyRVCw4oa0sutfAsgaSsb0Lmmy1Wi2y7X5vT9Euqw4gOsCyy0YfKURBg35nhUKZS4mDcfULw==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.1.tgz", + "integrity": "sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw==", "cpu": [ "arm" ], @@ -277,9 +274,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.4.tgz", - "integrity": "sha512-wzKRQXISyi9UdCVRqEd0H4cMpzvHYt1f/C3CoIjES6cG++RHKhrBj2+29nPF0IB5kpy9MS71vs07fvrNGAl/iA==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.1.tgz", + "integrity": "sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA==", "cpu": [ "arm64" ], @@ -291,9 +288,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.4.tgz", - "integrity": "sha512-PlNiRQapift4LNS8DPUHuDX/IdXiLjf8mc5vdEmUR0fF/pyy2qWwzdLjB+iZquGr8LuN4LnUoSEvKRwjSVYz3Q==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.1.tgz", + "integrity": "sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w==", "cpu": [ "arm64" ], @@ -305,9 +302,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.4.tgz", - "integrity": "sha512-o9bH2dbdgBDJaXWJCDTNDYa171ACUdzpxSZt+u/AAeQ20Nk5x+IhA+zsGmrQtpkLiumRJEYef68gcpn2ooXhSQ==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.1.tgz", + "integrity": "sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg==", "cpu": [ "x64" ], @@ -319,9 +316,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.4.tgz", - "integrity": "sha512-NBI2/i2hT9Q+HySSHTBh52da7isru4aAAo6qC3I7QFVsuhxi2gM8t/EI9EVcILiHLj1vfi+VGGPaLOUENn7pmw==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.1.tgz", + "integrity": "sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg==", "cpu": [ "arm64" ], @@ -333,9 +330,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.4.tgz", - "integrity": "sha512-wYcC5ycW2zvqtDYrE7deary2P2UFmSh85PUpAx+dwTCO9uw3sgzD6Gv9n5X4vLaQKsrfTSZZ7Z7uynQozPVvWA==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.1.tgz", + "integrity": "sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA==", "cpu": [ "x64" ], @@ -347,9 +344,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.4.tgz", - "integrity": "sha512-9OwUnK/xKw6DyRlgx8UizeqRFOfi9mf5TYCw1uolDaJSbUmBxP85DE6T4ouCMoN6pXw8ZoTeZCSEfSaYo+/s1w==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.1.tgz", + "integrity": "sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg==", "cpu": [ "arm" ], @@ -361,9 +358,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.4.tgz", - "integrity": "sha512-Vgdo4fpuphS9V24WOV+KwkCVJ72u7idTgQaBoLRD0UxBAWTF9GWurJO9YD9yh00BzbkhpeXtm6na+MvJU7Z73A==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.1.tgz", + "integrity": "sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA==", "cpu": [ "arm" ], @@ -375,9 +372,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.4.tgz", - "integrity": "sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.1.tgz", + "integrity": "sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA==", "cpu": [ "arm64" ], @@ -389,9 +386,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.4.tgz", - "integrity": "sha512-caluiUXvUuVyCHr5DxL8ohaaFFzPGmgmMvwmqAITMpV/Q+tPoaHZ/PWa3t8B2WyoRcIIuu1hkaW5KkeTDNSnMA==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.1.tgz", + "integrity": "sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg==", "cpu": [ "arm64" ], @@ -402,10 +399,24 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.1.tgz", + "integrity": "sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.4.tgz", - "integrity": "sha512-FScrpHrO60hARyHh7s1zHE97u0KlT/RECzCKAdmI+LEoC1eDh/RDji9JgFqyO+wPDb86Oa/sXkily1+oi4FzJQ==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.1.tgz", + "integrity": "sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A==", "cpu": [ "ppc64" ], @@ -417,9 +428,23 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.4.tgz", - "integrity": "sha512-qyyprhyGb7+RBfMPeww9FlHwKkCXdKHeGgSqmIXw9VSUtvyFZ6WZRtnxgbuz76FK7LyoN8t/eINRbPUcvXB5fw==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.1.tgz", + "integrity": "sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.1.tgz", + "integrity": "sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw==", "cpu": [ "riscv64" ], @@ -431,9 +456,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.4.tgz", - "integrity": "sha512-PFz+y2kb6tbh7m3A7nA9++eInGcDVZUACulf/KzDtovvdTizHpZaJty7Gp0lFwSQcrnebHOqxF1MaKZd7psVRg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.1.tgz", + "integrity": "sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g==", "cpu": [ "s390x" ], @@ -445,9 +470,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.4.tgz", - "integrity": "sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.1.tgz", + "integrity": "sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A==", "cpu": [ "x64" ], @@ -459,9 +484,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.4.tgz", - "integrity": "sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.1.tgz", + "integrity": "sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ==", "cpu": [ "x64" ], @@ -473,9 +498,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.4.tgz", - "integrity": "sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.1.tgz", + "integrity": "sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ==", "cpu": [ "arm64" ], @@ -487,9 +512,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.4.tgz", - "integrity": "sha512-KtwEJOaHAVJlxV92rNYiG9JQwQAdhBlrjNRp7P9L8Cb4Rer3in+0A+IPhJC9y68WAi9H0sX4AiG2NTsVlmqJeQ==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.1.tgz", + "integrity": "sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg==", "cpu": [ "ia32" ], @@ -501,9 +526,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.4.tgz", - "integrity": "sha512-3j4jx1TppORdTAoBJRd+/wJRGCPC0ETWkXOecJ6PPZLj6SptXkrXcNqdj0oclbKML6FkQltdz7bBA3rUSirZug==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.1.tgz", + "integrity": "sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw==", "cpu": [ "x64" ], @@ -514,10 +539,19 @@ "win32" ] }, + "node_modules/@sveltejs/acorn-typescript": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz", + "integrity": "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^8.9.0" + } + }, "node_modules/@sveltestrap/sveltestrap": { - "version": "6.2.7", - "resolved": "https://registry.npmjs.org/@sveltestrap/sveltestrap/-/sveltestrap-6.2.7.tgz", - "integrity": "sha512-WwLLfAFUb42BGuRrf3Vbct30bQMzlEMMipN/MfxhjuLTmLQeW9muVJfPyvjtWS+mY+RjkSCoHvAp/ZobP1NLlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@sveltestrap/sveltestrap/-/sveltestrap-7.1.0.tgz", + "integrity": "sha512-TpIx25kqLV+z+VD3yfqYayOI1IaCeWFbT0uqM6NfA4vQgDs9PjFwmjkU4YEAlV/ngs9e7xPmaRWE7lkrg4Miow==", "license": "MIT", "dependencies": { "@popperjs/core": "^2.11.8" @@ -534,9 +568,9 @@ "license": "MIT" }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "license": "MIT" }, "node_modules/@types/resolve": { @@ -547,9 +581,9 @@ "license": "MIT" }, "node_modules/@urql/core": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/@urql/core/-/core-5.0.8.tgz", - "integrity": "sha512-1GOnUw7/a9bzkcM0+U8U5MmxW2A7FE5YquuEmcJzTtW5tIs2EoS4F2ITpuKBjRBbyRjZgO860nWFPo1m4JImGA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@urql/core/-/core-5.1.1.tgz", + "integrity": "sha512-aGh024z5v2oINGD/In6rAtVKTm4VmQ2TxKQBAtk2ZSME5dunZFcjltw4p5ENQg+5CBhZ3FHMzl0Oa+rwqiWqlg==", "license": "MIT", "dependencies": { "@0no-co/graphql.web": "^1.0.5", @@ -557,12 +591,12 @@ } }, "node_modules/@urql/svelte": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@urql/svelte/-/svelte-4.2.2.tgz", - "integrity": "sha512-6ntLGsWcnNtaMZVmFpePfFTSpYxYpznCAqnuvLDjt7Oa7YqHcFiyPnz7IIsiPD9VE6hZSi0+RwmRk5BMba/teQ==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@urql/svelte/-/svelte-4.2.3.tgz", + "integrity": "sha512-v3eArfymhdjaM5VQFp3QZxq9veYPadmDfX7ueid/kD4DlRplIycPakJ2FrKigh46SXa5mWqJ3QWuWyRKVu61sw==", "license": "MIT", "dependencies": { - "@urql/core": "^5.0.0", + "@urql/core": "^5.1.1", "wonka": "^6.3.2" }, "peerDependencies": { @@ -571,9 +605,9 @@ } }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -600,23 +634,6 @@ "node": ">= 0.4" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -625,9 +642,9 @@ "license": "MIT" }, "node_modules/chart.js": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.6.tgz", - "integrity": "sha512-8Y406zevUPbbIBA/HRk33khEmQPk5+cxeflWE/2rx1NJsjVWMPw/9mSP9rxHP5eqi6LNoPBVMfZHxbwLSgldYA==", + "version": "4.4.9", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.9.tgz", + "integrity": "sha512-EyZ9wWKgpAU0fLJ43YAEIF8sr5F2W3LqbS40ZJyHIner2lY14ufqv2VMp69MAiZ2rpwxEUxEhIH/0U3xyRynxg==", "license": "MIT", "dependencies": { "@kurkle/color": "^0.3.0" @@ -636,26 +653,13 @@ "pnpm": ">=8" } }, - "node_modules/code-red": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", - "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15", - "@types/estree": "^1.0.1", - "acorn": "^8.10.0", - "estree-walker": "^3.0.3", - "periscopic": "^3.1.0" - } - }, - "node_modules/code-red/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" + "engines": { + "node": ">=6" } }, "node_modules/commander": { @@ -685,39 +689,20 @@ "url": "https://github.com/sponsors/rawify" } }, - "node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "license": "MIT", - "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, "node_modules/date-fns": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", - "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.21.0" - }, - "engines": { - "node": ">=0.11" - }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" } }, "node_modules/decimal.js": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", - "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", + "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", "license": "MIT" }, "node_modules/deepmerge": { @@ -736,32 +721,55 @@ "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==", "license": "MIT" }, + "node_modules/esm-env": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", + "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", + "license": "MIT" + }, + "node_modules/esrap": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.4.7.tgz", + "integrity": "sha512-0ZxW6guTF/AeKeKi7he93lmgv7Hx7giD1tBrOeVqkqsZGQJd2/kfnL7LdIsr9FT/AtkBK9XeDTov+gxprBqdEg==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "license": "MIT" }, + "node_modules/fdir": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.5.tgz", + "integrity": "sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/fraction.js": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.4.tgz", - "integrity": "sha512-pwiTgt0Q7t+GHZA4yaLjObx4vXmmdcS0iSJ19o8d/goUGgItX9UZWKWNnLHehxviD8wU2IWRsnR8cD5+yOJP2Q==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.2.2.tgz", + "integrity": "sha512-uXBDv5knpYmv/2gLzWQ5mBHGBRk9wcKTeWu6GLTUEQfjCxO09uM/mHDrojlL+Q1mVGIIFo149Gba7od1XPgSzQ==", "license": "MIT", "engines": { - "node": "*" + "node": ">= 12" }, "funding": { - "type": "patreon", + "type": "github", "url": "https://github.com/sponsors/rawify" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -787,31 +795,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/graphql": { - "version": "16.9.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", - "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", + "version": "16.11.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.11.0.tgz", + "integrity": "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==", "license": "MIT", "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" @@ -830,29 +817,10 @@ "node": ">= 0.4" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, "node_modules/is-core-module": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", - "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "license": "MIT", "dependencies": { @@ -895,29 +863,29 @@ "license": "MIT" }, "node_modules/magic-string": { - "version": "0.30.14", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.14.tgz", - "integrity": "sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==", + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "node_modules/mathjs": { - "version": "12.4.3", - "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-12.4.3.tgz", - "integrity": "sha512-oHdGPDbp7gO873xxG90RLq36IuicuKvbpr/bBG5g9c8Obm/VsKVrK9uoRZZHUodohzlnmCEqfDzbR3LH6m+aAQ==", + "version": "14.5.2", + "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-14.5.2.tgz", + "integrity": "sha512-51U6hp7j4M4Rj+l+q2KbmXAV9EhQVQzUdw1wE67RnUkKKq5ibxdrl9Ky2YkSUEIc2+VU8/IsThZNu6QSHUoyTA==", "license": "Apache-2.0", "dependencies": { - "@babel/runtime": "^7.24.4", - "complex.js": "^2.1.1", + "@babel/runtime": "^7.26.10", + "complex.js": "^2.2.5", "decimal.js": "^10.4.3", "escape-latex": "^1.2.0", - "fraction.js": "4.3.4", + "fraction.js": "^5.2.1", "javascript-natural-sort": "^0.7.1", "seedrandom": "^3.0.5", "tiny-emitter": "^2.1.0", - "typed-function": "^4.1.1" + "typed-function": "^4.2.1" }, "bin": { "mathjs": "bin/cli.js" @@ -926,35 +894,6 @@ "node": ">= 18" } }, - "node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "license": "CC0-1.0" - }, - "node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", @@ -962,35 +901,6 @@ "dev": true, "license": "MIT" }, - "node_modules/periscopic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", - "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^3.0.0", - "is-reference": "^3.0.0" - } - }, - "node_modules/periscopic/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/periscopic/node_modules/is-reference": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", - "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.6" - } - }, "node_modules/picomatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", @@ -1013,34 +923,31 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "license": "MIT" - }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/resolve.exports": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", - "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", "dev": true, "license": "MIT", "engines": { @@ -1048,13 +955,13 @@ } }, "node_modules/rollup": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.4.tgz", - "integrity": "sha512-RLKxqHEMjh/RGLsDxAEsaLO3mWgyoU6x9w6n1ikAzet4B3gI2/3yP6PWY2p9QzRTh6MfEIXB3MwsOY0Iv3vNrw==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.1.tgz", + "integrity": "sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==", "devOptional": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.6" + "@types/estree": "1.0.7" }, "bin": { "rollup": "dist/bin/rollup" @@ -1064,24 +971,26 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.27.4", - "@rollup/rollup-android-arm64": "4.27.4", - "@rollup/rollup-darwin-arm64": "4.27.4", - "@rollup/rollup-darwin-x64": "4.27.4", - "@rollup/rollup-freebsd-arm64": "4.27.4", - "@rollup/rollup-freebsd-x64": "4.27.4", - "@rollup/rollup-linux-arm-gnueabihf": "4.27.4", - "@rollup/rollup-linux-arm-musleabihf": "4.27.4", - "@rollup/rollup-linux-arm64-gnu": "4.27.4", - "@rollup/rollup-linux-arm64-musl": "4.27.4", - "@rollup/rollup-linux-powerpc64le-gnu": "4.27.4", - "@rollup/rollup-linux-riscv64-gnu": "4.27.4", - "@rollup/rollup-linux-s390x-gnu": "4.27.4", - "@rollup/rollup-linux-x64-gnu": "4.27.4", - "@rollup/rollup-linux-x64-musl": "4.27.4", - "@rollup/rollup-win32-arm64-msvc": "4.27.4", - "@rollup/rollup-win32-ia32-msvc": "4.27.4", - "@rollup/rollup-win32-x64-msvc": "4.27.4", + "@rollup/rollup-android-arm-eabi": "4.41.1", + "@rollup/rollup-android-arm64": "4.41.1", + "@rollup/rollup-darwin-arm64": "4.41.1", + "@rollup/rollup-darwin-x64": "4.41.1", + "@rollup/rollup-freebsd-arm64": "4.41.1", + "@rollup/rollup-freebsd-x64": "4.41.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.41.1", + "@rollup/rollup-linux-arm-musleabihf": "4.41.1", + "@rollup/rollup-linux-arm64-gnu": "4.41.1", + "@rollup/rollup-linux-arm64-musl": "4.41.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.41.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.41.1", + "@rollup/rollup-linux-riscv64-gnu": "4.41.1", + "@rollup/rollup-linux-riscv64-musl": "4.41.1", + "@rollup/rollup-linux-s390x-gnu": "4.41.1", + "@rollup/rollup-linux-x64-gnu": "4.41.1", + "@rollup/rollup-linux-x64-musl": "4.41.1", + "@rollup/rollup-win32-arm64-msvc": "4.41.1", + "@rollup/rollup-win32-ia32-msvc": "4.41.1", + "@rollup/rollup-win32-x64-msvc": "4.41.1", "fsevents": "~2.3.2" } }, @@ -1146,6 +1055,13 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/rollup/node_modules/@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "devOptional": true, + "license": "MIT" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -1200,15 +1116,6 @@ "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==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -1234,47 +1141,28 @@ } }, "node_modules/svelte": { - "version": "4.2.19", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.19.tgz", - "integrity": "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==", + "version": "5.33.14", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.33.14.tgz", + "integrity": "sha512-kRlbhIlMTijbFmVDQFDeKXPLlX1/ovXwV0I162wRqQhRcygaqDIcu1d/Ese3H2uI+yt3uT8E7ndgDthQv5v5BA==", "license": "MIT", "dependencies": { - "@ampproject/remapping": "^2.2.1", - "@jridgewell/sourcemap-codec": "^1.4.15", - "@jridgewell/trace-mapping": "^0.3.18", - "@types/estree": "^1.0.1", - "acorn": "^8.9.0", - "aria-query": "^5.3.0", - "axobject-query": "^4.0.0", - "code-red": "^1.0.3", - "css-tree": "^2.3.1", - "estree-walker": "^3.0.3", - "is-reference": "^3.0.1", + "@ampproject/remapping": "^2.3.0", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@sveltejs/acorn-typescript": "^1.0.5", + "@types/estree": "^1.0.5", + "acorn": "^8.12.1", + "aria-query": "^5.3.1", + "axobject-query": "^4.1.0", + "clsx": "^2.1.1", + "esm-env": "^1.2.1", + "esrap": "^1.4.6", + "is-reference": "^3.0.3", "locate-character": "^3.0.0", - "magic-string": "^0.30.4", - "periscopic": "^3.1.0" + "magic-string": "^0.30.11", + "zimmerframe": "^1.1.2" }, "engines": { - "node": ">=16" - } - }, - "node_modules/svelte-chartjs": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/svelte-chartjs/-/svelte-chartjs-3.1.5.tgz", - "integrity": "sha512-ka2zh7v5FiwfAX1oMflZ0HkNkgjHjFqANgRyC+vNYXfxtx2ku68Zo+2KgbKeBH2nS1ThDqkIACPzGxy4T0UaoA==", - "license": "MIT", - "peerDependencies": { - "chart.js": "^3.5.0 || ^4.0.0", - "svelte": "^4.0.0" - } - }, - "node_modules/svelte/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" + "node": ">=18" } }, "node_modules/svelte/node_modules/is-reference": { @@ -1287,14 +1175,14 @@ } }, "node_modules/terser": { - "version": "5.36.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", - "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", + "version": "5.41.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.41.0.tgz", + "integrity": "sha512-H406eLPXpZbAX14+B8psIuvIr8+3c+2hkuYzpMkoE0ij+NdsVATbA78vb8neA/eqrj7rywa2pIkdmWRsXW6wmw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", + "acorn": "^8.14.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -1321,23 +1209,22 @@ } }, "node_modules/uplot": { - "version": "1.6.31", - "resolved": "https://registry.npmjs.org/uplot/-/uplot-1.6.31.tgz", - "integrity": "sha512-sQZqSwVCbJGnFB4IQjQYopzj5CoTZJ4Br1fG/xdONimqgHmsacvCjNesdGDypNKFbrhLGIeshYhy89FxPF+H+w==", + "version": "1.6.32", + "resolved": "https://registry.npmjs.org/uplot/-/uplot-1.6.32.tgz", + "integrity": "sha512-KIMVnG68zvu5XXUbC4LQEPnhwOxBuLyW1AHtpm6IKTXImkbLgkMy+jabjLgSLMasNuGGzQm/ep3tOkyTxpiQIw==", "license": "MIT" }, "node_modules/wonka": { - "version": "6.3.4", - "resolved": "https://registry.npmjs.org/wonka/-/wonka-6.3.4.tgz", - "integrity": "sha512-CjpbqNtBGNAeyNS/9W6q3kSkKE52+FjIj7AkFlLr11s/VWGUu6a2CdYSdGxocIhIVjaW/zchesBQUKPVU69Cqg==", + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/wonka/-/wonka-6.3.5.tgz", + "integrity": "sha512-SSil+ecw6B4/Dm7Pf2sAshKQ5hWFvfyGlfPbEd6A14dOH6VDjrmbY86u6nZvy9omGwwIPFR8V41+of1EezgoUw==", "license": "MIT" }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" + "node_modules/zimmerframe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz", + "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==", + "license": "MIT" } } } diff --git a/web/frontend/package.json b/web/frontend/package.json index 389ffe6a..b10e2718 100644 --- a/web/frontend/package.json +++ b/web/frontend/package.json @@ -7,25 +7,24 @@ "dev": "rollup -c -w" }, "devDependencies": { - "@rollup/plugin-commonjs": "^25.0.8", - "@rollup/plugin-node-resolve": "^15.3.0", + "@rollup/plugin-commonjs": "^28.0.3", + "@rollup/plugin-node-resolve": "^16.0.1", "@rollup/plugin-terser": "^0.4.4", "@timohausmann/quadtree-js": "^1.2.6", - "rollup": "^4.27.4", + "rollup": "^4.41.1", "rollup-plugin-css-only": "^4.5.2", "rollup-plugin-svelte": "^7.2.2", - "svelte": "^4.2.19" + "svelte": "^5.33.14" }, "dependencies": { - "@rollup/plugin-replace": "^5.0.7", - "@sveltestrap/sveltestrap": "^6.2.7", - "@urql/svelte": "^4.2.2", - "chart.js": "^4.4.6", - "date-fns": "^2.30.0", - "graphql": "^16.9.0", - "mathjs": "^12.4.3", - "svelte-chartjs": "^3.1.5", - "uplot": "^1.6.31", - "wonka": "^6.3.4" + "@rollup/plugin-replace": "^6.0.2", + "@sveltestrap/sveltestrap": "^7.1.0", + "@urql/svelte": "^4.2.3", + "chart.js": "^4.4.9", + "date-fns": "^4.1.0", + "graphql": "^16.11.0", + "mathjs": "^14.5.2", + "uplot": "^1.6.32", + "wonka": "^6.3.5" } } diff --git a/web/frontend/rollup.config.mjs b/web/frontend/rollup.config.mjs index 0e151054..a7b47327 100644 --- a/web/frontend/rollup.config.mjs +++ b/web/frontend/rollup.config.mjs @@ -6,13 +6,20 @@ import terser from '@rollup/plugin-terser'; import css from 'rollup-plugin-css-only'; const production = !process.env.ROLLUP_WATCH; -// const production = false const plugins = [ svelte({ compilerOptions: { - // enable run-time checks when not in production - dev: !production + // Enable run-time checks when not in production + dev: !production, + // Enable Svelte 5-specific features + hydratable: true, // If using server-side rendering + immutable: true, // Optimize updates for immutable data + // As of sveltestrap 7.1.0, filtered warnings would appear for imported sveltestrap components + warningFilter: (warning) => ( + warning.code !== 'element_invalid_self_closing_tag' && + warning.code !== 'a11y_interactive_supports_focus' + ) } }), @@ -23,7 +30,7 @@ const plugins = [ // https://github.com/rollup/plugins/tree/master/packages/commonjs resolve({ browser: true, - dedupe: ['svelte'] + dedupe: ['svelte', '@sveltejs/kit'] // Ensure deduplication for Svelte 5 }), commonjs(), @@ -32,8 +39,10 @@ const plugins = [ production && terser(), replace({ - "process.env.NODE_ENV": JSON.stringify("development"), - preventAssignment: true + preventAssignment: true, + values: { + "process.env.NODE_ENV": JSON.stringify(production ? "production" : "development"), + } }) ]; diff --git a/web/frontend/src/Analysis.root.svelte b/web/frontend/src/Analysis.root.svelte index 8b327a25..83c67545 100644 --- a/web/frontend/src/Analysis.root.svelte +++ b/web/frontend/src/Analysis.root.svelte @@ -37,14 +37,12 @@ import ScatterPlot from "./generic/plots/Scatter.svelte"; import RooflineHeatmap from "./generic/plots/RooflineHeatmap.svelte"; - const { query: initq } = init(); - - export let filterPresets; + /* Svelte 5 Props */ + let { filterPresets } = $props(); // By default, look at the jobs of the last 6 hours: if (filterPresets?.startTime == null) { if (filterPresets == null) filterPresets = {}; - let now = new Date(Date.now()); let hourAgo = new Date(now); hourAgo.setHours(hourAgo.getHours() - 6); @@ -54,27 +52,10 @@ }; } - let cluster; - let filterComponent; // see why here: https://stackoverflow.com/questions/58287729/how-can-i-export-a-function-from-a-svelte-component-that-changes-a-value-in-the - let jobFilters = []; - let rooflineMaxY; - let colWidth1, colWidth2; - let numBins = 50; - let maxY = -1; - - const initialized = getContext("initialized"); - const globalMetrics = getContext("globalMetrics"); + /* Const Init */ + const { query: initq } = init(); + const client = getContextClient(); const ccconfig = getContext("cc-config"); - - let metricsInHistograms = ccconfig.analysis_view_histogramMetrics, - metricsInScatterplots = ccconfig.analysis_view_scatterPlotMetrics; - - $: metrics = [ - ...new Set([...metricsInHistograms, ...metricsInScatterplots.flat()]), - ]; - - $: clusterName = cluster?.name ? cluster.name : cluster; - const sortOptions = [ { key: "totalWalltime", label: "Walltime" }, { key: "totalNodeHours", label: "Node Hours" }, @@ -86,7 +67,22 @@ { key: "project", label: "Project ID" }, ]; - let sortSelection = + /* Var Init */ + let metricUnits = {}; + let metricScopes = {}; + let numBins = 50; + + /* State Init */ + let filterComponent = $state(); // see why here: https://stackoverflow.com/questions/58287729/how-can-i-export-a-function-from-a-svelte-component-that-changes-a-value-in-the + let cluster = $state(filterPresets?.cluster); + let rooflineMaxY = $state(0); + let maxY = $state(-1); + let colWidth1 = $state(0); + let colWidth2 = $state(0); + let jobFilters = $state([]); + let metricsInHistograms = $state(ccconfig.analysis_view_histogramMetrics) + let metricsInScatterplots = $state(ccconfig.analysis_view_scatterPlotMetrics) + let sortSelection = $state( sortOptions.find( (option) => option.key == @@ -94,17 +90,20 @@ ) || sortOptions.find( (option) => option.key == ccconfig.analysis_view_selectedTopCategory, - ); - let groupSelection = - groupOptions.find( - (option) => - option.key == - ccconfig[`analysis_view_selectedTopEntity:${filterPresets.cluster}`], - ) || - groupOptions.find( - (option) => option.key == ccconfig.analysis_view_selectedTopEntity, - ); + ) + ); + let groupSelection = $state( + groupOptions.find( + (option) => + option.key == + ccconfig[`analysis_view_selectedTopEntity:${filterPresets.cluster}`], + ) || + groupOptions.find( + (option) => option.key == ccconfig.analysis_view_selectedTopEntity, + ) + ); + /* Init Function */ getContext("on-init")(({ data }) => { if (data != null) { cluster = data.clusters.find((c) => c.name == filterPresets.cluster); @@ -121,120 +120,145 @@ } }); - const client = getContextClient(); + /* Derived Vars */ + const clusterName = $derived(cluster?.name ? cluster.name : cluster); + const availableMetrics = $derived(loadAvailable($initq?.data?.globalMetrics, clusterName)); + const metrics = $derived( + [...new Set([...metricsInHistograms, ...metricsInScatterplots.flat()])] + ); - $: statsQuery = queryStore({ - client: client, - query: gql` - query ($jobFilters: [JobFilter!]!) { - stats: jobsStatistics(filter: $jobFilters) { - totalJobs - shortJobs - totalWalltime - totalNodeHours - totalCoreHours - totalAccHours - histDuration { - count - value - } - histNumCores { - count - value + let statsQuery = $derived( + queryStore({ + client: client, + query: gql` + query ($jobFilters: [JobFilter!]!) { + stats: jobsStatistics(filter: $jobFilters) { + totalJobs + shortJobs + totalWalltime + totalNodeHours + totalCoreHours + totalAccHours + histDuration { + count + value + } + histNumCores { + count + value + } } } - } - `, - variables: { jobFilters }, - }); + `, + variables: { jobFilters }, + }) + ); - $: topQuery = queryStore({ - client: client, - query: gql` - query ( - $jobFilters: [JobFilter!]! - $paging: PageRequest! - $sortBy: SortByAggregate! - $groupBy: Aggregate! - ) { - topList: jobsStatistics( - filter: $jobFilters - page: $paging - sortBy: $sortBy - groupBy: $groupBy + let topQuery = $derived( + queryStore({ + client: client, + query: gql` + query ( + $jobFilters: [JobFilter!]! + $paging: PageRequest! + $sortBy: SortByAggregate! + $groupBy: Aggregate! ) { - id - name - totalWalltime - totalNodeHours - totalCoreHours - totalAccHours + topList: jobsStatistics( + filter: $jobFilters + page: $paging + sortBy: $sortBy + groupBy: $groupBy + ) { + id + name + totalWalltime + totalNodeHours + totalCoreHours + totalAccHours + } } - } - `, - variables: { - jobFilters, - paging: { itemsPerPage: 10, page: 1 }, - sortBy: sortSelection.key.toUpperCase(), - groupBy: groupSelection.key.toUpperCase(), - }, - }); + `, + variables: { + jobFilters, + paging: { itemsPerPage: 10, page: 1 }, + sortBy: sortSelection.key.toUpperCase(), + groupBy: groupSelection.key.toUpperCase(), + }, + }) + ); // Note: Different footprints than those saved in DB per Job -> Caused by Legacy Naming - $: footprintsQuery = queryStore({ - client: client, - query: gql` - query ($jobFilters: [JobFilter!]!, $metrics: [String!]!) { - footprints: jobsFootprints(filter: $jobFilters, metrics: $metrics) { - timeWeights { - nodeHours - accHours - coreHours - } - metrics { - metric - data + let footprintsQuery = $derived( + queryStore({ + client: client, + query: gql` + query ($jobFilters: [JobFilter!]!, $metrics: [String!]!) { + footprints: jobsFootprints(filter: $jobFilters, metrics: $metrics) { + timeWeights { + nodeHours + accHours + coreHours + } + metrics { + metric + data + } } } - } - `, - variables: { jobFilters, metrics }, - }); + `, + variables: { jobFilters, metrics }, + }) + ); - $: rooflineQuery = queryStore({ - client: client, - query: gql` - query ( - $jobFilters: [JobFilter!]! - $rows: Int! - $cols: Int! - $minX: Float! - $minY: Float! - $maxX: Float! - $maxY: Float! - ) { - rooflineHeatmap( - filter: $jobFilters - rows: $rows - cols: $cols - minX: $minX - minY: $minY - maxX: $maxX - maxY: $maxY - ) - } - `, - variables: { - jobFilters, - rows: 50, - cols: 50, - minX: 0.01, - minY: 1, - maxX: 1000, - maxY, - }, + let rooflineQuery = $derived( + queryStore({ + client: client, + query: gql` + query ( + $jobFilters: [JobFilter!]! + $rows: Int! + $cols: Int! + $minX: Float! + $minY: Float! + $maxX: Float! + $maxY: Float! + ) { + rooflineHeatmap( + filter: $jobFilters + rows: $rows + cols: $cols + minX: $minX + minY: $minY + maxX: $maxX + maxY: $maxY + ) + } + `, + variables: { + jobFilters, + rows: 50, + cols: 50, + minX: 0.01, + minY: 1, + maxX: 1000, + maxY, + }, + }) + ); + + /* Reactive Effects */ + $effect(() => { + loadUnitsAndScopes(availableMetrics.length, availableMetrics); + }); + $effect(() => { + updateEntityConfiguration(groupSelection.key); + }); + $effect(() => { + updateCategoryConfiguration(sortSelection.key); }); + /* Functions */ const updateConfigurationMutation = ({ name, value }) => { return mutationStore({ client: client, @@ -287,22 +311,26 @@ } } - let availableMetrics = []; - let metricUnits = {}; - let metricScopes = {}; - function loadMetrics(isInitialized) { - if (!isInitialized) return - availableMetrics = [...globalMetrics.filter((gm) => gm?.availability.find((av) => av.cluster == cluster.name))] - for (let sm of availableMetrics) { - metricUnits[sm.name] = (sm?.unit?.prefix ? sm.unit.prefix : "") + (sm?.unit?.base ? sm.unit.base : "") - metricScopes[sm.name] = sm?.scope + function loadAvailable(globals, name) { + const availableMetrics = new Set(); + if (globals && globals.length > 0) { + for (let gm of globals) { + if (gm.availability.find((av) => av.cluster == name)) { + availableMetrics.add({name: gm.name, scope: gm.scope, unit: gm.unit}); + }; + } } - } + return [...availableMetrics] + }; - $: loadMetrics($initialized) - $: updateEntityConfiguration(groupSelection.key); - $: updateCategoryConfiguration(sortSelection.key); + function loadUnitsAndScopes(length, available) { + for (let am of available) { + metricUnits[am.name] = (am?.unit?.prefix ? am.unit.prefix : "") + (am?.unit?.base ? am.unit.base : "") + metricScopes[am.name] = am?.scope + } + } + /* On Mount */ onMount(() => filterComponent.updateFilters()); @@ -329,7 +357,7 @@ {filterPresets} disableClusterSelection={true} startTimeQuickSelect={true} - on:update-filters={({ detail }) => { + applyFilters={(detail) => { jobFilters = detail.filters; }} /> @@ -392,6 +420,7 @@ {$topQuery.error.message} {:else} @@ -23,24 +24,21 @@ import NavbarLinks from "./header/NavbarLinks.svelte"; import NavbarTools from "./header/NavbarTools.svelte"; - export let username; - export let authlevel; - export let clusters; - export let subClusters; - export let roles; - - let isOpen = false; - let screenSize; + /* Svelte 5 Props */ + let { username, authlevel, clusters, subClusters, roles } = $props(); + /* Const Init */ const jobsTitle = new Map(); jobsTitle.set(2, "Job Search"); jobsTitle.set(3, "Managed Jobs"); jobsTitle.set(4, "Jobs"); jobsTitle.set(5, "Jobs"); + const usersTitle = new Map(); usersTitle.set(3, "Managed Users"); usersTitle.set(4, "Users"); usersTitle.set(5, "Users"); + const projectsTitle = new Map(); projectsTitle.set(3, "Managed Projects"); projectsTitle.set(4, "Projects"); @@ -120,29 +118,41 @@ menu: "Info", }, ]; + + /* State Init */ + let isOpen = $state(false); + let screenSize = $state(0); + + /* Derived Vars */ + let showMax = $derived(screenSize >= 1500); + let showMid = $derived(screenSize < 1500 && screenSize >= 1300); + let showSml = $derived(screenSize < 1300 && screenSize >= 768); + let showBrg = $derived(screenSize < 768); + ClusterCockpit Logo - (isOpen = !isOpen)} /> + (isOpen = !isOpen)} /> (isOpen = detail.isOpen)} + onupdate={({ detail }) => (isOpen = detail.isOpen)} > - + \ No newline at end of file diff --git a/web/frontend/src/Job.root.svelte b/web/frontend/src/Job.root.svelte index 92d8bb2e..427c9ae1 100644 --- a/web/frontend/src/Job.root.svelte +++ b/web/frontend/src/Job.root.svelte @@ -56,8 +56,8 @@ selectedScopes = [], plots = {}; - let availableMetrics = new Set(), - missingMetrics = [], + let totalMetrics = 0; + let missingMetrics = [], missingHosts = [], somethingMissing = false; @@ -294,7 +294,7 @@ {#if $initq?.data} {/if} @@ -428,12 +428,16 @@ {#if $initq?.data} + selectedMetrics = [...newMetrics] + } /> {/if} diff --git a/web/frontend/src/Jobs.root.svelte b/web/frontend/src/Jobs.root.svelte index 1e7f96d0..312c7262 100644 --- a/web/frontend/src/Jobs.root.svelte +++ b/web/frontend/src/Jobs.root.svelte @@ -8,7 +8,7 @@ --> @@ -85,25 +101,25 @@ - - + { + applyFilters={(detail) => { selectedCluster = detail.filters[0]?.cluster ? detail.filters[0].cluster.eq : null; @@ -122,29 +138,31 @@ {presetProject} bind:authlevel bind:roles - on:set-filter={({ detail }) => filterComponent.updateFilters(detail)} + setFilter={(filter) => filterComponent.updateFilters(filter)} /> {/if} - + {#if !showCompare} - { + { jobList.refreshJobs() jobList.refreshAllMetrics() }} /> {/if} - - - - {#if !showCompare && selectedJobs.length != 0} - {#if type == "USER"} @@ -148,9 +165,13 @@ {/if} @@ -159,9 +180,14 @@ @@ -169,9 +195,13 @@ @@ -179,9 +209,13 @@ @@ -189,9 +223,13 @@ diff --git a/web/frontend/src/Node.root.svelte b/web/frontend/src/Node.root.svelte index 60ab4048..ff6946ac 100644 --- a/web/frontend/src/Node.root.svelte +++ b/web/frontend/src/Node.root.svelte @@ -172,7 +172,7 @@ { + onRefresh={() => { const diff = Date.now() - to; from = new Date(from.getTime() + diff); to = new Date(to.getTime() + diff); diff --git a/web/frontend/src/Status.root.svelte b/web/frontend/src/Status.root.svelte index 86170d17..1bd3c07a 100644 --- a/web/frontend/src/Status.root.svelte +++ b/web/frontend/src/Status.root.svelte @@ -42,15 +42,14 @@ import Refresher from "./generic/helper/Refresher.svelte"; import HistogramSelection from "./generic/select/HistogramSelection.svelte"; + /* Svelte 5 Props */ + let { cluster } = $props(); + + /* Const Init */ const { query: initq } = init(); const ccconfig = getContext("cc-config"); - - export let cluster; - - let plotWidths = []; - let colWidth; - let from = new Date(Date.now() - 5 * 60 * 1000), - to = new Date(Date.now()); + const client = getContextClient(); + const paging = { itemsPerPage: 10, page: 1 }; // Top 10 const topOptions = [ { key: "totalJobs", label: "Jobs" }, { key: "totalNodes", label: "Nodes" }, @@ -58,7 +57,26 @@ { key: "totalAccs", label: "Accelerators" }, ]; - let topProjectSelection = + /* State Init */ + let from = $state(new Date(Date.now() - 5 * 60 * 1000)); + let to = $state(new Date(Date.now())); + let isHistogramSelectionOpen = $state(false); + let colWidth = $state(0); + let plotWidths = $state([]); + // Bar Gauges + let allocatedNodes = $state({}); + let flopRate = $state({}); + let flopRateUnitPrefix = $state({}); + let flopRateUnitBase = $state({}); + let memBwRate = $state({}); + let memBwRateUnitPrefix = $state({}); + let memBwRateUnitBase = $state({}); + + let selectedHistograms = $state(cluster + ? ccconfig[`user_view_histogramMetrics:${cluster}`] || ( ccconfig['user_view_histogramMetrics'] || [] ) + : ccconfig['user_view_histogramMetrics'] || []); + + let topProjectSelection = $state( topOptions.find( (option) => option.key == @@ -66,8 +84,10 @@ ) || topOptions.find( (option) => option.key == ccconfig.status_view_selectedTopProjectCategory, - ); - let topUserSelection = + ) + ); + + let topUserSelection = $state( topOptions.find( (option) => option.key == @@ -75,16 +95,12 @@ ) || topOptions.find( (option) => option.key == ccconfig.status_view_selectedTopUserCategory, - ); + ) + ); - let isHistogramSelectionOpen = false; - $: selectedHistograms = cluster - ? ccconfig[`user_view_histogramMetrics:${cluster}`] || ( ccconfig['user_view_histogramMetrics'] || [] ) - : ccconfig['user_view_histogramMetrics'] || []; - - const client = getContextClient(); + /* Derived */ // Note: nodeMetrics are requested on configured $timestep resolution - $: mainQuery = queryStore({ + const mainQuery = $derived(queryStore({ client: client, query: gql` query ( @@ -162,10 +178,9 @@ filter: [{ state: ["running"] }, { cluster: { eq: cluster } }], selectedHistograms: selectedHistograms, }, - }); + })); - const paging = { itemsPerPage: 10, page: 1 }; // Top 10 - $: topUserQuery = queryStore({ + const topUserQuery = $derived(queryStore({ client: client, query: gql` query ( @@ -193,9 +208,9 @@ paging, sortBy: topUserSelection.key.toUpperCase(), }, - }); + })); - $: topProjectQuery = queryStore({ + const topProjectQuery = $derived(queryStore({ client: client, query: gql` query ( @@ -222,8 +237,46 @@ paging, sortBy: topProjectSelection.key.toUpperCase(), }, + })); + + /* Effects */ + $effect(() => { + if ($initq.data && $mainQuery.data) { + let subClusters = $initq.data.clusters.find( + (c) => c.name == cluster, + ).subClusters; + for (let subCluster of subClusters) { + allocatedNodes[subCluster.name] = + $mainQuery.data.allocatedNodes.find( + ({ name }) => name == subCluster.name, + )?.count || 0; + flopRate[subCluster.name] = + Math.floor( + sumUp($mainQuery.data.nodeMetrics, subCluster.name, "flops_any") * + 100, + ) / 100; + flopRateUnitPrefix[subCluster.name] = subCluster.flopRateSimd.unit.prefix; + flopRateUnitBase[subCluster.name] = subCluster.flopRateSimd.unit.base; + memBwRate[subCluster.name] = + Math.floor( + sumUp($mainQuery.data.nodeMetrics, subCluster.name, "mem_bw") * 100, + ) / 100; + memBwRateUnitPrefix[subCluster.name] = + subCluster.memoryBandwidth.unit.prefix; + memBwRateUnitBase[subCluster.name] = subCluster.memoryBandwidth.unit.base; + } + } + }); + + $effect(() => { + updateTopUserConfiguration(topUserSelection.key); }); + $effect(() => { + updateTopProjectConfiguration(topProjectSelection.key); + }); + + /* Const Functions */ const sumUp = (data, subcluster, metric) => data.reduce( (sum, node) => @@ -239,39 +292,6 @@ 0, ); - let allocatedNodes = {}, - flopRate = {}, - flopRateUnitPrefix = {}, - flopRateUnitBase = {}, - memBwRate = {}, - memBwRateUnitPrefix = {}, - memBwRateUnitBase = {}; - $: if ($initq.data && $mainQuery.data) { - let subClusters = $initq.data.clusters.find( - (c) => c.name == cluster, - ).subClusters; - for (let subCluster of subClusters) { - allocatedNodes[subCluster.name] = - $mainQuery.data.allocatedNodes.find( - ({ name }) => name == subCluster.name, - )?.count || 0; - flopRate[subCluster.name] = - Math.floor( - sumUp($mainQuery.data.nodeMetrics, subCluster.name, "flops_any") * - 100, - ) / 100; - flopRateUnitPrefix[subCluster.name] = subCluster.flopRateSimd.unit.prefix; - flopRateUnitBase[subCluster.name] = subCluster.flopRateSimd.unit.base; - memBwRate[subCluster.name] = - Math.floor( - sumUp($mainQuery.data.nodeMetrics, subCluster.name, "mem_bw") * 100, - ) / 100; - memBwRateUnitPrefix[subCluster.name] = - subCluster.memoryBandwidth.unit.prefix; - memBwRateUnitBase[subCluster.name] = subCluster.memoryBandwidth.unit.base; - } - } - const updateConfigurationMutation = ({ name, value }) => { return mutationStore({ client: client, @@ -284,20 +304,17 @@ }); }; + /* Functions */ function updateTopUserConfiguration(select) { if (ccconfig[`status_view_selectedTopUserCategory:${cluster}`] != select) { updateConfigurationMutation({ name: `status_view_selectedTopUserCategory:${cluster}`, value: JSON.stringify(select), }).subscribe((res) => { - if (res.fetching === false && !res.error) { - // console.log(`status_view_selectedTopUserCategory:${cluster}` + ' -> Updated!') - } else if (res.fetching === false && res.error) { + if (res.fetching === false && res.error) { throw res.error; } }); - } else { - // console.log('No Mutation Required: Top User') } } @@ -309,19 +326,12 @@ name: `status_view_selectedTopProjectCategory:${cluster}`, value: JSON.stringify(select), }).subscribe((res) => { - if (res.fetching === false && !res.error) { - // console.log(`status_view_selectedTopProjectCategory:${cluster}` + ' -> Updated!') - } else if (res.fetching === false && res.error) { + if (res.fetching === false && res.error) { throw res.error; } }); - } else { - // console.log('No Mutation Required: Top Project') } } - - $: updateTopUserConfiguration(topUserSelection.key); - $: updateTopProjectConfiguration(topProjectSelection.key); @@ -334,7 +344,7 @@ @@ -342,7 +352,7 @@ { + onRefresh={() => { from = new Date(Date.now() - 5 * 60 * 1000); to = new Date(Date.now()); }} @@ -483,6 +493,7 @@ {$topUserQuery.error.message} {:else} {$topProjectQuery.error.message} {:else} gm?.availability.find((av) => av.cluster == cluster))] - for (let sm of systemMetrics) { - systemUnits[sm.name] = (sm?.unit?.prefix ? sm.unit.prefix : "") + (sm?.unit?.base ? sm.unit.base : "") - } - if (!selectedMetric) selectedMetric = systemMetrics[0].name - } - - $: loadMetrics($initialized) - - $: if (displayNodeOverview) { - selectedMetrics = [selectedMetric] - } - - $: { // Wait after input for some time to prevent too many requests - setTimeout(function () { + ) || [ccconfig.system_view_selectedMetric]); + + /* Derived States */ + const systemMetrics = $derived($initialized ? [...globalMetrics.filter((gm) => gm?.availability.find((av) => av.cluster == cluster))] : []); + const presetSystemUnits = $derived(loadUnits(systemMetrics)); + + /* Effects */ + $effect(() => { + // OnMount: Ping Var, without this, OVERVIEW metric select is empty (reason tbd) + systemMetrics + }); + + /* Functions */ + function loadUnits(systemMetrics) { + let pendingUnits = {}; + if (systemMetrics.length > 0) { + for (let sm of systemMetrics) { + pendingUnits[sm.name] = (sm?.unit?.prefix ? sm.unit.prefix : "") + (sm?.unit?.base ? sm.unit.base : "") + }; + }; + return {...pendingUnits}; + }; + + // Wait after input for some time to prevent too many requests + let timeoutId = null; + function updateHostnameFilter() { + if (timeoutId != null) clearTimeout(timeoutId); + timeoutId = setTimeout(function () { hostnameFilter = pendingHostnameFilter; }, 500); - } + }; @@ -108,7 +110,7 @@ @@ -139,6 +141,7 @@ placeholder="Filter hostname ..." type="text" bind:value={pendingHostnameFilter} + oninput={updateHostnameFilter} /> @@ -153,26 +156,28 @@ Metric - {#each systemMetrics as metric} + {#each systemMetrics as metric (metric.name)} {metric.name} {presetSystemUnits[metric.name] ? "("+presetSystemUnits[metric.name]+")" : ""} + {:else} + {/each} {/if} - - - { - const diff = Date.now() - to; - from = new Date(from.getTime() + diff); - to = new Date(to.getTime() + diff); - }} - /> - {/if} + + + { + const diff = Date.now() - to; + from = new Date(from.getTime() + diff); + to = new Date(to.getTime() + diff); + }} + /> + @@ -185,20 +190,22 @@ {:else} {#if displayNodeOverview} - + {:else} - + {/if} {/if} - { - selectedMetrics = [...detail] - }} -/> +{#if !displayNodeOverview} + + selectedMetrics = [...newMetrics] + } + /> +{/if} diff --git a/web/frontend/src/Tags.root.svelte b/web/frontend/src/Tags.root.svelte index 03311b45..e1be6a9d 100644 --- a/web/frontend/src/Tags.root.svelte +++ b/web/frontend/src/Tags.root.svelte @@ -24,15 +24,22 @@ init, } from "./generic/utils.js"; - export let username; - export let isAdmin; - export let tagmap; + /* Svelte 5 Props */ + let { + username, + isAdmin, + presetTagmap, + } = $props(); + /* Const Init */ const {} = init(); const client = getContextClient(); - let pendingChange = "none"; + /* State Init */ + let pendingChange = $state("none"); + let tagmap = $state(presetTagmap) + /* Functions */ const removeTagMutation = ({ tagIds }) => { return mutationStore({ client: client, @@ -96,7 +103,7 @@ diff --git a/web/frontend/src/User.root.svelte b/web/frontend/src/User.root.svelte index 0fad6ccf..7250399a 100644 --- a/web/frontend/src/User.root.svelte +++ b/web/frontend/src/User.root.svelte @@ -42,71 +42,90 @@ import TextFilter from "./generic/helper/TextFilter.svelte" import Refresher from "./generic/helper/Refresher.svelte"; - const { query: initq } = init(); + /* Svelte 5 Props */ + let { user, filterPresets } = $props(); + /* Const Init */ + const { query: initq } = init(); const ccconfig = getContext("cc-config"); + const client = getContextClient(); + const durationBinOptions = ["1m","10m","1h","6h","12h"]; + const metricBinOptions = [10, 20, 50, 100]; - export let user; - export let filterPresets; - - let filterComponent; // see why here: https://stackoverflow.com/questions/58287729/how-can-i-export-a-function-from-a-svelte-component-that-changes-a-value-in-the - let jobList; - let jobFilters = []; - let matchedListJobs = 0; - let sorting = { field: "startTime", type: "col", order: "DESC" }, - isSortingOpen = false; - let metrics = ccconfig.plot_list_selectedMetrics, - isMetricsSelectionOpen = false; - let isHistogramSelectionOpen = false; - let selectedCluster = filterPresets?.cluster ? filterPresets.cluster : null; - let showFootprint = filterPresets.cluster + /* State Init */ + // List & Control Vars + let filterComponent = $state(); // see why here: https://stackoverflow.com/questions/58287729/how-can-i-export-a-function-from-a-svelte-component-that-changes-a-value-in-the + let jobFilters = $state([]); + let jobList = $state(null); + let matchedListJobs = $state(0); + let isSortingOpen = $state(false); + let isMetricsSelectionOpen = $state(false); + let sorting = $state({ field: "startTime", type: "col", order: "DESC" }); + let selectedCluster = $state(filterPresets?.cluster ? filterPresets.cluster : null); + let metrics = $state(filterPresets.cluster + ? ccconfig[`plot_list_selectedMetrics:${filterPresets.cluster}`] || + ccconfig.plot_list_selectedMetrics + : ccconfig.plot_list_selectedMetrics + ); + let showFootprint = $state(filterPresets.cluster ? !!ccconfig[`plot_list_showFootprint:${filterPresets.cluster}`] - : !!ccconfig.plot_list_showFootprint; - - let numDurationBins = "1h"; - let numMetricBins = 10; - let durationBinOptions = ["1m","10m","1h","6h","12h"]; - let metricBinOptions = [10, 20, 50, 100]; + : !!ccconfig.plot_list_showFootprint + ); - $: selectedHistograms = selectedCluster - ? ccconfig[`user_view_histogramMetrics:${selectedCluster}`] || ( ccconfig['user_view_histogramMetrics'] || [] ) - : ccconfig['user_view_histogramMetrics'] || []; + // Histogram Vars + let isHistogramSelectionOpen = $state(false); + let numDurationBins = $state("1h"); + let numMetricBins = $state(10); - const client = getContextClient(); - $: stats = queryStore({ - client: client, - query: gql` - query ($jobFilters: [JobFilter!]!, $selectedHistograms: [String!], $numDurationBins: String, $numMetricBins: Int) { - jobsStatistics(filter: $jobFilters, metrics: $selectedHistograms, numDurationBins: $numDurationBins , numMetricBins: $numMetricBins ) { - totalJobs - shortJobs - totalWalltime - totalCoreHours - histDuration { - count - value - } - histNumNodes { - count - value - } - histMetrics { - metric - unit - stat - data { - min - max + // Compare Vars (TODO) + // let jobCompare = $state(null); + // let showCompare = $state(false); + // let selectedJobs = $state([]); + // let filterBuffer = $state([]); + // let matchedCompareJobs = $state(0); + + /* Derived Vars */ + let selectedHistograms = $derived(selectedCluster + ? ccconfig[`user_view_histogramMetrics:${selectedCluster}`] || ( ccconfig['user_view_histogramMetrics'] || [] ) + : ccconfig['user_view_histogramMetrics'] || []); + + let stats = $derived( + queryStore({ + client: client, + query: gql` + query ($jobFilters: [JobFilter!]!, $selectedHistograms: [String!], $numDurationBins: String, $numMetricBins: Int) { + jobsStatistics(filter: $jobFilters, metrics: $selectedHistograms, numDurationBins: $numDurationBins , numMetricBins: $numMetricBins ) { + totalJobs + shortJobs + totalWalltime + totalCoreHours + histDuration { + count + value + } + histNumNodes { count - bin + value + } + histMetrics { + metric + unit + stat + data { + min + max + count + bin + } } } } - } - `, - variables: { jobFilters, selectedHistograms, numDurationBins, numMetricBins }, - }); + `, + variables: { jobFilters, selectedHistograms, numDurationBins, numMetricBins }, + }) + ); + /* On Mount */ onMount(() => filterComponent.updateFilters()); @@ -129,13 +148,13 @@ - @@ -143,11 +162,11 @@ { + applyFilters={(detail) => { jobFilters = [...detail.filters, { user: { eq: user.username } }]; selectedCluster = jobFilters[0]?.cluster ? jobFilters[0].cluster.eq @@ -173,11 +192,11 @@ filterComponent.updateFilters(detail)} + setFilter={(filter) => filterComponent.updateFilters(filter)} /> - { + { jobList.refreshJobs() jobList.refreshAllMetrics() }} /> @@ -269,7 +288,7 @@ outline color="secondary" class="w-100" - on:click={() => (isHistogramSelectionOpen = true)} + onclick={() => (isHistogramSelectionOpen = true)} > Select Histograms @@ -347,12 +366,15 @@ + metrics = [...newMetrics] + } + footprintSelect /> Create User @@ -70,6 +71,7 @@ id="username" name="username" aria-describedby="usernameHelp" + autocomplete="username" />
Must be unique.
@@ -81,6 +83,7 @@ id="password" name="password" aria-describedby="passwordHelp" + autocomplete="new-password" />
Only API users are allowed to have a blank password. Users with a blank @@ -109,6 +112,7 @@ id="name" name="name" aria-describedby="nameHelp" + autocomplete="name" />
Optional, can be blank.
@@ -120,6 +124,7 @@ id="email" name="email" aria-describedby="emailHelp" + autocomplete="email" />
Optional, can be blank.
@@ -153,13 +158,13 @@ {/each}

- - {#if displayMessage}

- {message.msg} -
{/if} + + {#if displayMessage} + {message.msg} + {/if}

diff --git a/web/frontend/src/config/admin/EditProject.svelte b/web/frontend/src/config/admin/EditProject.svelte index 3c87d467..0623f12e 100644 --- a/web/frontend/src/config/admin/EditProject.svelte +++ b/web/frontend/src/config/admin/EditProject.svelte @@ -114,13 +114,13 @@ class="btn btn-primary" type="button" id="add-project-button" - on:click|preventDefault={handleAddProject}>Add handleAddProject()}>Add handleRemoveProject()}>Remove

diff --git a/web/frontend/src/config/admin/EditRole.svelte b/web/frontend/src/config/admin/EditRole.svelte index b8d12bdf..c351ab90 100644 --- a/web/frontend/src/config/admin/EditRole.svelte +++ b/web/frontend/src/config/admin/EditRole.svelte @@ -119,13 +119,13 @@ class="btn btn-primary" type="button" id="add-role-button" - on:click|preventDefault={handleAddRole}>Add handleAddRole()}>Add handleRemoveRole()}>Remove

diff --git a/web/frontend/src/config/admin/NoticeEdit.svelte b/web/frontend/src/config/admin/NoticeEdit.svelte index 325800bc..497f4e35 100644 --- a/web/frontend/src/config/admin/NoticeEdit.svelte +++ b/web/frontend/src/config/admin/NoticeEdit.svelte @@ -63,7 +63,7 @@ class="btn btn-primary" type="button" id="edit-notice-button" - on:click|preventDefault={handleEditNotice}>Edit Notice handleEditNotice()}>Edit Notice

diff --git a/web/frontend/src/config/admin/Options.svelte b/web/frontend/src/config/admin/Options.svelte index 38088346..aa762de9 100644 --- a/web/frontend/src/config/admin/Options.svelte +++ b/web/frontend/src/config/admin/Options.svelte @@ -33,7 +33,7 @@ type="checkbox" id="scramble-names-checkbox" style="margin-right: 1em;" - on:click={handleScramble} + on:click={() => handleScramble()} bind:checked={scrambled} /> Active? diff --git a/web/frontend/src/config/admin/ShowUsers.svelte b/web/frontend/src/config/admin/ShowUsers.svelte index d4988e89..25da2fb7 100644 --- a/web/frontend/src/config/admin/ShowUsers.svelte +++ b/web/frontend/src/config/admin/ShowUsers.svelte @@ -53,11 +53,11 @@

-
+
@@ -77,7 +77,7 @@ diff --git a/web/frontend/src/config/admin/ShowUsersRow.svelte b/web/frontend/src/config/admin/ShowUsersRow.svelte index 25c3710b..a30dc79b 100644 --- a/web/frontend/src/config/admin/ShowUsersRow.svelte +++ b/web/frontend/src/config/admin/ShowUsersRow.svelte @@ -30,7 +30,7 @@ diff --git a/web/frontend/src/generic/helper/Refresher.svelte b/web/frontend/src/generic/helper/Refresher.svelte index f5c64060..5378d26f 100644 --- a/web/frontend/src/generic/helper/Refresher.svelte +++ b/web/frontend/src/generic/helper/Refresher.svelte @@ -8,35 +8,40 @@ - `refresh`: When fired, the upstream component refreshes its contents --> - + @@ -46,7 +51,7 @@ @@ -282,7 +295,7 @@ @@ -314,7 +327,7 @@ outline style="width:100%;" color="success" - on:click={(e) => ( + onclick={(e) => ( e.preventDefault(), createTag(newTagType, newTagName, newTagScope) )} > @@ -345,11 +358,11 @@ {/if} - + - @@ -387,7 +400,7 @@ @@ -396,7 +409,7 @@ @@ -435,7 +448,7 @@ @@ -444,7 +457,7 @@ @@ -475,7 +488,7 @@ outline style="width:100%;" color="success" - on:click={(e) => ( + onclick={(e) => ( e.preventDefault(), createTag(newTagType, newTagName, newTagScope) )} > diff --git a/web/frontend/src/generic/helper/TextFilter.svelte b/web/frontend/src/generic/helper/TextFilter.svelte index c47c979d..7cb9f2da 100644 --- a/web/frontend/src/generic/helper/TextFilter.svelte +++ b/web/frontend/src/generic/helper/TextFilter.svelte @@ -12,21 +12,31 @@ @@ -86,10 +97,10 @@ {#if !presetProject} @@ -102,12 +113,12 @@ termChanged()} - on:keyup={(event) => termChanged(event.key == "Enter" ? 0 : throttle)} - placeholder={presetProject ? `Find ${mode} in ${scrambleNames ? scramble(presetProject) : presetProject} ...` : `Find ${mode} ...`} + onchange={() => termChanged()} + onkeyup={(event) => termChanged(event.key == "Enter" ? 0 : throttle)} + placeholder={presetProject ? `Find in ${scrambleNames ? scramble(presetProject) : presetProject} ...` : `Find ${mode} ...`} /> {#if presetProject} - {/if} diff --git a/web/frontend/src/generic/joblist/JobInfo.svelte b/web/frontend/src/generic/joblist/JobInfo.svelte index f5cb066a..5886c614 100644 --- a/web/frontend/src/generic/joblist/JobInfo.svelte +++ b/web/frontend/src/generic/joblist/JobInfo.svelte @@ -12,15 +12,22 @@ import Tag from "../helper/Tag.svelte"; import TagManagement from "../helper/TagManagement.svelte"; - export let job; - export let jobTags = job.tags; - export let showTagedit = false; - export let username = null; - export let authlevel= null; - export let roles = null; - export let isSelected = null; - export let showSelect = false; + /* Svelte 5 Props */ + let { + job, + jobTags = job.tags, + showTagedit = false, + username = null, + authlevel= null, + roles = null, + isSelected = null, + showSelect = false, + } = $props(); + /* State Init */ + let displayCheck = $state(false); + + /* Functions */ function formatDuration(duration) { const hours = Math.floor(duration / 3600); duration -= hours * 3600; @@ -41,9 +48,8 @@ } } - let displayCheck = false; function clipJobId(jid) { - displayCheck = true; + // Navigator clipboard api needs a secure context (https) if (navigator.clipboard && window.isSecureContext) { navigator.clipboard @@ -65,14 +71,11 @@ textArea.remove(); } } - setTimeout(function () { - displayCheck = false; - }, 1000); }
-

+

{job.jobId} @@ -81,7 +84,7 @@ {#if showSelect}

- - diff --git a/web/frontend/src/generic/joblist/Pagination.svelte b/web/frontend/src/generic/joblist/Pagination.svelte index 77f6bc9f..1a04fd25 100644 --- a/web/frontend/src/generic/joblist/Pagination.svelte +++ b/web/frontend/src/generic/joblist/Pagination.svelte @@ -11,11 +11,51 @@ - Dispatched once immediately and then each time page or itemsPerPage changes --> + +
- pageReset(e)} onchange={(e) => updateItems(e)} bind:value={itemsPerPage} id="cc-pagination-select" class="cc-pagination-select"> {#each pageSizes as size} {/each} @@ -28,49 +68,18 @@
{#if !backButtonDisabled} - - + + {/if} {#if !nextButtonDisabled} - + {/if}
- -
deleteUser(user.username)}>Delete
{user?.roles ? user.roles.join(", ") : "No Roles"} {#if !jwt} - {:else} diff --git a/web/frontend/src/config/support/SupportOptions.svelte b/web/frontend/src/config/support/SupportOptions.svelte index 7d9ce036..88541e07 100644 --- a/web/frontend/src/config/support/SupportOptions.svelte +++ b/web/frontend/src/config/support/SupportOptions.svelte @@ -3,7 +3,7 @@ --> diff --git a/web/frontend/src/generic/PlotTable.svelte b/web/frontend/src/generic/PlotTable.svelte deleted file mode 100644 index 4bc06941..00000000 --- a/web/frontend/src/generic/PlotTable.svelte +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - {#each rows as row} - - {#each row as item (item)} - - {/each} - - {/each} -
- {#if !isPlaceholder(item) && plotWidth > 0} - - {/if} -
diff --git a/web/frontend/src/generic/filters/Cluster.svelte b/web/frontend/src/generic/filters/Cluster.svelte index f8865824..894ce0cd 100644 --- a/web/frontend/src/generic/filters/Cluster.svelte +++ b/web/frontend/src/generic/filters/Cluster.svelte @@ -13,7 +13,7 @@ --> (isOpen = !isOpen)}> @@ -45,13 +50,13 @@

Cluster

{#if disableClusterSelection} - + {:else} ((pendingCluster = null), (pendingPartition = null))} + onclick={() => ((pendingCluster = null), (pendingPartition = null))} > Any Cluster @@ -59,7 +64,7 @@ ( + onclick={() => ( (pendingCluster = cluster.name), (pendingPartition = null) )} > @@ -75,14 +80,14 @@ (pendingPartition = null)} + onclick={() => (pendingPartition = null)} > Any Partition - {#each clusters.find((c) => c.name == pendingCluster).partitions as partition} + {#each clusters?.find((c) => c.name == pendingCluster)?.partitions as partition} (pendingPartition = partition)} + onclick={() => (pendingPartition = partition)} > {partition} @@ -93,22 +98,22 @@ - - + {#if !disableClusterSelection} + + {/if} +
diff --git a/web/frontend/src/generic/filters/Duration.svelte b/web/frontend/src/generic/filters/Duration.svelte index 6a22b988..75f2e801 100644 --- a/web/frontend/src/generic/filters/Duration.svelte +++ b/web/frontend/src/generic/filters/Duration.svelte @@ -13,7 +13,6 @@ --> (isOpen = !isOpen)}> @@ -92,7 +111,7 @@ type="number" min="0" class="form-control" - bind:value={pendingMoreThan.hours} + bind:value={moreState.hours} disabled={moreDisabled} />
@@ -107,7 +126,7 @@ min="0" max="59" class="form-control" - bind:value={pendingMoreThan.mins} + bind:value={moreState.mins} disabled={moreDisabled} />
@@ -126,7 +145,7 @@ type="number" min="0" class="form-control" - bind:value={pendingLessThan.hours} + bind:value={lessState.hours} disabled={lessDisabled} />
@@ -141,7 +160,7 @@ min="0" max="59" class="form-control" - bind:value={pendingLessThan.mins} + bind:value={lessState.mins} disabled={lessDisabled} />
@@ -160,7 +179,7 @@ type="number" min="0" class="form-control" - bind:value={pendingFrom.hours} + bind:value={fromState.hours} disabled={betweenDisabled} />
@@ -175,7 +194,7 @@ min="0" max="59" class="form-control" - bind:value={pendingFrom.mins} + bind:value={fromState.mins} disabled={betweenDisabled} />
@@ -192,7 +211,7 @@ type="number" min="0" class="form-control" - bind:value={pendingTo.hours} + bind:value={toState.hours} disabled={betweenDisabled} />
@@ -207,7 +226,7 @@ min="0" max="59" class="form-control" - bind:value={pendingTo.mins} + bind:value={toState.mins} disabled={betweenDisabled} />
@@ -220,39 +239,32 @@ - + diff --git a/web/frontend/src/generic/filters/Energy.svelte b/web/frontend/src/generic/filters/Energy.svelte index 9dd6dd8a..536510b1 100644 --- a/web/frontend/src/generic/filters/Energy.svelte +++ b/web/frontend/src/generic/filters/Energy.svelte @@ -10,7 +10,6 @@ --> (isOpen = !isOpen)}> Filter based on energy -

Total Job Energy (kWh)

- ( - (energy.from = detail[0]), (energy.to = detail[1]) - )} - min={0.0} - max={energyMaximum} - firstSlider={energy?.from ? energy.from : 0.0} - secondSlider={energy?.to ? energy.to : energyMaximum} - inputFieldFrom={energy?.from ? energy.from : null} - inputFieldTo={energy?.to ? energy.to : null} - /> +
+
Total Job Energy (kWh)
+ { + energyState.from = detail[0]; + energyState.to = detail[1]; + }} + sliderMin={0.0} + sliderMax={1000.0} + fromPreset={energyState?.from? energyState.from : 0.0} + toPreset={energyState?.to? energyState.to : 1000.0} + /> +
diff --git a/web/frontend/src/generic/filters/InfoBox.svelte b/web/frontend/src/generic/filters/InfoBox.svelte index ebd3526f..ea9eb3f2 100644 --- a/web/frontend/src/generic/filters/InfoBox.svelte +++ b/web/frontend/src/generic/filters/InfoBox.svelte @@ -4,16 +4,22 @@ Properties: - `icon String`: Sveltestrap icon name - `modified Bool?`: Optional if filter is modified [Default: false] + - `onclick Fn()`: Opens Modal on click + - `children Fn()?`: Internal prop, Svelte 5 version of --> - diff --git a/web/frontend/src/generic/filters/JobStates.svelte b/web/frontend/src/generic/filters/JobStates.svelte index d903abce..0e32885e 100644 --- a/web/frontend/src/generic/filters/JobStates.svelte +++ b/web/frontend/src/generic/filters/JobStates.svelte @@ -13,7 +13,7 @@ - `const allJobStates [String]`: List of all available job states used in cc-backend --> - (isOpen = !isOpen)}> @@ -71,28 +72,25 @@ - +
diff --git a/web/frontend/src/generic/filters/Resources.svelte b/web/frontend/src/generic/filters/Resources.svelte index 443dda77..02925d43 100644 --- a/web/frontend/src/generic/filters/Resources.svelte +++ b/web/frontend/src/generic/filters/Resources.svelte @@ -2,14 +2,11 @@ @component Filter sub-component for selecting job resources Properties: - - `cluster Object?`: The currently selected cluster config [Default: null] - `isOpen Bool?`: Is this filter component opened [Default: false] + - `activeCluster String?`: The currently selected cluster name [Default: null] - `numNodes Object?`: The currently selected numNodes filter [Default: {from:null, to:null}] - `numHWThreads Object?`: The currently selected numHWThreads filter [Default: {from:null, to:null}] - `numAccelerators Object?`: The currently selected numAccelerators filter [Default: {from:null, to:null}] - - `isNodesModified Bool?`: Is the node filter modified [Default: false] - - `isHwthreadsModified Bool?`: Is the Hwthreads filter modified [Default: false] - - `isAccsModified Bool?`: Is the Accelerator filter modified [Default: false] - `namedNode String?`: The currently selected single named node (= hostname) [Default: null] Events: @@ -17,7 +14,7 @@ --> (isOpen = !isOpen)}> Select number of utilized Resources -
Named Node
-
+
Named Node
+
@@ -164,82 +211,63 @@ {/each}
-
Number of Nodes
- { - pendingNumNodes = { from: detail[0], to: detail[1] }; - isNodesModified = true; - }} - min={minNumNodes} - max={maxNumNodes} - firstSlider={pendingNumNodes.from} - secondSlider={pendingNumNodes.to} - inputFieldFrom={pendingNumNodes.from} - inputFieldTo={pendingNumNodes.to} - /> -
- Number of HWThreads (Use for Single-Node Jobs) -
- { - pendingNumHWThreads = { from: detail[0], to: detail[1] }; - isHwthreadsModified = true; - }} - min={minNumHWThreads} - max={maxNumHWThreads} - firstSlider={pendingNumHWThreads.from} - secondSlider={pendingNumHWThreads.to} - inputFieldFrom={pendingNumHWThreads.from} - inputFieldTo={pendingNumHWThreads.to} - /> - {#if maxNumAccelerators != null && maxNumAccelerators > 1} -
Number of Accelerators
+ +
+
Number of Nodes
{ - pendingNumAccelerators = { from: detail[0], to: detail[1] }; - isAccsModified = true; + changeRange={(detail) => { + nodesState.from = detail[0]; + nodesState.to = detail[1]; }} - min={minNumAccelerators} - max={maxNumAccelerators} - firstSlider={pendingNumAccelerators.from} - secondSlider={pendingNumAccelerators.to} - inputFieldFrom={pendingNumAccelerators.from} - inputFieldTo={pendingNumAccelerators.to} + sliderMin={minNumNodes} + sliderMax={maxNumNodes} + fromPreset={nodesState.from} + toPreset={nodesState.to} /> +
+ +
+
Number of HWThreads (Use for Single-Node Jobs)
+ { + threadState.from = detail[0]; + threadState.to = detail[1]; + }} + sliderMin={1} + sliderMax={maxNumHWThreads} + fromPreset={threadState.from} + toPreset={threadState.to} + /> +
+ {#if maxNumAccelerators != null && maxNumAccelerators > 1} +
+
Number of Accelerators
+ { + accState.from = detail[0]; + accState.to = detail[1]; + }} + sliderMin={0} + sliderMax={maxNumAccelerators} + fromPreset={accState.from} + toPreset={accState.to} + /> +
{/if} - + diff --git a/web/frontend/src/generic/filters/StartTime.svelte b/web/frontend/src/generic/filters/StartTime.svelte index a109fbb3..c722baa9 100644 --- a/web/frontend/src/generic/filters/StartTime.svelte +++ b/web/frontend/src/generic/filters/StartTime.svelte @@ -12,8 +12,19 @@ - `set-filter, {String?, String?}`: Set 'from, to' filter in upstream component --> + + (isOpen = !isOpen)}> Select Start Time - {#if range !== ""} + {#if rangeSelect !== ""}

Current Range

- + {#each startTimeSelectOptions as { rangeLabel, range }} - {/each} @@ -101,42 +99,41 @@

From

- + - +

To

- + - +
- {#if pendingRange !== ""} + {#if rangeSelect !== ""} - +
diff --git a/web/frontend/src/generic/filters/Stats.svelte b/web/frontend/src/generic/filters/Stats.svelte index 3252d390..fe05466d 100644 --- a/web/frontend/src/generic/filters/Stats.svelte +++ b/web/frontend/src/generic/filters/Stats.svelte @@ -2,7 +2,6 @@ @component Filter sub-component for selecting job statistics Properties: - - `isModified Bool?`: Is this filter component modified [Default: false] - `isOpen Bool?`: Is this filter component opened [Default: false] - `stats [Object]?`: The currently selected statistics filter [Default: []] @@ -11,7 +10,6 @@ --> (isOpen = !isOpen)}> - Filter based on statistics + + Filter based on statistics + - {#each statistics as stat} -

{stat.text}

- ( - (stat.from = detail[0]), (stat.to = detail[1]), (stat.enabled = true) - )} - min={0} - max={stat.peak} - firstSlider={stat.from} - secondSlider={stat.to} - inputFieldFrom={stat.from} - inputFieldTo={stat.to} - /> + {#each availableStats as aStat} +
+
{aStat.text}
+ { + aStat.from = detail[0]; + aStat.to = detail[1]; + if (aStat.from == 0 && aStat.to == aStat.peak) { + aStat.enabled = false; + } else { + aStat.enabled = true; + } + }} + sliderMin={0.0} + sliderMax={aStat.peak} + fromPreset={aStat.from} + toPreset={aStat.to} + /> +
{/each}
- +
diff --git a/web/frontend/src/generic/filters/Tags.svelte b/web/frontend/src/generic/filters/Tags.svelte index e42d1857..0cbed278 100644 --- a/web/frontend/src/generic/filters/Tags.svelte +++ b/web/frontend/src/generic/filters/Tags.svelte @@ -11,7 +11,7 @@ --> (isOpen = !isOpen)}> @@ -55,7 +55,7 @@ @@ -81,21 +81,25 @@ + - + diff --git a/web/frontend/src/generic/helper/ConcurrentJobs.svelte b/web/frontend/src/generic/helper/ConcurrentJobs.svelte index 85bac83e..d42ace13 100644 --- a/web/frontend/src/generic/helper/ConcurrentJobs.svelte +++ b/web/frontend/src/generic/helper/ConcurrentJobs.svelte @@ -17,11 +17,14 @@ Icon } from "@sveltestrap/sveltestrap"; - export let cJobs; - export let showLinks = false; - export let renderCard = false; - export let width = "auto"; - export let height = "400px"; + /* Svelte 5 Props */ + let { + cJobs, + showLinks = false, + renderCard = false, + width = "auto", + height = "400px", + } = $props(); {#if renderCard} diff --git a/web/frontend/src/generic/helper/JobFootprint.svelte b/web/frontend/src/generic/helper/JobFootprint.svelte index 80e905bc..8d897310 100644 --- a/web/frontend/src/generic/helper/JobFootprint.svelte +++ b/web/frontend/src/generic/helper/JobFootprint.svelte @@ -23,79 +23,90 @@ } from "@sveltestrap/sveltestrap"; import { findJobFootprintThresholds } from "../utils.js"; - export let job; - export let displayTitle = true; - export let width = "auto"; - export let height = "310px"; + /* Svelte 5 Props */ + let { + job, + displayTitle = true, + width = "auto", + height = "310px", + } = $props(); - const footprintData = job?.footprint?.map((jf) => { - const fmc = getContext("getMetricConfig")(job.cluster, job.subCluster, jf.name); - if (fmc) { - // Unit - const unit = (fmc?.unit?.prefix ? fmc.unit.prefix : "") + (fmc?.unit?.base ? fmc.unit.base : "") + /* Derived */ + const footprintData = $derived(buildFootprint(job?.footprint)); + + /* Functions */ + function buildFootprint(input) { + let result = input?.map((jf) => { + const fmc = getContext("getMetricConfig")(job.cluster, job.subCluster, jf.name); + if (fmc) { + // Unit + const unit = (fmc?.unit?.prefix ? fmc.unit.prefix : "") + (fmc?.unit?.base ? fmc.unit.base : "") - // Threshold / -Differences - const fmt = findJobFootprintThresholds(job, jf.stat, fmc); + // Threshold / -Differences + const fmt = findJobFootprintThresholds(job, jf.stat, fmc); - // Define basic data -> Value: Use as Provided - const fmBase = { - name: jf.name + ' (' + jf.stat + ')', - avg: jf.value, - unit: unit, - max: fmt.peak, - dir: fmc.lowerIsBetter - }; - - if (evalFootprint(jf.value, fmt, fmc.lowerIsBetter, "alert")) { - return { - ...fmBase, - color: "danger", - message: `Footprint value way ${fmc.lowerIsBetter ? "above" : "below"} expected normal threshold.`, - impact: 3 - }; - } else if (evalFootprint(jf.value, fmt, fmc.lowerIsBetter, "caution")) { - return { - ...fmBase, - color: "warning", - message: `Footprint value ${fmc.lowerIsBetter ? "above" : "below"} expected normal threshold.`, - impact: 2, - }; - } else if (evalFootprint(jf.value, fmt, fmc.lowerIsBetter, "normal")) { - return { - ...fmBase, - color: "success", - message: "Footprint value within expected thresholds.", - impact: 1, + // Define basic data -> Value: Use as Provided + const fmBase = { + name: jf.name + ' (' + jf.stat + ')', + avg: jf.value, + unit: unit, + max: fmt.peak, + dir: fmc.lowerIsBetter }; - } else if (evalFootprint(jf.value, fmt, fmc.lowerIsBetter, "peak")) { - return { - ...fmBase, - color: "info", - message: - "Footprint value above expected normal threshold: Check for artifacts recommended.", - impact: 0, - }; - } else { + + if (evalFootprint(jf.value, fmt, fmc.lowerIsBetter, "alert")) { + return { + ...fmBase, + color: "danger", + message: `Footprint value way ${fmc.lowerIsBetter ? "above" : "below"} expected normal threshold.`, + impact: 3 + }; + } else if (evalFootprint(jf.value, fmt, fmc.lowerIsBetter, "caution")) { + return { + ...fmBase, + color: "warning", + message: `Footprint value ${fmc.lowerIsBetter ? "above" : "below"} expected normal threshold.`, + impact: 2, + }; + } else if (evalFootprint(jf.value, fmt, fmc.lowerIsBetter, "normal")) { + return { + ...fmBase, + color: "success", + message: "Footprint value within expected thresholds.", + impact: 1, + }; + } else if (evalFootprint(jf.value, fmt, fmc.lowerIsBetter, "peak")) { + return { + ...fmBase, + color: "info", + message: + "Footprint value above expected normal threshold: Check for artifacts recommended.", + impact: 0, + }; + } else { + return { + ...fmBase, + color: "secondary", + message: + "Footprint value above expected peak threshold: Check for artifacts!", + impact: -1, + }; + } + } else { // No matching metric config: display as single value return { - ...fmBase, - color: "secondary", + name: jf.name + ' (' + jf.stat + ')', + avg: jf.value, message: - "Footprint value above expected peak threshold: Check for artifacts!", - impact: -1, + `No config for metric ${jf.name} found.`, + impact: 4, }; } - } else { // No matching metric config: display as single value - return { - name: jf.name + ' (' + jf.stat + ')', - avg: jf.value, - message: - `No config for metric ${jf.name} found.`, - impact: 4, - }; - } - }).sort(function (a, b) { // Sort by impact value primarily, within impact sort name alphabetically - return a.impact - b.impact || ((a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0)); - });; + }).sort(function (a, b) { // Sort by impact value primarily, within impact sort name alphabetically + return a.impact - b.impact || ((a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0)); + });; + + return result; + }; function evalFootprint(value, thresholds, lowerIsBetter, level) { // Handle Metrics in which less value is better @@ -176,7 +187,7 @@ >{fpd.message}
- + {#if fpd.dir}