diff --git a/web/frontend/package-lock.json b/web/frontend/package-lock.json index 8874cafc..79757738 100644 --- a/web/frontend/package-lock.json +++ b/web/frontend/package-lock.json @@ -9,27 +9,26 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "@rollup/plugin-replace": "^5.0.2", - "@urql/svelte": "^4.0.1", - "chart.js": "^4.3.3", + "@rollup/plugin-replace": "^5.0.5", + "@sveltestrap/sveltestrap": "^6.2.6", + "@urql/svelte": "^4.1.0", + "chart.js": "^4.4.2", "date-fns": "^2.30.0", - "date-fns": "^2.30.0", - "graphql": "^16.6.0", - "mathjs": "^12.0.0", - "svelte-chartjs": "^3.1.2", - "sveltestrap": "^5.11.1", - "uplot": "^1.6.24", - "wonka": "^6.3.2" + "graphql": "^16.8.1", + "mathjs": "^12.4.0", + "svelte-chartjs": "^3.1.5", + "uplot": "^1.6.30", + "wonka": "^6.3.4" }, "devDependencies": { - "@rollup/plugin-commonjs": "^24.1.0", - "@rollup/plugin-node-resolve": "^15.0.2", - "@rollup/plugin-terser": "^0.4.1", - "@timohausmann/quadtree-js": "^1.2.5", - "rollup": "^3.21.0", - "rollup-plugin-css-only": "^4.3.0", - "rollup-plugin-svelte": "^7.1.4", - "svelte": "^3.58.0" + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-terser": "^0.4.4", + "@timohausmann/quadtree-js": "^1.2.6", + "rollup": "^4.12.1", + "rollup-plugin-css-only": "^4.5.2", + "rollup-plugin-svelte": "^7.1.6", + "svelte": "^4.2.12" } }, "node_modules/@0no-co/graphql.web": { @@ -45,10 +44,22 @@ } } }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/runtime": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz", - "integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", + "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -57,33 +68,30 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true, + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "engines": { "node": ">=6.0.0" } @@ -104,13 +112,9 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", - "dev": true, + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -131,9 +135,9 @@ } }, "node_modules/@rollup/plugin-commonjs": { - "version": "24.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-24.1.0.tgz", - "integrity": "sha512-eSL45hjhCWI0jCCXcNtLVqM5N1JlBGvlFfY0m6oOYnLCJ6N0qEXoZql4sY2MOUArzhH4SA/qBpTxvvZp2Sc+DQ==", + "version": "25.0.7", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz", + "integrity": "sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", @@ -141,13 +145,13 @@ "estree-walker": "^2.0.2", "glob": "^8.0.3", "is-reference": "1.2.1", - "magic-string": "^0.27.0" + "magic-string": "^0.30.3" }, "engines": { "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^2.68.0||^3.0.0" + "rollup": "^2.68.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -156,9 +160,6 @@ } }, "node_modules/@rollup/plugin-node-resolve": { - "version": "15.2.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", - "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", "version": "15.2.3", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", @@ -176,7 +177,6 @@ }, "peerDependencies": { "rollup": "^2.78.0||^3.0.0||^4.0.0" - "rollup": "^2.78.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -185,23 +185,18 @@ } }, "node_modules/@rollup/plugin-replace": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.5.tgz", - "integrity": "sha512-rYO4fOi8lMaTg/z5Jb+hKnrHHVn8j2lwkqwyS4kTRhKyWOLf2wST2sWXr4WzWiTcoHTp2sTjqUbqIj2E39slKQ==", "version": "5.0.5", "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.5.tgz", "integrity": "sha512-rYO4fOi8lMaTg/z5Jb+hKnrHHVn8j2lwkqwyS4kTRhKyWOLf2wST2sWXr4WzWiTcoHTp2sTjqUbqIj2E39slKQ==", "dependencies": { "@rollup/pluginutils": "^5.0.1", "magic-string": "^0.30.3" - "magic-string": "^0.30.3" }, "engines": { "node": ">=14.0.0" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -209,32 +204,7 @@ } } }, - "node_modules/@rollup/plugin-replace/node_modules/magic-string": { - "version": "0.30.5", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", - "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@rollup/plugin-replace/node_modules/magic-string": { - "version": "0.30.5", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", - "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@rollup/plugin-terser": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", - "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", "version": "0.4.4", "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", @@ -249,7 +219,6 @@ }, "peerDependencies": { "rollup": "^2.0.0||^3.0.0||^4.0.0" - "rollup": "^2.0.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -271,7 +240,6 @@ }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -279,6 +247,186 @@ } } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.1.tgz", + "integrity": "sha512-iU2Sya8hNn1LhsYyf0N+L4Gf9Qc+9eBTJJJsaOGUp+7x4n2M9dxTt8UvhJl3oeftSjblSlpCfvjA/IfP3g5VjQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.12.1.tgz", + "integrity": "sha512-wlzcWiH2Ir7rdMELxFE5vuM7D6TsOcJ2Yw0c3vaBR3VOsJFVTx9xvwnAvhgU5Ii8Gd6+I11qNHwndDscIm0HXg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.12.1.tgz", + "integrity": "sha512-YRXa1+aZIFN5BaImK+84B3uNK8C6+ynKLPgvn29X9s0LTVCByp54TB7tdSMHDR7GTV39bz1lOmlLDuedgTwwHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.12.1.tgz", + "integrity": "sha512-opjWJ4MevxeA8FhlngQWPBOvVWYNPFkq6/25rGgG+KOy0r8clYwL1CFd+PGwRqqMFVQ4/Qd3sQu5t7ucP7C/Uw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.12.1.tgz", + "integrity": "sha512-uBkwaI+gBUlIe+EfbNnY5xNyXuhZbDSx2nzzW8tRMjUmpScd6lCQYKY2V9BATHtv5Ef2OBq6SChEP8h+/cxifQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.12.1.tgz", + "integrity": "sha512-0bK9aG1kIg0Su7OcFTlexkVeNZ5IzEsnz1ept87a0TUgZ6HplSgkJAnFpEVRW7GRcikT4GlPV0pbtVedOaXHQQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.12.1.tgz", + "integrity": "sha512-qB6AFRXuP8bdkBI4D7UPUbE7OQf7u5OL+R94JE42Z2Qjmyj74FtDdLGeriRyBDhm4rQSvqAGCGC01b8Fu2LthQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.12.1.tgz", + "integrity": "sha512-sHig3LaGlpNgDj5o8uPEoGs98RII8HpNIqFtAI8/pYABO8i0nb1QzT0JDoXF/pxzqO+FkxvwkHZo9k0NJYDedg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.12.1.tgz", + "integrity": "sha512-nD3YcUv6jBJbBNFvSbp0IV66+ba/1teuBcu+fBBPZ33sidxitc6ErhON3JNavaH8HlswhWMC3s5rgZpM4MtPqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.12.1.tgz", + "integrity": "sha512-7/XVZqgBby2qp/cO0TQ8uJK+9xnSdJ9ct6gSDdEr4MfABrjTyrW6Bau7HQ73a2a5tPB7hno49A0y1jhWGDN9OQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.12.1.tgz", + "integrity": "sha512-CYc64bnICG42UPL7TrhIwsJW4QcKkIt9gGlj21gq3VV0LL6XNb1yAdHVp1pIi9gkts9gGcT3OfUYHjGP7ETAiw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.12.1.tgz", + "integrity": "sha512-LN+vnlZ9g0qlHGlS920GR4zFCqAwbv2lULrR29yGaWP9u7wF5L7GqWu9Ah6/kFZPXPUkpdZwd//TNR+9XC9hvA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.1.tgz", + "integrity": "sha512-n+vkrSyphvmU0qkQ6QBNXCGr2mKjhP08mPRM/Xp5Ck2FV4NrHU+y6axzDeixUrCBHVUS51TZhjqrKBBsHLKb2Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sveltestrap/sveltestrap": { + "version": "6.2.6", + "resolved": "https://registry.npmjs.org/@sveltestrap/sveltestrap/-/sveltestrap-6.2.6.tgz", + "integrity": "sha512-iB50tbVzsFXp0M10pe3XywRkNxjKPIHXJzV44mb1FhajWNWwxme8MkBis9m2QNivM2hyw5zDHjgGuzwTOB76JQ==", + "dependencies": { + "@popperjs/core": "^2.11.8" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0 || ^5.0.0-next.0" + } + }, "node_modules/@timohausmann/quadtree-js": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@timohausmann/quadtree-js/-/quadtree-js-1.2.6.tgz", @@ -289,9 +437,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" }, "node_modules/@types/resolve": { "version": "1.20.2", @@ -300,20 +445,20 @@ "dev": true }, "node_modules/@urql/core": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@urql/core/-/core-4.2.0.tgz", - "integrity": "sha512-GRkZ4kECR9UohWAjiSk2UYUetco6/PqSrvyC4AH6g16tyqEShA63M232cfbE1J9XJPaGNjia14Gi+oOqzp144w==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@urql/core/-/core-4.3.0.tgz", + "integrity": "sha512-wT+FeL8DG4x5o6RfHEnONNFVDM3616ouzATMYUClB6CB+iIu2mwfBKd7xSUxYOZmwtxna5/hDRQdMl3nbQZlnw==", "dependencies": { "@0no-co/graphql.web": "^1.0.1", "wonka": "^6.3.2" } }, "node_modules/@urql/svelte": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@urql/svelte/-/svelte-4.0.4.tgz", - "integrity": "sha512-HYz9dHdqEcs9d82WWczQ3XG+zuup3TS01H+txaij/QfQ+KHjrlrn0EkOHQQd1S+H8+nFjFU2x9+HE3+3fuwL1A==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@urql/svelte/-/svelte-4.1.0.tgz", + "integrity": "sha512-Ov3EclCjaXPPTjKNTcIDlAG3qY/jhLjl/J9yyz9FeLUQ9S2jEgsvlzNXibrY27f4ihD4gH36CNGuj1XOi5hEEQ==", "dependencies": { - "@urql/core": "^4.1.0", + "@urql/core": "^4.3.0", "wonka": "^6.3.2" }, "peerDependencies": { @@ -321,13 +466,9 @@ } }, "node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "dev": true, + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "bin": { "acorn": "bin/acorn" }, @@ -335,6 +476,22 @@ "node": ">=0.4.0" } }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/axobject-query": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", + "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", + "dependencies": { + "dequal": "^2.0.3" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -369,14 +526,34 @@ } }, "node_modules/chart.js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.1.tgz", - "integrity": "sha512-C74QN1bxwV1v2PEujhmKjOZ7iUM4w6BWs23Md/6aOZZSlwMzeCIDGuZay++rBgChYru7/+QFeoQW0fQoP534Dg==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.2.tgz", + "integrity": "sha512-6GD7iKwFpP5kbSD4MeRRRlTnQvxfQREy36uEtm1hzHzcOqwWx0YEHuspuoNlslu+nciLIB7fjjsHkUv/FzFcOg==", "dependencies": { "@kurkle/color": "^0.3.0" }, "engines": { - "pnpm": ">=7" + "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==", + "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==", + "dependencies": { + "@types/estree": "^1.0.0" } }, "node_modules/commander": { @@ -403,6 +580,18 @@ "url": "https://www.patreon.com/infusion" } }, + "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==", + "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", @@ -432,6 +621,14 @@ "node": ">=0.10.0" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, "node_modules/escape-latex": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz", @@ -482,13 +679,6 @@ "funding": { "url": "https://github.com/sponsors/ljharb" } - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } }, "node_modules/glob": { "version": "8.1.0", @@ -510,9 +700,6 @@ } }, "node_modules/graphql": { - "version": "16.8.1", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", - "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", "version": "16.8.1", "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", @@ -521,21 +708,15 @@ } }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", + "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", "dev": true, "dependencies": { "function-bind": "^1.1.2" - "function-bind": "^1.1.2" }, "engines": { "node": ">= 0.4" - "node": ">= 0.4" } }, "node_modules/inflight": { @@ -570,16 +751,12 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "dependencies": { "hasown": "^2.0.0" - "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -605,25 +782,28 @@ "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==" }, + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==" + }, "node_modules/magic-string": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", - "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", - "dev": true, - "dev": true, + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" + "@jridgewell/sourcemap-codec": "^1.4.15" }, "engines": { "node": ">=12" } }, "node_modules/mathjs": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-12.0.0.tgz", - "integrity": "sha512-Oz3swPplNPe7taoP6WrkKhQzhDE2SwvOgLzu8H3EN+hEadw2GjEJUm6Xl+hrioHoB8g2BYb3gfw1glSzhdBKYw==", + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-12.4.0.tgz", + "integrity": "sha512-4Moy0RNjwMSajEkGGxNUyMMC/CZAcl87WBopvNsJWB4E4EFebpTedr+0/rhqmnOSTH3Wu/3WfiWiw6mqiaHxVw==", "dependencies": { - "@babel/runtime": "^7.23.2", + "@babel/runtime": "^7.23.9", "complex.js": "^2.1.1", "decimal.js": "^10.4.3", "escape-latex": "^1.2.0", @@ -640,6 +820,11 @@ "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==" + }, "node_modules/minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", @@ -667,6 +852,32 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/periscopic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", + "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", + "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==", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/periscopic/node_modules/is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -688,19 +899,11 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" - }, - "node_modules/regenerator-runtime": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "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.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", @@ -727,28 +930,38 @@ } }, "node_modules/rollup": { - "version": "3.29.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", - "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", - "version": "3.29.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", - "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.12.1.tgz", + "integrity": "sha512-ggqQKvx/PsB0FaWXhIvVkSWh7a/PCLQAsMjBc+nA2M8Rv2/HG0X6zvixAB7KyZBRtifBUhy5k8voQX/mRnABPg==", "devOptional": true, + "dependencies": { + "@types/estree": "1.0.5" + }, "bin": { "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=14.18.0", + "node": ">=18.0.0", "npm": ">=8.0.0" }, "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.12.1", + "@rollup/rollup-android-arm64": "4.12.1", + "@rollup/rollup-darwin-arm64": "4.12.1", + "@rollup/rollup-darwin-x64": "4.12.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.12.1", + "@rollup/rollup-linux-arm64-gnu": "4.12.1", + "@rollup/rollup-linux-arm64-musl": "4.12.1", + "@rollup/rollup-linux-riscv64-gnu": "4.12.1", + "@rollup/rollup-linux-x64-gnu": "4.12.1", + "@rollup/rollup-linux-x64-musl": "4.12.1", + "@rollup/rollup-win32-arm64-msvc": "4.12.1", + "@rollup/rollup-win32-ia32-msvc": "4.12.1", + "@rollup/rollup-win32-x64-msvc": "4.12.1", "fsevents": "~2.3.2" } }, "node_modules/rollup-plugin-css-only": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-css-only/-/rollup-plugin-css-only-4.5.2.tgz", - "integrity": "sha512-7rj9+jB17Pz8LNcPgtMUb16JcgD8lxQMK9HcGfAVhMK3na/WXes3oGIo5QsrQQVqtgAU6q6KnQNXJrYunaUIQQ==", "version": "4.5.2", "resolved": "https://registry.npmjs.org/rollup-plugin-css-only/-/rollup-plugin-css-only-4.5.2.tgz", "integrity": "sha512-7rj9+jB17Pz8LNcPgtMUb16JcgD8lxQMK9HcGfAVhMK3na/WXes3oGIo5QsrQQVqtgAU6q6KnQNXJrYunaUIQQ==", @@ -761,7 +974,6 @@ }, "peerDependencies": { "rollup": "<5" - "rollup": "<5" } }, "node_modules/rollup-plugin-svelte": { @@ -820,18 +1032,15 @@ "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" }, "node_modules/serialize-javascript": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", - "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "dependencies": { "randombytes": "^2.1.0" } }, "node_modules/smob": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/smob/-/smob-1.4.1.tgz", - "integrity": "sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==", "version": "1.4.1", "resolved": "https://registry.npmjs.org/smob/-/smob-1.4.1.tgz", "integrity": "sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==", @@ -846,6 +1055,14 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "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", @@ -869,40 +1086,58 @@ } }, "node_modules/svelte": { - "version": "3.59.2", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.59.2.tgz", - "integrity": "sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA==", + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.12.tgz", + "integrity": "sha512-d8+wsh5TfPwqVzbm4/HCXC783/KPHV60NvwitJnyTA5lWn1elhXMNWhXGCJ7PwPa8qFUnyJNIyuIRt2mT0WMug==", + "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", + "locate-character": "^3.0.0", + "magic-string": "^0.30.4", + "periscopic": "^3.1.0" + }, "engines": { - "node": ">= 8" + "node": ">=16" } }, "node_modules/svelte-chartjs": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/svelte-chartjs/-/svelte-chartjs-3.1.2.tgz", - "integrity": "sha512-3+6gY2IJ9Ua8R9pk3iS1ypa7Z9OoXCJb9oPwIfTp7caJM+X+RrWnH2CTkGAq7FeSxc2nnmW08tYN88Q8Y+5M+w==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/svelte-chartjs/-/svelte-chartjs-3.1.5.tgz", + "integrity": "sha512-ka2zh7v5FiwfAX1oMflZ0HkNkgjHjFqANgRyC+vNYXfxtx2ku68Zo+2KgbKeBH2nS1ThDqkIACPzGxy4T0UaoA==", "peerDependencies": { "chart.js": "^3.5.0 || ^4.0.0", - "svelte": "^3.45.0" + "svelte": "^4.0.0" } }, - "node_modules/sveltestrap": { - "version": "5.11.2", - "resolved": "https://registry.npmjs.org/sveltestrap/-/sveltestrap-5.11.2.tgz", - "integrity": "sha512-fkLqIUh2QHBoom7v6kHI85grLeOqplmvtnTiA5Ck2gchzpVmwXWaWpf8qWhCFxfDuMhJBPlWbJvtSmwpDEowrg==", - "version": "5.11.2", - "resolved": "https://registry.npmjs.org/sveltestrap/-/sveltestrap-5.11.2.tgz", - "integrity": "sha512-fkLqIUh2QHBoom7v6kHI85grLeOqplmvtnTiA5Ck2gchzpVmwXWaWpf8qWhCFxfDuMhJBPlWbJvtSmwpDEowrg==", + "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==", "dependencies": { - "@popperjs/core": "^2.11.8" - }, - "peerDependencies": { - "svelte": "^3.53.1" + "@types/estree": "^1.0.0" + } + }, + "node_modules/svelte/node_modules/is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "dependencies": { + "@types/estree": "*" } }, "node_modules/terser": { - "version": "5.25.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.25.0.tgz", - "integrity": "sha512-we0I9SIsfvNUMP77zC9HG+MylwYYsGFSBG8qm+13oud2Yh+O104y614FRbyjpxys16jZwot72Fpi827YvGzuqg==", + "version": "5.29.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.1.tgz", + "integrity": "sha512-lZQ/fyaIGxsbGxApKmoPTODIzELy3++mXhS5hOqaAWZjQtpq/hFHAc+rm29NND1rYRxRWKcjuARNwULNXa5RtQ==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -931,12 +1166,9 @@ } }, "node_modules/uplot": { - "version": "1.6.27", - "resolved": "https://registry.npmjs.org/uplot/-/uplot-1.6.27.tgz", - "integrity": "sha512-78U4ss5YeU65kQkOC/QAKiyII+4uo+TYUJJKvuxRzeSpk/s5sjpY1TL0agkmhHBBShpvLtmbHIEiM7+C5lBULg==" - "version": "1.6.27", - "resolved": "https://registry.npmjs.org/uplot/-/uplot-1.6.27.tgz", - "integrity": "sha512-78U4ss5YeU65kQkOC/QAKiyII+4uo+TYUJJKvuxRzeSpk/s5sjpY1TL0agkmhHBBShpvLtmbHIEiM7+C5lBULg==" + "version": "1.6.30", + "resolved": "https://registry.npmjs.org/uplot/-/uplot-1.6.30.tgz", + "integrity": "sha512-48oVVRALM/128ttW19F2a2xobc2WfGdJ0VJFX00099CfqbCTuML7L2OrTKxNzeFP34eo1+yJbqFSoFAp2u28/Q==" }, "node_modules/wonka": { "version": "6.3.4", diff --git a/web/frontend/package.json b/web/frontend/package.json index cc84e1a8..c70e57a2 100644 --- a/web/frontend/package.json +++ b/web/frontend/package.json @@ -7,25 +7,25 @@ "dev": "rollup -c -w" }, "devDependencies": { - "@rollup/plugin-commonjs": "^24.1.0", - "@rollup/plugin-node-resolve": "^15.0.2", - "@rollup/plugin-terser": "^0.4.1", - "@timohausmann/quadtree-js": "^1.2.5", - "rollup": "^3.21.0", - "rollup-plugin-css-only": "^4.3.0", - "rollup-plugin-svelte": "^7.1.4", - "svelte": "^3.58.0" + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-terser": "^0.4.4", + "@timohausmann/quadtree-js": "^1.2.6", + "rollup": "^4.12.1", + "rollup-plugin-css-only": "^4.5.2", + "rollup-plugin-svelte": "^7.1.6", + "svelte": "^4.2.12" }, "dependencies": { - "@rollup/plugin-replace": "^5.0.2", - "@urql/svelte": "^4.0.1", - "chart.js": "^4.3.3", + "@rollup/plugin-replace": "^5.0.5", + "@sveltestrap/sveltestrap": "^6.2.6", + "@urql/svelte": "^4.1.0", + "chart.js": "^4.4.2", "date-fns": "^2.30.0", - "graphql": "^16.6.0", - "mathjs": "^12.0.0", - "svelte-chartjs": "^3.1.2", - "sveltestrap": "^5.11.1", - "uplot": "^1.6.24", - "wonka": "^6.3.2" + "graphql": "^16.8.1", + "mathjs": "^12.4.0", + "svelte-chartjs": "^3.1.5", + "uplot": "^1.6.30", + "wonka": "^6.3.4" } } diff --git a/web/frontend/src/Analysis.root.svelte b/web/frontend/src/Analysis.root.svelte index 163d5115..0592f28e 100644 --- a/web/frontend/src/Analysis.root.svelte +++ b/web/frontend/src/Analysis.root.svelte @@ -1,440 +1,610 @@ - {#if $initq.fetching || $statsQuery.fetching || $footprintsQuery.fetching} - - - - {/if} - - {#if $initq.error} - {$initq.error.message} - {:else if cluster} - mc.name)} - bind:metricsInHistograms={metricsInHistograms} - bind:metricsInScatterplots={metricsInScatterplots} /> - {/if} - + {#if $initq.fetching || $statsQuery.fetching || $footprintsQuery.fetching} - { - jobFilters = detail.filters; - }} /> + + {/if} + + {#if $initq.error} + {$initq.error.message} + {:else if cluster} + mc.name)} + bind:metricsInHistograms + bind:metricsInScatterplots + /> + {/if} + + + { + jobFilters = detail.filters; + }} + /> + -
+
{#if $statsQuery.error} - - - {$statsQuery.error.message} - - + + + {$statsQuery.error.message} + + {:else if $statsQuery.data} - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Total Jobs{$statsQuery.data.stats[0].totalJobs}
Short Jobs{$statsQuery.data.stats[0].shortJobs}
Total Walltime{$statsQuery.data.stats[0].totalWalltime}
Total Node Hours{$statsQuery.data.stats[0].totalNodeHours}
Total Core Hours{$statsQuery.data.stats[0].totalCoreHours}
Total Accelerator Hours{$statsQuery.data.stats[0].totalAccHours}
- - -
-
Top - + {#each groupOptions as option} + + {/each} + +
+ {#key $topQuery.data} + {#if $topQuery.fetching} + + {:else if $topQuery.error} + {$topQuery.error.message} + {:else} + t[sortSelection.key], + )} + entities={$topQuery.data.topList.map((t) => t.id)} + /> + {/if} + {/key} +
+ + + {#key $topQuery.data} + {#if $topQuery.fetching} + + {:else if $topQuery.error} + {$topQuery.error.message} + {:else} + + + + + - {#key $topQuery.data} - {#if $topQuery.fetching} - - {:else if $topQuery.error} - {$topQuery.error.message} + + + {#each $topQuery.data.topList as te, i} + + + {#if groupSelection.key == "user"} + {:else} -
Legend{groupSelection.label} + - - {#key $topQuery.data} - {#if $topQuery.fetching} - - {:else if $topQuery.error} - {$topQuery.error.message} - {:else} - t[sortSelection.key])} - entities={$topQuery.data.topList.map((t) => t.id)} - /> - {/if} - {/key} - - -
{te.id}
- - - - - - {#each $topQuery.data.topList as te, i} - - - {#if groupSelection.key == 'user'} - - {:else} - - {/if} - - - {/each} -
Legend{groupSelection.label} - -
{te.id}{te.id}{te[sortSelection.key]}
+ {te.id} {/if} - {/key} - -
- - - {#if $rooflineQuery.fetching} - - {:else if $rooflineQuery.error} - {$rooflineQuery.error.message} - {:else if $rooflineQuery.data && cluster} -
- {#key $rooflineQuery.data} - - {/key} -
- {/if} - - -
- {#key $statsQuery.data.stats[0].histDuration} - - {/key} -
- - -
- {#key $statsQuery.data.stats[0].histNumCores} - - {/key} -
- -
+ {te[sortSelection.key]} + + {/each} + + {/if} + {/key} + + + + + {#if $rooflineQuery.fetching} + + {:else if $rooflineQuery.error} + {$rooflineQuery.error.message} + {:else if $rooflineQuery.data && cluster} +
+ {#key $rooflineQuery.data} + + {/key} +
+ {/if} + + +
+ {#key $statsQuery.data.stats[0].histDuration} + + {/key} +
+ + +
+ {#key $statsQuery.data.stats[0].histNumCores} + + {/key} +
+ +
{/if} -
+
{#if $footprintsQuery.error} - - - {$footprintsQuery.error.message} - - + + + {$footprintsQuery.error.message} + + {:else if $footprintsQuery.data && $initq.data} - - - - These histograms show the distribution of the averages of all jobs matching the filters. Each job/average is weighted by its node hours by default - (Accelerator hours for native accelerator scope metrics, coreHours for native core scope metrics). - Note that some metrics could be disabled for specific subclusters as per metricConfig and thus could affect shown average values. - -
- -
- - - ({ metric, ...binsFromFootprint( - $footprintsQuery.data.footprints.timeWeights, - metricConfig(cluster.name, metric)?.scope, - $footprintsQuery.data.footprints.metrics.find(f => f.metric == metric).data, numBins) }))} - itemsPerRow={ccconfig.plot_view_plotsPerRow}> - - - - - -
- - - - Each circle represents one job. The size of a circle is proportional to its node hours. Darker circles mean multiple jobs have the same averages for the respective metrics. - Note that some metrics could be disabled for specific subclusters as per metricConfig and thus could affect shown average values. - -
- -
- - - ({ - m1, f1: $footprintsQuery.data.footprints.metrics.find(f => f.metric == m1).data, - m2, f2: $footprintsQuery.data.footprints.metrics.find(f => f.metric == m2).data }))} - itemsPerRow={ccconfig.plot_view_plotsPerRow}> - - - - - + + + + These histograms show the distribution of the averages of all jobs + matching the filters. Each job/average is weighted by its node hours by + default (Accelerator hours for native accelerator scope metrics, + coreHours for native core scope metrics). Note that some metrics could + be disabled for specific subclusters as per metricConfig and thus could + affect shown average values. + +
+ +
+ + + ({ + metric, + ...binsFromFootprint( + $footprintsQuery.data.footprints.timeWeights, + metricConfig(cluster.name, metric)?.scope, + $footprintsQuery.data.footprints.metrics.find( + (f) => f.metric == metric, + ).data, + numBins, + ), + }))} + itemsPerRow={ccconfig.plot_view_plotsPerRow} + > + + + + +
+ + + + Each circle represents one job. The size of a circle is proportional to + its node hours. Darker circles mean multiple jobs have the same averages + for the respective metrics. Note that some metrics could be disabled for + specific subclusters as per metricConfig and thus could affect shown + average values. + +
+ +
+ + + ({ + m1, + f1: $footprintsQuery.data.footprints.metrics.find( + (f) => f.metric == m1, + ).data, + m2, + f2: $footprintsQuery.data.footprints.metrics.find( + (f) => f.metric == m2, + ).data, + }))} + itemsPerRow={ccconfig.plot_view_plotsPerRow} + > + + + + {/if} diff --git a/web/frontend/src/Config.root.svelte b/web/frontend/src/Config.root.svelte index 6df579f3..ddd714f9 100644 --- a/web/frontend/src/Config.root.svelte +++ b/web/frontend/src/Config.root.svelte @@ -1,31 +1,30 @@ {#if isAdmin == true} - + - Admin Options + Admin Options - - + + {/if} - - Plotting Options - - + + Plotting Options + + diff --git a/web/frontend/src/Header.svelte b/web/frontend/src/Header.svelte index 03c8cd0a..cc96dd06 100644 --- a/web/frontend/src/Header.svelte +++ b/web/frontend/src/Header.svelte @@ -1,178 +1,169 @@ - - ClusterCockpit Logo - - (isOpen = !isOpen)} /> - (isOpen = detail.isOpen)} - > - - - + + ClusterCockpit Logo + + (isOpen = !isOpen)} /> + (isOpen = detail.isOpen)} + > + + + diff --git a/web/frontend/src/HistogramSelection.svelte b/web/frontend/src/HistogramSelection.svelte index 9856742d..39b18727 100644 --- a/web/frontend/src/HistogramSelection.svelte +++ b/web/frontend/src/HistogramSelection.svelte @@ -1,65 +1,73 @@ - (isOpen = !isOpen)}> - - Select metrics presented in histograms - - - - {#each availableMetrics as metric (metric)} - - - {metric} - - {/each} - - - - - - + (isOpen = !isOpen)}> + Select metrics presented in histograms + + + {#each availableMetrics as metric (metric)} + + + {metric} + + {/each} + + + + + + diff --git a/web/frontend/src/Job.root.svelte b/web/frontend/src/Job.root.svelte index 42cfee83..2020e1d8 100644 --- a/web/frontend/src/Job.root.svelte +++ b/web/frontend/src/Job.root.svelte @@ -1,43 +1,50 @@ - - {#if $initq.error} - {$initq.error.message} - {:else if $initq.data} - - {:else} - - {/if} - - {#if $jobMetrics.data} - {#key $jobMetrics.data} - - - - {/key} + + {#if $initq.error} + {$initq.error.message} + {:else if $initq.data} + + {:else} + {/if} - {#if $jobMetrics.data && $initq.data} - {#if $initq.data.job.concurrentJobs != null && $initq.data.job.concurrentJobs.items.length != 0} - {#if authlevel > roles.manager} - -
- Concurrent Jobs -
-
    -
  • - See All -
  • - {#each $initq.data.job.concurrentJobs.items as pjob, index} -
  • - {pjob.jobId} -
  • - {/each} -
- - {:else} - -
- {$initq.data.job.concurrentJobs.items.length} Concurrent - Jobs -
-

- Number of shared jobs on the same node with overlapping - runtimes. -

- - {/if} - {/if} + + {#if $jobMetrics.data} + {#key $jobMetrics.data} + + + + {/key} + {/if} + {#if $jobMetrics.data && $initq.data} + {#if $initq.data.job.concurrentJobs != null && $initq.data.job.concurrentJobs.items.length != 0} + {#if authlevel > roles.manager} - + Concurrent Jobs + +
    +
  • + See All +
  • + {#each $initq.data.job.concurrentJobs.items as pjob, index} +
  • + {pjob.jobId} +
  • + {/each} +
+ {:else} - c.name == $initq.data.job.cluster) - .subClusters.find( - (sc) => sc.name == $initq.data.job.subCluster - )} - data={ - transformDataForRoofline ( - $jobMetrics.data.jobMetrics.find((m) => m.name == "flops_any" && m.scope == "node").metric, - $jobMetrics.data.jobMetrics.find((m) => m.name == "mem_bw" && m.scope == "node").metric - ) - } - /> +
+ {$initq.data.job.concurrentJobs.items.length} Concurrent Jobs +
+

+ Number of shared jobs on the same node with overlapping runtimes. +

- {:else} - - + {/if} {/if} -
- - - {#if $initq.data} - - {/if} + + - - {#if $initq.data} - - {/if} + + c.name == $initq.data.job.cluster) + .subClusters.find((sc) => sc.name == $initq.data.job.subCluster)} + data={transformDataForRoofline( + $jobMetrics.data.jobMetrics.find( + (m) => m.name == "flops_any" && m.scope == "node", + ).metric, + $jobMetrics.data.jobMetrics.find( + (m) => m.name == "mem_bw" && m.scope == "node", + ).metric, + )} + /> - - - {#if $jobMetrics.error} - {#if $initq.data.job.monitoringStatus == 0 || $initq.data.job.monitoringStatus == 2} - Not monitored or archiving failed -
- {/if} - {$jobMetrics.error.message} - {:else if $jobMetrics.fetching} - - {:else if $jobMetrics.data && $initq.data} - - {#if item.data} - - statsTable.moreLoaded(detail)} - job={$initq.data.job} - metricName={item.metric} - rawData={item.data.map((x) => x.metric)} - scopes={item.data.map((x) => x.scope)} - {width} - isShared={$initq.data.job.exclusive != 1} - resources={$initq.data.job.resources} - /> - {:else} - No dataset returned for {item.metric} - {/if} - + + {#if $jobMetrics.error} + {#if $initq.data.job.monitoringStatus == 0 || $initq.data.job.monitoringStatus == 2} + Not monitored or archiving failed +
+ {/if} + {$jobMetrics.error.message} + {:else if $jobMetrics.fetching} + + {:else if $jobMetrics.data && $initq.data} + + {#if item.data} + statsTable.moreLoaded(detail)} + job={$initq.data.job} + metricName={item.metric} + rawData={item.data.map((x) => x.metric)} + scopes={item.data.map((x) => x.scope)} + {width} + isShared={$initq.data.job.exclusive != 1} + resources={$initq.data.job.resources} + /> + {:else} + No dataset returned for {item.metric} {/if} - + + {/if} +
- - {#if $initq.data} - - {#if somethingMissing} - -
- - - Missing Metrics/Reseources - - - {#if missingMetrics.length > 0} -

- No data at all is available for the - metrics: {missingMetrics.join(", ")} -

- {/if} - {#if missingHosts.length > 0} -

- Some metrics are missing for the - following hosts: -

-
    - {#each missingHosts as missing} -
  • - {missing.hostname}: {missing.metrics.join( - ", " - )} -
  • - {/each} -
- {/if} -
-
-
-
- {/if} - - {#if $jobMetrics.data} - {#key $jobMetrics.data} - - {/key} - {/if} - - -
- {#if $initq.data.job.metaData?.jobScript} -
{$initq.data.job.metaData?.jobScript}
- {:else} - No job script available - {/if} -
-
- -
- {#if $initq.data.job.metaData?.slurmInfo} -
{$initq.data.job.metaData?.slurmInfo}
- {:else} - No additional slurm information available - {/if} -
-
-
+ + {#if $initq.data} + + {#if somethingMissing} + +
+ + + Missing Metrics/Reseources + + + {#if missingMetrics.length > 0} +

+ No data at all is available for the metrics: {missingMetrics.join( + ", ", + )} +

+ {/if} + {#if missingHosts.length > 0} +

Some metrics are missing for the following hosts:

+
    + {#each missingHosts as missing} +
  • + {missing.hostname}: {missing.metrics.join(", ")} +
  • + {/each} +
+ {/if} +
+
+
+
{/if} - + + {#if $jobMetrics.data} + {#key $jobMetrics.data} + + {/key} + {/if} + + +
+ {#if $initq.data.job.metaData?.jobScript} +
{$initq.data.job.metaData?.jobScript}
+ {:else} + No job script available + {/if} +
+
+ +
+ {#if $initq.data.job.metaData?.slurmInfo} +
{$initq.data.job.metaData?.slurmInfo}
+ {:else} + No additional slurm information available + {/if} +
+
+
+ {/if} +
{#if $initq.data} - + {/if} diff --git a/web/frontend/src/JobFootprint.svelte b/web/frontend/src/JobFootprint.svelte index 30034c0f..e3a3ff7d 100644 --- a/web/frontend/src/JobFootprint.svelte +++ b/web/frontend/src/JobFootprint.svelte @@ -1,232 +1,263 @@ - - const footprintData = footprintMetrics.map((fm) => { - // Mean: Primarily use backend sourced avgs from job.*, secondarily calculate/read from metricdata - let mv = null - if (fm === 'cpu_load' && job.loadAvg !== 0) { - mv = round(job.loadAvg, 2) - } else if (fm === 'flops_any' && job.flopsAnyAvg !== 0) { - mv = round(job.flopsAnyAvg, 2) - } else if (fm === 'mem_bw' && job.memBwAvg !== 0) { - mv = round(job.memBwAvg, 2) - } else { // Calculate from jobMetrics - const jm = jobMetrics.find((jm) => jm.name === fm && jm.scope === 'node') - if (jm?.metric?.statisticsSeries) { - mv = round(mean(jm.metric.statisticsSeries.mean), 2) - } else if (jm?.metric?.series?.length > 1) { - const avgs = jm.metric.series.map(jms => jms.statistics.avg) - mv = round(mean(avgs), 2) - } else if (jm?.metric?.series) { - mv = round(jm.metric.series[0].statistics.avg, 2) - } else { - mv = 0.0 - } - } - - // Unit - const fmc = getContext('metrics')(job.cluster, fm) - let unit = '' - if (fmc?.unit?.base) unit = fmc.unit.prefix + fmc.unit.base + - - {#if view === 'job'} + {#if view === "job"} - - Core Metrics Footprint - + + Core Metrics Footprint + + {/if} + + {#each footprintData as fpd, index} +
+
 {fpd.name}
+ +
+
+ + {#if fpd.impact === 3 || fpd.impact === -1} + + {:else if fpd.impact === 2} + + {/if} + + {#if fpd.impact === 3} + + {:else if fpd.impact === 2} + + {:else if fpd.impact === 1} + + {:else if fpd.impact === 0} + + {:else if fpd.impact === -1} + + {/if} +
+
+ + {fpd.avg} / {fpd.max} + {fpd.unit}   +
+
+ {fpd.message} +
+
+ +
+ {/each} + {#if job?.metaData?.message} +
+ {@html job.metaData.message} {/if} - - {#each footprintData as fpd, index} -
-
 {fpd.name}
-
-
- - {#if fpd.impact === 3 || fpd.impact === -1} - - {:else if fpd.impact === 2} - - {/if} - - {#if fpd.impact === 3} - - {:else if fpd.impact === 2} - - {:else if fpd.impact === 1} - - {:else if fpd.impact === 0} - - {:else if fpd.impact === -1} - - {/if} -
-
- - {fpd.avg} / {fpd.max} {fpd.unit}   -
-
- {fpd.message} -
-
- -
- {/each} - {#if job?.metaData?.message} -
- {@html job.metaData.message} - {/if} -
+
diff --git a/web/frontend/src/Jobs.root.svelte b/web/frontend/src/Jobs.root.svelte index d7cbf37e..204a4e3c 100644 --- a/web/frontend/src/Jobs.root.svelte +++ b/web/frontend/src/Jobs.root.svelte @@ -1,102 +1,121 @@ - {#if $initq.fetching} - - - - {:else if $initq.error} - - {$initq.error.message} - - {/if} - - + {#if $initq.fetching} - - - + + {:else if $initq.error} - { - selectedCluster = detail.filters[0]?.cluster ? detail.filters[0].cluster.eq : null - jobList.update(detail.filters) - } - } /> + {$initq.error.message} + {/if} + + + + + + + + + { + selectedCluster = detail.filters[0]?.cluster + ? detail.filters[0].cluster.eq + : null; + jobList.update(detail.filters); + }} + /> + - - filterComponent.update(detail)}/> - - - jobList.refresh()} /> - + + filterComponent.update(detail)} + /> + + + jobList.refresh()} /> + -
+
- - - + + + - + + bind:cluster={selectedCluster} + configName="plot_list_selectedMetrics" + bind:metrics + bind:isOpen={isMetricsSelectionOpen} + bind:showFootprint + view="list" +/> diff --git a/web/frontend/src/List.root.svelte b/web/frontend/src/List.root.svelte index c0047369..bc1ac6f0 100644 --- a/web/frontend/src/List.root.svelte +++ b/web/frontend/src/List.root.svelte @@ -2,52 +2,58 @@ @component List of users or projects --> - - - - - - - - { - jobFilters = detail.filters; - }} - /> - + + + + + + + + { + jobFilters = detail.filters; + }} + /> + - + + + + {#if type == "USER"} + + {/if} + + + + + + + + {#if $stats.fetching} + + + + {:else if $stats.error} + + + + {:else if $stats.data} + {#each sort($stats.data.rows, sorting, nameFilter) as row (row.id)} - + + {scrambleNames ? scramble(row.id) : row.id} + {:else if type == "PROJECT"} + {scrambleNames ? scramble(row.id) : row.id} + {:else} + {row.id} {/if} - - - - + + {#if type == "USER"} + + {/if} + + + + - - - {#if $stats.fetching} - - - - {:else if $stats.error} - - - - {:else if $stats.data} - {#each sort($stats.data.rows, sorting, nameFilter) as row (row.id)} - - - {#if type == "USER"} - - {/if} - - - - - - {:else} - - - - {/each} - {/if} - + {:else} + + + + {/each} + {/if} +
+ {{ + USER: "Username", + PROJECT: "Project Name", + }[type]} + + + Name + + + Total Jobs + + + Total Walltime + + + Total Core Hours + + + Total Accelerator Hours + +
{$stats.error.message}
- {({ - USER: "Username", - PROJECT: "Project Name", - })[type]} - - {#if type == "USER"} - - Name - - - Total Jobs - - - Total Walltime - - - Total Core Hours - - - Total Accelerator Hours - - {scrambleNames + ? scramble(row?.name ? row.name : "-") + : row?.name + ? row.name + : "-"}{row.totalJobs}{row.totalWalltime}{row.totalCoreHours}{row.totalAccHours}
{$stats.error.message}
- {#if type == "USER"} - {scrambleNames ? scramble(row.id) : row.id} - {:else if type == "PROJECT"} - {scrambleNames ? scramble(row.id) : row.id} - {:else} - {row.id} - {/if} - {scrambleNames ? scramble(row?.name?row.name:"-") : row?.name?row.name:"-"}{row.totalJobs}{row.totalWalltime}{row.totalCoreHours}{row.totalAccHours}
No {type.toLowerCase()}s/jobs found
No {type.toLowerCase()}s/jobs found
diff --git a/web/frontend/src/Metric.svelte b/web/frontend/src/Metric.svelte index 8ff0a58a..6022ffbe 100644 --- a/web/frontend/src/Metric.svelte +++ b/web/frontend/src/Metric.svelte @@ -1,95 +1,118 @@ + - - {metricName} ({(metricConfig?.unit?.prefix ? metricConfig.unit.prefix : '') + - (metricConfig?.unit?.base ? metricConfig.unit.base : '')}) - - - {#if job.resources.length > 1} - + + {metricName} ({(metricConfig?.unit?.prefix + ? metricConfig.unit.prefix + : "") + (metricConfig?.unit?.base ? metricConfig.unit.base : "")}) + + + {#if job.resources.length > 1} + + {/if} {#key series} - {#if fetching == true} - - {:else if error != null} - {error.message} - {:else if series != null} - - {/if} + {#if fetching == true} + + {:else if error != null} + {error.message} + {:else if series != null} + + {/if} {/key} diff --git a/web/frontend/src/MetricSelection.svelte b/web/frontend/src/MetricSelection.svelte index 5f55cb71..689abefb 100644 --- a/web/frontend/src/MetricSelection.svelte +++ b/web/frontend/src/MetricSelection.svelte @@ -8,181 +8,206 @@ --> - - - (isOpen = !isOpen)}> - - Configure columns (Metric availability shown) - - - - {#if view === 'list'} -
  • - Show Footprint -
  • -
    - {/if} - {#each newMetricsOrder as metric, index (metric)} -
  • columnsDragStart(event, index)} - on:drop|preventDefault={event => columnsDrag(event, index)} - on:dragenter={() => columnHovering = index} - class:is-active={columnHovering === index}> - {#if unorderedMetrics.includes(metric)} - - {:else} - - {/if} - {metric} - - {cluster == null ? - clusters // No single cluster specified: List Clusters with Metric - .filter(c => c.metricConfig.find(m => m.name == metric) != null) - .map(c => c.name).join(', ') : - clusters // Single cluster requested: List Subclusters with do not have metric remove flag - .filter(c => c.name == cluster) - .filter(c => c.metricConfig.find(m => m.name == metric) != null) - .map(function(c) { - let scNames = c.subClusters.map(sc => sc.name) - scNames.forEach(function(scName){ - let met = c.metricConfig.find(m => m.name == metric) - let msc = met.subClusters.find(msc => msc.name == scName) - if (msc != null) { - if (msc.remove == true) { - scNames = scNames.filter(scn => scn != msc.name) - } - } - }) - return scNames - }) - .join(', ')} - -
  • - {/each} -
    -
    - - - -
    diff --git a/web/frontend/src/NavbarLinks.svelte b/web/frontend/src/NavbarLinks.svelte index 6861da58..24ecddf5 100644 --- a/web/frontend/src/NavbarLinks.svelte +++ b/web/frontend/src/NavbarLinks.svelte @@ -1,39 +1,38 @@ {#each links as item} - {#if !item.perCluster} - {item.title} - {:else} - - - - {item.title} - - - {#each clusters as cluster} - - {cluster.name} - - {/each} - - - {/if} + {#if !item.perCluster} + {item.title} + {:else} + + + + {item.title} + + + {#each clusters as cluster} + + {cluster.name} + + {/each} + + + {/if} {/each} diff --git a/web/frontend/src/NavbarTools.svelte b/web/frontend/src/NavbarTools.svelte index f6ded904..f44b4e97 100644 --- a/web/frontend/src/NavbarTools.svelte +++ b/web/frontend/src/NavbarTools.svelte @@ -1,143 +1,153 @@ diff --git a/web/frontend/src/Node.root.svelte b/web/frontend/src/Node.root.svelte index b23c71e4..0a5a75e8 100644 --- a/web/frontend/src/Node.root.svelte +++ b/web/frontend/src/Node.root.svelte @@ -1,238 +1,230 @@ - {#if $initq.error} - {$initq.error.message} - {:else if $initq.fetching} + {#if $initq.error} + {$initq.error.message} + {:else if $initq.fetching} + + {:else} + + + + {hostname} ({cluster}) + + + + {#if $nodeJobsData.fetching} - {:else} - - - - {hostname} ({cluster}) - - - - {#if $nodeJobsData.fetching} - - {:else if $nodeJobsData.data} - Currently running jobs on this node: {$nodeJobsData.data.jobs - .count} - [ - View in Job List ] - {:else} - No currently running jobs. - {/if} - - - { - const diff = Date.now() - to - from = new Date(from.getTime() + diff) - to = new Date(to.getTime() + diff) - }} /> - - - - - {/if} + {:else if $nodeJobsData.data} + Currently running jobs on this node: {$nodeJobsData.data.jobs.count} + [ + View in Job List ] + {:else} + No currently running jobs. + {/if} + + + { + const diff = Date.now() - to; + from = new Date(from.getTime() + diff); + to = new Date(to.getTime() + diff); + }} + /> + + + + + {/if}
    - - {#if $nodeMetricsData.error} - {$nodeMetricsData.error.message} - {:else if $nodeMetricsData.fetching || $initq.fetching} - + + {#if $nodeMetricsData.error} + {$nodeMetricsData.error.message} + {:else if $nodeMetricsData.fetching || $initq.fetching} + + {:else} + ({ + ...m, + disabled: checkMetricDisabled( + m.name, + cluster, + $nodeMetricsData.data.nodeMetrics[0].subCluster, + ), + })) + .sort((a, b) => a.name.localeCompare(b.name))} + > +

    + {item.name} + {metricUnits[item.name]} +

    + {#if item.disabled === false && item.metric} + c.name == cluster)} + subCluster={$nodeMetricsData.data.nodeMetrics[0].subCluster} + series={item.metric.series} + resources={[{ hostname: hostname }]} + forNode={true} + /> + {:else if item.disabled === true && item.metric} + Metric disabled for subcluster {item.name}:{$nodeMetricsData.data.nodeMetrics[0] + .subCluster} {:else} - ({ - ...m, - disabled: checkMetricDisabled( - m.name, - cluster, - $nodeMetricsData.data.nodeMetrics[0].subCluster - ), - })) - .sort((a, b) => a.name.localeCompare(b.name))} - > -

    - {item.name} - {metricUnits[item.name]} -

    - {#if item.disabled === false && item.metric} - c.name == cluster)} - subCluster={$nodeMetricsData.data.nodeMetrics[0] - .subCluster} - series={item.metric.series} - resources={[{hostname: hostname}]} - forNode={true} - /> - {:else if item.disabled === true && item.metric} - Metric disabled for subcluster {item.name}:{$nodeMetricsData.data.nodeMetrics[0] - .subCluster} - {:else} - No dataset returned for {item.name} - {/if} -
    + No dataset returned for {item.name} {/if} - +
    + {/if} +
    diff --git a/web/frontend/src/PlotSelection.svelte b/web/frontend/src/PlotSelection.svelte index 449de64f..b4cf58b5 100644 --- a/web/frontend/src/PlotSelection.svelte +++ b/web/frontend/src/PlotSelection.svelte @@ -1,139 +1,163 @@ - - - (isHistogramConfigOpen = !isHistogramConfigOpen)}> - - Select metrics presented in histograms - - - - {#each availableMetrics as metric (metric)} - - updateConfiguration({ - name: 'analysis_view_histogramMetrics', - value: metricsInHistograms - })} /> + (isHistogramConfigOpen = !isHistogramConfigOpen)} +> + Select metrics presented in histograms + + + {#each availableMetrics as metric (metric)} + + + updateConfiguration({ + name: "analysis_view_histogramMetrics", + value: metricsInHistograms, + })} + /> - {metric} - - {/each} - - - - - + {metric} + + {/each} + + + + + - (isScatterPlotConfigOpen = !isScatterPlotConfigOpen)}> - - Select metric pairs presented in scatter plots - - - - {#each metricsInScatterplots as pair} - - {pair[0]} / {pair[1]} + (isScatterPlotConfigOpen = !isScatterPlotConfigOpen)} +> + Select metric pairs presented in scatter plots + + + {#each metricsInScatterplots as pair} + + {pair[0]} / {pair[1]} - - - {/each} - + + + {/each} + -
    +
    - - - - - - -
    - - - + + + + + + + + +
    diff --git a/web/frontend/src/StatsTable.svelte b/web/frontend/src/StatsTable.svelte index e1d0c022..3a9d84df 100644 --- a/web/frontend/src/StatsTable.svelte +++ b/web/frontend/src/StatsTable.svelte @@ -1,139 +1,154 @@ - - - - {#each selectedMetrics as metric} - - {/each} - - - - {#each selectedMetrics as metric} - {#if selectedScopes[metric] != 'node'} - - {/if} - {#each ['min', 'avg', 'max'] as stat} - - {/each} - {/each} - - - - {#each hosts as host (host)} - - - {#each selectedMetrics as metric (metric)} - - {/each} - + + + + {#each selectedMetrics as metric} + + {/each} + + + + {#each selectedMetrics as metric} + {#if selectedScopes[metric] != "node"} + + {/if} + {#each ["min", "avg", "max"] as stat} + + {/each} + {/each} + + + + {#each hosts as host (host)} + + + {#each selectedMetrics as metric (metric)} + {/each} - + + {/each} +
    - - - - - {metric} - - - -
    NodeId sortBy(metric, stat)}> - {stat} - {#if selectedScopes[metric] == 'node'} - - {/if} -
    {host}
    + + + + + {metric} + + + +
    NodeId sortBy(metric, stat)}> + {stat} + {#if selectedScopes[metric] == "node"} + + {/if} +
    {host}
    -
    +
    + cluster={job.cluster} + configName="job_view_nodestats_selectedMetrics" + allMetrics={new Set(allMetrics)} + bind:metrics={selectedMetrics} + bind:isOpen={isMetricSelectionOpen} +/> diff --git a/web/frontend/src/StatsTableEntry.svelte b/web/frontend/src/StatsTableEntry.svelte index 5e497d4f..99cde216 100644 --- a/web/frontend/src/StatsTableEntry.svelte +++ b/web/frontend/src/StatsTableEntry.svelte @@ -1,82 +1,86 @@ {#if series == null || series.length == 0} - No data -{:else if series.length == 1 && scope == 'node'} - - {series[0].statistics.min} - - - {series[0].statistics.avg} - - - {series[0].statistics.max} - + No data +{:else if series.length == 1 && scope == "node"} + + {series[0].statistics.min} + + + {series[0].statistics.avg} + + + {series[0].statistics.max} + {:else} - - - - {#each ['id', 'min', 'avg', 'max'] as field} - - {/each} - - {#each series as s, i} - - - - - - - {/each} -
    sortByField(field)}> - Sort - -
    {s.id ?? i}{s.statistics.min}{s.statistics.avg}{s.statistics.max}
    - + + + + {#each ["id", "min", "avg", "max"] as field} + + {/each} + + {#each series as s, i} + + + + + + + {/each} +
    sortByField(field)}> + Sort + +
    {s.id ?? i}{s.statistics.min}{s.statistics.avg}{s.statistics.max}
    + {/if} diff --git a/web/frontend/src/Status.root.svelte b/web/frontend/src/Status.root.svelte index d0d7ba10..b5ccec00 100644 --- a/web/frontend/src/Status.root.svelte +++ b/web/frontend/src/Status.root.svelte @@ -1,366 +1,358 @@ - -

    Current utilization of cluster "{cluster}"

    - - - {#if $initq.fetching || $mainQuery.fetching} - - {:else if $initq.error} - {$initq.error.message} - {:else} - - {/if} - - - - - - { - from = new Date(Date.now() - 5 * 60 * 1000); - to = new Date(Date.now()); - }} - /> - + +

    Current utilization of cluster "{cluster}"

    + + + {#if $initq.fetching || $mainQuery.fetching} + + {:else if $initq.error} + {$initq.error.message} + {:else} + + {/if} + + + + + + { + from = new Date(Date.now() - 5 * 60 * 1000); + to = new Date(Date.now()); + }} + /> +
    {#if $mainQuery.error} - - - {$mainQuery.error.message} - - + + + {$mainQuery.error.message} + + {/if}
    @@ -368,358 +360,318 @@ {#if $initq.data && $mainQuery.data} - {#each $initq.data.clusters.find((c) => c.name == cluster).subClusters as subCluster, i} - - - - - SubCluster "{subCluster.name}" - - - - - - - - - - - - - - - - - - -
    Allocated Nodes
    - -
    {allocatedNodes[subCluster.name]} / {subCluster.numberOfNodes} - Nodes
    Flop Rate (Any)
    - -
    - {scaleNumbers( - flopRate[subCluster.name], - subCluster.flopRateSimd.value * - subCluster.numberOfNodes, - flopRateUnitPrefix[subCluster.name] - )}{flopRateUnitBase[subCluster.name]} [Max] -
    MemBw Rate
    - -
    - {scaleNumbers( - memBwRate[subCluster.name], - subCluster.memoryBandwidth.value * - subCluster.numberOfNodes, - memBwRateUnitPrefix[subCluster.name] - )}{memBwRateUnitBase[subCluster.name]} [Max] -
    -
    -
    - - -
    - {#key $mainQuery.data.nodeMetrics} - data.subCluster == subCluster.name - ) - ) - } - /> - {/key} -
    - -
    - {/each} - -
    - - - - - -
    -

    - Top Users on {cluster.charAt(0).toUpperCase() + - cluster.slice(1)} -

    - {#key $topUserQuery.data} - {#if $topUserQuery.fetching} - - {:else if $topUserQuery.error} - {$topUserQuery.error.message} - {:else} - tu[topUserSelection.key] - )} - entities={$topUserQuery.data.topUser.map( - (tu) => tu.id - )} - /> - {/if} - {/key} -
    - - - {#key $topUserQuery.data} - {#if $topUserQuery.fetching} - - {:else if $topUserQuery.error} - {$topUserQuery.error.message} - {:else} - - - - - - - {#each $topUserQuery.data.topUser as tu, i} - - - - - - {/each} -
    LegendUser NameNumber of - -
    {tu.id}{tu[topUserSelection.key]}
    - {/if} - {/key} - - -

    - Top Projects on {cluster.charAt(0).toUpperCase() + - cluster.slice(1)} -

    - {#key $topProjectQuery.data} - {#if $topProjectQuery.fetching} - - {:else if $topProjectQuery.error} - {$topProjectQuery.error.message} - {:else} - tp[topProjectSelection.key] - )} - entities={$topProjectQuery.data.topProjects.map( - (tp) => tp.id - )} + {#each $initq.data.clusters.find((c) => c.name == cluster).subClusters as subCluster, i} + + + + + SubCluster "{subCluster.name}" + + + + + + - {#key $topProjectQuery.data} - {#if $topProjectQuery.fetching} - - {:else if $topProjectQuery.error} - {$topProjectQuery.error.message} - {:else} -
    Allocated Nodes
    + - {/if} - {/key} - -
    - - - - - - {#each $topProjectQuery.data.topProjects as tp, i} - - - - - - {/each} -
    LegendProject CodeNumber of - -
    {tp.id}{tp[topProjectSelection.key]}
    - {/if} - {/key} - -
    -
    - - -
    - {#key $mainQuery.data.stats} - + {allocatedNodes[subCluster.name]} / {subCluster.numberOfNodes} + Nodes + + + Flop Rate (Any) +
    + - {/key} -
    - - - {#key $mainQuery.data.stats} - - {/key} - - - - -
    - {#key $mainQuery.data.stats} - + + {scaleNumbers( + flopRate[subCluster.name], + subCluster.flopRateSimd.value * subCluster.numberOfNodes, + flopRateUnitPrefix[subCluster.name], + )}{flopRateUnitBase[subCluster.name]} [Max] + + + + MemBw Rate +
    + - {/key} -
    - - - {#key $mainQuery.data.stats} - - {/key} - +
    + + {scaleNumbers( + memBwRate[subCluster.name], + subCluster.memoryBandwidth.value * subCluster.numberOfNodes, + memBwRateUnitPrefix[subCluster.name], + )}{memBwRateUnitBase[subCluster.name]} [Max] + + + + + + + +
    + {#key $mainQuery.data.nodeMetrics} + data.subCluster == subCluster.name, + ), + )} + /> + {/key} +
    +
    -
    - {#if metricsInHistograms} - - - {#key $mainQuery.data.stats[0].histMetrics} - + {/each} - - - {/key} - - - {/if} +
    + + + + + +
    +

    + Top Users on {cluster.charAt(0).toUpperCase() + cluster.slice(1)} +

    + {#key $topUserQuery.data} + {#if $topUserQuery.fetching} + + {:else if $topUserQuery.error} + {$topUserQuery.error.message} + {:else} + tu[topUserSelection.key], + )} + entities={$topUserQuery.data.topUser.map((tu) => tu.id)} + /> + {/if} + {/key} +
    + + + {#key $topUserQuery.data} + {#if $topUserQuery.fetching} + + {:else if $topUserQuery.error} + {$topUserQuery.error.message} + {:else} + + + + + + + {#each $topUserQuery.data.topUser as tu, i} + + + + + + {/each} +
    LegendUser NameNumber of + +
    {tu.id}{tu[topUserSelection.key]}
    + {/if} + {/key} + + +

    + Top Projects on {cluster.charAt(0).toUpperCase() + cluster.slice(1)} +

    + {#key $topProjectQuery.data} + {#if $topProjectQuery.fetching} + + {:else if $topProjectQuery.error} + {$topProjectQuery.error.message} + {:else} + tp[topProjectSelection.key], + )} + entities={$topProjectQuery.data.topProjects.map((tp) => tp.id)} + /> + {/if} + {/key} + + + {#key $topProjectQuery.data} + {#if $topProjectQuery.fetching} + + {:else if $topProjectQuery.error} + {$topProjectQuery.error.message} + {:else} + + + + + + + {#each $topProjectQuery.data.topProjects as tp, i} + + + + + + {/each} +
    LegendProject CodeNumber of + +
    {tp.id}{tp[topProjectSelection.key]}
    + {/if} + {/key} + +
    +
    + + +
    + {#key $mainQuery.data.stats} + + {/key} +
    + + + {#key $mainQuery.data.stats} + + {/key} + +
    + + +
    + {#key $mainQuery.data.stats} + + {/key} +
    + + + {#key $mainQuery.data.stats} + + {/key} + +
    +
    + {#if metricsInHistograms} + + + {#key $mainQuery.data.stats[0].histMetrics} + + + + {/key} + + + {/if} {/if} + bind:cluster + bind:metricsInHistograms + bind:isOpen={isHistogramSelectionOpen} +/> diff --git a/web/frontend/src/Systems.root.svelte b/web/frontend/src/Systems.root.svelte index d8812365..4a7f633a 100644 --- a/web/frontend/src/Systems.root.svelte +++ b/web/frontend/src/Systems.root.svelte @@ -1,159 +1,218 @@ - {#if $initq.error} - {$initq.error.message} - {:else if $initq.fetching} - - {:else} - - { - const diff = Date.now() - to - from = new Date(from.getTime() + diff) - to = new Date(to.getTime() + diff) - }} /> - - - - - - - - Metric - - - - - - - Find Node - - - - {/if} + {#if $initq.error} + {$initq.error.message} + {:else if $initq.fetching} + + {:else} + + { + const diff = Date.now() - to; + from = new Date(from.getTime() + diff); + to = new Date(to.getTime() + diff); + }} + /> + + + + + + + + Metric + + + + + + + Find Node + + + + {/if} -
    +
    - - {#if $nodesQuery.error} - {$nodesQuery.error.message} - {:else if $nodesQuery.fetching || $initq.fetching} - + + {#if $nodesQuery.error} + {$nodesQuery.error.message} + {:else if $nodesQuery.fetching || $initq.fetching} + + {:else} + + h.host.includes(hostnameFilter) && + h.metrics.some( + (m) => m.name == selectedMetric && m.scope == "node", + ), + ) + .map((h) => ({ + host: h.host, + subCluster: h.subCluster, + data: h.metrics.find( + (m) => m.name == selectedMetric && m.scope == "node", + ), + disabled: checkMetricDisabled( + selectedMetric, + cluster, + h.subCluster, + ), + })) + .sort((a, b) => a.host.localeCompare(b.host))} + > +

    + {item.host} ({item.subCluster}) +

    + {#if item.disabled === false && item.data} + c.name == cluster)} + subCluster={item.subCluster} + resources={[{ hostname: item.host }]} + forNode={true} + /> + {:else if item.disabled === true && item.data} + Metric disabled for subcluster {selectedMetric}:{item.subCluster} {:else} - h.host.includes(hostnameFilter) && h.metrics.some(m => m.name == selectedMetric && m.scope == 'node')) - .map(h => ({ - host: h.host, - subCluster: h.subCluster, - data: h.metrics.find(m => m.name == selectedMetric && m.scope == 'node'), - disabled: checkMetricDisabled(selectedMetric, cluster, h.subCluster) - })) - .sort((a, b) => a.host.localeCompare(b.host)) - }> - -

    {item.host} ({item.subCluster})

    - {#if item.disabled === false && item.data} - c.name == cluster)} - subCluster={item.subCluster} - resources={[{hostname: item.host}]} - forNode={true}/> - {:else if item.disabled === true && item.data} - Metric disabled for subcluster {selectedMetric}:{item.subCluster} - {:else} - No dataset returned for {selectedMetric} - {/if} -
    + No dataset returned for {selectedMetric} {/if} - +
    + {/if} +
    - diff --git a/web/frontend/src/TagManagement.svelte b/web/frontend/src/TagManagement.svelte index 6ab47529..e9fb9e9f 100644 --- a/web/frontend/src/TagManagement.svelte +++ b/web/frontend/src/TagManagement.svelte @@ -1,190 +1,234 @@ - - (isOpen = !isOpen)}> - - Manage Tags - {#if pendingChange !== false} - - {:else} - - {/if} - - - - -
    - - - Search using "type: name". If no tag matches your search, - a button for creating a new one will appear. - - -
      - {#each allTagsFiltered as tag} - - - - - {#if pendingChange === tag.id} - - {:else if job.tags.find(t => t.id == tag.id)} - - {:else} - - {/if} - - + + Manage Tags + {#if pendingChange !== false} + + {:else} + + {/if} + + + + +
      + + + Search using "type: name". If no tag matches your search, a + button for creating a new one will appear. + + +
        + {#each allTagsFiltered as tag} + + + + + {#if pendingChange === tag.id} + + {:else if job.tags.find((t) => t.id == tag.id)} + {:else} - - No tags matching - - {/each} -
      -
      - {#if newTagType && newTagName && isNewTag(newTagType, newTagName)} - - {:else if allTagsFiltered.length == 0} - Search Term is not a valid Tag (type: name) - {/if} -
      - - - + + {/if} + + + {:else} + + No tags matching + + {/each} +
    +
    + {#if newTagType && newTagName && isNewTag(newTagType, newTagName)} + + {:else if allTagsFiltered.length == 0} + Search Term is not a valid Tag (type: name) + {/if} +
    + + +
    + + diff --git a/web/frontend/src/User.root.svelte b/web/frontend/src/User.root.svelte index f3688512..c60ea20b 100644 --- a/web/frontend/src/User.root.svelte +++ b/web/frontend/src/User.root.svelte @@ -1,237 +1,276 @@ - {#if $initq.fetching} - - - - {:else if $initq.error} - - {$initq.error.message} - - {/if} - + {#if $initq.fetching} + + + + {:else if $initq.error} - + {$initq.error.message} + + {/if} - + + - + + + + + + { + jobFilters = [...detail.filters, { user: { eq: user.username } }]; + selectedCluster = jobFilters[0]?.cluster + ? jobFilters[0].cluster.eq + : null; + jobList.update(jobFilters); + }} + /> + + + jobList.refresh()} /> + + +
    + + {#if $stats.error} + + {$stats.error.message} - - { - jobFilters = [...detail.filters, { user: { eq: user.username } }] - selectedCluster = jobFilters[0]?.cluster ? jobFilters[0].cluster.eq : null - jobList.update(jobFilters) - }} /> + {:else if !$stats.data} + + - - jobList.refresh()} /> + {:else} + + + + + + + + {#if user.name} + + + + + {/if} + {#if user.email} + + + + + {/if} + + + + + + + + + + + + + + + + + +
    Username{scrambleNames ? scramble(user.username) : user.username}
    Name{scrambleNames ? scramble(user.name) : user.name}
    Email{user.email}
    Total Jobs{$stats.data.jobsStatistics[0].totalJobs}
    Short Jobs{$stats.data.jobsStatistics[0].shortJobs}
    Total Walltime{$stats.data.jobsStatistics[0].totalWalltime}
    Total Core Hours{$stats.data.jobsStatistics[0].totalCoreHours}
    +
    + {#key $stats.data.jobsStatistics[0].histDuration} + + {/key} +
    +
    + {#key $stats.data.jobsStatistics[0].histNumNodes} + + {/key} +
    + {/if}
    -
    - +{#if metricsInHistograms} + {#if $stats.error} - - {$stats.error.message} - + + {$stats.error.message} + {:else if !$stats.data} - - - + + + {:else} - - - - - - - - {#if user.name} - - - - - {/if} - {#if user.email} - - - - - {/if} - - - - - - - - - - - - - - - - - -
    Username{scrambleNames ? scramble(user.username) : user.username}
    Name{scrambleNames ? scramble(user.name) : user.name}
    Email{user.email}
    Total Jobs{$stats.data.jobsStatistics[0].totalJobs}
    Short Jobs{$stats.data.jobsStatistics[0].shortJobs}
    Total Walltime{$stats.data.jobsStatistics[0].totalWalltime}
    Total Core Hours{$stats.data.jobsStatistics[0].totalCoreHours}
    - -
    - {#key $stats.data.jobsStatistics[0].histDuration} - - {/key} -
    -
    - {#key $stats.data.jobsStatistics[0].histNumNodes} - - {/key} -
    + + {#key $stats.data.jobsStatistics[0].histMetrics} + + + + {/key} + {/if} -
    -{#if metricsInHistograms} - - {#if $stats.error} - - {$stats.error.message} - - {:else if !$stats.data} - - - - {:else} - - {#key $stats.data.jobsStatistics[0].histMetrics} - - - - - {/key} - - {/if} - +
    {/if} -
    +
    - - - + + + - + + + - - + bind:cluster={selectedCluster} + bind:metricsInHistograms + bind:isOpen={isHistogramSelectionOpen} +/> diff --git a/web/frontend/src/Zoom.svelte b/web/frontend/src/Zoom.svelte index ae842fcf..c5f73c1b 100644 --- a/web/frontend/src/Zoom.svelte +++ b/web/frontend/src/Zoom.svelte @@ -1,60 +1,65 @@
    - - - - - - Window Size: - - - ({windowSize}%) - - - - Window Position: - - - + + + + + + Window Size: + + + ({windowSize}%) + + + + Window Position: + + +
    diff --git a/web/frontend/src/config/AdminSettings.svelte b/web/frontend/src/config/AdminSettings.svelte index 97c5b17f..26e1d0f2 100644 --- a/web/frontend/src/config/AdminSettings.svelte +++ b/web/frontend/src/config/AdminSettings.svelte @@ -1,54 +1,53 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/web/frontend/src/config/PlotSettings.svelte b/web/frontend/src/config/PlotSettings.svelte index 36326bda..20a7f2e9 100644 --- a/web/frontend/src/config/PlotSettings.svelte +++ b/web/frontend/src/config/PlotSettings.svelte @@ -1,171 +1,498 @@ - - - -
    handleSettingSubmit('#line-width-form', 'lw')}> - - -
    Line Width
    - - {#if displayMessage && message.target == 'lw'} -
    - - Update: {message.msg} - -
    - {/if} -
    - -
    - - -
    Width of the lines in the timeseries plots.
    + + + + + handleSettingSubmit("#line-width-form", "lw")} + > + + +
    Line Width
    + + {#if displayMessage && message.target == "lw"} +
    + + Update: {message.msg} +
    - - -
    + {/if} + + +
    + + +
    + Width of the lines in the timeseries plots. +
    +
    + + + - - -
    handleSettingSubmit('#plots-per-row-form', 'ppr')}> - - -
    Plots per Row
    - {#if displayMessage && message.target == 'ppr'}
    Update: {message.msg}
    {/if} -
    - -
    - - -
    How many plots to show next to each other on pages such as /monitoring/job/, /monitoring/system/...
    -
    - -
    -
    + + +
    + handleSettingSubmit("#plots-per-row-form", "ppr")} + > + + +
    Plots per Row
    + {#if displayMessage && message.target == "ppr"}
    + Update: {message.msg} +
    {/if} +
    + +
    + + +
    + How many plots to show next to each other on pages such as + /monitoring/job/, /monitoring/system/... +
    +
    + +
    +
    - - -
    handleSettingSubmit('#backgrounds-form', 'bg')}> - - -
    Colored Backgrounds
    - {#if displayMessage && message.target == 'bg'}
    Update: {message.msg}
    {/if} -
    - -
    -
    - {#if config.plot_general_colorBackground} - - {:else} - - {/if} - -
    -
    - {#if config.plot_general_colorBackground} - - {:else} - - {/if} - -
    -
    - -
    -
    + + +
    + handleSettingSubmit("#backgrounds-form", "bg")} + > + + +
    Colored Backgrounds
    + {#if displayMessage && message.target == "bg"}
    + Update: {message.msg} +
    {/if} +
    + +
    +
    + {#if config.plot_general_colorBackground} + + {:else} + + {/if} + +
    +
    + {#if config.plot_general_colorBackground} + + {:else} + + {/if} + +
    +
    + +
    +
    - - -
    - - -
    Color Scheme for Timeseries Plots
    - {#if displayMessage && message.target == 'cs'}
    Update: {message.msg}
    {/if} -
    - - - - {#each Object.entries(colorschemes) as [name, rgbrow]} - - - - - - {/each} - -
    {name} - {#if rgbrow.join(',') == config.plot_general_colorscheme} - handleSettingSubmit("#colorscheme-form", "cs")}/> - {:else} - handleSettingSubmit("#colorscheme-form", "cs")}/> - {/if} - - {#each rgbrow as rgb} - - {/each} -
    -
    -
    + + +
    + + +
    Color Scheme for Timeseries Plots
    + {#if displayMessage && message.target == "cs"}
    + Update: {message.msg} +
    {/if} +
    + + + + {#each Object.entries(colorschemes) as [name, rgbrow]} + + + + + + {/each} + +
    {name} + {#if rgbrow.join(",") == config.plot_general_colorscheme} + + handleSettingSubmit("#colorscheme-form", "cs")} + /> + {:else} + + handleSettingSubmit("#colorscheme-form", "cs")} + /> + {/if} + + {#each rgbrow as rgb} + + {/each} +
    +
    +
    diff --git a/web/frontend/src/config/admin/AddUser.svelte b/web/frontend/src/config/admin/AddUser.svelte index 2712e175..43f08de1 100644 --- a/web/frontend/src/config/admin/AddUser.svelte +++ b/web/frontend/src/config/admin/AddUser.svelte @@ -1,103 +1,156 @@ -
    - Create User -
    - - -
    Must be unique.
    -
    -
    - - -
    Only API users are allowed to have a blank password. Users with a blank password can only authenticate via Tokens.
    -
    -
    - - -
    Only Manager users can have a project. Allows to inspect jobs and users of given project.
    -
    -
    - - -
    Optional, can be blank.
    -
    -
    - - -
    Optional, can be blank.
    -
    - + + Create User +
    + + +
    Must be unique.
    +
    +
    + + +
    + Only API users are allowed to have a blank password. Users with a blank + password can only authenticate via Tokens. +
    +
    +
    + + +
    + Only Manager users can have a project. Allows to inspect jobs and users + of given project. +
    +
    +
    + + +
    Optional, can be blank.
    +
    +
    + + +
    Optional, can be blank.
    +
    -
    -

    Role:

    - {#each roles as role, i} - {#if i == 0} -
    - - -
    - {:else if i == 1} -
    - - -
    - {:else} -
    - - -
    - {/if} - {/each} -
    -

    - - {#if displayMessage}

    {message.msg}
    {/if} -

    -
    +
    +

    Role:

    + {#each roles as role, i} + {#if i == 0} +
    + + +
    + {:else if i == 1} +
    + + +
    + {:else} +
    + + +
    + {/if} + {/each} +
    +

    + + {#if displayMessage}

    + {message.msg} +
    {/if} +

    +
    diff --git a/web/frontend/src/config/admin/EditProject.svelte b/web/frontend/src/config/admin/EditProject.svelte index 857f7dbd..a4a8d75a 100644 --- a/web/frontend/src/config/admin/EditProject.svelte +++ b/web/frontend/src/config/admin/EditProject.svelte @@ -1,97 +1,129 @@ - - Edit Project Managed By User (Manager Only) -
    - - - - - - -
    -

    - {#if displayMessage}Update: {message.msg}{/if} -

    -
    + + Edit Project Managed By User (Manager Only) +
    + + + + + + +
    +

    + {#if displayMessage}Update: {message.msg}{/if} +

    +
    diff --git a/web/frontend/src/config/admin/EditRole.svelte b/web/frontend/src/config/admin/EditRole.svelte index ca146992..f201f384 100644 --- a/web/frontend/src/config/admin/EditRole.svelte +++ b/web/frontend/src/config/admin/EditRole.svelte @@ -1,104 +1,131 @@ - - Edit User Roles -
    - - - - - - -
    -

    - {#if displayMessage}Update: {message.msg}{/if} -

    -
    + + Edit User Roles +
    + + + + + + +
    +

    + {#if displayMessage}Update: {message.msg}{/if} +

    +
    diff --git a/web/frontend/src/config/admin/Options.svelte b/web/frontend/src/config/admin/Options.svelte index 44f9650e..8ad3c44b 100644 --- a/web/frontend/src/config/admin/Options.svelte +++ b/web/frontend/src/config/admin/Options.svelte @@ -1,29 +1,34 @@ - - Scramble Names / Presentation Mode - - Active? - + + Scramble Names / Presentation Mode + + Active? + diff --git a/web/frontend/src/config/admin/ShowUsers.svelte b/web/frontend/src/config/admin/ShowUsers.svelte index 439bebb8..be9b146f 100644 --- a/web/frontend/src/config/admin/ShowUsers.svelte +++ b/web/frontend/src/config/admin/ShowUsers.svelte @@ -1,68 +1,87 @@ - - Special Users -

    - Not created by an LDAP sync and/or having a role other than user - -

    -
    - - - - - - - - - - - - - - {#each userList as user} - - - - - {:else} - - - - {/each} - -
    UsernameNameProject(s)EmailRolesJWTDelete
    -
    Loading...
    -
    -
    -
    + + Special Users +

    + Not created by an LDAP sync and/or having a role other than user + +

    +
    + + + + + + + + + + + + + + {#each userList as user} + + + + + {:else} + + + + {/each} + +
    UsernameNameProject(s)EmailRolesJWTDelete
    +
    + Loading... +
    +
    +
    +
    diff --git a/web/frontend/src/config/admin/ShowUsersRow.svelte b/web/frontend/src/config/admin/ShowUsersRow.svelte index 34b22404..9845241e 100644 --- a/web/frontend/src/config/admin/ShowUsersRow.svelte +++ b/web/frontend/src/config/admin/ShowUsersRow.svelte @@ -1,28 +1,32 @@ {user.username} {user.name} {user.projects} {user.email} -{user.roles.join(', ')} +{user.roles.join(", ")} - {#if ! jwt} - - {:else} - - {/if} + {#if !jwt} + + {:else} + + {/if} diff --git a/web/frontend/src/filters/Cluster.svelte b/web/frontend/src/filters/Cluster.svelte index 2740b74a..9c823210 100644 --- a/web/frontend/src/filters/Cluster.svelte +++ b/web/frontend/src/filters/Cluster.svelte @@ -1,77 +1,95 @@ - (isOpen = !isOpen)}> - - Select Cluster & Slurm Partition - - - {#if $initialized} -

    Cluster

    - - (pendingCluster = null, pendingPartition = null)}> - Any Cluster - - {#each clusters as cluster} - (pendingCluster = cluster.name, pendingPartition = null)}> - {cluster.name} - - {/each} - - {/if} - {#if $initialized && pendingCluster != null} -
    -

    Partiton

    - - (pendingPartition = null)}> - Any Partition - - {#each clusters.find(c => c.name == pendingCluster).partitions as partition} - (pendingPartition = partition)}> - {partition} - - {/each} - - {/if} -
    - - - - - + (isOpen = !isOpen)}> + Select Cluster & Slurm Partition + + {#if $initialized} +

    Cluster

    + + ((pendingCluster = null), (pendingPartition = null))} + > + Any Cluster + + {#each clusters as cluster} + ( + (pendingCluster = cluster.name), (pendingPartition = null) + )} + > + {cluster.name} + + {/each} + + {/if} + {#if $initialized && pendingCluster != null} +
    +

    Partiton

    + + (pendingPartition = null)} + > + Any Partition + + {#each clusters.find((c) => c.name == pendingCluster).partitions as partition} + (pendingPartition = partition)} + > + {partition} + + {/each} + + {/if} +
    + + + + +
    diff --git a/web/frontend/src/filters/Duration.svelte b/web/frontend/src/filters/Duration.svelte index ca2ce453..132ce05e 100644 --- a/web/frontend/src/filters/Duration.svelte +++ b/web/frontend/src/filters/Duration.svelte @@ -1,158 +1,244 @@ - (isOpen = !isOpen)}> - - Select Job Duration - - -

    Duration more than

    - - -
    - -
    -
    h
    -
    -
    - - -
    - -
    -
    m
    -
    -
    - -
    -
    + (isOpen = !isOpen)}> + Select Job Duration + +

    Duration more than

    + + +
    + +
    +
    h
    +
    +
    + + +
    + +
    +
    m
    +
    +
    + +
    +
    -

    Duration less than

    - - -
    - -
    -
    h
    -
    -
    - - -
    - -
    -
    m
    -
    -
    - -
    -
    +

    Duration less than

    + + +
    + +
    +
    h
    +
    +
    + + +
    + +
    +
    m
    +
    +
    + +
    +
    -

    Duration between

    - - -
    - -
    -
    h
    -
    -
    - - -
    - -
    -
    m
    -
    -
    - -
    -

    and

    - - -
    - -
    -
    h
    -
    -
    - - -
    - -
    -
    m
    -
    -
    - -
    -
    - - - - - - +

    Duration between

    + + +
    + +
    +
    h
    +
    +
    + + +
    + +
    +
    m
    +
    +
    + +
    +

    and

    + + +
    + +
    +
    h
    +
    +
    + + +
    + +
    +
    m
    +
    +
    + +
    +
    + + + + + +
    diff --git a/web/frontend/src/filters/Filters.svelte b/web/frontend/src/filters/Filters.svelte index 49eaed61..8e7a8ef6 100644 --- a/web/frontend/src/filters/Filters.svelte +++ b/web/frontend/src/filters/Filters.svelte @@ -10,373 +10,418 @@ - void update(additionalFilters: Object?): Triggers an update --> - - - - - Filters - - - - Manage Filters - - {#if menuText} - {menuText} - - {/if} - (isClusterOpen = true)}> - Cluster/Partition - - (isJobStatesOpen = true)}> - Job States - - (isStartTimeOpen = true)}> - Start Time - - (isDurationOpen = true)}> - Duration - - (isTagsOpen = true)}> - Tags - - (isResourcesOpen = true)}> - Resources - - (isStatsOpen = true)}> - (isStatsOpen = true)}/> Statistics - - {#if startTimeQuickSelect} - - Start Time Qick Selection - {#each [ - { text: 'Last 6hrs', url: 'last6h', seconds: 6*60*60 }, - // { text: 'Last 12hrs', seconds: 12*60*60 }, - { text: 'Last 24hrs', url: 'last24h', seconds: 24*60*60 }, - // { text: 'Last 48hrs', seconds: 48*60*60 }, - { text: 'Last 7 days', url: 'last7d', seconds: 7*24*60*60 }, - { text: 'Last 30 days', url: 'last30d', seconds: 30*24*60*60 } - ] as {text, url, seconds}} - { - filters.startTime.from = (new Date(Date.now() - seconds * 1000)).toISOString() - filters.startTime.to = (new Date(Date.now())).toISOString() - filters.startTime.text = text, - filters.startTime.url = url - update() - }}> - {text} - - {/each} - {/if} - - - - - {#if filters.cluster} - (isClusterOpen = true)}> - {filters.cluster} - {#if filters.partition} - ({filters.partition}) - {/if} - + + + + + Filters + + + Manage Filters + {#if menuText} + {menuText} + {/if} - - {#if filters.states.length != allJobStates.length} - (isJobStatesOpen = true)}> - {filters.states.join(', ')} - + (isClusterOpen = true)}> + Cluster/Partition + + (isJobStatesOpen = true)}> + Job States + + (isStartTimeOpen = true)}> + Start Time + + (isDurationOpen = true)}> + Duration + + (isTagsOpen = true)}> + Tags + + (isResourcesOpen = true)}> + Resources + + (isStatsOpen = true)}> + (isStatsOpen = true)} /> Statistics + + {#if startTimeQuickSelect} + + Start Time Qick Selection + {#each [{ text: "Last 6hrs", url: "last6h", seconds: 6 * 60 * 60 }, { text: "Last 24hrs", url: "last24h", seconds: 24 * 60 * 60 }, { text: "Last 7 days", url: "last7d", seconds: 7 * 24 * 60 * 60 }, { text: "Last 30 days", url: "last30d", seconds: 30 * 24 * 60 * 60 }] as { text, url, seconds }} + { + filters.startTime.from = new Date( + Date.now() - seconds * 1000, + ).toISOString(); + filters.startTime.to = new Date(Date.now()).toISOString(); + (filters.startTime.text = text), (filters.startTime.url = url); + update(); + }} + > + + {text} + + {/each} {/if} - - {#if filters.startTime.from || filters.startTime.to} - (isStartTimeOpen = true)}> - {#if filters.startTime.text} - {filters.startTime.text} - {:else} - {new Date(filters.startTime.from).toLocaleString()} - {new Date(filters.startTime.to).toLocaleString()} - {/if} - + + + + + {#if filters.cluster} + (isClusterOpen = true)}> + {filters.cluster} + {#if filters.partition} + ({filters.partition}) {/if} - - {#if filters.duration.from || filters.duration.to} - (isDurationOpen = true)}> - {Math.floor(filters.duration.from / 3600)}h:{Math.floor(filters.duration.from % 3600 / 60)}m - - - {Math.floor(filters.duration.to / 3600)}h:{Math.floor(filters.duration.to % 3600 / 60)}m - - {/if} - - {#if filters.duration.lessThan} - (isDurationOpen = true)}> - Duration less than {Math.floor(filters.duration.lessThan / 3600)}h:{Math.floor(filters.duration.lessThan % 3600 / 60)}m - + + {/if} + + {#if filters.states.length != allJobStates.length} + (isJobStatesOpen = true)}> + {filters.states.join(", ")} + + {/if} + + {#if filters.startTime.from || filters.startTime.to} + (isStartTimeOpen = true)}> + {#if filters.startTime.text} + {filters.startTime.text} + {:else} + {new Date(filters.startTime.from).toLocaleString()} - {new Date( + filters.startTime.to, + ).toLocaleString()} {/if} - - {#if filters.duration.moreThan} - (isDurationOpen = true)}> - Duration more than {Math.floor(filters.duration.moreThan / 3600)}h:{Math.floor(filters.duration.moreThan % 3600 / 60)}m - + + {/if} + + {#if filters.duration.from || filters.duration.to} + (isDurationOpen = true)}> + {Math.floor(filters.duration.from / 3600)}h:{Math.floor( + (filters.duration.from % 3600) / 60, + )}m - + {Math.floor(filters.duration.to / 3600)}h:{Math.floor( + (filters.duration.to % 3600) / 60, + )}m + + {/if} + + {#if filters.duration.lessThan} + (isDurationOpen = true)}> + Duration less than {Math.floor( + filters.duration.lessThan / 3600, + )}h:{Math.floor((filters.duration.lessThan % 3600) / 60)}m + + {/if} + + {#if filters.duration.moreThan} + (isDurationOpen = true)}> + Duration more than {Math.floor( + filters.duration.moreThan / 3600, + )}h:{Math.floor((filters.duration.moreThan % 3600) / 60)}m + + {/if} + + {#if filters.tags.length != 0} + (isTagsOpen = true)}> + {#each filters.tags as tagId} + + {/each} + + {/if} + + {#if filters.numNodes.from != null || filters.numNodes.to != null || filters.numHWThreads.from != null || filters.numHWThreads.to != null || filters.numAccelerators.from != null || filters.numAccelerators.to != null} + (isResourcesOpen = true)}> + {#if isNodesModified} + Nodes: {filters.numNodes.from} - {filters.numNodes.to} {/if} - - {#if filters.tags.length != 0} - (isTagsOpen = true)}> - {#each filters.tags as tagId} - - {/each} - + {#if isNodesModified && isHwthreadsModified}, {/if} - - {#if filters.numNodes.from != null || filters.numNodes.to != null || - filters.numHWThreads.from != null || filters.numHWThreads.to != null || - filters.numAccelerators.from != null || filters.numAccelerators.to != null } - (isResourcesOpen = true)}> - {#if isNodesModified } Nodes: {filters.numNodes.from} - {filters.numNodes.to} {/if} - {#if isNodesModified && isHwthreadsModified }, {/if} - {#if isHwthreadsModified } HWThreads: {filters.numHWThreads.from} - {filters.numHWThreads.to} {/if} - {#if (isNodesModified || isHwthreadsModified) && isAccsModified }, {/if} - {#if isAccsModified } Accelerators: {filters.numAccelerators.from} - {filters.numAccelerators.to} {/if} - + {#if isHwthreadsModified} + HWThreads: {filters.numHWThreads.from} - {filters.numHWThreads.to} {/if} - - {#if filters.node != null } - (isResourcesOpen = true)}> - Node: {filters.node} - + {#if (isNodesModified || isHwthreadsModified) && isAccsModified}, {/if} - - {#if filters.stats.length > 0} - (isStatsOpen = true)}> - {filters.stats.map(stat => `${stat.text}: ${stat.from} - ${stat.to}`).join(', ')} - + {#if isAccsModified} + Accelerators: {filters.numAccelerators.from} - {filters + .numAccelerators.to} {/if} - + + {/if} + + {#if filters.node != null} + (isResourcesOpen = true)}> + Node: {filters.node} + + {/if} + + {#if filters.stats.length > 0} + (isStatsOpen = true)}> + {filters.stats + .map((stat) => `${stat.text}: ${stat.from} - ${stat.to}`) + .join(", ")} + + {/if} + update()} /> + {disableClusterSelection} + bind:isOpen={isClusterOpen} + bind:cluster={filters.cluster} + bind:partition={filters.partition} + on:update={() => update()} +/> update()} /> + bind:isOpen={isJobStatesOpen} + bind:states={filters.states} + on:update={() => update()} +/> { - delete filters.startTime['text'] - delete filters.startTime['url'] - update() - }} /> + bind:isOpen={isStartTimeOpen} + bind:from={filters.startTime.from} + bind:to={filters.startTime.to} + on:update={() => { + delete filters.startTime["text"]; + delete filters.startTime["url"]; + update(); + }} +/> update()} /> + bind:isOpen={isDurationOpen} + bind:lessThan={filters.duration.lessThan} + bind:moreThan={filters.duration.moreThan} + bind:from={filters.duration.from} + bind:to={filters.duration.to} + on:update={() => update()} +/> update()} /> - - update()} /> - - update()} /> + bind:isOpen={isTagsOpen} + bind:tags={filters.tags} + on:update={() => update()} +/> + + update()} +/> + + update()} +/> diff --git a/web/frontend/src/filters/InfoBox.svelte b/web/frontend/src/filters/InfoBox.svelte index 58fc8a5c..8fe75ab6 100644 --- a/web/frontend/src/filters/InfoBox.svelte +++ b/web/frontend/src/filters/InfoBox.svelte @@ -1,11 +1,11 @@ - diff --git a/web/frontend/src/filters/JobStates.svelte b/web/frontend/src/filters/JobStates.svelte index 4e5db2e8..e22144fa 100644 --- a/web/frontend/src/filters/JobStates.svelte +++ b/web/frontend/src/filters/JobStates.svelte @@ -1,47 +1,76 @@ + - (isOpen = !isOpen)}> - - Select Job States - - - - {#each allJobStates as state} - - - {state} - - {/each} - - - - - - - + (isOpen = !isOpen)}> + Select Job States + + + {#each allJobStates as state} + + + {state} + + {/each} + + + + + + + diff --git a/web/frontend/src/filters/Resources.svelte b/web/frontend/src/filters/Resources.svelte index be5995a5..01f1c57e 100644 --- a/web/frontend/src/filters/Resources.svelte +++ b/web/frontend/src/filters/Resources.svelte @@ -1,145 +1,242 @@ - (isOpen = !isOpen)}> - - Select number of utilized Resources - - -
    Named Node
    - -
    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
    - { - pendingNumAccelerators = { from: detail[0], to: detail[1] } - isAccsModified = true - }} - min={minNumAccelerators} max={maxNumAccelerators} - firstSlider={pendingNumAccelerators.from} secondSlider={pendingNumAccelerators.to} - inputFieldFrom={pendingNumAccelerators.from} inputFieldTo={pendingNumAccelerators.to}/> - {/if} -
    - - - - - + (isOpen = !isOpen)}> + Select number of utilized Resources + +
    Named Node
    + +
    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
    + { + pendingNumAccelerators = { from: detail[0], to: detail[1] }; + isAccsModified = true; + }} + min={minNumAccelerators} + max={maxNumAccelerators} + firstSlider={pendingNumAccelerators.from} + secondSlider={pendingNumAccelerators.to} + inputFieldFrom={pendingNumAccelerators.from} + inputFieldTo={pendingNumAccelerators.to} + /> + {/if} +
    + + + + +
    diff --git a/web/frontend/src/filters/StartTime.svelte b/web/frontend/src/filters/StartTime.svelte index 59f85134..1759b6eb 100644 --- a/web/frontend/src/filters/StartTime.svelte +++ b/web/frontend/src/filters/StartTime.svelte @@ -1,86 +1,121 @@ - (isOpen = !isOpen)}> - - Select Start Time - - -

    From

    - - - - - - - - -

    To

    - - - - - - - - -
    - - - - - + (isOpen = !isOpen)}> + Select Start Time + +

    From

    + + + + + + + + +

    To

    + + + + + + + + +
    + + + + +
    diff --git a/web/frontend/src/filters/Stats.svelte b/web/frontend/src/filters/Stats.svelte index cf559da2..ee80a4b5 100644 --- a/web/frontend/src/filters/Stats.svelte +++ b/web/frontend/src/filters/Stats.svelte @@ -1,115 +1,137 @@ - (isOpen = !isOpen)}> - - Filter based on statistics (of non-running jobs) - - - {#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} -
    - - - - - + (isOpen = !isOpen)}> + Filter based on statistics (of non-running jobs) + + {#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} +
    + + + + +
    diff --git a/web/frontend/src/filters/Tags.svelte b/web/frontend/src/filters/Tags.svelte index b5a145a3..06153ed6 100644 --- a/web/frontend/src/filters/Tags.svelte +++ b/web/frontend/src/filters/Tags.svelte @@ -1,67 +1,89 @@ - (isOpen = !isOpen)}> - - Select Tags - - - -
    - - {#if $initialized} - {#each fuzzySearchTags(searchTerm, allTags) as tag (tag)} - - {#if pendingTags.includes(tag.id)} - - {:else} - - {/if} - - - - {:else} - No Tags - {/each} + (isOpen = !isOpen)}> + Select Tags + + +
    + + {#if $initialized} + {#each fuzzySearchTags(searchTerm, allTags) as tag (tag)} + + {#if pendingTags.includes(tag.id)} + + {:else} + {/if} - -
    - - - - - + + + + {:else} + No Tags + {/each} + {/if} +
    +
    + + + + +
    diff --git a/web/frontend/src/filters/TimeSelection.svelte b/web/frontend/src/filters/TimeSelection.svelte index c715b9c4..f9c230b4 100644 --- a/web/frontend/src/filters/TimeSelection.svelte +++ b/web/frontend/src/filters/TimeSelection.svelte @@ -1,81 +1,96 @@ - - - - {#if timeRange == -1} - from - updateExplicitTimeRange('from', event)}> - to - updateExplicitTimeRange('to', event)}> + + {#if timeRange == -1} + from + updateExplicitTimeRange("from", event)} + > + to + updateExplicitTimeRange("to", event)} + > + {/if} diff --git a/web/frontend/src/filters/UserOrProject.svelte b/web/frontend/src/filters/UserOrProject.svelte index 82358632..983192cf 100644 --- a/web/frontend/src/filters/UserOrProject.svelte +++ b/web/frontend/src/filters/UserOrProject.svelte @@ -1,75 +1,84 @@ {#if authlevel >= roles.manager} - - - termChanged()} on:keyup={(event) => termChanged(event.key == 'Enter' ? 0 : throttle)} - placeholder={mode == 'user' ? 'filter username...' : 'filter project...'} /> - + + + termChanged()} + on:keyup={(event) => termChanged(event.key == "Enter" ? 0 : throttle)} + placeholder={mode == "user" ? "filter username..." : "filter project..."} + /> + {:else} - - - termChanged()} on:keyup={(event) => termChanged(event.key == 'Enter' ? 0 : throttle)} placeholder='filter project...' - /> - + + + termChanged()} + on:keyup={(event) => termChanged(event.key == "Enter" ? 0 : throttle)} + placeholder="filter project..." + /> + {/if} diff --git a/web/frontend/src/joblist/JobInfo.svelte b/web/frontend/src/joblist/JobInfo.svelte index b7ca32ac..a30d0584 100644 --- a/web/frontend/src/joblist/JobInfo.svelte +++ b/web/frontend/src/joblist/JobInfo.svelte @@ -6,115 +6,138 @@ - jobTags: Defaults to job.tags, usefull for dynamically updating the tags. --> +
    -

    - {job.jobId} ({job.cluster}) - {#if job.metaData?.jobName} -
    - {#if job.metaData?.jobName.length <= 25} -

    {job.metaData.jobName}
    - {:else} -
    {job.metaData.jobName}
    - {/if} - {/if} - {#if job.arrayJobId} - Array Job: #{job.arrayJobId} - {/if} -

    +

    + {job.jobId} + ({job.cluster}) + {#if job.metaData?.jobName} +
    + {#if job.metaData?.jobName.length <= 25} +

    {job.metaData.jobName}
    + {:else} +
    + {job.metaData.jobName} +
    + {/if} + {/if} + {#if job.arrayJobId} + Array Job: #{job.arrayJobId} + {/if} +

    -

    - - - {scrambleNames ? scramble(job.user) : job.user} - - {#if job.userData && job.userData.name} - ({scrambleNames ? scramble(job.userData.name) : job.userData.name}) - {/if} - {#if job.project && job.project != 'no project'} -
    - - - {scrambleNames ? scramble(job.project) : job.project} - - {/if} -

    +

    + + + {scrambleNames ? scramble(job.user) : job.user} + + {#if job.userData && job.userData.name} + ({scrambleNames ? scramble(job.userData.name) : job.userData.name}) + {/if} + {#if job.project && job.project != "no project"} +
    + + + {scrambleNames ? scramble(job.project) : job.project} + + {/if} +

    -

    - {#if job.numNodes == 1} - {job.resources[0].hostname} - {:else} - {job.numNodes} - {/if} - - {#if job.exclusive != 1} - (shared) - {/if} - {#if job.numAcc > 0} - , {job.numAcc} - {/if} - {#if job.numHWThreads > 0} - , {job.numHWThreads} - {/if} -
    - {job.subCluster} -

    +

    + {#if job.numNodes == 1} + {job.resources[0].hostname} + {:else} + {job.numNodes} + {/if} + + {#if job.exclusive != 1} + (shared) + {/if} + {#if job.numAcc > 0} + , {job.numAcc} + {/if} + {#if job.numHWThreads > 0} + , {job.numHWThreads} + {/if} +
    + {job.subCluster} +

    -

    - Start: {(new Date(job.startTime)).toLocaleString()} -
    - Duration: {formatDuration(job.duration)} {job.state} - {#if job.walltime} -
    - Walltime: {formatDuration(job.walltime)} - {/if} -

    +

    + Start: {new Date(job.startTime).toLocaleString()} +
    + Duration: {formatDuration(job.duration)} + {job.state} + {#if job.walltime} +
    + Walltime: {formatDuration(job.walltime)} + {/if} +

    -

    - {#each jobTags as tag} - - {/each} -

    +

    + {#each jobTags as tag} + + {/each} +

    diff --git a/web/frontend/src/joblist/JobList.svelte b/web/frontend/src/joblist/JobList.svelte index 5f8d89b8..3efe069b 100644 --- a/web/frontend/src/joblist/JobList.svelte +++ b/web/frontend/src/joblist/JobList.svelte @@ -9,284 +9,275 @@ - update(filters?: [JobFilter]) --> -
    - - - - - {#if showFootprint} - - {/if} - {#each metrics as metric (metric)} - - {/each} - - - - {#if $jobs.error} - - - - {:else if $jobs.fetching || !$jobs.data} - - - - {:else if $jobs.data && $initialized} - {#each $jobs.data.jobs.items as job (job)} - - {:else} - - - - {/each} - {/if} - -
    - Job Info - - Job Footprint - - {metric} - {#if $initialized} - ({clusters - .map((cluster) => - cluster.metricConfig.find( - (m) => m.name == metric - ) - ) - .filter((m) => m != null) - .map( - (m) => - (m.unit?.prefix - ? m.unit?.prefix - : "") + - (m.unit?.base ? m.unit?.base : "") - ) // Build unitStr - .reduce( - (arr, unitStr) => - arr.includes(unitStr) - ? arr - : [...arr, unitStr], - [] - ) // w/o this, output would be [unitStr, unitStr] - .join(", ")}) - {/if} -
    -

    {$jobs.error.message}

    -
    - -
    - No jobs found -
    -
    +
    + + + + + {#if showFootprint} + + {/if} + {#each metrics as metric (metric)} + + {/each} + + + + {#if $jobs.error} + + + + {:else if $jobs.fetching || !$jobs.data} + + + + {:else if $jobs.data && $initialized} + {#each $jobs.data.jobs.items as job (job)} + + {:else} + + + + {/each} + {/if} + +
    + Job Info + + Job Footprint + + {metric} + {#if $initialized} + ({clusters + .map((cluster) => + cluster.metricConfig.find((m) => m.name == metric), + ) + .filter((m) => m != null) + .map( + (m) => + (m.unit?.prefix ? m.unit?.prefix : "") + + (m.unit?.base ? m.unit?.base : ""), + ) // Build unitStr + .reduce( + (arr, unitStr) => + arr.includes(unitStr) ? arr : [...arr, unitStr], + [], + ) // w/o this, output would be [unitStr, unitStr] + .join(", ")}) + {/if} +
    +

    {$jobs.error.message}

    +
    + +
    No jobs found
    +
    { - if (detail.itemsPerPage != itemsPerPage) { - updateConfiguration( - detail.itemsPerPage.toString(), - detail.page - ) - } else { - paging = { itemsPerPage: detail.itemsPerPage, page: detail.page } - } - }} + bind:page + {itemsPerPage} + itemText="Jobs" + totalItems={matchedJobs} + on:update={({ detail }) => { + if (detail.itemsPerPage != itemsPerPage) { + updateConfiguration(detail.itemsPerPage.toString(), detail.page); + } else { + paging = { itemsPerPage: detail.itemsPerPage, page: detail.page }; + } + }} /> diff --git a/web/frontend/src/joblist/Refresher.svelte b/web/frontend/src/joblist/Refresher.svelte index 25877111..635ffbe5 100644 --- a/web/frontend/src/joblist/Refresher.svelte +++ b/web/frontend/src/joblist/Refresher.svelte @@ -5,39 +5,46 @@ - 'reload': When fired, the parent component shoud refresh its contents --> - - - \ No newline at end of file + + + + diff --git a/web/frontend/src/joblist/Row.svelte b/web/frontend/src/joblist/Row.svelte index 4d9013c7..41caa539 100644 --- a/web/frontend/src/joblist/Row.svelte +++ b/web/frontend/src/joblist/Row.svelte @@ -9,168 +9,189 @@ --> - - + + + + {#if job.monitoringStatus == 0 || job.monitoringStatus == 2} + + Not monitored or archiving failed - {#if job.monitoringStatus == 0 || job.monitoringStatus == 2} - - Not monitored or archiving failed - - {:else if $metricsQuery.fetching} - - - - {:else if $metricsQuery.error} - - - {$metricsQuery.error.message.length > 500 - ? $metricsQuery.error.message.substring(0, 499) + "..." - : $metricsQuery.error.message} - - - {:else} - {#if showFootprint} - - - - {/if} - {#each sortAndSelectScope($metricsQuery.data.jobMetrics) as metric, i (metric || i)} - - - {#if metric.disabled == false && metric.data} - - {:else if metric.disabled == true && metric.data} - Metric disabled for subcluster {metric.data.name}:{job.subCluster} - {:else} - No dataset returned - {/if} - - {/each} + {:else if $metricsQuery.fetching} + + + + {:else if $metricsQuery.error} + + + {$metricsQuery.error.message.length > 500 + ? $metricsQuery.error.message.substring(0, 499) + "..." + : $metricsQuery.error.message} + + + {:else} + {#if showFootprint} + + + {/if} + {#each sortAndSelectScope($metricsQuery.data.jobMetrics) as metric, i (metric || i)} + + + {#if metric.disabled == false && metric.data} + + {:else if metric.disabled == true && metric.data} + Metric disabled for subcluster {metric.data.name}:{job.subCluster} + {:else} + No dataset returned + {/if} + + {/each} + {/if} diff --git a/web/frontend/src/joblist/SortSelection.svelte b/web/frontend/src/joblist/SortSelection.svelte index 59419642..2cc86151 100644 --- a/web/frontend/src/joblist/SortSelection.svelte +++ b/web/frontend/src/joblist/SortSelection.svelte @@ -7,65 +7,94 @@ --> - { isOpen = !isOpen }}> - - Sort rows - - - - {#each sortableColumns as col, i (col)} - - + sortableColumns[i] = { ...sortableColumns[i] }; + activeColumnIdx = i; + sortableColumns = [...sortableColumns]; + sorting = { field: col.field, order: col.order }; + }} + > + + - {col.text} - - {/each} - - - - - + {col.text} + + {/each} + + + + + \ No newline at end of file + .sort { + border: none; + margin: 0; + padding: 0; + background: 0 0; + transition: all 70ms; + } + + diff --git a/web/frontend/src/plots/Histogram.svelte b/web/frontend/src/plots/Histogram.svelte index 499ea4fa..83003843 100644 --- a/web/frontend/src/plots/Histogram.svelte +++ b/web/frontend/src/plots/Histogram.svelte @@ -5,221 +5,222 @@ --> {#if data.length > 0} -
    +
    {:else} - Cannot render histogram: No data! + Cannot render histogram: No data! {/if} - - diff --git a/web/frontend/src/plots/MetricPlot.svelte b/web/frontend/src/plots/MetricPlot.svelte index 7bd264c3..af8f22a3 100644 --- a/web/frontend/src/plots/MetricPlot.svelte +++ b/web/frontend/src/plots/MetricPlot.svelte @@ -1,3 +1,120 @@ + + - {#if series[0].data.length > 0} -
    +
    {:else} - Cannot render plot: No series data returned for {metric} + Cannot render plot: No series data returned for {metric} {/if} diff --git a/web/frontend/src/plots/Roofline.svelte b/web/frontend/src/plots/Roofline.svelte index d4ed5f6b..1e47f6f4 100644 --- a/web/frontend/src/plots/Roofline.svelte +++ b/web/frontend/src/plots/Roofline.svelte @@ -1,254 +1,339 @@ {#if data != null} -
    +
    {:else} - Cannot render roofline: No data! -{/if} \ No newline at end of file + Cannot render roofline: No data! +{/if} +