diff --git a/package-lock.json b/package-lock.json index 45c6287f8725e19e617dfef4de6a9ef61b8d5d8c..be37a3e534aed19236f7bfe8186a5a27bf938ed0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@aws-sdk/s3-request-presigner": "<3.530.0", "@fortawesome/fontawesome-free": "~6.5.0", "@popperjs/core": "~2.11.8", - "ajv": "~8.14.0", + "ajv": "~8.16.0", "bootstrap": "~5.3.0", "chart.js": "~4.4.0", "chartjs-plugin-zoom": "~2.0.1", @@ -52,7 +52,7 @@ "highlight.js": "^11.9.0", "npm-run-all": "~4.1.5", "openapi-typescript-codegen": "^0.29.0", - "prettier": "~3.2.0", + "prettier": "~3.3.0", "rollup-plugin-node-polyfills": "~0.2.1", "sass": "^1.66.0", "typescript": "~5.4.0", @@ -61,9 +61,9 @@ } }, "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "11.6.2", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.6.2.tgz", - "integrity": "sha512-ENUdLLT04aDbbHCRwfKf8gR67AhV0CdFrOAtk+FcakBAgaq6ds3HLK9X0BCyiFUz8pK9uP+k6YZyJaGG7Mt7vQ==", + "version": "11.6.4", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.6.4.tgz", + "integrity": "sha512-9K6xOqeevacvweLGik6LnZCb1fBtCOSIWQs8d096XGeqoLKC33UVMGz9+77Gw44KvbH4pKcQPWo4ZpxkXYj05w==", "dev": true, "dependencies": { "@jsdevtools/ono": "^7.1.3", @@ -929,9 +929,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.6.tgz", - "integrity": "sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", + "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -1368,9 +1368,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", + "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -2476,9 +2476,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.12.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", - "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", + "version": "20.14.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz", + "integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -2509,16 +2509,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.11.0.tgz", - "integrity": "sha512-P+qEahbgeHW4JQ/87FuItjBj8O3MYv5gELDzr8QaQ7fsll1gSMTYb6j87MYyxwf3DtD7uGFB9ShwgmCJB5KmaQ==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.12.0.tgz", + "integrity": "sha512-7F91fcbuDf/d3S8o21+r3ZncGIke/+eWk0EpO21LXhDfLahriZF9CGj4fbAetEjlaBdjdSm9a6VeXbpbT6Z40Q==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.11.0", - "@typescript-eslint/type-utils": "7.11.0", - "@typescript-eslint/utils": "7.11.0", - "@typescript-eslint/visitor-keys": "7.11.0", + "@typescript-eslint/scope-manager": "7.12.0", + "@typescript-eslint/type-utils": "7.12.0", + "@typescript-eslint/utils": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -2542,15 +2542,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.11.0.tgz", - "integrity": "sha512-yimw99teuaXVWsBcPO1Ais02kwJ1jmNA1KxE7ng0aT7ndr1pT1wqj0OJnsYVGKKlc4QJai86l/025L6z8CljOg==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.12.0.tgz", + "integrity": "sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.11.0", - "@typescript-eslint/types": "7.11.0", - "@typescript-eslint/typescript-estree": "7.11.0", - "@typescript-eslint/visitor-keys": "7.11.0", + "@typescript-eslint/scope-manager": "7.12.0", + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/typescript-estree": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0", "debug": "^4.3.4" }, "engines": { @@ -2570,13 +2570,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.11.0.tgz", - "integrity": "sha512-27tGdVEiutD4POirLZX4YzT180vevUURJl4wJGmm6TrQoiYwuxTIY98PBp6L2oN+JQxzE0URvYlzJaBHIekXAw==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.12.0.tgz", + "integrity": "sha512-itF1pTnN6F3unPak+kutH9raIkL3lhH1YRPGgt7QQOh43DQKVJXmWkpb+vpc/TiDHs6RSd9CTbDsc/Y+Ygq7kg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.11.0", - "@typescript-eslint/visitor-keys": "7.11.0" + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2587,13 +2587,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.11.0.tgz", - "integrity": "sha512-WmppUEgYy+y1NTseNMJ6mCFxt03/7jTOy08bcg7bxJJdsM4nuhnchyBbE8vryveaJUf62noH7LodPSo5Z0WUCg==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.12.0.tgz", + "integrity": "sha512-lib96tyRtMhLxwauDWUp/uW3FMhLA6D0rJ8T7HmH7x23Gk1Gwwu8UZ94NMXBvOELn6flSPiBrCKlehkiXyaqwA==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.11.0", - "@typescript-eslint/utils": "7.11.0", + "@typescript-eslint/typescript-estree": "7.12.0", + "@typescript-eslint/utils": "7.12.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -2614,9 +2614,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.11.0.tgz", - "integrity": "sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.12.0.tgz", + "integrity": "sha512-o+0Te6eWp2ppKY3mLCU+YA9pVJxhUJE15FV7kxuD9jgwIAa+w/ycGJBMrYDTpVGUM/tgpa9SeMOugSabWFq7bg==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2627,13 +2627,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.11.0.tgz", - "integrity": "sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.12.0.tgz", + "integrity": "sha512-5bwqLsWBULv1h6pn7cMW5dXX/Y2amRqLaKqsASVwbBHMZSnHqE/HN4vT4fE0aFsiwxYvr98kqOWh1a8ZKXalCQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.11.0", - "@typescript-eslint/visitor-keys": "7.11.0", + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2655,15 +2655,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.11.0.tgz", - "integrity": "sha512-xlAWwPleNRHwF37AhrZurOxA1wyXowW4PqVXZVUNCLjB48CqdPJoJWkrpH2nij9Q3Lb7rtWindtoXwxjxlKKCA==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.12.0.tgz", + "integrity": "sha512-Y6hhwxwDx41HNpjuYswYp6gDbkiZ8Hin9Bf5aJQn1bpTs3afYY4GX+MPYxma8jtoIV2GRwTM/UJm/2uGCVv+DQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.11.0", - "@typescript-eslint/types": "7.11.0", - "@typescript-eslint/typescript-estree": "7.11.0" + "@typescript-eslint/scope-manager": "7.12.0", + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/typescript-estree": "7.12.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2677,12 +2677,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.11.0.tgz", - "integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.12.0.tgz", + "integrity": "sha512-uZk7DevrQLL3vSnfFl5bj4sL75qC9D6EdjemIdbtkuUmIheWpuiiylSY01JxJE7+zGrOWDZrp1WxOuDntvKrHQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/types": "7.12.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -2700,9 +2700,9 @@ "dev": true }, "node_modules/@vitejs/plugin-vue": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz", - "integrity": "sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.5.tgz", + "integrity": "sha512-LOjm7XeIimLBZyzinBQ6OSm3UBCNVCpLkxGC0oWmm2YPzVZoxMsdvNVimLTBzpAnR9hl/yn1SHGuRfe6/Td9rQ==", "dev": true, "engines": { "node": "^18.0.0 || >=20.0.0" @@ -2805,9 +2805,9 @@ } }, "node_modules/@vue/devtools-api": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.1.tgz", - "integrity": "sha512-LgPscpE3Vs0x96PzSSB4IGVSZXZBZHpfxs+ZA1d+VEPwHdOXowy/Y2CsvCAIFrf+ssVU1pD1jidj505EpUnfbA==" + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.3.tgz", + "integrity": "sha512-0MiMsFma/HqA6g3KLKn+AGpL1kgKhFWszC9U29NfpWK5LE7bjeXxySWJrOJ77hBz+TBrBQ7o4QJqbPbqbs8rJw==" }, "node_modules/@vue/eslint-config-prettier": { "version": "9.0.0", @@ -2942,9 +2942,9 @@ } }, "node_modules/ajv": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.14.0.tgz", - "integrity": "sha512-oYs1UUtO97ZO2lJ4bwnWeQW8/zvOIQLGKcvPTsWmvc2SYgBb+upuNS5NxoLaMU4h8Ju3Nbj6Cq8mD2LQoqVKFA==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", "dependencies": { "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", @@ -3433,9 +3433,9 @@ "dev": true }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -3523,9 +3523,9 @@ } }, "node_modules/dompurify": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.4.tgz", - "integrity": "sha512-2gnshi6OshmuKil8rMZuQCGiUF3cUxHY3NGDzUAdUx/NPEe5DVnO8BDoAQouvgwnx0R/+a6jUn36Z0FSdq8vww==" + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.5.tgz", + "integrity": "sha512-lwG+n5h8QNpxtyrJW/gJWckL+1/DQiYMX8f7t8Z2AZTPw1esVrqjI63i7Zc2Gz0aKzLVMYC1V1PL/ky+aY/NgA==" }, "node_modules/entities": { "version": "4.5.0", @@ -5639,9 +5639,9 @@ } }, "node_modules/pinia/node_modules/vue-demi": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz", - "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==", + "version": "0.14.8", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.8.tgz", + "integrity": "sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==", "hasInstallScript": true, "bin": { "vue-demi-fix": "bin/vue-demi-fix.js", @@ -5722,9 +5722,9 @@ } }, "node_modules/prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.1.tgz", + "integrity": "sha512-7CAwy5dRsxs8PHXT3twixW9/OEll8MLE0VRPCJyl7CkS6VHGPSlsVaWTiASPTyGyYRyApxlaWTzwUxVNrhcwDg==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -6054,9 +6054,9 @@ } }, "node_modules/sass": { - "version": "1.77.2", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.2.tgz", - "integrity": "sha512-eb4GZt1C3avsX3heBNlrc7I09nyT00IUuo4eFhAbeXWU2fvA7oXI53SxODVAA+zgZCk9aunAZgO+losjR3fAwA==", + "version": "1.77.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.4.tgz", + "integrity": "sha512-vcF3Ckow6g939GMA4PeU7b2K/9FALXk2KF9J87txdHzXbUF9XRQRwSxcAs/fGaTnJeBFd7UoV22j3lzMLdM0Pw==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -6447,9 +6447,9 @@ } }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/type-check": { "version": "0.4.0", @@ -6640,9 +6640,9 @@ } }, "node_modules/vite": { - "version": "5.2.11", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz", - "integrity": "sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==", + "version": "5.2.13", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.13.tgz", + "integrity": "sha512-SSq1noJfY9pR3I1TUENL3rQYDQCFqgD+lM6fTRAM8Nv6Lsg5hDLaXkjETVeBt+7vZBCMoibD+6IWnT2mJ+Zb/A==", "dev": true, "dependencies": { "esbuild": "^0.20.1", @@ -7121,9 +7121,9 @@ } }, "node_modules/vue-eslint-parser": { - "version": "9.4.2", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.2.tgz", - "integrity": "sha512-Ry9oiGmCAK91HrKMtCrKFWmSFWvYkpGglCeFAIqDdr9zdXmMMpJOmUJS7WWsW7fX81h6mwHmUZCQQ1E0PkSwYQ==", + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz", + "integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==", "dev": true, "dependencies": { "debug": "^4.3.4", diff --git a/package.json b/package.json index 142ddef1ccc6fa6f09741e4161fc2fa9c6a973a6..fece0f765c7be49bec6b7c3abae08de28887b33c 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "@aws-sdk/s3-request-presigner": "<3.530.0", "@fortawesome/fontawesome-free": "~6.5.0", "@popperjs/core": "~2.11.8", - "ajv": "~8.14.0", + "ajv": "~8.16.0", "bootstrap": "~5.3.0", "chart.js": "~4.4.0", "chartjs-plugin-zoom": "~2.0.1", @@ -56,7 +56,7 @@ "highlight.js": "^11.9.0", "npm-run-all": "~4.1.5", "openapi-typescript-codegen": "^0.29.0", - "prettier": "~3.2.0", + "prettier": "~3.3.0", "rollup-plugin-node-polyfills": "~0.2.1", "sass": "^1.66.0", "typescript": "~5.4.0", diff --git a/src/App.vue b/src/App.vue index 190e60f004f0fb2b041d6f2e3e47e93ae22c441e..a3bef75cae380982e55d1128d9755588f159e95d 100644 --- a/src/App.vue +++ b/src/App.vue @@ -76,19 +76,19 @@ onBeforeMount(() => { to.meta.requiresDeveloperRole && !(userRepository.workflowDev || userRepository.admin) ) { - return { name: "dashboard" }; + return { name: "workflows" }; } else if ( to.meta.requiresReviewerRole && !(userRepository.rewiewer || userRepository.admin) ) { - return { name: "dashboard" }; + return "/"; } else if ( to.meta.requiresMaintainerRole && !(userRepository.resourceMaintainer || userRepository.admin) ) { - return { name: "dashboard" }; + return { name: "resources" }; } else if (to.meta.adminRole && !userRepository.admin) { - return { name: "dashboard" }; + return "/"; } else if (to.name !== "login" && to.query.next) { // return to original path after login return { path: decodeURI(to.query.next as string) }; diff --git a/src/components/workflows/modals/ArbitraryWorkflowModal.vue b/src/components/workflows/modals/ArbitraryWorkflowModal.vue index 6cf0681d247976f3ae80547e0edff2ed53a17899..132dd4a27f224721d79fb8aeaa6d96e7b0a60029 100644 --- a/src/components/workflows/modals/ArbitraryWorkflowModal.vue +++ b/src/components/workflows/modals/ArbitraryWorkflowModal.vue @@ -11,6 +11,10 @@ import { import { Collapse, Modal } from "bootstrap"; import { useWorkflowStore } from "@/stores/workflows"; import type { WorkflowModeOut } from "@/client"; +import { environment } from "@/environment"; +import { useS3KeyStore } from "@/stores/s3keys"; +import { useResourceStore } from "@/stores/resources"; +import { createDownloadUrl } from "@/utils/DownloadJson"; const props = defineProps<{ modalId: string; @@ -25,6 +29,8 @@ const workflowRepositoryElement = ref<HTMLInputElement | undefined>(undefined); const router = useRouter(); const workflowStore = useWorkflowStore(); +const s3KeyStore = useS3KeyStore(); +const resourceStore = useResourceStore(); const workflow = reactive<{ repository_url: string; @@ -55,6 +61,14 @@ const workflowMode = reactive<{ modeEnabled: false, }); +const executionEnvironmentState = reactive<{ + cli: boolean; + cluster: boolean; +}>({ + cli: false, + cluster: false, +}); + const formState = reactive<{ loading: boolean; checkRepoLoading: boolean; @@ -122,8 +136,199 @@ function viewWorkflow() { }); } +const resourcePathPrefix = computed<string>(() => { + let resourcePath: string | null = null; + for (const resource of resourceStore.resources) { + for (const version of resource.versions) { + if (version.cluster_path.length > 0) { + resourcePath = version.cluster_path; + } + } + } + if (resourcePath == null) { + return ""; + } + const ind = resourcePath.search(/CLDB-[\da-f]{32}/); + if (ind == -1) { + return ""; + } + return resourcePath.slice(0, ind - 1); +}); + +const nextflowConfig = computed<string>(() => { + if (executionEnvironmentState.cluster) { + return `// Nextflow config to emulate CloWM native execution +aws { + accessKey = '${s3KeyStore.keys[0]?.access_key ?? ""}' + secretKey = '${s3KeyStore.keys[0]?.secret_key ?? ""}' + client { + endpoint = '${environment.S3_URL}' + s3PathStyleAccess = true + } +} + +// Docker container options +docker { + enabled = true + runOptions = "-u \\$(id -u):\\$(id -g) -q \\ + -v ${resourcePathPrefix.value}:${resourcePathPrefix.value}:ro \\ + -v /var/lib/lxcfs/proc/cpuinfo:/proc/cpuinfo:rw \\ + -v /var/lib/lxcfs/proc/diskstats:/proc/diskstats:rw \\ + -v /var/lib/lxcfs/proc/meminfo:/proc/meminfo:rw \\ + -v /var/lib/lxcfs/proc/stat:/proc/stat:rw \\ + -v /var/lib/lxcfs/proc/swaps:/proc/swaps:rw \\ + -v /var/lib/lxcfs/proc/uptime:/proc/uptime:rw" +} + +// Disable unwanted features +// Attention: Docker is the only supported container engine so far! +weblog.enabled = false +shifter.enabled = false +singularity.enabled = false +podman.enabled = false +charliecloud.enabled = false +dag.enabled = false +trace.enabled = false + +// Nextflow provenance tracking plugin +plugins { + id 'nf-prov' +} + +prov { + enabled = true + formats { + legacy { + file = "./nf-prov_manifest.json" + overwrite = true + } + bco { + file = "./nf-prov_bco.json" + overwrite = true + } + dag { + file = "./nf-prov_dag.html" + overwrite = true + } + } +} + +executor { + submitRateLimit = '5 sec' +} + +// Process resource labels currently used by CloWM +process { + executor = 'slurm' + container = 'ubuntu:22.04' + cpus = { 2 } + memory = { 4000.MB } + maxErrors = '-1' + + // Process-specific resource requirements + withLabel:process_single { + cpus = { 1 } + memory = { 6000.MB } + } + withLabel:process_low { + cpus = { 2 } + memory = { 12000.MB } + } + withLabel:process_medium { + cpus = { 6 } + memory = { 36000.MB } + } + withLabel:process_high { + cpus = { 12 } + memory = { 72000.MB } + } + withLabel:process_high_memory { + memory = { 200000.MB } + } + withLabel:error_ignore { + errorStrategy = 'ignore' + } + withLabel: highmemXLarge { + cpus = { 28 } + memory = {470000.MB} + } + withLabel: computeXLarge { + cpus = {28} + memory = {470000.MB} + } + withLabel: highmemLarge { + cpus = {28} + memory = {240000.MB} + } + withLabel: highmemMedium { + cpus = {14} + memory = {120000.MB} + } + withLabel: large { + cpus = {28} + memory = {64000.MB} + } + withLabel: medium { + cpus = {14} + memory = {32000.MB} + } + withLabel: small { + cpus = {8} + memory = {16000.MB} + } + withLabel: mini { + cpus = {4} + memory = {8000.MB} + } + withLabel: tiny { + cpus = {1} + memory = {2000.MB} + } +}`; + } + return `aws { + client { + endpoint = '${environment.S3_URL}' + s3PathStyleAccess = true + } + accessKey = '${s3KeyStore.keys[0]?.access_key ?? ""}' + secretKey = '${s3KeyStore.keys[0]?.secret_key ?? ""}' +} + +docker { + enabled = true + runOptions = "-u \\$(id -u):\\$(id -g) -q" +} + +// Disable unwanted features +tower.enabled = false +weblog.enabled = false +shifter.enabled = false +singularity.enabled = false +podman.enabled = false +charliecloud.enabled = false +dag.enabled = true +trace.enabled = true + +process { + executor = 'local' + container = 'ubuntu:22.04' + cpus = { 2 } + memory = { 4000.MB } +} +`; +}); + +const configDownloadUrl = computed<string>(() => + createDownloadUrl(nextflowConfig.value, "text/plain"), +); + function checkRepository() { formState.validated = true; + // remove trailing slash (/) + workflow.repository_url = workflow.repository_url + .trim() + .replace(/(^\/+|\/+$)/g, ""); if (arbitraryWorkflowForm.value?.checkValidity() && !formState.allowUpload) { formState.unsupportedRepository = false; formState.missingFiles = []; @@ -181,6 +386,7 @@ onMounted(() => { tokenHelpCollapse = new Collapse("#tokenHelpCollapse", { toggle: false, }); + console.log(nextflowConfig.value); }); </script> @@ -188,12 +394,90 @@ onMounted(() => { <bootstrap-modal :modalId="modalId" :static-backdrop="false" - modal-label="Create Workflow Modal" + modal-label="Test My Workflow Modal" v-on="{ 'hidden.bs.modal': modalClosed }" + size-modifier-modal="lg" > - <template v-slot:header>Start arbitrary Workflow</template> + <template v-slot:header>Test workflow prior registration</template> <template v-slot:body> + <h5>Choose your execution environment</h5> + <div class="btn-group justify-content-center w-100 mb-2" role="group"> + <input + type="radio" + class="btn-check" + name="execution-environment-choice" + id="clowm-outlined" + autocomplete="off" + checked + v-model="executionEnvironmentState.cli" + :value="false" + /> + <label class="btn btn-outline-primary" for="clowm-outlined" + >CloWM native execution</label + > + + <input + type="radio" + class="btn-check" + name="execution-environment-choice" + id="cli-outlined" + autocomplete="off" + v-model="executionEnvironmentState.cli" + :value="true" + /> + <label class="btn btn-outline-primary" for="cli-outlined" + >Local Execution</label + > + </div> + <div v-if="executionEnvironmentState.cli"> + <div class="btn-group justify-content-center w-100 mb-2" role="group"> + <input + type="radio" + class="btn-check" + name="cluster-environment-choice" + id="laptop-outlined" + autocomplete="off" + checked + v-model="executionEnvironmentState.cluster" + :value="false" + /> + <label class="btn btn-outline-primary" for="laptop-outlined" + >Personal computer</label + > + + <input + type="radio" + class="btn-check" + name="cluster-environment-choice" + id="cluster-outlined" + autocomplete="off" + v-model="executionEnvironmentState.cluster" + :value="true" + /> + <label class="btn btn-outline-primary" for="cluster-outlined" + >Emulated CloWM environment</label + > + </div> + <p v-if="executionEnvironmentState.cluster"> + To emulate the CloWM native execution environment (e.g. docker + configuration, S3 access, resource labels etc.) on the workflow + development system, please download and use the Nextflow configuration + file (<code>clowm-nextflow.config</code>) as described below. + </p> + <p v-else> + To emulate a basic CloWM native execution environment (e.g. docker + configuration, S3 access etc.) on your personal computer, please + download and use the Nextflow configuration file + (<code>clowm-nextflow.config</code>) as described below. + </p> + <pre + class="rounded-1 w-100" + ><code>nextflow run /path/to/main.nf -c clowm-nextflow.config ...</code></pre> + <h6>clowm-nextflow.config:</h6> + <pre class="w-100 rounded-1"><code>{{ nextflowConfig }}</code></pre> + </div> <form + v-else id="arbitraryWorkflowForm" :class="{ 'was-validated': formState.validated }" ref="arbitraryWorkflowForm" @@ -389,6 +673,7 @@ onMounted(() => { </template> <template v-slot:footer> <button + v-if="!executionEnvironmentState.cli" type="button" class="btn btn-info me-auto" @click="checkRepository" @@ -406,6 +691,7 @@ onMounted(() => { Close </button> <button + v-if="!executionEnvironmentState.cli" type="submit" form="workflowCreateForm" class="btn btn-primary" @@ -420,6 +706,16 @@ onMounted(() => { ></span> View </button> + <a + v-else + class="btn btn-primary" + role="button" + :href="configDownloadUrl" + download="clowm-nextflow.config" + > + Download config + <font-awesome-icon icon="fa-solid fa-download" class="ms-1" /> + </a> </template> </bootstrap-modal> </template> diff --git a/src/components/workflows/modals/CreateWorkflowModal.vue b/src/components/workflows/modals/CreateWorkflowModal.vue index db2e210cb8163fe455f5e2d1352af40948d06df5..5eb0dd416bcad9e74601a3c1a3c1c1ceeab9c223 100644 --- a/src/components/workflows/modals/CreateWorkflowModal.vue +++ b/src/components/workflows/modals/CreateWorkflowModal.vue @@ -227,6 +227,10 @@ function checkRepository() { formState.validated = true; workflowRepositoryElement.value?.setCustomValidity(""); workflowGitCommitHashElement.value?.setCustomValidity(""); + // remove trailing slash (/) + workflow.repository_url = workflow.repository_url + .trim() + .replace(/(^\/+|\/+$)/g, ""); if (workflowCreateForm.value?.checkValidity() && !formState.allowUpload) { formState.unsupportedRepository = false; formState.missingFiles = []; diff --git a/src/views/workflows/ListWorkflowsView.vue b/src/views/workflows/ListWorkflowsView.vue index d6167b396b94758200311c9e65cca1191ae0a9fc..9ee51bded4b9037152defb23bd4f65611b73fe54 100644 --- a/src/views/workflows/ListWorkflowsView.vue +++ b/src/views/workflows/ListWorkflowsView.vue @@ -39,7 +39,9 @@ const filterFunctionMapping: Record< function filterWorkflowByString(workflow: WorkflowOut): boolean { return workflowsState.filterString.length > 0 - ? workflow.name.includes(workflowsState.filterString) + ? workflow.name + .toLowerCase() + .includes(workflowsState.filterString.toLowerCase()) : true; } diff --git a/src/views/workflows/MyWorkflowsView.vue b/src/views/workflows/MyWorkflowsView.vue index 4f12f2e3eccad54ee9d738af27e0fccec1e2005b..9ad162d2b3c0af57da23e5dbff5083c690bfd68f 100644 --- a/src/views/workflows/MyWorkflowsView.vue +++ b/src/views/workflows/MyWorkflowsView.vue @@ -11,6 +11,8 @@ import UpdateWorkflowVersionIconModal from "@/components/workflows/modals/Update import UpdateWorkflowCredentialsModal from "@/components/workflows/modals/UpdateWorkflowCredentialsModal.vue"; import { useWorkflowStore } from "@/stores/workflows"; import { useWorkflowExecutionStore } from "@/stores/workflowExecutions"; +import { environment } from "@/environment"; +import ArbitraryWorkflowModal from "@/components/workflows/modals/ArbitraryWorkflowModal.vue"; const workflowRepository = useWorkflowStore(); const workflowExecutionRepository = useWorkflowExecutionStore(); @@ -131,6 +133,17 @@ onMounted(() => { Create </button> </div> + <div v-if="environment.DEV_SYSTEM" class="d-grid gap-2 col-4 mx-auto"> + <button + class="btn btn-success btn-lg fs-3" + role="button" + data-bs-toggle="modal" + data-bs-target="#arbitraryWorkflowModal" + > + Test my Workflow + </button> + <arbitrary-workflow-modal modal-id="arbitraryWorkflowModal" /> + </div> <div v-if="!workflowsState.loading"> <card-transition-group v-if="sortedWorkflows.length > 0"