diff --git a/.browserslistrc b/.browserslistrc index 7e0bc736..a12a242c 100644 --- a/.browserslistrc +++ b/.browserslistrc @@ -2,11 +2,15 @@ # For additional information regarding the format and rule options, please see: # https://github.com/browserslist/browserslist#queries +# For the full list of supported browsers by the Angular framework, please see: +# https://angular.io/guide/browser-support + # You can see what browsers were selected by your queries by running: # npx browserslist -> 1% -last 2 versions -not dead -not ie <= 11 +last 2 Chrome versions +last 2 Firefox version +last 2 Edge major versions +last 2 Safari major versions +last 2 iOS major versions Firefox ESR diff --git a/.eslintrc.json b/.eslintrc.json index 27ab053f..bcc7ef05 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -20,6 +20,8 @@ "plugin:@angular-eslint/template/process-inline-templates" ], "rules": { + "no-console": "error", + "no-debugger": "error", "@angular-eslint/component-selector": [ "error", { @@ -88,7 +90,9 @@ "extends": [ "plugin:@angular-eslint/template/recommended" ], - "rules": {} + "rules": { + "@angular-eslint/template/use-track-by-function": "warn" + } } ] } diff --git a/.gitignore b/.gitignore index 5c775133..f619940e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,6 @@ /out-tsc /gen-code /src/__ngcc_entry_points__.json -.angular/ # dependencies /node_modules @@ -30,6 +29,7 @@ !.vscode/extensions.json # misc +/.angular/cache /.sass-cache /connect.lock /coverage diff --git a/angular.json b/angular.json index 603c42c8..349d0158 100644 --- a/angular.json +++ b/angular.json @@ -47,7 +47,6 @@ "node_modules/ngx-markdown-editor/assets/marked.min.js" ], "allowedCommonJsDependencies": [ - "lodash/fp", "ansi-to-html", "has-ansi", "fabric/dist/fabric.min", @@ -66,7 +65,10 @@ "britecharts/dist/umd/line.min", "britecharts/dist/umd/tooltip.min", "britecharts/dist/umd/miniTooltip.min", - "britecharts/dist/umd/scatterPlot.min" + "britecharts/dist/umd/scatterPlot.min", + "localforage", + "dom-to-image", + "ace-builds" ], "vendorChunk": true, "extractLicenses": false, @@ -128,7 +130,10 @@ "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { - "browserTarget": "trains-webapp:build" + "browserTarget": "trains-webapp:build", + "proxyConfig": "proxy.config.js", + "liveReload": false, + "port": 4300 }, "configurations": { "appdev": { @@ -292,7 +297,6 @@ "src/app/webapp-common/clearml-applications/report-widgets/src/app/webapp-common/assets", "src/app/webapp-common/clearml-applications/report-widgets/src/app/webapp-common/assets/fonts/trains.ttf" ], - "styles": [ "src/app/webapp-common/clearml-applications/report-widgets/src/styles.scss", { @@ -311,6 +315,12 @@ "@schematics/angular:component": { "prefix": "sm", "style": "scss" + }, + "@angular-eslint/schematics:application": { + "setParserOptionsProject": true + }, + "@angular-eslint/schematics:library": { + "setParserOptionsProject": true } } } diff --git a/package-lock.json b/package-lock.json index f793eb2e..fe551c80 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,61 +1,61 @@ { "name": "clearml-webapp", - "version": "1.10.0", + "version": "1.11.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "clearml-webapp", - "version": "1.10.0", + "version": "1.11.0", "dependencies": { - "@angular/animations": "^15.1.3", - "@angular/cdk": "^15.1.3", - "@angular/common": "^15.1.3", - "@angular/compiler": "^15.1.3", - "@angular/core": "^15.1.3", - "@angular/forms": "^15.1.3", - "@angular/material": "^15.1.3", - "@angular/platform-browser": "^15.1.3", - "@angular/platform-browser-dynamic": "^15.1.3", - "@angular/platform-server": "^15.1.3", - "@angular/router": "^15.1.3", - "@angular/service-worker": "^15.1.3", - "@angular/youtube-player": "^15.1.3", - "@aws-sdk/client-s3": "^3.266.1", - "@aws-sdk/s3-request-presigner": "^3.266.1", + "@angular/animations": "^15.2.8", + "@angular/cdk": "^15.2.8", + "@angular/common": "^15.2.8", + "@angular/compiler": "^15.2.8", + "@angular/core": "^15.2.8", + "@angular/forms": "^15.2.8", + "@angular/material": "^15.2.8", + "@angular/platform-browser": "^15.2.8", + "@angular/platform-browser-dynamic": "^15.2.8", + "@angular/platform-server": "^15.2.8", + "@angular/router": "^15.2.8", + "@angular/service-worker": "^15.2.8", + "@angular/youtube-player": "^15.2.8", + "@aws-sdk/client-s3": "^3.317.0", + "@aws-sdk/s3-request-presigner": "^3.317.0", "@ctrl/ngx-github-buttons": "^8.0.0", "@ngneat/dag": "^2.0.0", - "@ngrx/effects": "^15.2.1", - "@ngrx/entity": "^15.2.1", - "@ngrx/router-store": "^15.2.1", - "@ngrx/store": "^15.2.1", - "ace-builds": "^1.15.0", + "@ngrx/effects": "^15.4.0", + "@ngrx/entity": "^15.4.0", + "@ngrx/router-store": "^15.4.0", + "@ngrx/store": "^15.4.0", + "ace-builds": "^1.18.0", "angular-google-tag-manager": "^1.7.0", "angular-resizable-element": "^7.0.2", - "angular-split": "^14.1.0", + "angular-split": "^15.0.0", "ansi-to-html": "^0.7.2", - "bootstrap": "^4.6.2", + "bootstrap": "^5.2.3", "britecharts": "^2.18.0", "curved-arrows": "^0.1.0", "d3-selection": "^3.0.0", "diff": "^5.1.0", "dom-to-image": "^2.6.0", - "filesize": "^10.0.6", + "filesize": "^10.0.7", "has-ansi": "^5.0.1", "hocon-parser": "^1.0.1", "jwt-decode": "^3.1.2", "localforage": "^1.10.0", "lodash-es": "^4.17.21", "lucene": "^2.1.1", - "ngx-clipboard": "^15.1.0", - "ngx-color-picker": "^13.0.0", + "ngx-clipboard": "^16.0.0", + "ngx-color-picker": "^14.0.0", "ngx-device-detector": "^5.0.1", - "ngx-markdown-editor": "^5.1.0", + "ngx-markdown-editor": "^5.3.0", "ngx-print": "^1.3.1", - "ngx-window-token": "^6.0.0", + "ngx-window-token": "^7.0.0", "object-hash": "^3.0.0", "primeicons": "^6.0.1", - "primeng": "^15.2.0", + "primeng": "^15.4.1", "process": "^0.11.10", "rxjs": "^7.8.0", "string-to-color": "^2.2.2", @@ -63,35 +63,35 @@ "tslib": "^2.5.0", "url": "^0.11.0", "uuid": "^9.0.0", - "zone.js": "~0.12.0" + "zone.js": "^0.12.0" }, "devDependencies": { - "@angular-devkit/build-angular": "^15.1.4", - "@angular-devkit/core": "^15.1.4", - "@angular-devkit/schematics": "^15.1.4", - "@angular-devkit/schematics-cli": "^15.1.4", - "@angular-eslint/builder": "^15.2.0", - "@angular-eslint/eslint-plugin": "^15.2.0", - "@angular-eslint/eslint-plugin-template": "^15.2.0", - "@angular-eslint/schematics": "15.2.0", - "@angular-eslint/template-parser": "^15.2.0", - "@angular/cli": "^15.1.4", - "@angular/compiler-cli": "^15.1.3", - "@angular/language-service": "^15.1.3", - "@fortawesome/fontawesome-free": "^6.3.0", - "@ngrx/schematics": "^15.2.1", - "@ngrx/store-devtools": "^15.2.1", - "@types/d3-selection": "^3.0.4", - "@types/lodash-es": "^4.17.6", - "@types/node": "^18.13.0", - "@types/plotly.js": "^2.12.13", - "@types/uuid": "^9.0.0", - "@typescript-eslint/eslint-plugin": "^5.51.0", - "@typescript-eslint/parser": "^5.51.0", + "@angular-devkit/build-angular": "^15.2.6", + "@angular-devkit/core": "^15.2.6", + "@angular-devkit/schematics": "^15.2.6", + "@angular-devkit/schematics-cli": "^15.2.5", + "@angular-eslint/builder": "^15.2.1", + "@angular-eslint/eslint-plugin": "^15.2.1", + "@angular-eslint/eslint-plugin-template": "^15.2.1", + "@angular-eslint/schematics": "15.2.1", + "@angular-eslint/template-parser": "^15.2.1", + "@angular/cli": "^15.2.6", + "@angular/compiler-cli": "^15.2.8", + "@angular/language-service": "^15.2.8", + "@fortawesome/fontawesome-free": "^6.4.0", + "@ngrx/schematics": "^15.4.0", + "@ngrx/store-devtools": "^15.4.0", + "@types/d3-selection": "^3.0.5", + "@types/lodash-es": "^4.17.7", + "@types/node": "^18.16.0", + "@types/plotly.js": "^2.12.18", + "@types/uuid": "^9.0.1", + "@typescript-eslint/eslint-plugin": "^5.59.1", + "@typescript-eslint/parser": "^5.59.1", "codelyzer": "^6.0.2", - "eslint": "^8.33.0", + "eslint": "^8.39.0", "eslint-plugin-import": "2.27.5", - "eslint-plugin-jsdoc": "39.8.0", + "eslint-plugin-jsdoc": "41.1.2", "eslint-plugin-prefer-arrow": "1.2.3", "typescript": "~4.9.5" } @@ -110,12 +110,12 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1501.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1501.4.tgz", - "integrity": "sha512-PE0CqPaNzcz8yHEuJwqtKxYvXX9hgWWvC6hI2DWKtC+5WgJLAYJNEGofXQRc227Nj+YySEYUUo8Ja8SYl3lDxA==", + "version": "0.1502.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1502.6.tgz", + "integrity": "sha512-n4oJ9vzFWwabf+AfgqqevVzdJhNKNCav7ytefjD/Y01vkNwlXqWnHcvyyHCLkVibJ6WR8J9lK4t77j/HFlDvWQ==", "dev": true, "dependencies": { - "@angular-devkit/core": "15.1.4", + "@angular-devkit/core": "15.2.6", "rxjs": "6.6.7" }, "engines": { @@ -143,38 +143,39 @@ "dev": true }, "node_modules/@angular-devkit/build-angular": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-15.1.4.tgz", - "integrity": "sha512-+vubHYyQn8HJ+uJQndr8xFlX6C7y1kdnzTiKgx6QFvA5sd/IhXXzsnDd1wFer1lCrZ+1qgfhG9HI/RL3cBeKrA==", + "version": "15.2.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-15.2.6.tgz", + "integrity": "sha512-OmMcdXXUrAdZNxwxDE8SUx1FMcq9FyMnrSv1PmP9sHPBoxAdBVc/qNdGA9V7C5yHvWHGgzsx7ZK5TDuvifzS5g==", "dev": true, "dependencies": { "@ampproject/remapping": "2.2.0", - "@angular-devkit/architect": "0.1501.4", - "@angular-devkit/build-webpack": "0.1501.4", - "@angular-devkit/core": "15.1.4", + "@angular-devkit/architect": "0.1502.6", + "@angular-devkit/build-webpack": "0.1502.6", + "@angular-devkit/core": "15.2.6", "@babel/core": "7.20.12", - "@babel/generator": "7.20.7", + "@babel/generator": "7.20.14", "@babel/helper-annotate-as-pure": "7.18.6", + "@babel/helper-split-export-declaration": "7.18.6", "@babel/plugin-proposal-async-generator-functions": "7.20.7", "@babel/plugin-transform-async-to-generator": "7.20.7", "@babel/plugin-transform-runtime": "7.19.6", "@babel/preset-env": "7.20.2", - "@babel/runtime": "7.20.7", + "@babel/runtime": "7.20.13", "@babel/template": "7.20.7", "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "15.1.4", + "@ngtools/webpack": "15.2.6", "ansi-colors": "4.1.3", "autoprefixer": "10.4.13", "babel-loader": "9.1.2", "babel-plugin-istanbul": "6.1.1", - "browserslist": "4.21.4", + "browserslist": "4.21.5", "cacache": "17.0.4", "chokidar": "3.5.3", "copy-webpack-plugin": "11.0.0", "critters": "0.0.16", "css-loader": "6.7.3", - "esbuild-wasm": "0.16.17", - "glob": "8.0.3", + "esbuild-wasm": "0.17.8", + "glob": "8.1.0", "https-proxy-agent": "5.0.1", "inquirer": "8.2.4", "jsonc-parser": "3.2.0", @@ -183,26 +184,26 @@ "less-loader": "11.1.0", "license-webpack-plugin": "4.0.2", "loader-utils": "3.2.1", - "magic-string": "0.27.0", + "magic-string": "0.29.0", "mini-css-extract-plugin": "2.7.2", - "open": "8.4.0", + "open": "8.4.1", "ora": "5.4.1", - "parse5-html-rewriting-stream": "6.0.1", + "parse5-html-rewriting-stream": "7.0.0", "piscina": "3.2.0", "postcss": "8.4.21", "postcss-loader": "7.0.2", "resolve-url-loader": "5.0.0", "rxjs": "6.6.7", - "sass": "1.57.1", + "sass": "1.58.1", "sass-loader": "13.2.0", "semver": "7.3.8", "source-map-loader": "4.0.1", "source-map-support": "0.5.21", - "terser": "5.16.1", + "terser": "5.16.3", "text-table": "0.2.0", "tree-kill": "1.2.2", - "tslib": "2.4.1", - "webpack": "5.75.0", + "tslib": "2.5.0", + "webpack": "5.76.1", "webpack-dev-middleware": "6.0.1", "webpack-dev-server": "4.11.1", "webpack-merge": "5.8.0", @@ -214,7 +215,7 @@ "yarn": ">= 1.13.0" }, "optionalDependencies": { - "esbuild": "0.16.17" + "esbuild": "0.17.8" }, "peerDependencies": { "@angular/compiler-cli": "^15.0.0", @@ -300,9 +301,9 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -318,28 +319,10 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@angular-devkit/build-angular/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "node_modules/@angular-devkit/build-angular/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, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@angular-devkit/build-angular/node_modules/minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -366,19 +349,13 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, - "node_modules/@angular-devkit/build-angular/node_modules/tslib": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", - "dev": true - }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1501.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1501.4.tgz", - "integrity": "sha512-rJ7KTBDW0UHgVJjQ23qJfGun+pDX3ZG2z0OtsskdsOI62SAvW1cVLuS50ICTcWW6gtcDO0R/6Q1RLbaV1JHZ5A==", + "version": "0.1502.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1502.6.tgz", + "integrity": "sha512-X7XQ11QDz2Bs5qpJ3a5glIytvI+S74ORQxdzvT6a6KB8ayW0SgZEhTwD+GF7pa5My8draIaXBGzzQR1qmpWK5Q==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1501.4", + "@angular-devkit/architect": "0.1502.6", "rxjs": "6.6.7" }, "engines": { @@ -410,9 +387,9 @@ "dev": true }, "node_modules/@angular-devkit/core": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.1.4.tgz", - "integrity": "sha512-PW5MRmd9DHJR4FaXchwQtj9pXnsghSTnwRvfZeCRNYgU2sv0DKyTV+YTSJB+kNXnoPNG1Je6amDEkiXecpspXg==", + "version": "15.2.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.2.6.tgz", + "integrity": "sha512-YVTWZ+M+xNKdFX4EnY9QX49PZraawiaA0iTd2CUW8ZoTUvU7yOGMKZLSdz6aokTMRVfm0449wt6YL994ibOo1g==", "dev": true, "dependencies": { "ajv": "8.12.0", @@ -435,28 +412,6 @@ } } }, - "node_modules/@angular-devkit/core/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@angular-devkit/core/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, "node_modules/@angular-devkit/core/node_modules/rxjs": { "version": "6.6.7", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", @@ -476,14 +431,14 @@ "dev": true }, "node_modules/@angular-devkit/schematics": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-15.1.4.tgz", - "integrity": "sha512-jpddxo9Qd2yRQ1t9FLhAx5S+luz6HkyhDytq0LFKbxf9ikf1J4oy9riPBFl4pRmrNARWcHZ6GbD20/Ky8PjmXQ==", + "version": "15.2.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-15.2.6.tgz", + "integrity": "sha512-f7VgnAcok7AwR/DhX0ZWskB0rFBo/KsvtIUA2qZSrpKMf8eFiwu03dv/b2mI0vnf+1FBfIQzJvO0ww45zRp6dA==", "dev": true, "dependencies": { - "@angular-devkit/core": "15.1.4", + "@angular-devkit/core": "15.2.6", "jsonc-parser": "3.2.0", - "magic-string": "0.27.0", + "magic-string": "0.29.0", "ora": "5.4.1", "rxjs": "6.6.7" }, @@ -494,13 +449,13 @@ } }, "node_modules/@angular-devkit/schematics-cli": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics-cli/-/schematics-cli-15.1.4.tgz", - "integrity": "sha512-qkM5Mfs28jZzNcJnSM6RlyrKkYvzhQmWFTxBXnn15k5T4EnSs1gI6O054Xn7jo/senfwNNt7h2Mlz2OmBLo6+w==", + "version": "15.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics-cli/-/schematics-cli-15.2.5.tgz", + "integrity": "sha512-MOmdYMCT4Bbl8B9L4zDqbJwakYpECb0K9guERxUqMwpufi9GqOa/GNhIsbHcc4J8qn6ykG2y3BZQf8Q14/eRZQ==", "dev": true, "dependencies": { - "@angular-devkit/core": "15.1.4", - "@angular-devkit/schematics": "15.1.4", + "@angular-devkit/core": "15.2.5", + "@angular-devkit/schematics": "15.2.5", "ansi-colors": "4.1.3", "inquirer": "8.2.4", "symbol-observable": "4.0.0", @@ -515,24 +470,68 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular-devkit/schematics/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "node_modules/@angular-devkit/schematics/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==", + "node_modules/@angular-devkit/schematics-cli/node_modules/@angular-devkit/core": { + "version": "15.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.2.5.tgz", + "integrity": "sha512-ZfjEkAe2yYeekc3xjZ/U4pK9nb+w6BFwAEjou6mE8PWZH7iYskm0YCCXkmu+B+zViEcCLhAkJAxu9MwX4efd8g==", "dev": true, "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.0", + "rxjs": "6.6.7", + "source-map": "0.7.4" }, "engines": { - "node": ">=12" + "node": "^14.20.0 || ^16.13.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } } }, + "node_modules/@angular-devkit/schematics-cli/node_modules/@angular-devkit/schematics": { + "version": "15.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-15.2.5.tgz", + "integrity": "sha512-zm7chQRQtPXQzzSAvK/mbZ+RJ3eP7hlU53yyJ/i6kjWAh3Y5uiSHNYGmqhhAHFuzw4Jhb4OC2S9iycxrqmI8TA==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "15.2.5", + "jsonc-parser": "3.2.0", + "magic-string": "0.29.0", + "ora": "5.4.1", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "node_modules/@angular-devkit/schematics/node_modules/rxjs": { "version": "6.6.7", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", @@ -552,9 +551,9 @@ "dev": true }, "node_modules/@angular-eslint/builder": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-15.2.0.tgz", - "integrity": "sha512-5xnJub1G7+F9Ra75N90Ln9yn/KFzWnMIHfqDVRRDrlwgja1Zc9ZmqcazLWc/k12yzKyJoO3uwBSycyVwG2fYVg==", + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-15.2.1.tgz", + "integrity": "sha512-7x2DANebLRl997Mj4DhZrnz5+vnSjavGGveJ0mBuU7CEsL0ZYLftdRqL0e0HtU3ksseS7xpchD6OM08nkNgySw==", "dev": true, "peerDependencies": { "eslint": "^7.20.0 || ^8.0.0", @@ -562,19 +561,19 @@ } }, "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-15.2.0.tgz", - "integrity": "sha512-a0bfXxYyGoWJHrVQ4QER0HdRgselcTtJeyqiFPAxID2ZxF0IBGKLNTtugUTXekEmiLev8yGLX9TqAtthN57fEg==", + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-15.2.1.tgz", + "integrity": "sha512-LO7Am8eVCr7oh6a0VmKSL7K03CnQEQhFO7Wt/YtbfYOxVjrbwmYLwJn+wZPOT7A02t/BttOD/WXuDrOWtSMQ/Q==", "dev": true }, "node_modules/@angular-eslint/eslint-plugin": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-15.2.0.tgz", - "integrity": "sha512-yJGbmSUU0B0MFJ48ktpkqqEK+zv5k9iwlZSqEHtiQMKvDelfluovnEusihel7uPRo1c1iVlbSgXfGpxpUCfocA==", + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-15.2.1.tgz", + "integrity": "sha512-OM7b1kS4E4CkXjkaWN+lEzawh4VxY6l7FO1Cuk4s7iv3/YpZG3rJxIZBqnFLTixwrBuqw8y4FNBzF3eDgmFAUw==", "dev": true, "dependencies": { - "@angular-eslint/utils": "15.2.0", - "@typescript-eslint/utils": "5.48.1" + "@angular-eslint/utils": "15.2.1", + "@typescript-eslint/utils": "5.48.2" }, "peerDependencies": { "eslint": "^7.20.0 || ^8.0.0", @@ -582,15 +581,15 @@ } }, "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-15.2.0.tgz", - "integrity": "sha512-aL3czf5Jpv29rKN3UG20tQepX1+V0d6xc0g+1l0zPHZJYjVd6Oy0nIxWiGfl4yanaXiVpmxiV4vUcLlqqaFwbw==", + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-15.2.1.tgz", + "integrity": "sha512-IeiSLk6YxapFdH2z5o/O3R7VwtBd2T6fWmhLFPwDYMDknrwegnOjwswCdBplOccpUp0wqlCeGUx7LTsuzwaz7w==", "dev": true, "dependencies": { - "@angular-eslint/bundled-angular-compiler": "15.2.0", - "@angular-eslint/utils": "15.2.0", - "@typescript-eslint/type-utils": "5.48.1", - "@typescript-eslint/utils": "5.48.1", + "@angular-eslint/bundled-angular-compiler": "15.2.1", + "@angular-eslint/utils": "15.2.1", + "@typescript-eslint/type-utils": "5.48.2", + "@typescript-eslint/utils": "5.48.2", "aria-query": "5.1.3", "axobject-query": "3.1.1" }, @@ -600,13 +599,13 @@ } }, "node_modules/@angular-eslint/eslint-plugin-template/node_modules/@typescript-eslint/scope-manager": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", - "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz", + "integrity": "sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1" + "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/visitor-keys": "5.48.2" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -617,13 +616,13 @@ } }, "node_modules/@angular-eslint/eslint-plugin-template/node_modules/@typescript-eslint/type-utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz", - "integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.2.tgz", + "integrity": "sha512-QVWx7J5sPMRiOMJp5dYshPxABRoZV1xbRirqSk8yuIIsu0nvMTZesKErEA3Oix1k+uvsk8Cs8TGJ6kQ0ndAcew==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.48.1", - "@typescript-eslint/utils": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.2", + "@typescript-eslint/utils": "5.48.2", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -644,9 +643,9 @@ } }, "node_modules/@angular-eslint/eslint-plugin-template/node_modules/@typescript-eslint/types": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", - "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.2.tgz", + "integrity": "sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -657,13 +656,13 @@ } }, "node_modules/@angular-eslint/eslint-plugin-template/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", - "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz", + "integrity": "sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1", + "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/visitor-keys": "5.48.2", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -684,16 +683,16 @@ } }, "node_modules/@angular-eslint/eslint-plugin-template/node_modules/@typescript-eslint/utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", - "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.2.tgz", + "integrity": "sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/scope-manager": "5.48.2", + "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/typescript-estree": "5.48.2", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -710,12 +709,12 @@ } }, "node_modules/@angular-eslint/eslint-plugin-template/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", - "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz", + "integrity": "sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/types": "5.48.2", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -727,13 +726,13 @@ } }, "node_modules/@angular-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", - "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz", + "integrity": "sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1" + "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/visitor-keys": "5.48.2" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -744,9 +743,9 @@ } }, "node_modules/@angular-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", - "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.2.tgz", + "integrity": "sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -757,13 +756,13 @@ } }, "node_modules/@angular-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", - "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz", + "integrity": "sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1", + "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/visitor-keys": "5.48.2", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -784,16 +783,16 @@ } }, "node_modules/@angular-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", - "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.2.tgz", + "integrity": "sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/scope-manager": "5.48.2", + "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/typescript-estree": "5.48.2", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -810,12 +809,12 @@ } }, "node_modules/@angular-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", - "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz", + "integrity": "sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/types": "5.48.2", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -827,13 +826,13 @@ } }, "node_modules/@angular-eslint/schematics": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-15.2.0.tgz", - "integrity": "sha512-N9tuVu3vL47beppTsV9wAF+v6M9trbJnuNWYQGGsqA3mtCAkFUvJuHyWcXNPdSCNv/cJtR1OOJ7Y922uB5JPJQ==", + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-15.2.1.tgz", + "integrity": "sha512-0ZfBCejHWIcgy3J5kFs9sS/jqi8i5AptxggOwFySOlCLJ+CzNrktjD4jff1Zy8K/VLzY0Ci0BSZXvgWfP0k9Rg==", "dev": true, "dependencies": { - "@angular-eslint/eslint-plugin": "15.2.0", - "@angular-eslint/eslint-plugin-template": "15.2.0", + "@angular-eslint/eslint-plugin": "15.2.1", + "@angular-eslint/eslint-plugin-template": "15.2.1", "ignore": "5.2.4", "strip-json-comments": "3.1.1", "tmp": "0.2.1" @@ -843,12 +842,12 @@ } }, "node_modules/@angular-eslint/template-parser": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-15.2.0.tgz", - "integrity": "sha512-xnnxPfV/G0Ll3B0HGrF1ucsc/DHmNE6UhhmWxYPTERq0McbZGRiATa66hCoOZ/Rdylun4ogBfsRKAG8XxEvlvw==", + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-15.2.1.tgz", + "integrity": "sha512-ViCi79gC2aKJecmYLkOT+QlT5WMRNXeYz0Dr9Pr8qXzIbY0oAWE7nOT5jkXwQ9oUk+ybtGCWHma5JVJWVJsIog==", "dev": true, "dependencies": { - "@angular-eslint/bundled-angular-compiler": "15.2.0", + "@angular-eslint/bundled-angular-compiler": "15.2.1", "eslint-scope": "^7.0.0" }, "peerDependencies": { @@ -879,13 +878,13 @@ } }, "node_modules/@angular-eslint/utils": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-15.2.0.tgz", - "integrity": "sha512-qfTOKQ+aef/YER679/xN1E+FkZKMd0I73P6txUZAb9k2G1ACVktG+wOUIBfgjIlUVq9Q01AV91LGOWcd+rdEEA==", + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-15.2.1.tgz", + "integrity": "sha512-++FneAJHxJqcSu0igVN6uOkSoHxlzgLoMBswuovYJy3UKwm33/T6WFku8++753Ca/JucIoR1gdUfO7SoSspMDg==", "dev": true, "dependencies": { - "@angular-eslint/bundled-angular-compiler": "15.2.0", - "@typescript-eslint/utils": "5.48.1" + "@angular-eslint/bundled-angular-compiler": "15.2.1", + "@typescript-eslint/utils": "5.48.2" }, "peerDependencies": { "eslint": "^7.20.0 || ^8.0.0", @@ -893,13 +892,13 @@ } }, "node_modules/@angular-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", - "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz", + "integrity": "sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1" + "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/visitor-keys": "5.48.2" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -910,9 +909,9 @@ } }, "node_modules/@angular-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", - "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.2.tgz", + "integrity": "sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -923,13 +922,13 @@ } }, "node_modules/@angular-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", - "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz", + "integrity": "sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1", + "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/visitor-keys": "5.48.2", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -950,16 +949,16 @@ } }, "node_modules/@angular-eslint/utils/node_modules/@typescript-eslint/utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", - "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.2.tgz", + "integrity": "sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/scope-manager": "5.48.2", + "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/typescript-estree": "5.48.2", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -976,12 +975,12 @@ } }, "node_modules/@angular-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", - "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz", + "integrity": "sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/types": "5.48.2", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -993,9 +992,9 @@ } }, "node_modules/@angular/animations": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-15.1.3.tgz", - "integrity": "sha512-qvOLYx8XWolwFWwYoPjt+jQLDFaCQEPjb26iczewiqd+xcAdYn4Tl10NCJtOsx+YfTdpWtKRzvxYr1JxnGQTdw==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-15.2.8.tgz", + "integrity": "sha512-I3xh8EASQ04s3qXQYpIORI0jFiFmvBQERBqS70TieTCIML7banOf9R3K7sAWB9frG5J0CEUwr+wtF47DCs/7eQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -1003,13 +1002,13 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/core": "15.1.3" + "@angular/core": "15.2.8" } }, "node_modules/@angular/cdk": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-15.1.3.tgz", - "integrity": "sha512-FRb1ZirybQGVlRx34vsnkIyy4WHJlrRg2mwPeJ90b0DzIWuIZIiPYxxR2bAi/Si1IjnK8YBdacd5DXPdrW1jyw==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-15.2.8.tgz", + "integrity": "sha512-jiCoxfBFMH29IZIiPmVUzIWetfUNpMIvC20xYVF8RMM819vPogoObzwK4DN/sXcp/6oVbBzZFaYdijhhIt9soQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -1023,15 +1022,15 @@ } }, "node_modules/@angular/cli": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-15.1.4.tgz", - "integrity": "sha512-ebZiI4arb9wtOUMmTyUvjgDovmwpY8hmGLbkKZiEmAX8+2gbl4e97M+zd0SICZDU8bu5VcpoP6Q3Qb6vVjab9A==", + "version": "15.2.6", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-15.2.6.tgz", + "integrity": "sha512-wNkQ/qCVbd4pERaGVagKJPifEvjRNY5otwsd4iRVubY/XOcIHcYChUThZwgQdVfNAImfJPMZNrhbGxejuWLA9w==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1501.4", - "@angular-devkit/core": "15.1.4", - "@angular-devkit/schematics": "15.1.4", - "@schematics/angular": "15.1.4", + "@angular-devkit/architect": "0.1502.6", + "@angular-devkit/core": "15.2.6", + "@angular-devkit/schematics": "15.2.6", + "@schematics/angular": "15.2.6", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.3", "ini": "3.0.1", @@ -1039,9 +1038,9 @@ "jsonc-parser": "3.2.0", "npm-package-arg": "10.1.0", "npm-pick-manifest": "8.0.1", - "open": "8.4.0", + "open": "8.4.1", "ora": "5.4.1", - "pacote": "15.0.8", + "pacote": "15.1.0", "resolve": "1.22.1", "semver": "7.3.8", "symbol-observable": "4.0.0", @@ -1056,16 +1055,10 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular/cli/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, "node_modules/@angular/common": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-15.1.3.tgz", - "integrity": "sha512-UjC0COaOcU1g/ODBBetv/BpdaFC/Y32DvXJ9qbD7kkwLwoqCjGOLDvtP36r9zEzPmH7oNkgNGDkgR3gyb82s5A==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-15.2.8.tgz", + "integrity": "sha512-yLDQihiRcVl38HrWMPbqgzOaSUw85AQH5BsGdjbS6BpoBQj3EXOpccCMFsuxOKxPG4toatgawNqrEnK0Jpv9Mw==", "dependencies": { "tslib": "^2.3.0" }, @@ -1073,14 +1066,14 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/core": "15.1.3", + "@angular/core": "15.2.8", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-15.1.3.tgz", - "integrity": "sha512-CxEpm5Z3EpjeGNoWKtcHOrf2IQTSckpAEFwsRrADP2nqcXXYp/IjIHi+PUTjLhjrOEbukH9zreHsL5BoIQhgUQ==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-15.2.8.tgz", + "integrity": "sha512-+dvspIDvuGoYqdL7r/3o9ojkR3fH1zevgC0ISJivcIrMi+WcJ0FV2JmJdnm8V52oNsHy+sMF9eEZGEbCbACE/A==", "dependencies": { "tslib": "^2.3.0" }, @@ -1088,7 +1081,7 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/core": "15.1.3" + "@angular/core": "15.2.8" }, "peerDependenciesMeta": { "@angular/core": { @@ -1097,9 +1090,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-15.1.3.tgz", - "integrity": "sha512-z5bGdQQcStXWPpb5vztqqUOET+vxw+GUFtfktYxV40kE2d1zHLZh93AGEnM1NnBaOz+9NZrX+dWoEyWmv/T2LQ==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-15.2.8.tgz", + "integrity": "sha512-fFxaDlbILo0t2t662qA0cjgn+kWItGlc1tFYKU6X7bvYb3t2e0cd9FzrFPLXUQVboGis83ULcJ2zkDxScnuPuQ==", "dev": true, "dependencies": { "@babel/core": "7.19.3", @@ -1122,7 +1115,7 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/compiler": "15.1.3", + "@angular/compiler": "15.2.8", "typescript": ">=4.8.2 <5.0" } }, @@ -1139,9 +1132,9 @@ } }, "node_modules/@angular/core": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-15.1.3.tgz", - "integrity": "sha512-rad9OYnaoRnXBztOBXsiD59VvOZTpsvO3sWx6KndytQFceFfkL722bF2l2LARN+R3IWDOwRap46HOtc0O0N+sw==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-15.2.8.tgz", + "integrity": "sha512-NDs+g4uM4EhyCvluf8a0YBCFXsDAEfCMHOD5cS00Bl+liTQ7JwtmepkWXMyjLB92irC9JaR79kdy4BoIKOh8WA==", "dependencies": { "tslib": "^2.3.0" }, @@ -1150,13 +1143,13 @@ }, "peerDependencies": { "rxjs": "^6.5.3 || ^7.4.0", - "zone.js": "~0.11.4 || ~0.12.0" + "zone.js": "~0.11.4 || ~0.12.0 || ~0.13.0" } }, "node_modules/@angular/forms": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-15.1.3.tgz", - "integrity": "sha512-vEgiZBk3rGGp4tBQHl9EaspEjYh70lkz6/zYreObTbMdCB54bkbl+jn+JbQyFj+TPfukiumtiG3/477vKzYnSg==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-15.2.8.tgz", + "integrity": "sha512-VyevVj20DdQWjAQUyiFTe+DAzqG9GqfAOWn376Y/lhPcwxAojXePTGNgtQud566/urDrNrP5haaLD6O36/3n+w==", "dependencies": { "tslib": "^2.3.0" }, @@ -1164,25 +1157,25 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/common": "15.1.3", - "@angular/core": "15.1.3", - "@angular/platform-browser": "15.1.3", + "@angular/common": "15.2.8", + "@angular/core": "15.2.8", + "@angular/platform-browser": "15.2.8", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/language-service": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-15.1.3.tgz", - "integrity": "sha512-Sxp5nXQ/VR7ESLL35iRkHun8R4w3Zp+d5KmkCmgw67zjDgAJhosrsoqIUbGWYFMFJ5YUA4IHhQUwY8snyUDwug==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-15.2.8.tgz", + "integrity": "sha512-3wlaJrpxe8ZLe7ZGIOs/Z++kgJMOHZCUvdXLyp/4t1ejULgUgW9yi7nGsemWnSzsUCjf7595BP1Cp1gA/J/1QQ==", "dev": true, "engines": { "node": "^14.20.0 || ^16.13.0 || >=18.10.0" } }, "node_modules/@angular/material": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-15.1.3.tgz", - "integrity": "sha512-Jj17GwvL1PsIVPiRBRQQRRvTQb5TlmMP+49JgIWTSTF03G7F9guoYapoYzuufK7dWA3Ga0KzDPKfjUmcnBg+Fw==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-15.2.8.tgz", + "integrity": "sha512-bk0dv8PSJGFDgAv3CU3+jfvnOO0ah/L9JUyvw73kjiKezgjW/O8Lgq/dwkDTQ1dF3zCF+JWNqhEJmgi0GVW/cQ==", "dependencies": { "@material/animation": "15.0.0-canary.684e33d25.0", "@material/auto-init": "15.0.0-canary.684e33d25.0", @@ -1235,7 +1228,7 @@ }, "peerDependencies": { "@angular/animations": "^15.0.0 || ^16.0.0", - "@angular/cdk": "15.1.3", + "@angular/cdk": "15.2.8", "@angular/common": "^15.0.0 || ^16.0.0", "@angular/core": "^15.0.0 || ^16.0.0", "@angular/forms": "^15.0.0 || ^16.0.0", @@ -1244,9 +1237,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-15.1.3.tgz", - "integrity": "sha512-WJBN3klssfcRGKY2L2DIpNGbaMQfi2X1le1ZXQAnsfECQ/pua+lFstJUT+RP+Bx4X8icuDggKkS/JPOiBhxARw==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-15.2.8.tgz", + "integrity": "sha512-8sKFUld54inj0FnQ1ydhFxnDgsbbf43W9FALye/5uEtLgwwE/ZvkNYMaQ7hq1JPuQRMDj3gJkFqaLeFjplpHDA==", "dependencies": { "tslib": "^2.3.0" }, @@ -1254,9 +1247,9 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/animations": "15.1.3", - "@angular/common": "15.1.3", - "@angular/core": "15.1.3" + "@angular/animations": "15.2.8", + "@angular/common": "15.2.8", + "@angular/core": "15.2.8" }, "peerDependenciesMeta": { "@angular/animations": { @@ -1265,9 +1258,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-15.1.3.tgz", - "integrity": "sha512-lUfHmO+x3goSL1KnlAbekieKpak2KVGcOcAzOVOIMFt1SyWPBHq0NyyPOH2PUAnjPRbvCLEs2casjFggk0JzsQ==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-15.2.8.tgz", + "integrity": "sha512-75HyoZNibA3u/FvdK4Aw5KMzUmS/nDk5N8s7gfM09fe1resSPgFiW8JJEkr1xiUdA2WtSRbHs34y5rHLDe7n1Q==", "dependencies": { "tslib": "^2.3.0" }, @@ -1275,16 +1268,16 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/common": "15.1.3", - "@angular/compiler": "15.1.3", - "@angular/core": "15.1.3", - "@angular/platform-browser": "15.1.3" + "@angular/common": "15.2.8", + "@angular/compiler": "15.2.8", + "@angular/core": "15.2.8", + "@angular/platform-browser": "15.2.8" } }, "node_modules/@angular/platform-server": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-15.1.3.tgz", - "integrity": "sha512-FOqCcsW1dCaT8xB1zJZezlHSZxsfnnWflapauWszitCNmqav27jAXsJdQDcQN/j1KwsrvDkL7zaPksmphqebvg==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-15.2.8.tgz", + "integrity": "sha512-YfPAoK2zp3mTO6ubDe0C9Vzg9Vi4BxXkxHCPG0k8IM3Ivjedkv5PZ+vC0a+GjV2xR/0YqiVE3FCwXk4X6m6LuQ==", "dependencies": { "domino": "^2.1.2", "tslib": "^2.3.0", @@ -1294,18 +1287,18 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/animations": "15.1.3", - "@angular/common": "15.1.3", - "@angular/compiler": "15.1.3", - "@angular/core": "15.1.3", - "@angular/platform-browser": "15.1.3", - "@angular/platform-browser-dynamic": "15.1.3" + "@angular/animations": "15.2.8", + "@angular/common": "15.2.8", + "@angular/compiler": "15.2.8", + "@angular/core": "15.2.8", + "@angular/platform-browser": "15.2.8", + "@angular/platform-browser-dynamic": "15.2.8" } }, "node_modules/@angular/router": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-15.1.3.tgz", - "integrity": "sha512-GxvGZO0N7LIoaTV2EZ082kqb9asJl2rWe0kNsUQwu9IQAODOCCTQu2USg63J6hEOcKPJSZzbxdXLaxlpqKeC4A==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-15.2.8.tgz", + "integrity": "sha512-C62QBEeJSBTNTrQHZiklPrxwJwuENoZzWX22MMJ7dxl+7VjRgnmj8J7mcX9fLjHlL+mC3RvesMlX7sGZRQV1cg==", "dependencies": { "tslib": "^2.3.0" }, @@ -1313,16 +1306,16 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/common": "15.1.3", - "@angular/core": "15.1.3", - "@angular/platform-browser": "15.1.3", + "@angular/common": "15.2.8", + "@angular/core": "15.2.8", + "@angular/platform-browser": "15.2.8", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/service-worker": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-15.1.3.tgz", - "integrity": "sha512-eQR8dOJXml87FCI3O53vOItAJPErxwNbRluczyhIg/+ExVzfW9750FHWIQs1KWoFf4XNy8+0pUygyGMFfuMkYg==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-15.2.8.tgz", + "integrity": "sha512-iD3qsqN/N2014uCuCka77pu0tqPPsLcP9rUZgAJEM01o/A/ez+E3TmWW2PYvSq2zLZQnZZ40a7dWonIAclJq3Q==", "dependencies": { "tslib": "^2.3.0" }, @@ -1333,14 +1326,14 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/common": "15.1.3", - "@angular/core": "15.1.3" + "@angular/common": "15.2.8", + "@angular/core": "15.2.8" } }, "node_modules/@angular/youtube-player": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/youtube-player/-/youtube-player-15.1.3.tgz", - "integrity": "sha512-sJH1RfDrfPDaLKaGcZdegW4JYXgZteDvE092c7o+iHRZGitgKn+XWb3Vy+eYLh5xpuTFqlLxWKhJ1/kgJVG93w==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/youtube-player/-/youtube-player-15.2.8.tgz", + "integrity": "sha512-yo5C48spbYF3S8iMg7XCgXEapA2azOhUqiEsFv38DMCKcd8UyvUEtoNaW85J3JTsb/oB66hjtxcF8xyZbWdaBQ==", "dependencies": { "@types/youtube": "^0.0.42", "tslib": "^2.3.0" @@ -1483,632 +1476,618 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@aws-sdk/abort-controller": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.266.1.tgz", - "integrity": "sha512-6tG6dAgMMKh86U2kgo58J6pyC2pSEAtm1bXnhYOuuXBjFgieNvikwjoj//zzciudmp1qTu5Wh99u8LBLmYofFg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.310.0.tgz", + "integrity": "sha512-v1zrRQxDLA1MdPim159Vx/CPHqsB4uybSxRi1CnfHO5ZjHryx3a5htW2gdGAykVCul40+yJXvfpufMrELVxH+g==", "dependencies": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/chunked-blob-reader": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/chunked-blob-reader/-/chunked-blob-reader-3.188.0.tgz", - "integrity": "sha512-zkPRFZZPL3eH+kH86LDYYXImiClA1/sW60zYOjse9Pgka+eDJlvBN6hcYxwDEKjcwATYiSRR1aVQHcfCinlGXg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/chunked-blob-reader/-/chunked-blob-reader-3.310.0.tgz", + "integrity": "sha512-CrJS3exo4mWaLnWxfCH+w88Ou0IcAZSIkk4QbmxiHl/5Dq705OLoxf4385MVyExpqpeVJYOYQ2WaD8i/pQZ2fg==", "dependencies": { - "tslib": "^2.3.1" - } - }, - "node_modules/@aws-sdk/chunked-blob-reader-native": { - "version": "3.208.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/chunked-blob-reader-native/-/chunked-blob-reader-native-3.208.0.tgz", - "integrity": "sha512-JeOZ95PW+fJ6bbuqPySYqLqHk1n4+4ueEEraJsiUrPBV0S1ZtyvOGHcnGztKUjr2PYNaiexmpWuvUve9K12HRA==", - "dependencies": { - "@aws-sdk/util-base64": "3.208.0", - "tslib": "^2.3.1" + "tslib": "^2.5.0" } }, "node_modules/@aws-sdk/client-s3": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.266.1.tgz", - "integrity": "sha512-W6dI7WJD30zfbM46hn7aDdpgq1zq0k4kjSzpW+2VQ+MqYf7qXXuE4FKcDA5z2N7M86TWn3qiF1FcyTH0V+5tAw==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.319.0.tgz", + "integrity": "sha512-/XzElEO4iZTBgvrcWq20sxKLvhRetjT1gOPRF4Ra2iSCbeVIT/feYdEaSSgMsaiqrREywBc+59NiOyxImWTaOA==", "dependencies": { "@aws-crypto/sha1-browser": "3.0.0", "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sts": "3.266.1", - "@aws-sdk/config-resolver": "3.266.1", - "@aws-sdk/credential-provider-node": "3.266.1", - "@aws-sdk/eventstream-serde-browser": "3.266.1", - "@aws-sdk/eventstream-serde-config-resolver": "3.266.1", - "@aws-sdk/eventstream-serde-node": "3.266.1", - "@aws-sdk/fetch-http-handler": "3.266.1", - "@aws-sdk/hash-blob-browser": "3.266.1", - "@aws-sdk/hash-node": "3.266.1", - "@aws-sdk/hash-stream-node": "3.266.1", - "@aws-sdk/invalid-dependency": "3.266.1", - "@aws-sdk/md5-js": "3.266.1", - "@aws-sdk/middleware-bucket-endpoint": "3.266.1", - "@aws-sdk/middleware-content-length": "3.266.1", - "@aws-sdk/middleware-endpoint": "3.266.1", - "@aws-sdk/middleware-expect-continue": "3.266.1", - "@aws-sdk/middleware-flexible-checksums": "3.266.1", - "@aws-sdk/middleware-host-header": "3.266.1", - "@aws-sdk/middleware-location-constraint": "3.266.1", - "@aws-sdk/middleware-logger": "3.266.1", - "@aws-sdk/middleware-recursion-detection": "3.266.1", - "@aws-sdk/middleware-retry": "3.266.1", - "@aws-sdk/middleware-sdk-s3": "3.266.1", - "@aws-sdk/middleware-serde": "3.266.1", - "@aws-sdk/middleware-signing": "3.266.1", - "@aws-sdk/middleware-ssec": "3.266.1", - "@aws-sdk/middleware-stack": "3.266.1", - "@aws-sdk/middleware-user-agent": "3.266.1", - "@aws-sdk/node-config-provider": "3.266.1", - "@aws-sdk/node-http-handler": "3.266.1", - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/signature-v4-multi-region": "3.266.1", - "@aws-sdk/smithy-client": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/url-parser": "3.266.1", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.266.1", - "@aws-sdk/util-defaults-mode-node": "3.266.1", - "@aws-sdk/util-endpoints": "3.266.1", - "@aws-sdk/util-retry": "3.266.1", - "@aws-sdk/util-stream-browser": "3.266.1", - "@aws-sdk/util-stream-node": "3.266.1", - "@aws-sdk/util-user-agent-browser": "3.266.1", - "@aws-sdk/util-user-agent-node": "3.266.1", - "@aws-sdk/util-utf8": "3.254.0", - "@aws-sdk/util-waiter": "3.266.1", - "@aws-sdk/xml-builder": "3.201.0", - "fast-xml-parser": "4.0.11", - "tslib": "^2.3.1" + "@aws-sdk/client-sts": "3.319.0", + "@aws-sdk/config-resolver": "3.310.0", + "@aws-sdk/credential-provider-node": "3.319.0", + "@aws-sdk/eventstream-serde-browser": "3.310.0", + "@aws-sdk/eventstream-serde-config-resolver": "3.310.0", + "@aws-sdk/eventstream-serde-node": "3.310.0", + "@aws-sdk/fetch-http-handler": "3.310.0", + "@aws-sdk/hash-blob-browser": "3.310.0", + "@aws-sdk/hash-node": "3.310.0", + "@aws-sdk/hash-stream-node": "3.310.0", + "@aws-sdk/invalid-dependency": "3.310.0", + "@aws-sdk/md5-js": "3.310.0", + "@aws-sdk/middleware-bucket-endpoint": "3.310.0", + "@aws-sdk/middleware-content-length": "3.310.0", + "@aws-sdk/middleware-endpoint": "3.310.0", + "@aws-sdk/middleware-expect-continue": "3.310.0", + "@aws-sdk/middleware-flexible-checksums": "3.310.0", + "@aws-sdk/middleware-host-header": "3.310.0", + "@aws-sdk/middleware-location-constraint": "3.310.0", + "@aws-sdk/middleware-logger": "3.310.0", + "@aws-sdk/middleware-recursion-detection": "3.310.0", + "@aws-sdk/middleware-retry": "3.310.0", + "@aws-sdk/middleware-sdk-s3": "3.310.0", + "@aws-sdk/middleware-serde": "3.310.0", + "@aws-sdk/middleware-signing": "3.310.0", + "@aws-sdk/middleware-ssec": "3.310.0", + "@aws-sdk/middleware-stack": "3.310.0", + "@aws-sdk/middleware-user-agent": "3.319.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/node-http-handler": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/signature-v4-multi-region": "3.310.0", + "@aws-sdk/smithy-client": "3.316.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", + "@aws-sdk/util-body-length-browser": "3.310.0", + "@aws-sdk/util-body-length-node": "3.310.0", + "@aws-sdk/util-defaults-mode-browser": "3.316.0", + "@aws-sdk/util-defaults-mode-node": "3.316.0", + "@aws-sdk/util-endpoints": "3.319.0", + "@aws-sdk/util-retry": "3.310.0", + "@aws-sdk/util-stream-browser": "3.310.0", + "@aws-sdk/util-stream-node": "3.310.0", + "@aws-sdk/util-user-agent-browser": "3.310.0", + "@aws-sdk/util-user-agent-node": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", + "@aws-sdk/util-waiter": "3.310.0", + "@aws-sdk/xml-builder": "3.310.0", + "fast-xml-parser": "4.1.2", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/client-sso": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.266.1.tgz", - "integrity": "sha512-mgrRfNSa7sJyBgAuMvRE5W2izHYl1n0tpxjLZ8rP+AoOp0GrZLpuj9T2XhmVwyR4ibVBNFKdr8nUHWekF4HA+w==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.319.0.tgz", + "integrity": "sha512-g46KgAjRiYBS8Oi85DPwSAQpt+Hgmw/YFgGVwZqMfTL70KNJwLFKRa5D9UocQd7t7OjPRdKF7g0Gp5peyAK9dw==", "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/config-resolver": "3.266.1", - "@aws-sdk/fetch-http-handler": "3.266.1", - "@aws-sdk/hash-node": "3.266.1", - "@aws-sdk/invalid-dependency": "3.266.1", - "@aws-sdk/middleware-content-length": "3.266.1", - "@aws-sdk/middleware-endpoint": "3.266.1", - "@aws-sdk/middleware-host-header": "3.266.1", - "@aws-sdk/middleware-logger": "3.266.1", - "@aws-sdk/middleware-recursion-detection": "3.266.1", - "@aws-sdk/middleware-retry": "3.266.1", - "@aws-sdk/middleware-serde": "3.266.1", - "@aws-sdk/middleware-stack": "3.266.1", - "@aws-sdk/middleware-user-agent": "3.266.1", - "@aws-sdk/node-config-provider": "3.266.1", - "@aws-sdk/node-http-handler": "3.266.1", - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/smithy-client": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/url-parser": "3.266.1", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.266.1", - "@aws-sdk/util-defaults-mode-node": "3.266.1", - "@aws-sdk/util-endpoints": "3.266.1", - "@aws-sdk/util-retry": "3.266.1", - "@aws-sdk/util-user-agent-browser": "3.266.1", - "@aws-sdk/util-user-agent-node": "3.266.1", - "@aws-sdk/util-utf8": "3.254.0", - "tslib": "^2.3.1" + "@aws-sdk/config-resolver": "3.310.0", + "@aws-sdk/fetch-http-handler": "3.310.0", + "@aws-sdk/hash-node": "3.310.0", + "@aws-sdk/invalid-dependency": "3.310.0", + "@aws-sdk/middleware-content-length": "3.310.0", + "@aws-sdk/middleware-endpoint": "3.310.0", + "@aws-sdk/middleware-host-header": "3.310.0", + "@aws-sdk/middleware-logger": "3.310.0", + "@aws-sdk/middleware-recursion-detection": "3.310.0", + "@aws-sdk/middleware-retry": "3.310.0", + "@aws-sdk/middleware-serde": "3.310.0", + "@aws-sdk/middleware-stack": "3.310.0", + "@aws-sdk/middleware-user-agent": "3.319.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/node-http-handler": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/smithy-client": "3.316.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", + "@aws-sdk/util-body-length-browser": "3.310.0", + "@aws-sdk/util-body-length-node": "3.310.0", + "@aws-sdk/util-defaults-mode-browser": "3.316.0", + "@aws-sdk/util-defaults-mode-node": "3.316.0", + "@aws-sdk/util-endpoints": "3.319.0", + "@aws-sdk/util-retry": "3.310.0", + "@aws-sdk/util-user-agent-browser": "3.310.0", + "@aws-sdk/util-user-agent-node": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.266.1.tgz", - "integrity": "sha512-eErpowPr6etcZH25v8JfJNdSPr+jet98cFWhsCN8GSxVNkyZci6aZnx6pBsTQCQn7L/zx8i4QZuOo5LYXdzF6A==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.319.0.tgz", + "integrity": "sha512-GJBgT/tephRZY3oTbDBMv+G9taoqKUIvGPn+7shmzz2P1SerutsRSfKfDXV+VptPNRoGmjjCLPmWjMFYbFKILQ==", "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/config-resolver": "3.266.1", - "@aws-sdk/fetch-http-handler": "3.266.1", - "@aws-sdk/hash-node": "3.266.1", - "@aws-sdk/invalid-dependency": "3.266.1", - "@aws-sdk/middleware-content-length": "3.266.1", - "@aws-sdk/middleware-endpoint": "3.266.1", - "@aws-sdk/middleware-host-header": "3.266.1", - "@aws-sdk/middleware-logger": "3.266.1", - "@aws-sdk/middleware-recursion-detection": "3.266.1", - "@aws-sdk/middleware-retry": "3.266.1", - "@aws-sdk/middleware-serde": "3.266.1", - "@aws-sdk/middleware-stack": "3.266.1", - "@aws-sdk/middleware-user-agent": "3.266.1", - "@aws-sdk/node-config-provider": "3.266.1", - "@aws-sdk/node-http-handler": "3.266.1", - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/smithy-client": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/url-parser": "3.266.1", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.266.1", - "@aws-sdk/util-defaults-mode-node": "3.266.1", - "@aws-sdk/util-endpoints": "3.266.1", - "@aws-sdk/util-retry": "3.266.1", - "@aws-sdk/util-user-agent-browser": "3.266.1", - "@aws-sdk/util-user-agent-node": "3.266.1", - "@aws-sdk/util-utf8": "3.254.0", - "tslib": "^2.3.1" + "@aws-sdk/config-resolver": "3.310.0", + "@aws-sdk/fetch-http-handler": "3.310.0", + "@aws-sdk/hash-node": "3.310.0", + "@aws-sdk/invalid-dependency": "3.310.0", + "@aws-sdk/middleware-content-length": "3.310.0", + "@aws-sdk/middleware-endpoint": "3.310.0", + "@aws-sdk/middleware-host-header": "3.310.0", + "@aws-sdk/middleware-logger": "3.310.0", + "@aws-sdk/middleware-recursion-detection": "3.310.0", + "@aws-sdk/middleware-retry": "3.310.0", + "@aws-sdk/middleware-serde": "3.310.0", + "@aws-sdk/middleware-stack": "3.310.0", + "@aws-sdk/middleware-user-agent": "3.319.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/node-http-handler": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/smithy-client": "3.316.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", + "@aws-sdk/util-body-length-browser": "3.310.0", + "@aws-sdk/util-body-length-node": "3.310.0", + "@aws-sdk/util-defaults-mode-browser": "3.316.0", + "@aws-sdk/util-defaults-mode-node": "3.316.0", + "@aws-sdk/util-endpoints": "3.319.0", + "@aws-sdk/util-retry": "3.310.0", + "@aws-sdk/util-user-agent-browser": "3.310.0", + "@aws-sdk/util-user-agent-node": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/client-sts": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.266.1.tgz", - "integrity": "sha512-P1hIyJkzojIG5NHuW2u/oae36KUvTB2q4nSIWuU4BrUPDeBoHg+5+zRRavtfK88aLRohwYDumRdLegT6sQNt0g==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.319.0.tgz", + "integrity": "sha512-PRGGKCSKtyM3x629J9j4DMsH1cQT8UGW+R67u9Q5HrMK05gfjpmg+X1DQ3pgve4D8MI4R/Cm3NkYl2eUTbQHQg==", "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/config-resolver": "3.266.1", - "@aws-sdk/credential-provider-node": "3.266.1", - "@aws-sdk/fetch-http-handler": "3.266.1", - "@aws-sdk/hash-node": "3.266.1", - "@aws-sdk/invalid-dependency": "3.266.1", - "@aws-sdk/middleware-content-length": "3.266.1", - "@aws-sdk/middleware-endpoint": "3.266.1", - "@aws-sdk/middleware-host-header": "3.266.1", - "@aws-sdk/middleware-logger": "3.266.1", - "@aws-sdk/middleware-recursion-detection": "3.266.1", - "@aws-sdk/middleware-retry": "3.266.1", - "@aws-sdk/middleware-sdk-sts": "3.266.1", - "@aws-sdk/middleware-serde": "3.266.1", - "@aws-sdk/middleware-signing": "3.266.1", - "@aws-sdk/middleware-stack": "3.266.1", - "@aws-sdk/middleware-user-agent": "3.266.1", - "@aws-sdk/node-config-provider": "3.266.1", - "@aws-sdk/node-http-handler": "3.266.1", - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/smithy-client": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/url-parser": "3.266.1", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.266.1", - "@aws-sdk/util-defaults-mode-node": "3.266.1", - "@aws-sdk/util-endpoints": "3.266.1", - "@aws-sdk/util-retry": "3.266.1", - "@aws-sdk/util-user-agent-browser": "3.266.1", - "@aws-sdk/util-user-agent-node": "3.266.1", - "@aws-sdk/util-utf8": "3.254.0", - "fast-xml-parser": "4.0.11", - "tslib": "^2.3.1" + "@aws-sdk/config-resolver": "3.310.0", + "@aws-sdk/credential-provider-node": "3.319.0", + "@aws-sdk/fetch-http-handler": "3.310.0", + "@aws-sdk/hash-node": "3.310.0", + "@aws-sdk/invalid-dependency": "3.310.0", + "@aws-sdk/middleware-content-length": "3.310.0", + "@aws-sdk/middleware-endpoint": "3.310.0", + "@aws-sdk/middleware-host-header": "3.310.0", + "@aws-sdk/middleware-logger": "3.310.0", + "@aws-sdk/middleware-recursion-detection": "3.310.0", + "@aws-sdk/middleware-retry": "3.310.0", + "@aws-sdk/middleware-sdk-sts": "3.310.0", + "@aws-sdk/middleware-serde": "3.310.0", + "@aws-sdk/middleware-signing": "3.310.0", + "@aws-sdk/middleware-stack": "3.310.0", + "@aws-sdk/middleware-user-agent": "3.319.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/node-http-handler": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/smithy-client": "3.316.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", + "@aws-sdk/util-body-length-browser": "3.310.0", + "@aws-sdk/util-body-length-node": "3.310.0", + "@aws-sdk/util-defaults-mode-browser": "3.316.0", + "@aws-sdk/util-defaults-mode-node": "3.316.0", + "@aws-sdk/util-endpoints": "3.319.0", + "@aws-sdk/util-retry": "3.310.0", + "@aws-sdk/util-user-agent-browser": "3.310.0", + "@aws-sdk/util-user-agent-node": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", + "fast-xml-parser": "4.1.2", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/config-resolver": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.266.1.tgz", - "integrity": "sha512-MqMVki/y40Ot7XWJnziYuO35zqww3JbpH9jzCRCf8vtOE9u6C8VpuiG/OHIR9WQj63Yhcr+7fohmN3kGFnNWFg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.310.0.tgz", + "integrity": "sha512-8vsT+/50lOqfDxka9m/rRt6oxv1WuGZoP8oPMk0Dt+TxXMbAzf4+rejBgiB96wshI1k3gLokYRjSQZn+dDtT8g==", "dependencies": { - "@aws-sdk/signature-v4": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-config-provider": "3.208.0", - "@aws-sdk/util-middleware": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-config-provider": "3.310.0", + "@aws-sdk/util-middleware": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.266.1.tgz", - "integrity": "sha512-RPq9/FV7fOv14P5DxpqpcwuCa7P6ijUrN1vhpiYaWMQNJSsJK8cIsPECI3xQ1z+oPZ5/1qA++0RpTLqIhq/ifg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.310.0.tgz", + "integrity": "sha512-vvIPQpI16fj95xwS7M3D48F7QhZJBnnCgB5lR+b7So+vsG9ibm1mZRVGzVpdxCvgyOhHFbvrby9aalNJmmIP1A==", "dependencies": { - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/credential-provider-imds": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.266.1.tgz", - "integrity": "sha512-pTJnJtKaR0JWVqyt9XgHiqlK+3GnZfd3cuKGv9IsYxumVzladm7gNKiNFw0A2KsDj9jhrCRRZwEsH9ooDzZ/Ow==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.310.0.tgz", + "integrity": "sha512-baxK7Zp6dai5AGW01FIW27xS2KAaPUmKLIXv5SvFYsUgXXvNW55im4uG3b+2gA0F7V+hXvVBH08OEqmwW6we5w==", "dependencies": { - "@aws-sdk/node-config-provider": "3.266.1", - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/url-parser": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.266.1.tgz", - "integrity": "sha512-N52GNeHRJufEx+V0mWfwe5cV3ukHong75uRAB0IeapJwj+kKwxxLH1dKOUaGjd/ALx6/hsISoUE/6jm/Qf/DsA==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.319.0.tgz", + "integrity": "sha512-pzx388Fw1KlSgmIMUyRY8DJVYM3aXpwzjprD4RiQVPJeAI+t7oQmEvd2FiUZEuHDjWXcuonxgU+dk7i7HUk/HQ==", "dependencies": { - "@aws-sdk/credential-provider-env": "3.266.1", - "@aws-sdk/credential-provider-imds": "3.266.1", - "@aws-sdk/credential-provider-process": "3.266.1", - "@aws-sdk/credential-provider-sso": "3.266.1", - "@aws-sdk/credential-provider-web-identity": "3.266.1", - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/shared-ini-file-loader": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/credential-provider-env": "3.310.0", + "@aws-sdk/credential-provider-imds": "3.310.0", + "@aws-sdk/credential-provider-process": "3.310.0", + "@aws-sdk/credential-provider-sso": "3.319.0", + "@aws-sdk/credential-provider-web-identity": "3.310.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.266.1.tgz", - "integrity": "sha512-6/iTi/zugdvuyQDmEakYn01kiFKUArL+rIYwcMf20YguXNml6G4HVWJGbX2JklY6ovnznU5ENw6+ftzBAiw/PA==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.319.0.tgz", + "integrity": "sha512-DS4a0Rdd7ZtMshoeE+zuSgbC05YBcdzd0h89u/eX+1Yqx+HCjeb8WXkbXsz0Mwx8q9TE04aS8f6Bw9J4x4mO5g==", "dependencies": { - "@aws-sdk/credential-provider-env": "3.266.1", - "@aws-sdk/credential-provider-imds": "3.266.1", - "@aws-sdk/credential-provider-ini": "3.266.1", - "@aws-sdk/credential-provider-process": "3.266.1", - "@aws-sdk/credential-provider-sso": "3.266.1", - "@aws-sdk/credential-provider-web-identity": "3.266.1", - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/shared-ini-file-loader": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/credential-provider-env": "3.310.0", + "@aws-sdk/credential-provider-imds": "3.310.0", + "@aws-sdk/credential-provider-ini": "3.319.0", + "@aws-sdk/credential-provider-process": "3.310.0", + "@aws-sdk/credential-provider-sso": "3.319.0", + "@aws-sdk/credential-provider-web-identity": "3.310.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.266.1.tgz", - "integrity": "sha512-4V/7zVnaZo1IP4Is09dlwd2CkltlUdgbX4NUIb+QxZ/BlY7Ws47xyCjjyJhVVCe+y184M58bG4+HR5dHnrBfSA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.310.0.tgz", + "integrity": "sha512-h73sg6GPMUWC+3zMCbA1nZ2O03nNJt7G96JdmnantiXBwHpRKWW8nBTLzx5uhXn6hTuTaoQRP/P+oxQJKYdMmA==", "dependencies": { - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/shared-ini-file-loader": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.266.1.tgz", - "integrity": "sha512-d9hcV7XV1Gh0Dkt8kADsSoB/hZPlbuTp/Vzbj0HMO7hlGxFGcTrGN1UoQc11UAp4kKeF3i2ZQlMsch0d/2gK3w==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.319.0.tgz", + "integrity": "sha512-gAUnWH41lxkIbANXu+Rz5zS0Iavjjmpf3C56vAMT7oaYZ3Cg/Ys5l2SwAucQGOCA2DdS2hDiSI8E+Yhr4F5toA==", "dependencies": { - "@aws-sdk/client-sso": "3.266.1", - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/shared-ini-file-loader": "3.266.1", - "@aws-sdk/token-providers": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/client-sso": "3.319.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/token-providers": "3.319.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.266.1.tgz", - "integrity": "sha512-JIktczlqxIc+Gqc/99e7pPzNSgUjYX23fA2dmLt1bHRPH15p8S1Kv73lvqsgLF5EKP1H/UXDu+jVWDklYM6fVA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.310.0.tgz", + "integrity": "sha512-H4SzuZXILNhK6/IR1uVvsUDZvzc051hem7GLyYghBCu8mU+tq28YhKE8MfSroi6eL2e5Vujloij1OM2EQQkPkw==", "dependencies": { - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/eventstream-codec": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-codec/-/eventstream-codec-3.266.1.tgz", - "integrity": "sha512-4d39jHq8zSfhE2+aPq/fX72ZeekC5iUnqA7NDPxycYKdfULYPEVKrnMytuVon3QaTQVekxtsfHaD4cIh6VvxZg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-codec/-/eventstream-codec-3.310.0.tgz", + "integrity": "sha512-clIeSgWbZbxwtsxZ/yoedNM0/kJFSIjjHPikuDGhxhqc+vP6TN3oYyVMFrYwFaTFhk2+S5wZcWYMw8Op1pWo+A==", "dependencies": { "@aws-crypto/crc32": "3.0.0", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-hex-encoding": "3.201.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-hex-encoding": "3.310.0", + "tslib": "^2.5.0" } }, "node_modules/@aws-sdk/eventstream-serde-browser": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-serde-browser/-/eventstream-serde-browser-3.266.1.tgz", - "integrity": "sha512-h2UkUvlY8J9RqyXXqBNJYBlDw4TB9xZZpajvA4ZALftY/NcLFXVWbh/AkyQVgVht4SlGba/0CiG5p5se0w7udA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-serde-browser/-/eventstream-serde-browser-3.310.0.tgz", + "integrity": "sha512-3S6ziuQVALgEyz0TANGtYDVeG8ArK4Y05mcgrs8qUTmsvlDIXX37cR/DvmVbNB76M4IrsZeSAIajL9644CywkA==", "dependencies": { - "@aws-sdk/eventstream-serde-universal": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/eventstream-serde-universal": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/eventstream-serde-config-resolver": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.266.1.tgz", - "integrity": "sha512-ocQiyJw3rSaz+Y6SNZMI7R6yKqI3ffehNqgGoDvm/meKlvAtptj1zXGGyxsNQ+MwB1+t27+RUX/565rF9SJYjQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.310.0.tgz", + "integrity": "sha512-8s1Qdn9STj+sV75nUp9yt0W6fHS4BZ2jTm4Z/1Pcbvh2Gqs0WjH5n2StS+pDW5Y9J/HSGBl0ogmUr5lC5bXFHg==", "dependencies": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/eventstream-serde-node": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-serde-node/-/eventstream-serde-node-3.266.1.tgz", - "integrity": "sha512-ofMVEdu8TO4vGHXw6ozipy+JoaQB5yog9B6EYj1q/Pq1fBk5AtL9lz6Oar/2VwfYy4XzjIp+axg34XnXUPsN9g==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-serde-node/-/eventstream-serde-node-3.310.0.tgz", + "integrity": "sha512-kSnRomCgW43K9TmQYuwN9+AoYPnhyOKroanUMyZEzJk7rpCPMj4OzaUpXfDYOvznFNYn7NLaH6nHLJAr0VPlJA==", "dependencies": { - "@aws-sdk/eventstream-serde-universal": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/eventstream-serde-universal": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/eventstream-serde-universal": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-serde-universal/-/eventstream-serde-universal-3.266.1.tgz", - "integrity": "sha512-CftsPIKTw7WyCjoaVur3XTLShPIAy+//VavpDI19rjHL66aGE+RSKCNL5mYJ1HJs3A65Cb0BuEp8VsIT8KYnJQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-serde-universal/-/eventstream-serde-universal-3.310.0.tgz", + "integrity": "sha512-Qyjt5k/waV5cDukpgT824ISZAz5U0pwzLz5ztR409u85AGNkF/9n7MS+LSyBUBSb0WJ5pUeSD47WBk+nLq9Nhw==", "dependencies": { - "@aws-sdk/eventstream-codec": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/eventstream-codec": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/fetch-http-handler": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.266.1.tgz", - "integrity": "sha512-tyVMLBrJF1weMUqLU81lhuHES5QtFg7RmSysYM8mndePwBl81iQjLF5D7M8CU3aVzXY3TNU3rZBrm5xEK3xK1w==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.310.0.tgz", + "integrity": "sha512-Bi9vIwzdkw1zMcvi/zGzlWS9KfIEnAq4NNhsnCxbQ4OoIRU9wvU+WGZdBBhxg0ZxZmpp1j1aZhU53lLjA07MHw==", "dependencies": { - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/querystring-builder": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-base64": "3.208.0", - "tslib": "^2.3.1" + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/querystring-builder": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", + "tslib": "^2.5.0" } }, "node_modules/@aws-sdk/hash-blob-browser": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/hash-blob-browser/-/hash-blob-browser-3.266.1.tgz", - "integrity": "sha512-VsDjFtbHL5hZkeIq9BRACqvDecfpIJf323F7o1u5q0yATCMq2A4ogL0E8S1TxvlrJAUepFufUVkZxcFL2g4N2w==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/hash-blob-browser/-/hash-blob-browser-3.310.0.tgz", + "integrity": "sha512-OoR8p0cbypToysLT0v3o2oyjy6+DKrY7GNCAzHOHJK9xmqXCt+DsjKoPeiY7o1sWX2aN6Plmvubj/zWxMKEn/A==", "dependencies": { - "@aws-sdk/chunked-blob-reader": "3.188.0", - "@aws-sdk/chunked-blob-reader-native": "3.208.0", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/chunked-blob-reader": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "node_modules/@aws-sdk/hash-node": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.266.1.tgz", - "integrity": "sha512-2DbuY/AmtF4ORJVEAdzHfbM1p8w9ThRlu4BGdI7DXpO6/o1kgRBvNEbZc6MZkg7D2bI7TT6bI83u7AAbbMUMng==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.310.0.tgz", + "integrity": "sha512-NvE2fhRc8GRwCXBfDehxVAWCmVwVMILliAKVPAEr4yz2CkYs0tqU51S48x23dtna07H4qHtgpeNqVTthcIQOEQ==", "dependencies": { - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-buffer-from": "3.208.0", - "@aws-sdk/util-utf8": "3.254.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-buffer-from": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/hash-stream-node": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/hash-stream-node/-/hash-stream-node-3.266.1.tgz", - "integrity": "sha512-hdFv9pvQOdjNhi5kXEfBgfH5Z28jc0KXh+7x4eUp6dTGoDUP8BPPUTMMtnrVVPnRFVYOsC3ej5xjvuPQhTs9Cw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/hash-stream-node/-/hash-stream-node-3.310.0.tgz", + "integrity": "sha512-ZoXdybNgvMz1Hl6k/e32xVL3jmG5p2IEk5mTtLfFEuskTJ74Z+VMYKkkF1whyy7KQfH83H+TQGnsGtlRCchQKw==", "dependencies": { - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-utf8": "3.254.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/invalid-dependency": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.266.1.tgz", - "integrity": "sha512-rGc2Bv10eEVQW2Zwrd4/I2QBj5MOhl8qr1NA3UCHJa2501Z97/jn2BGZoX+Cc+iE55so66GKmqMYpibqdtDARw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.310.0.tgz", + "integrity": "sha512-1s5RG5rSPXoa/aZ/Kqr5U/7lqpx+Ry81GprQ2bxWqJvWQIJ0IRUwo5pk8XFxbKVr/2a+4lZT/c3OGoBOM1yRRA==", "dependencies": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "node_modules/@aws-sdk/is-array-buffer": { - "version": "3.201.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.201.0.tgz", - "integrity": "sha512-UPez5qLh3dNgt0DYnPD/q0mVJY84rA17QE26hVNOW3fAji8W2wrwrxdacWOxyXvlxWsVRcKmr+lay1MDqpAMfg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.310.0.tgz", + "integrity": "sha512-urnbcCR+h9NWUnmOtet/s4ghvzsidFmspfhYaHAmSRdy9yDjdjBJMFjjsn85A1ODUktztm+cVncXjQ38WCMjMQ==", "dependencies": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/md5-js": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/md5-js/-/md5-js-3.266.1.tgz", - "integrity": "sha512-AsNAQ0/6xoWrPU6ZgNKFi7DWhTSXt9Ogp2xaZqT5jY+s5DCsQ6Ydpe1i4HwFLJiJCEAEEw1OurXLp0D8NMaJdA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/md5-js/-/md5-js-3.310.0.tgz", + "integrity": "sha512-x5sRBUrEfLWAS1EhwbbDQ7cXq6uvBxh3qR2XAsnGvFFceTeAadk7cVogWxlk3PC+OCeeym7c3/6Bv2HQ2f1YyQ==", "dependencies": { - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-utf8": "3.254.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", + "tslib": "^2.5.0" } }, "node_modules/@aws-sdk/middleware-bucket-endpoint": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.266.1.tgz", - "integrity": "sha512-6wygf79/YA5ezNhHXsXKkP09jdVm1CzwVZV6Z3b/FqBZJ48FfgFXYhUF7E6mbZepGva7yRFzAwLZEhwYGj5DZw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.310.0.tgz", + "integrity": "sha512-uJJfHI7v4AgbJZRLtyI8ap2QRWkBokGc3iyUoQ+dVNT3/CE2ZCu694A6W+H0dRqg79dIE+f9CRNdtLGa/Ehhvg==", "dependencies": { - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-arn-parser": "3.208.0", - "@aws-sdk/util-config-provider": "3.208.0", - "tslib": "^2.3.1" + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-arn-parser": "3.310.0", + "@aws-sdk/util-config-provider": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/middleware-content-length": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.266.1.tgz", - "integrity": "sha512-Clq14Fr9WkiSg59jnIelL2F5D81HAhdE1MCZIAEEjN1ZK6bEM2kECnNT9CKJjDsuPvhdkrVGv9rjUSANWHLETw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.310.0.tgz", + "integrity": "sha512-P8tQZxgDt6CAh1wd/W6WPzjc+uWPJwQkm+F7rAwRlM+k9q17HrhnksGDKcpuuLyIhPQYdmOMIkpKVgXGa4avhQ==", "dependencies": { - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/middleware-endpoint": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.266.1.tgz", - "integrity": "sha512-EVnzd51U/Jhz9x68jFwqHjU4KPsLIXfuS1PSNV598OT04WLQXerBx/fvZh17Y4Dmmu6hf/JUWI9PI5To+oC3mQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.310.0.tgz", + "integrity": "sha512-Z+N2vOL8K354/lstkClxLLsr6hCpVRh+0tCMXrVj66/NtKysCEZ/0b9LmqOwD9pWHNiI2mJqXwY0gxNlKAroUg==", "dependencies": { - "@aws-sdk/middleware-serde": "3.266.1", - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/signature-v4": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/url-parser": "3.266.1", - "@aws-sdk/util-config-provider": "3.208.0", - "@aws-sdk/util-middleware": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/middleware-serde": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "@aws-sdk/util-middleware": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/middleware-expect-continue": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.266.1.tgz", - "integrity": "sha512-8vM1YY/4ub+0s+aWtwubXd2LB2VZ0aTO0X7M/Xjm+fAiCkfqNea5r+T6n2wg/sZCGGgQkBBswTg1I+c2/WbD2Q==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.310.0.tgz", + "integrity": "sha512-l3d1z2gt+gINJDnPSyu84IxfzjzPfCQrqC1sunw2cZGo/sXtEiq698Q3SiTcO2PGP4LBQAy2RHb5wVBJP708CQ==", "dependencies": { - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/middleware-flexible-checksums": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.266.1.tgz", - "integrity": "sha512-Z9KBIN6IDgnjyjCL7oPxS8yByRi+T7qcLqPm+1QHefLVHWYsAUSD24+0zlshgUQPz6jn8xNnfB9AqTbtuW05NQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.310.0.tgz", + "integrity": "sha512-5ndnLgzgGVpWkmHBAiYkagHqiSuow8q62J4J6E2PzaQ77+fm8W3nfdy7hK5trHokEyouCZdxT/XK/IRhgj/4PA==", "dependencies": { "@aws-crypto/crc32": "3.0.0", "@aws-crypto/crc32c": "3.0.0", - "@aws-sdk/is-array-buffer": "3.201.0", - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-utf8": "3.254.0", - "tslib": "^2.3.1" + "@aws-sdk/is-array-buffer": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.266.1.tgz", - "integrity": "sha512-3FSD8EkxOGV4O2iKgBnAwvj3PG/lABzcqmX6hABnsIusXAlUV5umh39FteipLcjnMXB04cLgmcgcG2o3cSA3tQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.310.0.tgz", + "integrity": "sha512-QWSA+46/hXorXyWa61ic2K7qZzwHTiwfk2e9mRRjeIRepUgI3qxFjsYqrWtrOGBjmFmq0pYIY8Bb/DCJuQqcoA==", "dependencies": { - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/middleware-location-constraint": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.266.1.tgz", - "integrity": "sha512-m3ZKtv+bfzFNe8O5cYraaSoFs2IkwELJ20ResV6RlyXfkHxML22ftCaKf+jTNQqHVFg6m0l3ECWirGfDLUvicw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.310.0.tgz", + "integrity": "sha512-LFm0JTQWwTPWL/tZU2wsQTl8J5PpDEkXjEhaXVKamtyH0xhysRqd+0n92n65dc8oztAuQkb9xUbErGn5b6gsew==", "dependencies": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/middleware-logger": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.266.1.tgz", - "integrity": "sha512-FbD9Hqt994PyDm7OTG8PbIuB6Mv9vYhqOM2RhqC1UGtprDmk084/cEv9Sp+qY33lFPxjZstKneQK6FhAfozIAQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.310.0.tgz", + "integrity": "sha512-Lurm8XofrASBRnAVtiSNuDSRsRqPNg27RIFLLsLp/pqog9nFJ0vz0kgdb9S5Z+zw83Mm+UlqOe6D8NTUNp4fVg==", "dependencies": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.266.1.tgz", - "integrity": "sha512-rgRxdgrLOD20zIFrjFW7Bu3s4MXC1KLDbqJY6sMpc5D8mmQlxfaQiSnCQrjgUxbW0Ni+rXiatlW2q2MwCUAPzw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.310.0.tgz", + "integrity": "sha512-SuB75/xk/gyue24gkriTwO2jFd7YcUGZDClQYuRejgbXSa3CO0lWyawQtfLcSSEBp9izrEVXuFH24K1eAft5nQ==", "dependencies": { - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/middleware-retry": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.266.1.tgz", - "integrity": "sha512-xBiKAjAP1j8SbKhF28bk1g2iZoiVMI7XV/x5d0g6igsvI4RiqzywTsiLi2VVsYPCY6bwbn0Zgt93Mej/MFfn5w==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.310.0.tgz", + "integrity": "sha512-oTPsRy2W4s+dfxbJPW7Km+hHtv/OMsNsVfThAq8DDYKC13qlr1aAyOqGLD+dpBy2aKe7ss517Sy2HcHtHqm7/g==", "dependencies": { - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/service-error-classification": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-middleware": "3.266.1", - "@aws-sdk/util-retry": "3.266.1", - "tslib": "^2.3.1", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/service-error-classification": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-middleware": "3.310.0", + "@aws-sdk/util-retry": "3.310.0", + "tslib": "^2.5.0", "uuid": "^8.3.2" }, "engines": { @@ -2124,243 +2103,238 @@ } }, "node_modules/@aws-sdk/middleware-sdk-s3": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.266.1.tgz", - "integrity": "sha512-d3Ow2YjPTIgi2WGx0lMRdoO86JOII3VwzGN4R7GViCY7Ic+Vj920IvGTz/olqSJWIA2tF9l+D2dQTNuU0btaDQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.310.0.tgz", + "integrity": "sha512-QK9x9g2ksg0hOjjYgqddeFcn5ctUEGdxJVu4OumPXceulefMcSO2jyH2qTybYSA93nqNQFdFmg5wQfvIRUWFCQ==", "dependencies": { - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-arn-parser": "3.208.0", - "tslib": "^2.3.1" + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-arn-parser": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/middleware-sdk-sts": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.266.1.tgz", - "integrity": "sha512-lM9t+S+PjmJ/xhoP9e/sIUS2bZyuEbobHo6a9WPk0UcdiqDWBIp+8MlTRDafKZtlN36gPDk5+qM9tXcI6P5YCA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.310.0.tgz", + "integrity": "sha512-+5PFwlYNLvLLIfw0ASAoWV/iIF8Zv6R6QGtyP0CclhRSvNjgbQDVnV0g95MC5qvh+GB/Yjlkt8qAjLSPjHfsrQ==", "dependencies": { - "@aws-sdk/middleware-signing": "3.266.1", - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/signature-v4": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/middleware-signing": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/middleware-serde": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.266.1.tgz", - "integrity": "sha512-UFJ4BlRG/MUOJq5afHohkDsMDPAkbuXGCkhTz93MGxbACEOJYoEvsaMjpLft88wu4D11GY1Y2PVFkfxJUYWDXA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.310.0.tgz", + "integrity": "sha512-RNeeTVWSLTaentUeCgQKZhAl+C6hxtwD78cQWS10UymWpQFwbaxztzKUu4UQS5xA2j6PxwPRRUjqa4jcFjfLsg==", "dependencies": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/middleware-signing": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.266.1.tgz", - "integrity": "sha512-PbVwt7xSP3xlT5x4Xdj7+2T1PgCW00bh5QrCJi2wo3dEN9UowU/IVGzGSv4/OJItLZWe4puGb1WtA+LKeWA40w==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.310.0.tgz", + "integrity": "sha512-f9mKq+XMdW207Af3hKjdTnpNhdtwqWuvFs/ZyXoOkp/g1MY1O6L23Jy6i52m29LxbT4AuNRG1oKODfXM0vYVjQ==", "dependencies": { - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/signature-v4": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-middleware": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/signature-v4": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-middleware": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/middleware-ssec": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.266.1.tgz", - "integrity": "sha512-HEiFZVLLzLPRKI16MvsIUGv9rZASP6dCYIldYpYj8hT2upxh2fhm4hYxHmspfIBgVo2RFK147pTpBwnfYQBeEA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.310.0.tgz", + "integrity": "sha512-CnEwNKVpd5bXnrCKPaePF8mWTA9ET21OMBb54y9b0fd8K02zoOcdBz4DWfh1SjFD4HkgCdja4egd8l2ivyvqmw==", "dependencies": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/middleware-stack": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.266.1.tgz", - "integrity": "sha512-liqq541u1eCDe+TCDOSrOcH6kAB6Dn1R8pbtJ23hP3fYM5/8W3V0f6VcywALVL9Pam+mkYmodWeDRQK8ieLEOg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.310.0.tgz", + "integrity": "sha512-010O1PD+UAcZVKRvqEusE1KJqN96wwrf6QsqbRM0ywsKQ21NDweaHvEDlds2VHpgmofxkRLRu/IDrlPkKRQrRg==", "dependencies": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.266.1.tgz", - "integrity": "sha512-yoHQSP3OngZnLWeuqMrYkOifMD8FUZxyXoUO9iHPytxns1Gri/4Gn/1raNWMqdrSIlBKPorKzCEu24DX5klf0w==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.319.0.tgz", + "integrity": "sha512-ytaLx2dlR5AdMSne6FuDCISVg8hjyKj+cHU20b2CRA/E/z+XXrLrssp4JrCgizRKPPUep0psMIa22Zd6osTT5Q==", "dependencies": { - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-endpoints": "3.319.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/node-config-provider": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.266.1.tgz", - "integrity": "sha512-cDDuj64nGskZNJQdwglIRqTazfZt0f8pooT1ZJrFoydLfMmR9yi6orizQ7C0i1vMkY02HxgwqJiwXuJ73gmaqA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.310.0.tgz", + "integrity": "sha512-T/Pp6htc6hq/Cq+MLNDSyiwWCMVF6GqbBbXKVlO5L8rdHx4sq9xPdoPveZhGWrxvkanjA6eCwUp6E0riBOSVng==", "dependencies": { - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/shared-ini-file-loader": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/node-http-handler": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.266.1.tgz", - "integrity": "sha512-oa1cDeD+fwGFg8xMfNUZ95xAE0dxiXaTdJwSqOzCVIBz/auahHrcfXey+Oynw1zUjv8ijOH9z/SXYrqfwlZosw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.310.0.tgz", + "integrity": "sha512-irv9mbcM9xC2xYjArQF5SYmHBMu4ciMWtGsoHII1nRuFOl9FoT4ffTvEPuLlfC6pznzvKt9zvnm6xXj7gDChKg==", "dependencies": { - "@aws-sdk/abort-controller": "3.266.1", - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/querystring-builder": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/abort-controller": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/querystring-builder": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/property-provider": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.266.1.tgz", - "integrity": "sha512-1ZRWqc4sNFGDRZ0Tl4WaukU9jR4ghB84QEQOqc48cJIoDiwOAP9UBJTNBJXCVllmPWGNgx4/lfWJoaFcvwsrzw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.310.0.tgz", + "integrity": "sha512-3lxDb0akV6BBzmFe4nLPaoliQbAifyWJhuvuDOu7e8NzouvpQXs0275w9LePhhcgjKAEVXUIse05ZW2DLbxo/g==", "dependencies": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/protocol-http": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.266.1.tgz", - "integrity": "sha512-8Z1Yfkf59of1R9qRSPmDKIHDo0n5YNCh1FrRLmCRqjjiZ4Ed7FJV/W6YYnJ6VbPcVv1WK6FvwzrGPM2gg4P48Q==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.310.0.tgz", + "integrity": "sha512-fgZ1aw/irQtnrsR58pS8ThKOWo57Py3xX6giRvwSgZDEcxHfVzuQjy9yPuV++v04fdmdtgpbGf8WfvAAJ11yXQ==", "dependencies": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/querystring-builder": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.266.1.tgz", - "integrity": "sha512-D1LoDv3A+c6YIYq6F2T5m8V0C14vQAarSoT6romVIIYCDuMK4R5BwB1NLFRco1dczyAYmqScxdV2C26+xjXJfw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.310.0.tgz", + "integrity": "sha512-ZHH8GV/80+pWGo7DzsvwvXR5xVxUHXUvPJPFAkhr6nCf78igdoF8gR10ScFoEKbtEapoNTaZlKHPXxpD8aPG7A==", "dependencies": { - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-uri-escape": "3.201.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-uri-escape": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/querystring-parser": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.266.1.tgz", - "integrity": "sha512-Ck8Ahluj+/eK4FcX8IlbO7DA1MNWdnh1rKjc1qx/ZWh71G/FdZ8Sse33N+Ed/z9v7H8W695dprRT6CuRlqyAbw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.310.0.tgz", + "integrity": "sha512-YkIznoP6lsiIUHinx++/lbb3tlMURGGqMpo0Pnn32zYzGrJXA6eC3D0as2EcMjo55onTfuLcIiX4qzXes2MYOA==", "dependencies": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/s3-request-presigner": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.266.1.tgz", - "integrity": "sha512-bLbVQCFQ+VwGEkRfmQ+IFB8nkRZRtZW3QbsXwNYeQ7VD387gYhvV/hnNbWlOWrNjiNNaLuvwcgzlMgFR3sRHIQ==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.319.0.tgz", + "integrity": "sha512-mq/4nqr/3sHGx9iJqPXXkfBPAlXGB000u4dX4QCMPFmMupfH5sT8M+hYgcB6N/2HuZ+JNJQntwu9q97gjhwpDQ==", "dependencies": { - "@aws-sdk/middleware-endpoint": "3.266.1", - "@aws-sdk/middleware-sdk-s3": "3.266.1", - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/signature-v4-multi-region": "3.266.1", - "@aws-sdk/smithy-client": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-create-request": "3.266.1", - "@aws-sdk/util-format-url": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/middleware-endpoint": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/signature-v4-multi-region": "3.310.0", + "@aws-sdk/smithy-client": "3.316.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-format-url": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/service-error-classification": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.266.1.tgz", - "integrity": "sha512-c2EvUvn9XLaDjKozCcYlO4cbtbJzBgx6EuhW1eLsMGLY3EobVRo1hGT0PtRmWQNnoW0BXv6oi/8NLOV6x37fxA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.310.0.tgz", + "integrity": "sha512-PuyC7k3qfIKeH2LCnDwbttMOKq3qAx4buvg0yfnJtQOz6t1AR8gsnAq0CjKXXyfkXwNKWTqCpE6lVNUIkXgsMw==", "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/shared-ini-file-loader": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.266.1.tgz", - "integrity": "sha512-yV8GY1Cgbc6pl0SRRQtx3PPcZpqYvKf/h1pz0FgkMBPHwOhp7zJYUkYmu3yvXulfORNsM5ro7wnKa0kxb5ljmg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.310.0.tgz", + "integrity": "sha512-N0q9pG0xSjQwc690YQND5bofm+4nfUviQ/Ppgan2kU6aU0WUq8KwgHJBto/YEEI+VlrME30jZJnxtOvcZJc2XA==", "dependencies": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/signature-v4": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.266.1.tgz", - "integrity": "sha512-kiHHA3voQKz4QYLKbR/3hKkY2n62MuGewYctvtQsh1069U/OI7FVceIE5hZnrlC5XX4jiNoF1lKdyRhXmK5GMQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.310.0.tgz", + "integrity": "sha512-1M60P1ZBNAjCFv9sYW29OF6okktaeibWyW3lMXqzoHF70lHBZh+838iUchznXUA5FLabfn4jBFWMRxlAXJUY2Q==", "dependencies": { - "@aws-sdk/is-array-buffer": "3.201.0", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-hex-encoding": "3.201.0", - "@aws-sdk/util-middleware": "3.266.1", - "@aws-sdk/util-uri-escape": "3.201.0", - "@aws-sdk/util-utf8": "3.254.0", - "tslib": "^2.3.1" + "@aws-sdk/is-array-buffer": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-hex-encoding": "3.310.0", + "@aws-sdk/util-middleware": "3.310.0", + "@aws-sdk/util-uri-escape": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.266.1.tgz", - "integrity": "sha512-G94sV+RfGpYMiGEFvXNf8y4COEywoRmDJ2Dx9yVIZnhkQJgToffazwLHmfAHcDS7UUs+p1LoBEaKCzb5cW/+NA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.310.0.tgz", + "integrity": "sha512-q8W+RIomTS/q85Ntgks/CoDElwqkC9+4OCicee5YznNHjQ4gtNWhUkYIyIRWRmXa/qx/AUreW9DM8FAecCOdng==", "dependencies": { - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/signature-v4": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-arn-parser": "3.208.0", - "tslib": "^2.3.1" + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/signature-v4": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" @@ -2375,194 +2349,180 @@ } }, "node_modules/@aws-sdk/smithy-client": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.266.1.tgz", - "integrity": "sha512-fg/+JzHeYPS0poVckSiaE/h1eWf5+u2Cs8/zh/4bAvVPqSA3Gg/yBrtvP+HxKLoSo+ObuPb9aXXkeCKPke6ktA==", + "version": "3.316.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.316.0.tgz", + "integrity": "sha512-6YXOKbRnXeS8r8RWzuL6JMBolDYM5Wa4fD/VY6x/wK78i2xErHOvqzHgyyeLI1MMw4uqyd4wRNJNWC9TMPduXw==", "dependencies": { - "@aws-sdk/middleware-stack": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/middleware-stack": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/token-providers": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.266.1.tgz", - "integrity": "sha512-N+qiLQvPvel9dFdEoffRG4Mcp2p82OMyUvS12P5iYWqPCDuPzU72rYT2PmVFKINmflqEySjsKo8vIaWx7Kl4pQ==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.319.0.tgz", + "integrity": "sha512-5utg6VL6Pl0uiLUn8ZJPYYxzCb9VRPsgJmGXktRUwq0YlTJ6ABcaxTXwZcC++sjh/qyCQDK5PPLNU5kIBttHMQ==", "dependencies": { - "@aws-sdk/client-sso-oidc": "3.266.1", - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/shared-ini-file-loader": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/client-sso-oidc": "3.319.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/types": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.266.1.tgz", - "integrity": "sha512-OVg3CjHKT3/Ws33jx3TUYYkbFOv/CLb9m3P4gZQDvgKPsOagp96LOsG8ZWdcVZCvSorAUqSb5kuc1utsjJxDTw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.310.0.tgz", + "integrity": "sha512-j8eamQJ7YcIhw7fneUfs8LYl3t01k4uHi4ZDmNRgtbmbmTTG3FZc2MotStZnp3nZB6vLiPF1o5aoJxWVvkzS6A==", "dependencies": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/url-parser": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.266.1.tgz", - "integrity": "sha512-7IBZ8TjTWafug26CnNpz6cdrLU0TZ0G7N9LNfqjM/+69KI/Ragvv2Lsm4jhSv2uMx5OEzwlVYIEYaKMnAUiRLQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.310.0.tgz", + "integrity": "sha512-mCLnCaSB9rQvAgx33u0DujLvr4d5yEm/W5r789GblwwQnlNXedVu50QRizMLTpltYWyAUoXjJgQnJHmJMaKXhw==", "dependencies": { - "@aws-sdk/querystring-parser": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/querystring-parser": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "node_modules/@aws-sdk/util-arn-parser": { - "version": "3.208.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.208.0.tgz", - "integrity": "sha512-QV4af+kscova9dv4VuHOgH8wEr/IIYHDGcnyVtkUEqahCejWr1Kuk+SBK0xMwnZY5LSycOtQ8aeqHOn9qOjZtA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.310.0.tgz", + "integrity": "sha512-jL8509owp/xB9+Or0pvn3Fe+b94qfklc2yPowZZIFAkFcCSIdkIglz18cPDWnYAcy9JGewpMS1COXKIUhZkJsA==", "dependencies": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/util-base64": { - "version": "3.208.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64/-/util-base64-3.208.0.tgz", - "integrity": "sha512-PQniZph5A6N7uuEOQi+1hnMz/FSOK/8kMFyFO+4DgA1dZ5pcKcn5wiFwHkcTb/BsgVqQa3Jx0VHNnvhlS8JyTg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64/-/util-base64-3.310.0.tgz", + "integrity": "sha512-v3+HBKQvqgdzcbL+pFswlx5HQsd9L6ZTlyPVL2LS9nNXnCcR3XgGz9jRskikRUuUvUXtkSG1J88GAOnJ/apTPg==", "dependencies": { - "@aws-sdk/util-buffer-from": "3.208.0", - "tslib": "^2.3.1" + "@aws-sdk/util-buffer-from": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/util-body-length-browser": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.188.0.tgz", - "integrity": "sha512-8VpnwFWXhnZ/iRSl9mTf+VKOX9wDE8QtN4bj9pBfxwf90H1X7E8T6NkiZD3k+HubYf2J94e7DbeHs7fuCPW5Qg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.310.0.tgz", + "integrity": "sha512-sxsC3lPBGfpHtNTUoGXMQXLwjmR0zVpx0rSvzTPAuoVILVsp5AU/w5FphNPxD5OVIjNbZv9KsKTuvNTiZjDp9g==", "dependencies": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" } }, "node_modules/@aws-sdk/util-body-length-node": { - "version": "3.208.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.208.0.tgz", - "integrity": "sha512-3zj50e5g7t/MQf53SsuuSf0hEELzMtD8RX8C76f12OSRo2Bca4FLLYHe0TZbxcfQHom8/hOaeZEyTyMogMglqg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.310.0.tgz", + "integrity": "sha512-2tqGXdyKhyA6w4zz7UPoS8Ip+7sayOg9BwHNidiGm2ikbDxm1YrCfYXvCBdwaJxa4hJfRVz+aL9e+d3GqPI9pQ==", "dependencies": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/util-buffer-from": { - "version": "3.208.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.208.0.tgz", - "integrity": "sha512-7L0XUixNEFcLUGPeBF35enCvB9Xl+K6SQsmbrPk1P3mlV9mguWSDQqbOBwY1Ir0OVbD6H/ZOQU7hI/9RtRI0Zw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.310.0.tgz", + "integrity": "sha512-i6LVeXFtGih5Zs8enLrt+ExXY92QV25jtEnTKHsmlFqFAuL3VBeod6boeMXkN2p9lbSVVQ1sAOOYZOHYbYkntw==", "dependencies": { - "@aws-sdk/is-array-buffer": "3.201.0", - "tslib": "^2.3.1" + "@aws-sdk/is-array-buffer": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/util-config-provider": { - "version": "3.208.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.208.0.tgz", - "integrity": "sha512-DSRqwrERUsT34ug+anlMBIFooBEGwM8GejC7q00Y/9IPrQy50KnG5PW2NiTjuLKNi7pdEOlwTSEocJE15eDZIg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.310.0.tgz", + "integrity": "sha512-xIBaYo8dwiojCw8vnUcIL4Z5tyfb1v3yjqyJKJWV/dqKUFOOS0U591plmXbM+M/QkXyML3ypon1f8+BoaDExrg==", "dependencies": { - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/util-create-request": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-create-request/-/util-create-request-3.266.1.tgz", - "integrity": "sha512-S7Kj9AvryLYIAuHaNGdnC+eF0NqzD7DkW6n/wWRjaKg4eR36VfG5AXNCQcsXkpd8eo66OHDPv6VRjX2SaL50yA==", - "dependencies": { - "@aws-sdk/middleware-stack": "3.266.1", - "@aws-sdk/smithy-client": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/util-defaults-mode-browser": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.266.1.tgz", - "integrity": "sha512-4arGHXzTwLIPlNb3a2v7i2fpKFBLQfFygUDT1E6VCAbNpvPVJk+/w0foFs0Zc8BQsPQsC+ZKe20pFw0hnHZJGw==", + "version": "3.316.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.316.0.tgz", + "integrity": "sha512-6FSqLhYmaihtH2n1s4b2rlLW0ABU8N6VZIfzLfe2ING4PF0MzfaMMhnTFUHVXfKCVGoR8yP6iyFTRCyHGVEL1w==", "dependencies": { - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/types": "3.266.1", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", "bowser": "^2.11.0", - "tslib": "^2.3.1" + "tslib": "^2.5.0" }, "engines": { "node": ">= 10.0.0" } }, "node_modules/@aws-sdk/util-defaults-mode-node": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.266.1.tgz", - "integrity": "sha512-EOo2pPtvJUd9vkwRAptBIeF4P5zHeHcvCcCw6ZuP7bLvaUNHxepKAy4iesaB4aqqRgVn6AdV7w489HnTxa8Kpw==", + "version": "3.316.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.316.0.tgz", + "integrity": "sha512-dkYy10hdjPSScXXvnjGpZpnJxllkb6ICHgLMwZ4JczLHhPM12T/4PQ758YN8HS+muiYDGX1Bl2z1jd/bMcewBQ==", "dependencies": { - "@aws-sdk/config-resolver": "3.266.1", - "@aws-sdk/credential-provider-imds": "3.266.1", - "@aws-sdk/node-config-provider": "3.266.1", - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/config-resolver": "3.310.0", + "@aws-sdk/credential-provider-imds": "3.310.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">= 10.0.0" } }, "node_modules/@aws-sdk/util-endpoints": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.266.1.tgz", - "integrity": "sha512-w2VjoAIvfw2gau+cVQ5vahfy5CqQJrNOnSXbH6kjpd8RVQ0wOWBDVKb8tUwF4ROD1zovx0jT9d7bsYdMyo3HJw==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.319.0.tgz", + "integrity": "sha512-3I64UMoYA2e2++oOUJXRcFtYLpLylnZFRltWfPo1B3dLlf+MIWat9djT+mMus+hW1ntLsvAIVu1hLVePJC0gvw==", "dependencies": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/util-format-url": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.266.1.tgz", - "integrity": "sha512-hCOgeAv1Oc4vK9VIkvbruchXXTxutFgLYFvqt43q5Tnu2jXyWinnIsenKS0PszUxuccmqy/fDcoYQWAqRML1fQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.310.0.tgz", + "integrity": "sha512-NBOvmvvVR3ydquHmznfgtakiSgDhq8Ww6fq8TUaEjM+Es6+iqY4AwZo0rZ9xTX3GpCcoZy391HUi6kiXRAFzuA==", "dependencies": { - "@aws-sdk/querystring-builder": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/querystring-builder": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/util-hex-encoding": { - "version": "3.201.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.201.0.tgz", - "integrity": "sha512-7t1vR1pVxKx0motd3X9rI3m/xNp78p3sHtP5yo4NP4ARpxyJ0fokBomY8ScaH2D/B+U5o9ARxldJUdMqyBlJcA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.310.0.tgz", + "integrity": "sha512-sVN7mcCCDSJ67pI1ZMtk84SKGqyix6/0A1Ab163YKn+lFBQRMKexleZzpYzNGxYzmQS6VanP/cfU7NiLQOaSfA==", "dependencies": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" @@ -2580,84 +2540,84 @@ } }, "node_modules/@aws-sdk/util-middleware": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.266.1.tgz", - "integrity": "sha512-iZq+lq80byWZMsdII4OS7CdhgGeuBXBPd//iFWq4YmGts5W1QI1FLIFcsOuUnZtQMiaAuvLXtEO8ZrfaKTFKgw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.310.0.tgz", + "integrity": "sha512-FTSUKL/eRb9X6uEZClrTe27QFXUNNp7fxYrPndZwk1hlaOP5ix+MIHBcI7pIiiY/JPfOUmPyZOu+HetlFXjWog==", "dependencies": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/util-retry": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-retry/-/util-retry-3.266.1.tgz", - "integrity": "sha512-mQZshXR31iM9eV+x50pdmIFuDAjd8wDrxJ/kDnwR0H9NaeIQ3SKcNFTs0PPqtu/JUX0vb4wvm2KjIkUyO2iijg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-retry/-/util-retry-3.310.0.tgz", + "integrity": "sha512-FwWGhCBLfoivTMUHu1LIn4NjrN9JLJ/aX5aZmbcPIOhZVFJj638j0qDgZXyfvVqBuBZh7M8kGq0Oahy3dp69OA==", "dependencies": { - "@aws-sdk/service-error-classification": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/service-error-classification": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@aws-sdk/util-stream-browser": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-stream-browser/-/util-stream-browser-3.266.1.tgz", - "integrity": "sha512-u1Tyb8x3PkOZfMuSugRSfyY28dKnPv8oG70jGTRwpscqFQMOjzXMB8ciwNRlPeuivwSOhX2ZWkgnQg6Sx0JuQg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-stream-browser/-/util-stream-browser-3.310.0.tgz", + "integrity": "sha512-bysXZHwFwvbqOTCScCdCnoLk1K3GCo0HRIYEZuL7O7MHrQmfaYRXcaft/p22+GUv9VeFXS/eJJZ5r4u32az94w==", "dependencies": { - "@aws-sdk/fetch-http-handler": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-hex-encoding": "3.201.0", - "@aws-sdk/util-utf8": "3.254.0", - "tslib": "^2.3.1" + "@aws-sdk/fetch-http-handler": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", + "@aws-sdk/util-hex-encoding": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", + "tslib": "^2.5.0" } }, "node_modules/@aws-sdk/util-stream-node": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-stream-node/-/util-stream-node-3.266.1.tgz", - "integrity": "sha512-tZm6KKf8fdv/MS3oKe9C0iK5vukQOvYdAVXSOSROuU6q3GVQXTLEl593KC/GkhjO1hjF9o72IlRZZ/QA0PvnNg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-stream-node/-/util-stream-node-3.310.0.tgz", + "integrity": "sha512-hueAXFK0GVvnfYFgqbF7587xZfMZff5jlIFZOHqx7XVU7bl7qrRUCnphHk8H6yZ7RoQbDPcfmHJgtEoAJg1T1Q==", "dependencies": { - "@aws-sdk/node-http-handler": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-buffer-from": "3.208.0", - "tslib": "^2.3.1" + "@aws-sdk/node-http-handler": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-buffer-from": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/util-uri-escape": { - "version": "3.201.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.201.0.tgz", - "integrity": "sha512-TeTWbGx4LU2c5rx0obHeDFeO9HvwYwQtMh1yniBz00pQb6Qt6YVOETVQikRZ+XRQwEyCg/dA375UplIpiy54mA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.310.0.tgz", + "integrity": "sha512-drzt+aB2qo2LgtDoiy/3sVG8w63cgLkqFIa2NFlGpUgHFWTXkqtbgf4L5QdjRGKWhmZsnqkbtL7vkSWEcYDJ4Q==", "dependencies": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.266.1.tgz", - "integrity": "sha512-zT5Sc0rNLOhBC+RhFF0FRE2y+CIf50rJZLkxRXoVRXJeFVSKPyhk3AKqe2Q6FE+yQsTV2FlwSDI98SxgaDORkQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.310.0.tgz", + "integrity": "sha512-yU/4QnHHuQ5z3vsUqMQVfYLbZGYwpYblPiuZx4Zo9+x0PBkNjYMqctdDcrpoH9Z2xZiDN16AmQGK1tix117ZKw==", "dependencies": { - "@aws-sdk/types": "3.266.1", + "@aws-sdk/types": "3.310.0", "bowser": "^2.11.0", - "tslib": "^2.3.1" + "tslib": "^2.5.0" } }, "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.266.1.tgz", - "integrity": "sha512-o8uYR38GxaKj95acC0tIxM2K0vANVMpEpgpWcW+QTvVc4Vm4im0SBD7BvgXbQV2VW8X28ZNddVbCK7pHHEJrtg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.310.0.tgz", + "integrity": "sha512-Ra3pEl+Gn2BpeE7KiDGpi4zj7WJXZA5GXnGo3mjbi9+Y3zrbuhJAbdZO3mO/o7xDgMC6ph4xCTbaSGzU6b6EDg==", "dependencies": { - "@aws-sdk/node-config-provider": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" @@ -2672,12 +2632,12 @@ } }, "node_modules/@aws-sdk/util-utf8": { - "version": "3.254.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8/-/util-utf8-3.254.0.tgz", - "integrity": "sha512-14Kso/eIt5/qfIBmhEL9L1IfyUqswjSTqO2mY7KOzUZ9SZbwn3rpxmtkhmATkRjD7XIlLKaxBkI7tU9Zjzj8Kw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8/-/util-utf8-3.310.0.tgz", + "integrity": "sha512-DnLfFT8uCO22uOJc0pt0DsSNau1GTisngBCDw8jQuWT5CqogMJu4b/uXmwEqfj8B3GX6Xsz8zOd6JpRlPftQoA==", "dependencies": { - "@aws-sdk/util-buffer-from": "3.208.0", - "tslib": "^2.3.1" + "@aws-sdk/util-buffer-from": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" @@ -2692,24 +2652,24 @@ } }, "node_modules/@aws-sdk/util-waiter": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-waiter/-/util-waiter-3.266.1.tgz", - "integrity": "sha512-g3uzVouAs6LfYU7vZEy4BIEIiCXSAjZnGV4RjTagfxZRpNtAriFn29Zys4nA/cBHxUkOS3XTzbt5eTBwEdK/FA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-waiter/-/util-waiter-3.310.0.tgz", + "integrity": "sha512-AV5j3guH/Y4REu+Qh3eXQU9igljHuU4XjX2sADAgf54C0kkhcCCkkiuzk3IsX089nyJCqIcj5idbjdvpnH88Vw==", "dependencies": { - "@aws-sdk/abort-controller": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/abort-controller": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@aws-sdk/xml-builder": { - "version": "3.201.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.201.0.tgz", - "integrity": "sha512-brRdB1wwMgjWEnOQsv7zSUhIQuh7DEicrfslAqHop4S4FtSI3GQAShpQqgOpMTNFYcpaWKmE/Y1MJmNY7xLCnw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.310.0.tgz", + "integrity": "sha512-TqELu4mOuSIKQCqj63fGVs86Yh+vBx5nHRpWKNUNhB2nPTpfbziTs5c1X358be3peVWA4wPxW7Nt53KIg1tnNw==", "dependencies": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" @@ -2776,9 +2736,9 @@ } }, "node_modules/@babel/generator": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz", - "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==", + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", + "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", "dev": true, "dependencies": { "@babel/types": "^7.20.7", @@ -4322,9 +4282,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz", - "integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==", + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", + "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", "dev": true, "dependencies": { "regenerator-runtime": "^0.13.11" @@ -4404,23 +4364,23 @@ } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.36.1", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.36.1.tgz", - "integrity": "sha512-922xqFsTpHs6D0BUiG4toiyPOMc8/jafnWKxz1KWgS4XzKPy2qXf1Pe6UFuNSCQqt6tOuhAWXBNuuyUhJmw9Vg==", + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.37.0.tgz", + "integrity": "sha512-hjK0wnsPCYLlF+HHB4R/RbUjOWeLW2SlarB67+Do5WsKILOkmIZvvPJFbtWSmbypxcjpoECLAMzoao0D4Bg5ZQ==", "dev": true, "dependencies": { "comment-parser": "1.3.1", "esquery": "^1.4.0", - "jsdoc-type-pratt-parser": "~3.1.0" + "jsdoc-type-pratt-parser": "~4.0.0" }, "engines": { "node": "^14 || ^16 || ^17 || ^18 || ^19" } }, "node_modules/@esbuild/android-arm": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz", - "integrity": "sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.8.tgz", + "integrity": "sha512-0/rb91GYKhrtbeglJXOhAv9RuYimgI8h623TplY2X+vA4EXnk3Zj1fXZreJ0J3OJJu1bwmb0W7g+2cT/d8/l/w==", "cpu": [ "arm" ], @@ -4434,9 +4394,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz", - "integrity": "sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.8.tgz", + "integrity": "sha512-oa/N5j6v1svZQs7EIRPqR8f+Bf8g6HBDjD/xHC02radE/NjKHK7oQmtmLxPs1iVwYyvE+Kolo6lbpfEQ9xnhxQ==", "cpu": [ "arm64" ], @@ -4450,9 +4410,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz", - "integrity": "sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.8.tgz", + "integrity": "sha512-bTliMLqD7pTOoPg4zZkXqCDuzIUguEWLpeqkNfC41ODBHwoUgZ2w5JBeYimv4oP6TDVocoYmEhZrCLQTrH89bg==", "cpu": [ "x64" ], @@ -4466,9 +4426,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz", - "integrity": "sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.8.tgz", + "integrity": "sha512-ghAbV3ia2zybEefXRRm7+lx8J/rnupZT0gp9CaGy/3iolEXkJ6LYRq4IpQVI9zR97ID80KJVoUlo3LSeA/sMAg==", "cpu": [ "arm64" ], @@ -4482,9 +4442,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz", - "integrity": "sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.8.tgz", + "integrity": "sha512-n5WOpyvZ9TIdv2V1K3/iIkkJeKmUpKaCTdun9buhGRWfH//osmUjlv4Z5mmWdPWind/VGcVxTHtLfLCOohsOXw==", "cpu": [ "x64" ], @@ -4498,9 +4458,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz", - "integrity": "sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.8.tgz", + "integrity": "sha512-a/SATTaOhPIPFWvHZDoZYgxaZRVHn0/LX1fHLGfZ6C13JqFUZ3K6SMD6/HCtwOQ8HnsNaEeokdiDSFLuizqv5A==", "cpu": [ "arm64" ], @@ -4514,9 +4474,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz", - "integrity": "sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.8.tgz", + "integrity": "sha512-xpFJb08dfXr5+rZc4E+ooZmayBW6R3q59daCpKZ/cDU96/kvDM+vkYzNeTJCGd8rtO6fHWMq5Rcv/1cY6p6/0Q==", "cpu": [ "x64" ], @@ -4530,9 +4490,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz", - "integrity": "sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.8.tgz", + "integrity": "sha512-6Ij8gfuGszcEwZpi5jQIJCVIACLS8Tz2chnEBfYjlmMzVsfqBP1iGmHQPp7JSnZg5xxK9tjCc+pJ2WtAmPRFVA==", "cpu": [ "arm" ], @@ -4546,9 +4506,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz", - "integrity": "sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.8.tgz", + "integrity": "sha512-v3iwDQuDljLTxpsqQDl3fl/yihjPAyOguxuloON9kFHYwopeJEf1BkDXODzYyXEI19gisEsQlG1bM65YqKSIww==", "cpu": [ "arm64" ], @@ -4562,9 +4522,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz", - "integrity": "sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.8.tgz", + "integrity": "sha512-8svILYKhE5XetuFk/B6raFYIyIqydQi+GngEXJgdPdI7OMKUbSd7uzR02wSY4kb53xBrClLkhH4Xs8P61Q2BaA==", "cpu": [ "ia32" ], @@ -4578,9 +4538,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz", - "integrity": "sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.8.tgz", + "integrity": "sha512-B6FyMeRJeV0NpyEOYlm5qtQfxbdlgmiGdD+QsipzKfFky0K5HW5Td6dyK3L3ypu1eY4kOmo7wW0o94SBqlqBSA==", "cpu": [ "loong64" ], @@ -4594,9 +4554,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz", - "integrity": "sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.8.tgz", + "integrity": "sha512-CCb67RKahNobjm/eeEqeD/oJfJlrWyw29fgiyB6vcgyq97YAf3gCOuP6qMShYSPXgnlZe/i4a8WFHBw6N8bYAA==", "cpu": [ "mips64el" ], @@ -4610,9 +4570,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz", - "integrity": "sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.8.tgz", + "integrity": "sha512-bytLJOi55y55+mGSdgwZ5qBm0K9WOCh0rx+vavVPx+gqLLhxtSFU0XbeYy/dsAAD6xECGEv4IQeFILaSS2auXw==", "cpu": [ "ppc64" ], @@ -4626,9 +4586,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz", - "integrity": "sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.8.tgz", + "integrity": "sha512-2YpRyQJmKVBEHSBLa8kBAtbhucaclb6ex4wchfY0Tj3Kg39kpjeJ9vhRU7x4mUpq8ISLXRXH1L0dBYjAeqzZAw==", "cpu": [ "riscv64" ], @@ -4642,9 +4602,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz", - "integrity": "sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.8.tgz", + "integrity": "sha512-QgbNY/V3IFXvNf11SS6exkpVcX0LJcob+0RWCgV9OiDAmVElnxciHIisoSix9uzYzScPmS6dJFbZULdSAEkQVw==", "cpu": [ "s390x" ], @@ -4658,9 +4618,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz", - "integrity": "sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.8.tgz", + "integrity": "sha512-mM/9S0SbAFDBc4OPoyP6SEOo5324LpUxdpeIUUSrSTOfhHU9hEfqRngmKgqILqwx/0DVJBzeNW7HmLEWp9vcOA==", "cpu": [ "x64" ], @@ -4674,9 +4634,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz", - "integrity": "sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.8.tgz", + "integrity": "sha512-eKUYcWaWTaYr9zbj8GertdVtlt1DTS1gNBWov+iQfWuWyuu59YN6gSEJvFzC5ESJ4kMcKR0uqWThKUn5o8We6Q==", "cpu": [ "x64" ], @@ -4690,9 +4650,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz", - "integrity": "sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.8.tgz", + "integrity": "sha512-Vc9J4dXOboDyMXKD0eCeW0SIeEzr8K9oTHJU+Ci1mZc5njPfhKAqkRt3B/fUNU7dP+mRyralPu8QUkiaQn7iIg==", "cpu": [ "x64" ], @@ -4706,9 +4666,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz", - "integrity": "sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.8.tgz", + "integrity": "sha512-0xvOTNuPXI7ft1LYUgiaXtpCEjp90RuBBYovdd2lqAFxje4sEucurg30M1WIm03+3jxByd3mfo+VUmPtRSVuOw==", "cpu": [ "x64" ], @@ -4722,9 +4682,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz", - "integrity": "sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.8.tgz", + "integrity": "sha512-G0JQwUI5WdEFEnYNKzklxtBheCPkuDdu1YrtRrjuQv30WsYbkkoixKxLLv8qhJmNI+ATEWquZe/N0d0rpr55Mg==", "cpu": [ "arm64" ], @@ -4738,9 +4698,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz", - "integrity": "sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.8.tgz", + "integrity": "sha512-Fqy63515xl20OHGFykjJsMnoIWS+38fqfg88ClvPXyDbLtgXal2DTlhb1TfTX34qWi3u4I7Cq563QcHpqgLx8w==", "cpu": [ "ia32" ], @@ -4754,9 +4714,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz", - "integrity": "sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.8.tgz", + "integrity": "sha512-1iuezdyDNngPnz8rLRDO2C/ZZ/emJLb72OsZeqQ6gL6Avko/XCXZw+NuxBSNhBAP13Hie418V7VMt9et1FMvpg==", "cpu": [ "x64" ], @@ -4769,15 +4729,39 @@ "node": ">=12" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", + "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", + "espree": "^9.5.1", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -4859,10 +4843,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/js": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", + "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/@fortawesome/fontawesome-free": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.3.0.tgz", - "integrity": "sha512-qVtd5i1Cc7cdrqnTWqTObKQHjPWAiRwjUPaXObaeNPcy7+WKxJumGBx66rfSFgK6LNpIasVKkEgW8oyf0tmPLA==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.4.0.tgz", + "integrity": "sha512-0NyytTlPJwB/BF5LtRV8rrABDbe3TdTXqNB3PdZ+UUUZAEIrdOJdmABqKjt4AXwIoJNaRVVZEXxpNrqvE1GAYQ==", "dev": true, "hasInstallScript": true, "engines": { @@ -5776,35 +5769,35 @@ } }, "node_modules/@ngrx/effects": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-15.2.1.tgz", - "integrity": "sha512-dHMXZ3jIgAJ6l5W+IxYTkWKeq0BE5RG87LVrfH6mVi1X41j7dXqXeALvjvyZ5CUSTUMHq8WiiJg5w9LeLJci0g==", + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-15.4.0.tgz", + "integrity": "sha512-/8gHhOM9aeGaw8OG2LLwi4I4p84xzG0EU9TqWrvQcW74wn8sFZONjLvUte5YOzJ5502PPFFrfXSOc+lHnVAJUA==", "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@angular/core": "^15.0.0", - "@ngrx/store": "15.2.1", + "@ngrx/store": "15.4.0", "rxjs": "^6.5.3 || ^7.5.0" } }, "node_modules/@ngrx/entity": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/@ngrx/entity/-/entity-15.2.1.tgz", - "integrity": "sha512-MtaqBK5Z8vtRULtVXOkukpnYiVYsK/aDbCMocg4GTE0sOuw2Jo6VbjUWYJmWpv4pKitO9LfiIVzE8XnC3Byp3w==", + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@ngrx/entity/-/entity-15.4.0.tgz", + "integrity": "sha512-DmfbbasV5bth9APAiwH9ovDwJ/rtEUm4pJvTd6Eds/kOJ6Ime9MZwEhtglXlk2jMwe7f08pl1jzFhYIjI277aQ==", "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@angular/core": "^15.0.0", - "@ngrx/store": "15.2.1", + "@ngrx/store": "15.4.0", "rxjs": "^6.5.3 || ^7.5.0" } }, "node_modules/@ngrx/router-store": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/@ngrx/router-store/-/router-store-15.2.1.tgz", - "integrity": "sha512-muGlunaZqu05gShZ4wO+BUc5vknBLsf0n+qOZGqMkjRNrbuwja2DNQKjZd83EUewlIRJRBuV4M1ljeiwINBR3g==", + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@ngrx/router-store/-/router-store-15.4.0.tgz", + "integrity": "sha512-uc8gx+SMr2gyly+WSBmGnpHTPsMVhenUG6skH3Qk67hrwdVG3SABjw3qdP4GibbfwwajMQ67sLaLY8PQZ5Sb2g==", "dependencies": { "tslib": "^2.0.0" }, @@ -5812,20 +5805,20 @@ "@angular/common": "^15.0.0", "@angular/core": "^15.0.0", "@angular/router": "^15.0.0", - "@ngrx/store": "15.2.1", + "@ngrx/store": "15.4.0", "rxjs": "^6.5.3 || ^7.5.0" } }, "node_modules/@ngrx/schematics": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/@ngrx/schematics/-/schematics-15.2.1.tgz", - "integrity": "sha512-pNkicfq+1NdUOKf13hqXMYNoEJIDkx2M8eLS3Sor/iOE/vDDHQu59lYp+wFdF+Zf8v2BHpiRcaKkD8cmC/6qEw==", + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@ngrx/schematics/-/schematics-15.4.0.tgz", + "integrity": "sha512-vOio2+0BNuzgde8OtIR5Gbzn/+59V0V2TyDyrxxpOi8v7FuaKCPh+o525ekjU/PfVi3ZiMVRjbmrTAR4wzBmug==", "dev": true }, "node_modules/@ngrx/store": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-15.2.1.tgz", - "integrity": "sha512-s4V2ylfQ/IvjVJrJaqRMNF/LkeUjHG+bkis6xl06CjpwCQ4I2FpLog9le+dfayQLSAu+OXmUOl4/OAY3ewvEtw==", + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-15.4.0.tgz", + "integrity": "sha512-OvCuNBHL8mAUnRTS6QSFm+IunspsYNu2cCwDovBNn7EGhxRuGihBeNoX47jCqWPHBFtokj4BlatDfpJ/yCh4xQ==", "dependencies": { "tslib": "^2.0.0" }, @@ -5835,22 +5828,22 @@ } }, "node_modules/@ngrx/store-devtools": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/@ngrx/store-devtools/-/store-devtools-15.2.1.tgz", - "integrity": "sha512-mzsW2LEXY2/Qcz/VQbvst2dsR/qU5bFlnx2XgolmlCJRo00buy99Goo0umJi81V5Ii917w/TO8F2UqLMqk0s+w==", + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@ngrx/store-devtools/-/store-devtools-15.4.0.tgz", + "integrity": "sha512-AqWRprSyS3u/vZlpsBOPMW1/0TZS2LE13/KpZedEY+RMCW+mi53esqgrdNGOB3Wr4vrI82Ar9fgaIm4TQO6LPg==", "dev": true, "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { - "@ngrx/store": "15.2.1", + "@ngrx/store": "15.4.0", "rxjs": "^6.5.3 || ^7.5.0" } }, "node_modules/@ngtools/webpack": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-15.1.4.tgz", - "integrity": "sha512-IvKXK8AvPlLkP99Uf0RL1EHlcsXNQd86II9HsLjupUtmFC/pPuDWrRFMP9bjWUMh2ZeYpgUeEAbcCH3doSrdIA==", + "version": "15.2.6", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-15.2.6.tgz", + "integrity": "sha512-I+kekKItfsCLdX+ZjjmsWqd0AyoYGTQPjlbQAiPtmdH73/rfPOF4Q/3AU4tzTdn0n0GXqZWv6VOs91w99ydi0A==", "dev": true, "engines": { "node": "^14.20.0 || ^16.13.0 || >=18.10.0", @@ -5911,14 +5904,13 @@ } }, "node_modules/@npmcli/git": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.0.3.tgz", - "integrity": "sha512-8cXNkDIbnXPVbhXMmQ7/bklCAjtmPaXfI9aEM4iH+xSuEHINLMHhlfESvVwdqmHJRJkR48vNJTSUvoF6GRPSFA==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.0.4.tgz", + "integrity": "sha512-5yZghx+u5M47LghaybLCkdSyFzV/w4OuH12d96HO389Ik9CDsLaDZJVynSGGVJOLn6gy/k7Dz5XYcplM3uxXRg==", "dev": true, "dependencies": { "@npmcli/promise-spawn": "^6.0.0", "lru-cache": "^7.4.4", - "mkdirp": "^1.0.4", "npm-pick-manifest": "^8.0.0", "proc-log": "^3.0.0", "promise-inflight": "^1.0.1", @@ -5931,9 +5923,9 @@ } }, "node_modules/@npmcli/git/node_modules/lru-cache": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", - "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, "engines": { "node": ">=12" @@ -5955,9 +5947,9 @@ } }, "node_modules/@npmcli/installed-package-contents": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.1.tgz", - "integrity": "sha512-GIykAFdOVK31Q1/zAtT5MbxqQL2vyl9mvFJv+OGu01zxbhL3p0xc8gJjdNGX1mWmUT43aEKVO2L6V/2j4TOsAA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", + "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", "dev": true, "dependencies": { "npm-bundled": "^3.0.0", @@ -6052,13 +6044,13 @@ } }, "node_modules/@schematics/angular": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-15.1.4.tgz", - "integrity": "sha512-4SV8dDGZeSvts01b8y2W6FmpDD0dQhBlGMhMJKC/tUnhfNKfYCs2VKtMBsIc3ZiGP2yoA3+nUiMmtS6hEkXYHw==", + "version": "15.2.6", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-15.2.6.tgz", + "integrity": "sha512-OcBUvVAxZEMBX+fi0ytybeAdmStra+GwtlvipS70yOxcAgJ84ZrnZGN7a072cCVQcq7AgqUfssnyqCx1wu+yCg==", "dev": true, "dependencies": { - "@angular-devkit/core": "15.1.4", - "@angular-devkit/schematics": "15.1.4", + "@angular-devkit/core": "15.2.6", + "@angular-devkit/schematics": "15.2.6", "jsonc-parser": "3.2.0" }, "engines": { @@ -6067,11 +6059,14 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@schematics/angular/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true + "node_modules/@sigstore/protobuf-specs": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.1.0.tgz", + "integrity": "sha512-a31EnjuIDSX8IXBUib3cYLDRlPMU36AWX4xS8ysLaNu4ZzUesDiPt83pgrW2X1YLMe5L2HbDyaKK5BrL4cNKaQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, "node_modules/@tootallnate/once": { "version": "2.0.0", @@ -6082,6 +6077,42 @@ "node": ">= 10" } }, + "node_modules/@tufjs/models": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.1.tgz", + "integrity": "sha512-AY0VoG/AXdlSOocuREfPoEW4SNhOPp/7fw6mpAxfVIny1uZ+0fEtMoCi7NhELSlqQIRLMu7RgfKhkxT+AJ+EXg==", + "dev": true, + "dependencies": { + "minimatch": "^7.4.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/minimatch": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz", + "integrity": "sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -6121,9 +6152,9 @@ } }, "node_modules/@types/d3-selection": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.4.tgz", - "integrity": "sha512-ZeykX7286BCyMg9sH5fIAORyCB6hcATPSRQpN47jwBA2bMbAT0s+EvtDP5r1FZYJ95R8QoEE1CKJX+n0/M5Vhg==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.5.tgz", + "integrity": "sha512-xCB0z3Hi8eFIqyja3vW8iV01+OHGYR2di/+e+AiOcXIOrY82lcvWW8Ke1DYE/EUVMsBl4Db9RppSBS3X1U6J0w==", "dev": true }, "node_modules/@types/eslint": { @@ -6176,9 +6207,9 @@ } }, "node_modules/@types/http-proxy": { - "version": "1.17.9", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", - "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", + "version": "1.17.10", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.10.tgz", + "integrity": "sha512-Qs5aULi+zV1bwKAg5z1PWnDXWmsn+LxIvUGv6E2+OOMYhclZMO+OXd9pYVf2gLykf2I7IV2u7oTHwChPNsvJ7g==", "dev": true, "dependencies": { "@types/node": "*" @@ -6203,9 +6234,9 @@ "dev": true }, "node_modules/@types/lodash-es": { - "version": "4.17.6", - "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.6.tgz", - "integrity": "sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==", + "version": "4.17.7", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.7.tgz", + "integrity": "sha512-z0ptr6UI10VlU6l5MYhGwS4mC8DZyYer2mCoyysZtSF7p26zOX8UpbrV0YpNYLGS8K4PUFIyEr62IMFFjveSiQ==", "dev": true, "dependencies": { "@types/lodash": "*" @@ -6218,9 +6249,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.13.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", - "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==", + "version": "18.16.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.0.tgz", + "integrity": "sha512-BsAaKhB+7X+H4GnSjGhJG9Qi8Tw+inU9nJDwmD5CgOmBLEI6ArdhikpLX7DjbjDRDTbqZzU2LSQNZg8WGPiSZQ==", "dev": true }, "node_modules/@types/parse-json": { @@ -6230,9 +6261,9 @@ "dev": true }, "node_modules/@types/plotly.js": { - "version": "2.12.13", - "resolved": "https://registry.npmjs.org/@types/plotly.js/-/plotly.js-2.12.13.tgz", - "integrity": "sha512-p/xo8LuJMxSvT/szkjgUJVlopRu049NZ+p46MpcSlovmO6tIgyzldm8kLUo9p24XE/5iZzGSTtvIUQjLwIUQxw==", + "version": "2.12.18", + "resolved": "https://registry.npmjs.org/@types/plotly.js/-/plotly.js-2.12.18.tgz", + "integrity": "sha512-ff+CIEWnqZNjZqHtQZvkEAVuLs9fkm1f54QnPVmgoET7wMHdSqUka2hasVN4e5yfHD05YwGjsAtCseewJh/BMw==", "dev": true }, "node_modules/@types/qs": { @@ -6269,9 +6300,9 @@ } }, "node_modules/@types/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", + "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", "dev": true, "dependencies": { "@types/mime": "*", @@ -6288,9 +6319,9 @@ } }, "node_modules/@types/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==", "dev": true }, "node_modules/@types/ws": { @@ -6308,19 +6339,19 @@ "integrity": "sha512-Nqo3HMPFPcNyZ7HNFZJjpH+N4yXqpxBItG+41e7nL9zednovMRZMXWj36CctSznbBcbj6ucvkJDo5iZ8SKqLIw==" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.51.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.51.0.tgz", - "integrity": "sha512-wcAwhEWm1RgNd7dxD/o+nnLW8oH+6RK1OGnmbmkj/GGoDPV1WWMVP0FXYQBivKHdwM1pwii3bt//RC62EriIUQ==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.1.tgz", + "integrity": "sha512-AVi0uazY5quFB9hlp2Xv+ogpfpk77xzsgsIEWyVS7uK/c7MZ5tw7ZPbapa0SbfkqE0fsAMkz5UwtgMLVk2BQAg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.51.0", - "@typescript-eslint/type-utils": "5.51.0", - "@typescript-eslint/utils": "5.51.0", + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.59.1", + "@typescript-eslint/type-utils": "5.59.1", + "@typescript-eslint/utils": "5.59.1", "debug": "^4.3.4", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", "semver": "^7.3.7", "tsutils": "^3.21.0" }, @@ -6342,14 +6373,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.51.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.51.0.tgz", - "integrity": "sha512-fEV0R9gGmfpDeRzJXn+fGQKcl0inIeYobmmUWijZh9zA7bxJ8clPhV9up2ZQzATxAiFAECqPQyMDB4o4B81AaA==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.1.tgz", + "integrity": "sha512-nzjFAN8WEu6yPRDizIFyzAfgK7nybPodMNFGNH0M9tei2gYnYszRDqVA0xlnRjkl7Hkx2vYrEdb6fP2a21cG1g==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.51.0", - "@typescript-eslint/types": "5.51.0", - "@typescript-eslint/typescript-estree": "5.51.0", + "@typescript-eslint/scope-manager": "5.59.1", + "@typescript-eslint/types": "5.59.1", + "@typescript-eslint/typescript-estree": "5.59.1", "debug": "^4.3.4" }, "engines": { @@ -6369,13 +6400,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.51.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.51.0.tgz", - "integrity": "sha512-gNpxRdlx5qw3yaHA0SFuTjW4rxeYhpHxt491PEcKF8Z6zpq0kMhe0Tolxt0qjlojS+/wArSDlj/LtE69xUJphQ==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.1.tgz", + "integrity": "sha512-mau0waO5frJctPuAzcxiNWqJR5Z8V0190FTSqRw1Q4Euop6+zTwHAf8YIXNwDOT29tyUDrQ65jSg9aTU/H0omA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.51.0", - "@typescript-eslint/visitor-keys": "5.51.0" + "@typescript-eslint/types": "5.59.1", + "@typescript-eslint/visitor-keys": "5.59.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -6386,13 +6417,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.51.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.51.0.tgz", - "integrity": "sha512-QHC5KKyfV8sNSyHqfNa0UbTbJ6caB8uhcx2hYcWVvJAZYJRBo5HyyZfzMdRx8nvS+GyMg56fugMzzWnojREuQQ==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.1.tgz", + "integrity": "sha512-ZMWQ+Oh82jWqWzvM3xU+9y5U7MEMVv6GLioM3R5NJk6uvP47kZ7YvlgSHJ7ERD6bOY7Q4uxWm25c76HKEwIjZw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.51.0", - "@typescript-eslint/utils": "5.51.0", + "@typescript-eslint/typescript-estree": "5.59.1", + "@typescript-eslint/utils": "5.59.1", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -6413,9 +6444,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.51.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.51.0.tgz", - "integrity": "sha512-SqOn0ANn/v6hFn0kjvLwiDi4AzR++CBZz0NV5AnusT2/3y32jdc0G4woXPWHCumWtUXZKPAS27/9vziSsC9jnw==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.1.tgz", + "integrity": "sha512-dg0ICB+RZwHlysIy/Dh1SP+gnXNzwd/KS0JprD3Lmgmdq+dJAJnUPe1gNG34p0U19HvRlGX733d/KqscrGC1Pg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -6426,13 +6457,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.51.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.51.0.tgz", - "integrity": "sha512-TSkNupHvNRkoH9FMA3w7TazVFcBPveAAmb7Sz+kArY6sLT86PA5Vx80cKlYmd8m3Ha2SwofM1KwraF24lM9FvA==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.1.tgz", + "integrity": "sha512-lYLBBOCsFltFy7XVqzX0Ju+Lh3WPIAWxYpmH/Q7ZoqzbscLiCW00LeYCdsUnnfnj29/s1WovXKh2gwCoinHNGA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.51.0", - "@typescript-eslint/visitor-keys": "5.51.0", + "@typescript-eslint/types": "5.59.1", + "@typescript-eslint/visitor-keys": "5.59.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -6453,18 +6484,18 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.51.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.51.0.tgz", - "integrity": "sha512-76qs+5KWcaatmwtwsDJvBk4H76RJQBFe+Gext0EfJdC3Vd2kpY2Pf//OHHzHp84Ciw0/rYoGTDnIAr3uWhhJYw==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.1.tgz", + "integrity": "sha512-MkTe7FE+K1/GxZkP5gRj3rCztg45bEhsd8HYjczBuYm+qFHP5vtZmjx3B0yUCDotceQ4sHgTyz60Ycl225njmA==", "dev": true, "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.51.0", - "@typescript-eslint/types": "5.51.0", - "@typescript-eslint/typescript-estree": "5.51.0", + "@typescript-eslint/scope-manager": "5.59.1", + "@typescript-eslint/types": "5.59.1", + "@typescript-eslint/typescript-estree": "5.59.1", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", "semver": "^7.3.7" }, "engines": { @@ -6479,12 +6510,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.51.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.51.0.tgz", - "integrity": "sha512-Oh2+eTdjHjOFjKA27sxESlA87YPSOJafGCR0md5oeMdh1ZcCfAGCIOL216uTBAkAIptvLIfKQhl7lHxMJet4GQ==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.1.tgz", + "integrity": "sha512-6waEYwBTCWryx0VJmP7JaM4FpipLsFl9CvYf2foAE8Qh/Y0s+bxWysciwOs0LTBED4JCaNxTZ5rGadB14M6dwA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/types": "5.59.1", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -6685,9 +6716,9 @@ } }, "node_modules/ace-builds": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.15.0.tgz", - "integrity": "sha512-L1RXgqxDvzbJ7H8Y2v9lb4kHaZRn5JNTECG+oZTH2EDewMmpQMLDC4GnFKIh3+xb/gk2nVPO7gGwpTYPw91QzA==" + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.18.0.tgz", + "integrity": "sha512-ETLeQ3X1XvcWckOZFR+KvTectZyEwDm2p+CckWazS+xsK3THHVxn/PkfkPr37OTNKVY/yJRx29JGERV77YQYXw==" }, "node_modules/acorn": { "version": "8.8.1", @@ -6759,13 +6790,13 @@ } }, "node_modules/agentkeepalive": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", - "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", + "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", "dev": true, "dependencies": { "debug": "^4.1.0", - "depd": "^1.1.2", + "depd": "^2.0.0", "humanize-ms": "^1.2.1" }, "engines": { @@ -6786,9 +6817,9 @@ } }, "node_modules/ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -6854,9 +6885,9 @@ } }, "node_modules/angular-split": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/angular-split/-/angular-split-14.1.0.tgz", - "integrity": "sha512-WJ7LUROpvuEy9r7/EHBO2TwrJXrHeB8PUeAWmM5gU1lCmfttAXcCGSCMMIuiCs/QNSsq8mR8rTMCvNs4Xeihfg==", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/angular-split/-/angular-split-15.0.0.tgz", + "integrity": "sha512-An/f0NobbxHxA9bowwYIuKHPoP2yoQldrPklpMvmQdqntExys+B92m7kkfs4K0ANuowyFIZHMeEzounC4j7ocQ==", "dependencies": { "tslib": "^2.0.0" }, @@ -6967,6 +6998,15 @@ "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", "dev": true }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/are-we-there-yet": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", @@ -7323,15 +7363,6 @@ "ms": "2.0.0" } }, - "node_modules/body-parser/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -7339,9 +7370,9 @@ "dev": true }, "node_modules/bonjour-service": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.0.tgz", - "integrity": "sha512-LVRinRB3k1/K0XzZ2p58COnWvkQknIY6sf0zF2rpErvcJXpMBttEPQSxK+HEXSS9VmpZlDoDnQWv8ftJT20B0Q==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", + "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", "dev": true, "dependencies": { "array-flatten": "^2.1.2", @@ -7357,9 +7388,9 @@ "dev": true }, "node_modules/bootstrap": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz", - "integrity": "sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.2.3.tgz", + "integrity": "sha512-cEKPM+fwb3cT8NzQZYEu4HilJ3anCrWqh3CHAok1p9jXqMPsPTBhU25fBckEJHJ/p+tTxTFTsFQGM+gaHpi3QQ==", "funding": [ { "type": "github", @@ -7371,8 +7402,7 @@ } ], "peerDependencies": { - "jquery": "1.9.1 - 3", - "popper.js": "^1.16.1" + "@popperjs/core": "^2.11.6" } }, "node_modules/bowser": { @@ -7413,9 +7443,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", "dev": true, "funding": [ { @@ -7428,10 +7458,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" }, "bin": { "browserslist": "cli.js" @@ -7593,9 +7623,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001426", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001426.tgz", - "integrity": "sha512-n7cosrHLl8AWt0wwZw/PJZgUg3lV0gk9LMI7ikGJwhyhgsd2Nb65vKvmSexCqq/J7rbH3mFG6yZZiPR5dLPW5A==", + "version": "1.0.30001477", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001477.tgz", + "integrity": "sha512-lZim4iUHhGcy5p+Ri/G7m84hJwncj+Kz7S5aD4hoQfslKZJgt0tHc/hafVbqHC5bbhHb+mrW2JOUHkI5KH7toQ==", "dev": true, "funding": [ { @@ -7605,6 +7635,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, @@ -8757,12 +8791,12 @@ "dev": true }, "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/dependency-graph": { @@ -8817,9 +8851,9 @@ "dev": true }, "node_modules/dns-packet": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", - "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.0.tgz", + "integrity": "sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ==", "dev": true, "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" @@ -9141,9 +9175,9 @@ } }, "node_modules/esbuild": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz", - "integrity": "sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.8.tgz", + "integrity": "sha512-g24ybC3fWhZddZK6R3uD2iF/RIPnRpwJAqLov6ouX3hMbY4+tKolP0VMF3zuIYCaXun+yHwS5IPQ91N2BT191g==", "dev": true, "hasInstallScript": true, "optional": true, @@ -9154,34 +9188,34 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.16.17", - "@esbuild/android-arm64": "0.16.17", - "@esbuild/android-x64": "0.16.17", - "@esbuild/darwin-arm64": "0.16.17", - "@esbuild/darwin-x64": "0.16.17", - "@esbuild/freebsd-arm64": "0.16.17", - "@esbuild/freebsd-x64": "0.16.17", - "@esbuild/linux-arm": "0.16.17", - "@esbuild/linux-arm64": "0.16.17", - "@esbuild/linux-ia32": "0.16.17", - "@esbuild/linux-loong64": "0.16.17", - "@esbuild/linux-mips64el": "0.16.17", - "@esbuild/linux-ppc64": "0.16.17", - "@esbuild/linux-riscv64": "0.16.17", - "@esbuild/linux-s390x": "0.16.17", - "@esbuild/linux-x64": "0.16.17", - "@esbuild/netbsd-x64": "0.16.17", - "@esbuild/openbsd-x64": "0.16.17", - "@esbuild/sunos-x64": "0.16.17", - "@esbuild/win32-arm64": "0.16.17", - "@esbuild/win32-ia32": "0.16.17", - "@esbuild/win32-x64": "0.16.17" + "@esbuild/android-arm": "0.17.8", + "@esbuild/android-arm64": "0.17.8", + "@esbuild/android-x64": "0.17.8", + "@esbuild/darwin-arm64": "0.17.8", + "@esbuild/darwin-x64": "0.17.8", + "@esbuild/freebsd-arm64": "0.17.8", + "@esbuild/freebsd-x64": "0.17.8", + "@esbuild/linux-arm": "0.17.8", + "@esbuild/linux-arm64": "0.17.8", + "@esbuild/linux-ia32": "0.17.8", + "@esbuild/linux-loong64": "0.17.8", + "@esbuild/linux-mips64el": "0.17.8", + "@esbuild/linux-ppc64": "0.17.8", + "@esbuild/linux-riscv64": "0.17.8", + "@esbuild/linux-s390x": "0.17.8", + "@esbuild/linux-x64": "0.17.8", + "@esbuild/netbsd-x64": "0.17.8", + "@esbuild/openbsd-x64": "0.17.8", + "@esbuild/sunos-x64": "0.17.8", + "@esbuild/win32-arm64": "0.17.8", + "@esbuild/win32-ia32": "0.17.8", + "@esbuild/win32-x64": "0.17.8" } }, "node_modules/esbuild-wasm": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.16.17.tgz", - "integrity": "sha512-Tn7NuMqRcM+T/qCOxbQRq0qrwWl1sUWp6ARfJRakE8Bepew6zata4qrKgH2YqovNC5e/2fcTa7o+VL/FAOZC1Q==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.17.8.tgz", + "integrity": "sha512-zCmpxv95E0FuCmvdw1K836UHnj4EdiQnFfjTby35y3LAjRPtXMj3sbHDRHjbD8Mqg5lTwq3knacr/1qIFU51CQ==", "dev": true, "bin": { "esbuild": "bin/esbuild" @@ -9215,12 +9249,15 @@ } }, "node_modules/eslint": { - "version": "8.33.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.33.0.tgz", - "integrity": "sha512-WjOpFQgKK8VrCnAtl8We0SUOy/oVZ5NHykyMiagV1M9r8IFpIJX7DduK6n1mpfhlG7T1NLWm2SuD8QB7KFySaA==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", + "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.4.1", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.39.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -9230,11 +9267,10 @@ "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.0", + "espree": "^9.5.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", @@ -9255,7 +9291,6 @@ "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" @@ -9376,16 +9411,17 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "39.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.8.0.tgz", - "integrity": "sha512-ZwGmk0jJoJD/NILeDRBKrpq/PCgddUdATjeU5JGTqTzKsOWfeaHOnaAwZjuOh7T8EB4hSoZ/9pR4+Qns2ldQVg==", + "version": "41.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-41.1.2.tgz", + "integrity": "sha512-MePJXdGiPW7AG06CU5GbKzYtKpoHwTq1lKijjq+RwL/cQkZtBZ59Zbv5Ep0RVxSMnq6242249/n+w4XrTZ1Afg==", "dev": true, "dependencies": { - "@es-joy/jsdoccomment": "~0.36.1", + "@es-joy/jsdoccomment": "~0.37.0", + "are-docs-informative": "^0.0.2", "comment-parser": "1.3.1", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", - "esquery": "^1.4.0", + "esquery": "^1.5.0", "semver": "^7.3.8", "spdx-expression-parse": "^3.0.1" }, @@ -9458,12 +9494,15 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/ajv": { @@ -9550,9 +9589,9 @@ } }, "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", @@ -9560,6 +9599,9 @@ }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/estraverse": { @@ -9711,14 +9753,14 @@ } }, "node_modules/espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", "dev": true, "dependencies": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -9741,9 +9783,9 @@ } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -9910,15 +9952,6 @@ "ms": "2.0.0" } }, - "node_modules/express/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/express/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -9986,9 +10019,9 @@ "dev": true }, "node_modules/fast-xml-parser": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.0.11.tgz", - "integrity": "sha512-4aUg3aNRR/WjQAcpceODG1C3x3lFANXRo8+1biqfieHmg9pyMt7qB4lQV/Ta6sJCTbA5vfD8fnA8S54JATiFUA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.1.2.tgz", + "integrity": "sha512-CDYeykkle1LiA/uqQyNwYpFbyF6Axec6YapmpUP+/RHWIoR1zKjocdvNaTsxCxZzQ6v9MLXaSYm9Qq0thv0DHg==", "dependencies": { "strnum": "^1.0.5" }, @@ -10055,9 +10088,9 @@ } }, "node_modules/filesize": { - "version": "10.0.6", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.0.6.tgz", - "integrity": "sha512-rzpOZ4C9vMFDqOa6dNpog92CoLYjD79dnjLk2TYDDtImRIyLTOzqojCb05Opd1WuiWjs+fshhCgTd8cl7y5t+g==", + "version": "10.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.0.7.tgz", + "integrity": "sha512-iMRG7Qo9nayLoU3PNCiLizYtsy4W1ClrapeCwEgtiQelOAOuRJiw4QaLI+sSr8xr901dgHv+EYP2bCusGZgoiA==", "engines": { "node": ">= 10.4.0" } @@ -10634,9 +10667,9 @@ } }, "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", - "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, "engines": { "node": ">=12" @@ -10655,9 +10688,9 @@ } }, "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "dependencies": { "core-util-is": "~1.0.0", @@ -10709,15 +10742,6 @@ "node": ">= 0.8" } }, - "node_modules/http-errors/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/http-parser-js": { "version": "0.5.8", "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", @@ -10860,12 +10884,12 @@ } }, "node_modules/ignore-walk": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.1.tgz", - "integrity": "sha512-/c8MxUAqpRccq+LyDOecwF+9KqajueJHh8fz7g3YqjMZt+NSfJzx05zrKiXwa2sKwFCzaiZ5qUVfRj0pmxixEA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.2.tgz", + "integrity": "sha512-ezmQ1Dg2b3jVZh2Dh+ar6Eu2MqNSTkyb32HU2MAQQQX9tKM3q/UQ/9lf03lQ5hW+fOeoMnwxwkleZ0xcNp0/qg==", "dev": true, "dependencies": { - "minimatch": "^6.1.6" + "minimatch": "^7.4.2" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -10881,9 +10905,9 @@ } }, "node_modules/ignore-walk/node_modules/minimatch": { - "version": "6.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-6.1.6.tgz", - "integrity": "sha512-6bR3UIeh/DF8+p6A9Spyuy67ShOq42rOkHWi7eUe3Ua99Zo5lZfGC6lJJWkeoK4k9jQFT3Pl7czhTXimG2XheA==", + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz", + "integrity": "sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -11652,9 +11676,9 @@ } }, "node_modules/jsdoc-type-pratt-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz", - "integrity": "sha512-MgtD0ZiCDk9B+eI73BextfRrVQl0oyzRG8B2BjORts6jbunj4ScKPcyXGTbB6eXL4y9TzxCm6hyeLq/2ASzNdw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", "dev": true, "engines": { "node": ">=12.0.0" @@ -11702,6 +11726,12 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, "node_modules/jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", @@ -12051,6 +12081,18 @@ "resolved": "https://registry.npmjs.org/lucene/-/lucene-2.1.1.tgz", "integrity": "sha512-l0qCX+pgXEZh/7sYQNG+vzhOIFRPjlJJkQ/irk9n7Ak3d+1MrU6F7IV31KILwFkUn153oLK8a2AIt48DzLdVPg==" }, + "node_modules/magic-string": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.29.0.tgz", + "integrity": "sha512-WcfidHrDjMY+eLjlU+8OvwREqHwpgCeKVBUpQ3OhYYuvfaYCUgcbuBzappNzZvg/v8onU3oQj+BYpkOJe9Iw4Q==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.13" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -12185,9 +12227,9 @@ } }, "node_modules/make-fetch-happen/node_modules/lru-cache": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", - "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, "engines": { "node": ">=12" @@ -12403,9 +12445,9 @@ "dev": true }, "node_modules/minipass": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.3.tgz", - "integrity": "sha512-OW2r4sQ0sI+z5ckEt5c1Tri4xTgZwYDxpE54eqWlQloQRoWtXjqt9udJ5Z4dSv7wK+nfFI7FRXyCpBSft+gpFw==", + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.7.tgz", + "integrity": "sha512-ScVIgqHcXRMyfflqHmEW0bm8z8rb5McHyOY3ewX9JBgZaR77G7nxq9L/mtV96/QbAAwtbCAHVVLzD1kkyfFQEw==", "dev": true, "engines": { "node": ">=8" @@ -12701,11 +12743,11 @@ "dev": true }, "node_modules/ngx-clipboard": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/ngx-clipboard/-/ngx-clipboard-15.1.0.tgz", - "integrity": "sha512-dUJl1cNtdkCqL953oAhP7wmUPFrqW2aDg5OPhwPU9R3cLEdQgU2NbsHEUz4zaPyEopTXu8SR37onVm1Ep8qOHg==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/ngx-clipboard/-/ngx-clipboard-16.0.0.tgz", + "integrity": "sha512-rZ/Eo1PqiKMiyF8tdjhmUkoUu68f7OzBJ7YH1YFeh2RAaNrerTaW8XfFOzppSckjFQqA1fwGSYuTTJlDhDag5w==", "dependencies": { - "ngx-window-token": ">=6.0.0", + "ngx-window-token": ">=7.0.0", "tslib": "^2.0.0" }, "peerDependencies": { @@ -12714,9 +12756,9 @@ } }, "node_modules/ngx-color-picker": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/ngx-color-picker/-/ngx-color-picker-13.0.0.tgz", - "integrity": "sha512-3mgMbs21KeqnmmY5p1cn71ckTH3q7gBt6Qn0fMfeF/Ql7ddTZsW4Z7Z8ga6LymMP/ugooGuLOFX+V6yx0dDxAw==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/ngx-color-picker/-/ngx-color-picker-14.0.0.tgz", + "integrity": "sha512-w28zx2DyVpIJeNsTB3T2LUI4Ed/Ujf5Uhxuh0dllputfpxXwZG9ocSJM/0L67+fxA3UnfvvXVZNUX1Ny5nZIIw==", "dependencies": { "tslib": "^2.3.0" }, @@ -12739,9 +12781,9 @@ } }, "node_modules/ngx-markdown-editor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ngx-markdown-editor/-/ngx-markdown-editor-5.1.0.tgz", - "integrity": "sha512-KE7j8apkcjncMOWIZJpkV41hOi99ki6KHOTUtLai/WrD4P6bebz9Ig/ZtdX8zhSPR8xep9tmm7hEF/9eXvePaw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ngx-markdown-editor/-/ngx-markdown-editor-5.3.0.tgz", + "integrity": "sha512-IeGqtvq+jDMjGGnFFdHhEPphx+jM27EdvcJ3IboCQlXzolpe10JUdCCe53T6TgFe2MFvegVlaVuo44Dcve5IZw==", "dependencies": { "tslib": "^2.3.0" }, @@ -12760,14 +12802,14 @@ } }, "node_modules/ngx-window-token": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ngx-window-token/-/ngx-window-token-6.0.0.tgz", - "integrity": "sha512-IeLKO1jzfzSvZ6vlAt4QSY/B5XcHEhdOwTjqvWEPt6/esWV9T3mA2ln10kj6SCc9pUSx4NybxE10gcyyYroImg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ngx-window-token/-/ngx-window-token-7.0.0.tgz", + "integrity": "sha512-5+XfRVSY7Dciu8xyCNMkOlH2UfwR9W2P1Pirz7caaZgOZDjFbL8aEO2stjfJJm2FFf1D6dlVHNzhLWGk9HGkqA==", "dependencies": { "tslib": "^2.0.0" }, "engines": { - "node": ">=12.20.x" + "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { "@angular/common": ">=13.0.0", @@ -12842,9 +12884,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", "dev": true }, "node_modules/nopt": { @@ -12908,9 +12950,9 @@ } }, "node_modules/npm-install-checks": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.0.0.tgz", - "integrity": "sha512-SBU9oFglRVZnfElwAtF14NivyulDqF1VKqqwNsFW9HDcbHMAPHpRSsVFgKuwFGq/hVvWZExz62Th0kvxn/XE7Q==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.1.0.tgz", + "integrity": "sha512-udSGENih/5xKh3Ex+L0PtZcOt0Pa+6ppDLnpG5D49/EhMja3LupaY9E/DtJTxyFBwE09ot7Fc+H4DywnZNWTVA==", "dev": true, "dependencies": { "semver": "^7.1.1" @@ -12989,9 +13031,9 @@ } }, "node_modules/npm-registry-fetch/node_modules/lru-cache": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", - "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, "engines": { "node": ">=12" @@ -13208,9 +13250,9 @@ } }, "node_modules/open": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.1.tgz", + "integrity": "sha512-/4b7qZNhv6Uhd7jjnREh1NjnPxlTq+XNWPG88Ydkj5AILcA5m3ajvcg57pB24EQjKv0dK62XnDqk9c/hkIG5Kg==", "dev": true, "dependencies": { "define-lazy-prop": "^2.0.0", @@ -13417,9 +13459,9 @@ } }, "node_modules/pacote": { - "version": "15.0.8", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.0.8.tgz", - "integrity": "sha512-UlcumB/XS6xyyIMwg/WwMAyUmga+RivB5KgkRwA1hZNtrx+0Bt41KxHCvg1kr0pZ/ZeD8qjhW4fph6VaYRCbLw==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.1.0.tgz", + "integrity": "sha512-FFcjtIl+BQNfeliSm7MZz5cpdohvUV1yjGnqgVM4UnVF7JslRY0ImXAygdaCDV0jjUADEWu4y5xsDV8brtrTLg==", "dev": true, "dependencies": { "@npmcli/git": "^4.0.0", @@ -13437,6 +13479,7 @@ "promise-retry": "^2.0.1", "read-package-json": "^6.0.0", "read-package-json-fast": "^3.0.0", + "sigstore": "^1.0.0", "ssri": "^10.0.0", "tar": "^6.1.11" }, @@ -13496,7 +13539,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "optional": true, + "devOptional": true, "dependencies": { "entities": "^4.4.0" }, @@ -13505,20 +13548,30 @@ } }, "node_modules/parse5-html-rewriting-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-6.0.1.tgz", - "integrity": "sha512-vwLQzynJVEfUlURxgnf51yAJDQTtVpNyGD8tKi2Za7m+akukNHxCcUQMAa/mUGLhCeicFdpy7Tlvj8ZNKadprg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", + "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", "dev": true, "dependencies": { - "parse5": "^6.0.1", - "parse5-sax-parser": "^6.0.1" + "entities": "^4.3.0", + "parse5": "^7.0.0", + "parse5-sax-parser": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/parse5-html-rewriting-stream/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true + "node_modules/parse5-html-rewriting-stream/node_modules/entities": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", + "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } }, "node_modules/parse5-htmlparser2-tree-adapter": { "version": "6.0.1", @@ -13536,25 +13589,22 @@ "dev": true }, "node_modules/parse5-sax-parser": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-6.0.1.tgz", - "integrity": "sha512-kXX+5S81lgESA0LsDuGjAlBybImAChYRMT+/uKCEXFBFOeEhS52qUCydGhU3qLRD8D9DVjaUo821WK7DM4iCeg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", + "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", "dev": true, "dependencies": { - "parse5": "^6.0.1" + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/parse5-sax-parser/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, "node_modules/parse5/node_modules/entities": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", - "optional": true, + "devOptional": true, "engines": { "node": ">=0.12" }, @@ -13604,6 +13654,40 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-scurry": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.6.4.tgz", + "integrity": "sha512-Qp/9IHkdNiXJ3/Kon++At2nVpnhRiPq/aSvQN+H3U1WZbvNRK0RIQK/o4HMqPoXjpuGJUEWpHSs6Mnjxqh3TQg==", + "dev": true, + "dependencies": { + "lru-cache": "^9.0.0", + "minipass": "^5.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.0.0.tgz", + "integrity": "sha512-9AEKXzvOZc4BMacFnYiTOlDH/197LNnQIK9wZ6iMB5NXPzuv4bWR/Msv7iUMplkiMQ1qQL+KSv/JF1mZAB5Lrg==", + "dev": true, + "engines": { + "node": ">=16.14" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -13824,19 +13908,18 @@ "integrity": "sha512-KDeO94CbWI4pKsPnYpA1FPjo79EsY9I+M8ywoPBSf9XMXoe/0crjbUK7jcQEDHuc0ZMRIZsxH3TYLv4TUtHmAA==" }, "node_modules/primeng": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/primeng/-/primeng-15.2.0.tgz", - "integrity": "sha512-CLcB4RYiI4PcQ8nwov01L5CQHbhl7n1OufA2OKIq9+C4sBEv9sLsnEN2/Cah4m1jtrRkNbsac8JJE7LdPxecaQ==", + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/primeng/-/primeng-15.4.1.tgz", + "integrity": "sha512-j2unOQZk6756l6SgkzcmlHF6JlawF0bIjKTgAPWwT+S5RYeWEjpCPg/ABV8TylwW7CTNQX2oCHbyqCAuhtr++w==", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/common": "^15.1.0", - "@angular/core": "^15.1.0", - "@angular/forms": "^15.1.0", - "primeicons": "^6.0.1", + "@angular/common": "^15.2.1", + "@angular/core": "^15.2.1", + "@angular/forms": "^15.2.1", "rxjs": "^6.0.0 || ^7.5.0", - "zone.js": "^0.10.2 || ^0.11.0 || ^0.12.0" + "zone.js": "^0.10.2 || ^0.11.0 || ^0.12.0 || ^0.13.0" } }, "node_modules/proc-log": { @@ -14006,12 +14089,12 @@ } }, "node_modules/read-package-json": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.0.tgz", - "integrity": "sha512-b/9jxWJ8EwogJPpv99ma+QwtqB7FSl3+V6UXS7Aaay8/5VwMY50oIFooY1UKXMWpfNCM6T/PoGqa5GD1g9xf9w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.1.tgz", + "integrity": "sha512-AaHqXxfAVa+fNL07x8iAghfKOds/XXsu7zoouIVsbm7PEbQ3nMWXlvjcbrNLjElnUHWQtAo4QEa0RXuvD4XlpA==", "dev": true, "dependencies": { - "glob": "^8.0.1", + "glob": "^9.3.0", "json-parse-even-better-errors": "^3.0.0", "normalize-package-data": "^5.0.0", "npm-normalize-package-bin": "^3.0.0" @@ -14052,19 +14135,18 @@ } }, "node_modules/read-package-json/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" }, "engines": { - "node": ">=12" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -14080,15 +14162,18 @@ } }, "node_modules/read-package-json/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/readable-stream": { @@ -14179,18 +14264,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/regexpu-core": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz", @@ -14469,9 +14542,9 @@ "integrity": "sha512-LRneZZRXNgjzwG4bDQdOTSbze3fHm1EAKN/8bePxnlEZiBmkYEDggaHbuvHI9/hoqHbGfsEA7tWS9GhYHZBBsw==" }, "node_modules/sass": { - "version": "1.57.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.57.1.tgz", - "integrity": "sha512-O2+LwLS79op7GI0xZ8fqzF7X2m/m8WFfI02dHOdsK5R2ECeS5F62zrwg/relM1rjSLy7Vd/DiMNIvPrQGsA0jw==", + "version": "1.58.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.58.1.tgz", + "integrity": "sha512-bnINi6nPXbP1XNRaranMFEBZWUfdW/AF16Ql5+ypRxfTvCRTTKrLsMIakyDcayUt2t/RZotmL4kgJwNH5xO+bg==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -14639,15 +14712,6 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/send/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -14690,6 +14754,15 @@ "ms": "2.0.0" } }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/serve-index/node_modules/http-errors": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", @@ -14812,6 +14885,75 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/sigstore": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.2.0.tgz", + "integrity": "sha512-Fr9+W1nkBSIZCkJQR7jDn/zI0UXNsVpp+7mDQkCnZOIxG9p6yNXBx9xntHsfUyYHE55XDkkVV3+rYbrkzAeesA==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.1.0", + "make-fetch-happen": "^11.0.1", + "tuf-js": "^1.0.0" + }, + "bin": { + "sigstore": "bin/sigstore.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/sigstore/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/sigstore/node_modules/make-fetch-happen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", + "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/sigstore/node_modules/minipass-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", + "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -14950,9 +15092,9 @@ } }, "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, "dependencies": { "spdx-expression-parse": "^3.0.0", @@ -15248,9 +15390,9 @@ } }, "node_modules/terser": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", - "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", + "version": "5.16.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.3.tgz", + "integrity": "sha512-v8wWLaS/xt3nE9dgKEWhNUFP6q4kngO5B8eYFUuebsu7Dw/UNAnpUod6UHo04jSSkv8TzKHjZDSd7EXdDQAl8Q==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.2", @@ -15495,6 +15637,71 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "node_modules/tuf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.2.tgz", + "integrity": "sha512-gBfbnS6khluxjvoFCpRV0fhWT265xNfpiNXOcBX0Ze6HGbPhe93UG5V5DdKcgm/aXsMadnY76l/h6j63GmJS5g==", + "dev": true, + "dependencies": { + "@tufjs/models": "1.0.1", + "make-fetch-happen": "^11.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/tuf-js/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/tuf-js/node_modules/make-fetch-happen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", + "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/tuf-js/node_modules/minipass-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", + "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -15788,9 +15995,9 @@ } }, "node_modules/webpack": { - "version": "5.75.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", - "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "version": "5.76.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", + "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -16197,9 +16404,9 @@ "dev": true }, "node_modules/ws": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz", - "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "dev": true, "engines": { "node": ">=10.0.0" @@ -16309,12 +16516,12 @@ } }, "@angular-devkit/architect": { - "version": "0.1501.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1501.4.tgz", - "integrity": "sha512-PE0CqPaNzcz8yHEuJwqtKxYvXX9hgWWvC6hI2DWKtC+5WgJLAYJNEGofXQRc227Nj+YySEYUUo8Ja8SYl3lDxA==", + "version": "0.1502.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1502.6.tgz", + "integrity": "sha512-n4oJ9vzFWwabf+AfgqqevVzdJhNKNCav7ytefjD/Y01vkNwlXqWnHcvyyHCLkVibJ6WR8J9lK4t77j/HFlDvWQ==", "dev": true, "requires": { - "@angular-devkit/core": "15.1.4", + "@angular-devkit/core": "15.2.6", "rxjs": "6.6.7" }, "dependencies": { @@ -16336,39 +16543,40 @@ } }, "@angular-devkit/build-angular": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-15.1.4.tgz", - "integrity": "sha512-+vubHYyQn8HJ+uJQndr8xFlX6C7y1kdnzTiKgx6QFvA5sd/IhXXzsnDd1wFer1lCrZ+1qgfhG9HI/RL3cBeKrA==", + "version": "15.2.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-15.2.6.tgz", + "integrity": "sha512-OmMcdXXUrAdZNxwxDE8SUx1FMcq9FyMnrSv1PmP9sHPBoxAdBVc/qNdGA9V7C5yHvWHGgzsx7ZK5TDuvifzS5g==", "dev": true, "requires": { "@ampproject/remapping": "2.2.0", - "@angular-devkit/architect": "0.1501.4", - "@angular-devkit/build-webpack": "0.1501.4", - "@angular-devkit/core": "15.1.4", + "@angular-devkit/architect": "0.1502.6", + "@angular-devkit/build-webpack": "0.1502.6", + "@angular-devkit/core": "15.2.6", "@babel/core": "7.20.12", - "@babel/generator": "7.20.7", + "@babel/generator": "7.20.14", "@babel/helper-annotate-as-pure": "7.18.6", + "@babel/helper-split-export-declaration": "7.18.6", "@babel/plugin-proposal-async-generator-functions": "7.20.7", "@babel/plugin-transform-async-to-generator": "7.20.7", "@babel/plugin-transform-runtime": "7.19.6", "@babel/preset-env": "7.20.2", - "@babel/runtime": "7.20.7", + "@babel/runtime": "7.20.13", "@babel/template": "7.20.7", "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "15.1.4", + "@ngtools/webpack": "15.2.6", "ansi-colors": "4.1.3", "autoprefixer": "10.4.13", "babel-loader": "9.1.2", "babel-plugin-istanbul": "6.1.1", - "browserslist": "4.21.4", + "browserslist": "4.21.5", "cacache": "17.0.4", "chokidar": "3.5.3", "copy-webpack-plugin": "11.0.0", "critters": "0.0.16", "css-loader": "6.7.3", - "esbuild": "0.16.17", - "esbuild-wasm": "0.16.17", - "glob": "8.0.3", + "esbuild": "0.17.8", + "esbuild-wasm": "0.17.8", + "glob": "8.1.0", "https-proxy-agent": "5.0.1", "inquirer": "8.2.4", "jsonc-parser": "3.2.0", @@ -16377,26 +16585,26 @@ "less-loader": "11.1.0", "license-webpack-plugin": "4.0.2", "loader-utils": "3.2.1", - "magic-string": "0.27.0", + "magic-string": "0.29.0", "mini-css-extract-plugin": "2.7.2", - "open": "8.4.0", + "open": "8.4.1", "ora": "5.4.1", - "parse5-html-rewriting-stream": "6.0.1", + "parse5-html-rewriting-stream": "7.0.0", "piscina": "3.2.0", "postcss": "8.4.21", "postcss-loader": "7.0.2", "resolve-url-loader": "5.0.0", "rxjs": "6.6.7", - "sass": "1.57.1", + "sass": "1.58.1", "sass-loader": "13.2.0", "semver": "7.3.8", "source-map-loader": "4.0.1", "source-map-support": "0.5.21", - "terser": "5.16.1", + "terser": "5.16.3", "text-table": "0.2.0", "tree-kill": "1.2.2", - "tslib": "2.4.1", - "webpack": "5.75.0", + "tslib": "2.5.0", + "webpack": "5.76.1", "webpack-dev-middleware": "6.0.1", "webpack-dev-server": "4.11.1", "webpack-merge": "5.8.0", @@ -16444,9 +16652,9 @@ } }, "glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -16456,25 +16664,10 @@ "once": "^1.3.0" } }, - "jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "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, - "requires": { - "@jridgewell/sourcemap-codec": "^1.4.13" - } - }, "minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -16496,22 +16689,16 @@ "dev": true } } - }, - "tslib": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", - "dev": true } } }, "@angular-devkit/build-webpack": { - "version": "0.1501.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1501.4.tgz", - "integrity": "sha512-rJ7KTBDW0UHgVJjQ23qJfGun+pDX3ZG2z0OtsskdsOI62SAvW1cVLuS50ICTcWW6gtcDO0R/6Q1RLbaV1JHZ5A==", + "version": "0.1502.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1502.6.tgz", + "integrity": "sha512-X7XQ11QDz2Bs5qpJ3a5glIytvI+S74ORQxdzvT6a6KB8ayW0SgZEhTwD+GF7pa5My8draIaXBGzzQR1qmpWK5Q==", "dev": true, "requires": { - "@angular-devkit/architect": "0.1501.4", + "@angular-devkit/architect": "0.1502.6", "rxjs": "6.6.7" }, "dependencies": { @@ -16533,9 +16720,9 @@ } }, "@angular-devkit/core": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.1.4.tgz", - "integrity": "sha512-PW5MRmd9DHJR4FaXchwQtj9pXnsghSTnwRvfZeCRNYgU2sv0DKyTV+YTSJB+kNXnoPNG1Je6amDEkiXecpspXg==", + "version": "15.2.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.2.6.tgz", + "integrity": "sha512-YVTWZ+M+xNKdFX4EnY9QX49PZraawiaA0iTd2CUW8ZoTUvU7yOGMKZLSdz6aokTMRVfm0449wt6YL994ibOo1g==", "dev": true, "requires": { "ajv": "8.12.0", @@ -16545,24 +16732,6 @@ "source-map": "0.7.4" }, "dependencies": { - "ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, "rxjs": { "version": "6.6.7", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", @@ -16581,31 +16750,73 @@ } }, "@angular-devkit/schematics": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-15.1.4.tgz", - "integrity": "sha512-jpddxo9Qd2yRQ1t9FLhAx5S+luz6HkyhDytq0LFKbxf9ikf1J4oy9riPBFl4pRmrNARWcHZ6GbD20/Ky8PjmXQ==", + "version": "15.2.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-15.2.6.tgz", + "integrity": "sha512-f7VgnAcok7AwR/DhX0ZWskB0rFBo/KsvtIUA2qZSrpKMf8eFiwu03dv/b2mI0vnf+1FBfIQzJvO0ww45zRp6dA==", "dev": true, "requires": { - "@angular-devkit/core": "15.1.4", + "@angular-devkit/core": "15.2.6", "jsonc-parser": "3.2.0", - "magic-string": "0.27.0", + "magic-string": "0.29.0", "ora": "5.4.1", "rxjs": "6.6.7" }, "dependencies": { - "jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "magic-string": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", - "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", "dev": true, "requires": { - "@jridgewell/sourcemap-codec": "^1.4.13" + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@angular-devkit/schematics-cli": { + "version": "15.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics-cli/-/schematics-cli-15.2.5.tgz", + "integrity": "sha512-MOmdYMCT4Bbl8B9L4zDqbJwakYpECb0K9guERxUqMwpufi9GqOa/GNhIsbHcc4J8qn6ykG2y3BZQf8Q14/eRZQ==", + "dev": true, + "requires": { + "@angular-devkit/core": "15.2.5", + "@angular-devkit/schematics": "15.2.5", + "ansi-colors": "4.1.3", + "inquirer": "8.2.4", + "symbol-observable": "4.0.0", + "yargs-parser": "21.1.1" + }, + "dependencies": { + "@angular-devkit/core": { + "version": "15.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.2.5.tgz", + "integrity": "sha512-ZfjEkAe2yYeekc3xjZ/U4pK9nb+w6BFwAEjou6mE8PWZH7iYskm0YCCXkmu+B+zViEcCLhAkJAxu9MwX4efd8g==", + "dev": true, + "requires": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.0", + "rxjs": "6.6.7", + "source-map": "0.7.4" + } + }, + "@angular-devkit/schematics": { + "version": "15.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-15.2.5.tgz", + "integrity": "sha512-zm7chQRQtPXQzzSAvK/mbZ+RJ3eP7hlU53yyJ/i6kjWAh3Y5uiSHNYGmqhhAHFuzw4Jhb4OC2S9iycxrqmI8TA==", + "dev": true, + "requires": { + "@angular-devkit/core": "15.2.5", + "jsonc-parser": "3.2.0", + "magic-string": "0.29.0", + "ora": "5.4.1", + "rxjs": "6.6.7" } }, "rxjs": { @@ -16625,66 +16836,52 @@ } } }, - "@angular-devkit/schematics-cli": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics-cli/-/schematics-cli-15.1.4.tgz", - "integrity": "sha512-qkM5Mfs28jZzNcJnSM6RlyrKkYvzhQmWFTxBXnn15k5T4EnSs1gI6O054Xn7jo/senfwNNt7h2Mlz2OmBLo6+w==", - "dev": true, - "requires": { - "@angular-devkit/core": "15.1.4", - "@angular-devkit/schematics": "15.1.4", - "ansi-colors": "4.1.3", - "inquirer": "8.2.4", - "symbol-observable": "4.0.0", - "yargs-parser": "21.1.1" - } - }, "@angular-eslint/builder": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-15.2.0.tgz", - "integrity": "sha512-5xnJub1G7+F9Ra75N90Ln9yn/KFzWnMIHfqDVRRDrlwgja1Zc9ZmqcazLWc/k12yzKyJoO3uwBSycyVwG2fYVg==", + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-15.2.1.tgz", + "integrity": "sha512-7x2DANebLRl997Mj4DhZrnz5+vnSjavGGveJ0mBuU7CEsL0ZYLftdRqL0e0HtU3ksseS7xpchD6OM08nkNgySw==", "dev": true }, "@angular-eslint/bundled-angular-compiler": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-15.2.0.tgz", - "integrity": "sha512-a0bfXxYyGoWJHrVQ4QER0HdRgselcTtJeyqiFPAxID2ZxF0IBGKLNTtugUTXekEmiLev8yGLX9TqAtthN57fEg==", + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-15.2.1.tgz", + "integrity": "sha512-LO7Am8eVCr7oh6a0VmKSL7K03CnQEQhFO7Wt/YtbfYOxVjrbwmYLwJn+wZPOT7A02t/BttOD/WXuDrOWtSMQ/Q==", "dev": true }, "@angular-eslint/eslint-plugin": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-15.2.0.tgz", - "integrity": "sha512-yJGbmSUU0B0MFJ48ktpkqqEK+zv5k9iwlZSqEHtiQMKvDelfluovnEusihel7uPRo1c1iVlbSgXfGpxpUCfocA==", + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-15.2.1.tgz", + "integrity": "sha512-OM7b1kS4E4CkXjkaWN+lEzawh4VxY6l7FO1Cuk4s7iv3/YpZG3rJxIZBqnFLTixwrBuqw8y4FNBzF3eDgmFAUw==", "dev": true, "requires": { - "@angular-eslint/utils": "15.2.0", - "@typescript-eslint/utils": "5.48.1" + "@angular-eslint/utils": "15.2.1", + "@typescript-eslint/utils": "5.48.2" }, "dependencies": { "@typescript-eslint/scope-manager": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", - "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz", + "integrity": "sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1" + "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/visitor-keys": "5.48.2" } }, "@typescript-eslint/types": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", - "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.2.tgz", + "integrity": "sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", - "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz", + "integrity": "sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1", + "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/visitor-keys": "5.48.2", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -16693,83 +16890,83 @@ } }, "@typescript-eslint/utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", - "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.2.tgz", + "integrity": "sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/scope-manager": "5.48.2", + "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/typescript-estree": "5.48.2", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" } }, "@typescript-eslint/visitor-keys": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", - "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz", + "integrity": "sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/types": "5.48.2", "eslint-visitor-keys": "^3.3.0" } } } }, "@angular-eslint/eslint-plugin-template": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-15.2.0.tgz", - "integrity": "sha512-aL3czf5Jpv29rKN3UG20tQepX1+V0d6xc0g+1l0zPHZJYjVd6Oy0nIxWiGfl4yanaXiVpmxiV4vUcLlqqaFwbw==", + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-15.2.1.tgz", + "integrity": "sha512-IeiSLk6YxapFdH2z5o/O3R7VwtBd2T6fWmhLFPwDYMDknrwegnOjwswCdBplOccpUp0wqlCeGUx7LTsuzwaz7w==", "dev": true, "requires": { - "@angular-eslint/bundled-angular-compiler": "15.2.0", - "@angular-eslint/utils": "15.2.0", - "@typescript-eslint/type-utils": "5.48.1", - "@typescript-eslint/utils": "5.48.1", + "@angular-eslint/bundled-angular-compiler": "15.2.1", + "@angular-eslint/utils": "15.2.1", + "@typescript-eslint/type-utils": "5.48.2", + "@typescript-eslint/utils": "5.48.2", "aria-query": "5.1.3", "axobject-query": "3.1.1" }, "dependencies": { "@typescript-eslint/scope-manager": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", - "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz", + "integrity": "sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1" + "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/visitor-keys": "5.48.2" } }, "@typescript-eslint/type-utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz", - "integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.2.tgz", + "integrity": "sha512-QVWx7J5sPMRiOMJp5dYshPxABRoZV1xbRirqSk8yuIIsu0nvMTZesKErEA3Oix1k+uvsk8Cs8TGJ6kQ0ndAcew==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.48.1", - "@typescript-eslint/utils": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.2", + "@typescript-eslint/utils": "5.48.2", "debug": "^4.3.4", "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", - "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.2.tgz", + "integrity": "sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", - "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz", + "integrity": "sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1", + "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/visitor-keys": "5.48.2", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -16778,53 +16975,53 @@ } }, "@typescript-eslint/utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", - "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.2.tgz", + "integrity": "sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/scope-manager": "5.48.2", + "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/typescript-estree": "5.48.2", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" } }, "@typescript-eslint/visitor-keys": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", - "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz", + "integrity": "sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/types": "5.48.2", "eslint-visitor-keys": "^3.3.0" } } } }, "@angular-eslint/schematics": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-15.2.0.tgz", - "integrity": "sha512-N9tuVu3vL47beppTsV9wAF+v6M9trbJnuNWYQGGsqA3mtCAkFUvJuHyWcXNPdSCNv/cJtR1OOJ7Y922uB5JPJQ==", + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-15.2.1.tgz", + "integrity": "sha512-0ZfBCejHWIcgy3J5kFs9sS/jqi8i5AptxggOwFySOlCLJ+CzNrktjD4jff1Zy8K/VLzY0Ci0BSZXvgWfP0k9Rg==", "dev": true, "requires": { - "@angular-eslint/eslint-plugin": "15.2.0", - "@angular-eslint/eslint-plugin-template": "15.2.0", + "@angular-eslint/eslint-plugin": "15.2.1", + "@angular-eslint/eslint-plugin-template": "15.2.1", "ignore": "5.2.4", "strip-json-comments": "3.1.1", "tmp": "0.2.1" } }, "@angular-eslint/template-parser": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-15.2.0.tgz", - "integrity": "sha512-xnnxPfV/G0Ll3B0HGrF1ucsc/DHmNE6UhhmWxYPTERq0McbZGRiATa66hCoOZ/Rdylun4ogBfsRKAG8XxEvlvw==", + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-15.2.1.tgz", + "integrity": "sha512-ViCi79gC2aKJecmYLkOT+QlT5WMRNXeYz0Dr9Pr8qXzIbY0oAWE7nOT5jkXwQ9oUk+ybtGCWHma5JVJWVJsIog==", "dev": true, "requires": { - "@angular-eslint/bundled-angular-compiler": "15.2.0", + "@angular-eslint/bundled-angular-compiler": "15.2.1", "eslint-scope": "^7.0.0" }, "dependencies": { @@ -16847,39 +17044,39 @@ } }, "@angular-eslint/utils": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-15.2.0.tgz", - "integrity": "sha512-qfTOKQ+aef/YER679/xN1E+FkZKMd0I73P6txUZAb9k2G1ACVktG+wOUIBfgjIlUVq9Q01AV91LGOWcd+rdEEA==", + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-15.2.1.tgz", + "integrity": "sha512-++FneAJHxJqcSu0igVN6uOkSoHxlzgLoMBswuovYJy3UKwm33/T6WFku8++753Ca/JucIoR1gdUfO7SoSspMDg==", "dev": true, "requires": { - "@angular-eslint/bundled-angular-compiler": "15.2.0", - "@typescript-eslint/utils": "5.48.1" + "@angular-eslint/bundled-angular-compiler": "15.2.1", + "@typescript-eslint/utils": "5.48.2" }, "dependencies": { "@typescript-eslint/scope-manager": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", - "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz", + "integrity": "sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1" + "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/visitor-keys": "5.48.2" } }, "@typescript-eslint/types": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", - "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.2.tgz", + "integrity": "sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", - "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz", + "integrity": "sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/visitor-keys": "5.48.1", + "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/visitor-keys": "5.48.2", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -16888,60 +17085,60 @@ } }, "@typescript-eslint/utils": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", - "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.2.tgz", + "integrity": "sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.48.1", - "@typescript-eslint/types": "5.48.1", - "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/scope-manager": "5.48.2", + "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/typescript-estree": "5.48.2", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" } }, "@typescript-eslint/visitor-keys": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", - "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "version": "5.48.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz", + "integrity": "sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/types": "5.48.2", "eslint-visitor-keys": "^3.3.0" } } } }, "@angular/animations": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-15.1.3.tgz", - "integrity": "sha512-qvOLYx8XWolwFWwYoPjt+jQLDFaCQEPjb26iczewiqd+xcAdYn4Tl10NCJtOsx+YfTdpWtKRzvxYr1JxnGQTdw==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-15.2.8.tgz", + "integrity": "sha512-I3xh8EASQ04s3qXQYpIORI0jFiFmvBQERBqS70TieTCIML7banOf9R3K7sAWB9frG5J0CEUwr+wtF47DCs/7eQ==", "requires": { "tslib": "^2.3.0" } }, "@angular/cdk": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-15.1.3.tgz", - "integrity": "sha512-FRb1ZirybQGVlRx34vsnkIyy4WHJlrRg2mwPeJ90b0DzIWuIZIiPYxxR2bAi/Si1IjnK8YBdacd5DXPdrW1jyw==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-15.2.8.tgz", + "integrity": "sha512-jiCoxfBFMH29IZIiPmVUzIWetfUNpMIvC20xYVF8RMM819vPogoObzwK4DN/sXcp/6oVbBzZFaYdijhhIt9soQ==", "requires": { "parse5": "^7.1.2", "tslib": "^2.3.0" } }, "@angular/cli": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-15.1.4.tgz", - "integrity": "sha512-ebZiI4arb9wtOUMmTyUvjgDovmwpY8hmGLbkKZiEmAX8+2gbl4e97M+zd0SICZDU8bu5VcpoP6Q3Qb6vVjab9A==", + "version": "15.2.6", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-15.2.6.tgz", + "integrity": "sha512-wNkQ/qCVbd4pERaGVagKJPifEvjRNY5otwsd4iRVubY/XOcIHcYChUThZwgQdVfNAImfJPMZNrhbGxejuWLA9w==", "dev": true, "requires": { - "@angular-devkit/architect": "0.1501.4", - "@angular-devkit/core": "15.1.4", - "@angular-devkit/schematics": "15.1.4", - "@schematics/angular": "15.1.4", + "@angular-devkit/architect": "0.1502.6", + "@angular-devkit/core": "15.2.6", + "@angular-devkit/schematics": "15.2.6", + "@schematics/angular": "15.2.6", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.3", "ini": "3.0.1", @@ -16949,43 +17146,35 @@ "jsonc-parser": "3.2.0", "npm-package-arg": "10.1.0", "npm-pick-manifest": "8.0.1", - "open": "8.4.0", + "open": "8.4.1", "ora": "5.4.1", - "pacote": "15.0.8", + "pacote": "15.1.0", "resolve": "1.22.1", "semver": "7.3.8", "symbol-observable": "4.0.0", "yargs": "17.6.2" - }, - "dependencies": { - "jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - } } }, "@angular/common": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-15.1.3.tgz", - "integrity": "sha512-UjC0COaOcU1g/ODBBetv/BpdaFC/Y32DvXJ9qbD7kkwLwoqCjGOLDvtP36r9zEzPmH7oNkgNGDkgR3gyb82s5A==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-15.2.8.tgz", + "integrity": "sha512-yLDQihiRcVl38HrWMPbqgzOaSUw85AQH5BsGdjbS6BpoBQj3EXOpccCMFsuxOKxPG4toatgawNqrEnK0Jpv9Mw==", "requires": { "tslib": "^2.3.0" } }, "@angular/compiler": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-15.1.3.tgz", - "integrity": "sha512-CxEpm5Z3EpjeGNoWKtcHOrf2IQTSckpAEFwsRrADP2nqcXXYp/IjIHi+PUTjLhjrOEbukH9zreHsL5BoIQhgUQ==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-15.2.8.tgz", + "integrity": "sha512-+dvspIDvuGoYqdL7r/3o9ojkR3fH1zevgC0ISJivcIrMi+WcJ0FV2JmJdnm8V52oNsHy+sMF9eEZGEbCbACE/A==", "requires": { "tslib": "^2.3.0" } }, "@angular/compiler-cli": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-15.1.3.tgz", - "integrity": "sha512-z5bGdQQcStXWPpb5vztqqUOET+vxw+GUFtfktYxV40kE2d1zHLZh93AGEnM1NnBaOz+9NZrX+dWoEyWmv/T2LQ==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-15.2.8.tgz", + "integrity": "sha512-fFxaDlbILo0t2t662qA0cjgn+kWItGlc1tFYKU6X7bvYb3t2e0cd9FzrFPLXUQVboGis83ULcJ2zkDxScnuPuQ==", "dev": true, "requires": { "@babel/core": "7.19.3", @@ -17012,31 +17201,31 @@ } }, "@angular/core": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-15.1.3.tgz", - "integrity": "sha512-rad9OYnaoRnXBztOBXsiD59VvOZTpsvO3sWx6KndytQFceFfkL722bF2l2LARN+R3IWDOwRap46HOtc0O0N+sw==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-15.2.8.tgz", + "integrity": "sha512-NDs+g4uM4EhyCvluf8a0YBCFXsDAEfCMHOD5cS00Bl+liTQ7JwtmepkWXMyjLB92irC9JaR79kdy4BoIKOh8WA==", "requires": { "tslib": "^2.3.0" } }, "@angular/forms": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-15.1.3.tgz", - "integrity": "sha512-vEgiZBk3rGGp4tBQHl9EaspEjYh70lkz6/zYreObTbMdCB54bkbl+jn+JbQyFj+TPfukiumtiG3/477vKzYnSg==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-15.2.8.tgz", + "integrity": "sha512-VyevVj20DdQWjAQUyiFTe+DAzqG9GqfAOWn376Y/lhPcwxAojXePTGNgtQud566/urDrNrP5haaLD6O36/3n+w==", "requires": { "tslib": "^2.3.0" } }, "@angular/language-service": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-15.1.3.tgz", - "integrity": "sha512-Sxp5nXQ/VR7ESLL35iRkHun8R4w3Zp+d5KmkCmgw67zjDgAJhosrsoqIUbGWYFMFJ5YUA4IHhQUwY8snyUDwug==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-15.2.8.tgz", + "integrity": "sha512-3wlaJrpxe8ZLe7ZGIOs/Z++kgJMOHZCUvdXLyp/4t1ejULgUgW9yi7nGsemWnSzsUCjf7595BP1Cp1gA/J/1QQ==", "dev": true }, "@angular/material": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-15.1.3.tgz", - "integrity": "sha512-Jj17GwvL1PsIVPiRBRQQRRvTQb5TlmMP+49JgIWTSTF03G7F9guoYapoYzuufK7dWA3Ga0KzDPKfjUmcnBg+Fw==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-15.2.8.tgz", + "integrity": "sha512-bk0dv8PSJGFDgAv3CU3+jfvnOO0ah/L9JUyvw73kjiKezgjW/O8Lgq/dwkDTQ1dF3zCF+JWNqhEJmgi0GVW/cQ==", "requires": { "@material/animation": "15.0.0-canary.684e33d25.0", "@material/auto-init": "15.0.0-canary.684e33d25.0", @@ -17089,25 +17278,25 @@ } }, "@angular/platform-browser": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-15.1.3.tgz", - "integrity": "sha512-WJBN3klssfcRGKY2L2DIpNGbaMQfi2X1le1ZXQAnsfECQ/pua+lFstJUT+RP+Bx4X8icuDggKkS/JPOiBhxARw==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-15.2.8.tgz", + "integrity": "sha512-8sKFUld54inj0FnQ1ydhFxnDgsbbf43W9FALye/5uEtLgwwE/ZvkNYMaQ7hq1JPuQRMDj3gJkFqaLeFjplpHDA==", "requires": { "tslib": "^2.3.0" } }, "@angular/platform-browser-dynamic": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-15.1.3.tgz", - "integrity": "sha512-lUfHmO+x3goSL1KnlAbekieKpak2KVGcOcAzOVOIMFt1SyWPBHq0NyyPOH2PUAnjPRbvCLEs2casjFggk0JzsQ==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-15.2.8.tgz", + "integrity": "sha512-75HyoZNibA3u/FvdK4Aw5KMzUmS/nDk5N8s7gfM09fe1resSPgFiW8JJEkr1xiUdA2WtSRbHs34y5rHLDe7n1Q==", "requires": { "tslib": "^2.3.0" } }, "@angular/platform-server": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-15.1.3.tgz", - "integrity": "sha512-FOqCcsW1dCaT8xB1zJZezlHSZxsfnnWflapauWszitCNmqav27jAXsJdQDcQN/j1KwsrvDkL7zaPksmphqebvg==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-15.2.8.tgz", + "integrity": "sha512-YfPAoK2zp3mTO6ubDe0C9Vzg9Vi4BxXkxHCPG0k8IM3Ivjedkv5PZ+vC0a+GjV2xR/0YqiVE3FCwXk4X6m6LuQ==", "requires": { "domino": "^2.1.2", "tslib": "^2.3.0", @@ -17115,25 +17304,25 @@ } }, "@angular/router": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-15.1.3.tgz", - "integrity": "sha512-GxvGZO0N7LIoaTV2EZ082kqb9asJl2rWe0kNsUQwu9IQAODOCCTQu2USg63J6hEOcKPJSZzbxdXLaxlpqKeC4A==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-15.2.8.tgz", + "integrity": "sha512-C62QBEeJSBTNTrQHZiklPrxwJwuENoZzWX22MMJ7dxl+7VjRgnmj8J7mcX9fLjHlL+mC3RvesMlX7sGZRQV1cg==", "requires": { "tslib": "^2.3.0" } }, "@angular/service-worker": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-15.1.3.tgz", - "integrity": "sha512-eQR8dOJXml87FCI3O53vOItAJPErxwNbRluczyhIg/+ExVzfW9750FHWIQs1KWoFf4XNy8+0pUygyGMFfuMkYg==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-15.2.8.tgz", + "integrity": "sha512-iD3qsqN/N2014uCuCka77pu0tqPPsLcP9rUZgAJEM01o/A/ez+E3TmWW2PYvSq2zLZQnZZ40a7dWonIAclJq3Q==", "requires": { "tslib": "^2.3.0" } }, "@angular/youtube-player": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/@angular/youtube-player/-/youtube-player-15.1.3.tgz", - "integrity": "sha512-sJH1RfDrfPDaLKaGcZdegW4JYXgZteDvE092c7o+iHRZGitgKn+XWb3Vy+eYLh5xpuTFqlLxWKhJ1/kgJVG93w==", + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/@angular/youtube-player/-/youtube-player-15.2.8.tgz", + "integrity": "sha512-yo5C48spbYF3S8iMg7XCgXEapA2azOhUqiEsFv38DMCKcd8UyvUEtoNaW85J3JTsb/oB66hjtxcF8xyZbWdaBQ==", "requires": { "@types/youtube": "^0.0.42", "tslib": "^2.3.0" @@ -17287,545 +17476,531 @@ } }, "@aws-sdk/abort-controller": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.266.1.tgz", - "integrity": "sha512-6tG6dAgMMKh86U2kgo58J6pyC2pSEAtm1bXnhYOuuXBjFgieNvikwjoj//zzciudmp1qTu5Wh99u8LBLmYofFg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.310.0.tgz", + "integrity": "sha512-v1zrRQxDLA1MdPim159Vx/CPHqsB4uybSxRi1CnfHO5ZjHryx3a5htW2gdGAykVCul40+yJXvfpufMrELVxH+g==", "requires": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/chunked-blob-reader": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/chunked-blob-reader/-/chunked-blob-reader-3.188.0.tgz", - "integrity": "sha512-zkPRFZZPL3eH+kH86LDYYXImiClA1/sW60zYOjse9Pgka+eDJlvBN6hcYxwDEKjcwATYiSRR1aVQHcfCinlGXg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/chunked-blob-reader/-/chunked-blob-reader-3.310.0.tgz", + "integrity": "sha512-CrJS3exo4mWaLnWxfCH+w88Ou0IcAZSIkk4QbmxiHl/5Dq705OLoxf4385MVyExpqpeVJYOYQ2WaD8i/pQZ2fg==", "requires": { - "tslib": "^2.3.1" - } - }, - "@aws-sdk/chunked-blob-reader-native": { - "version": "3.208.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/chunked-blob-reader-native/-/chunked-blob-reader-native-3.208.0.tgz", - "integrity": "sha512-JeOZ95PW+fJ6bbuqPySYqLqHk1n4+4ueEEraJsiUrPBV0S1ZtyvOGHcnGztKUjr2PYNaiexmpWuvUve9K12HRA==", - "requires": { - "@aws-sdk/util-base64": "3.208.0", - "tslib": "^2.3.1" + "tslib": "^2.5.0" } }, "@aws-sdk/client-s3": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.266.1.tgz", - "integrity": "sha512-W6dI7WJD30zfbM46hn7aDdpgq1zq0k4kjSzpW+2VQ+MqYf7qXXuE4FKcDA5z2N7M86TWn3qiF1FcyTH0V+5tAw==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.319.0.tgz", + "integrity": "sha512-/XzElEO4iZTBgvrcWq20sxKLvhRetjT1gOPRF4Ra2iSCbeVIT/feYdEaSSgMsaiqrREywBc+59NiOyxImWTaOA==", "requires": { "@aws-crypto/sha1-browser": "3.0.0", "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sts": "3.266.1", - "@aws-sdk/config-resolver": "3.266.1", - "@aws-sdk/credential-provider-node": "3.266.1", - "@aws-sdk/eventstream-serde-browser": "3.266.1", - "@aws-sdk/eventstream-serde-config-resolver": "3.266.1", - "@aws-sdk/eventstream-serde-node": "3.266.1", - "@aws-sdk/fetch-http-handler": "3.266.1", - "@aws-sdk/hash-blob-browser": "3.266.1", - "@aws-sdk/hash-node": "3.266.1", - "@aws-sdk/hash-stream-node": "3.266.1", - "@aws-sdk/invalid-dependency": "3.266.1", - "@aws-sdk/md5-js": "3.266.1", - "@aws-sdk/middleware-bucket-endpoint": "3.266.1", - "@aws-sdk/middleware-content-length": "3.266.1", - "@aws-sdk/middleware-endpoint": "3.266.1", - "@aws-sdk/middleware-expect-continue": "3.266.1", - "@aws-sdk/middleware-flexible-checksums": "3.266.1", - "@aws-sdk/middleware-host-header": "3.266.1", - "@aws-sdk/middleware-location-constraint": "3.266.1", - "@aws-sdk/middleware-logger": "3.266.1", - "@aws-sdk/middleware-recursion-detection": "3.266.1", - "@aws-sdk/middleware-retry": "3.266.1", - "@aws-sdk/middleware-sdk-s3": "3.266.1", - "@aws-sdk/middleware-serde": "3.266.1", - "@aws-sdk/middleware-signing": "3.266.1", - "@aws-sdk/middleware-ssec": "3.266.1", - "@aws-sdk/middleware-stack": "3.266.1", - "@aws-sdk/middleware-user-agent": "3.266.1", - "@aws-sdk/node-config-provider": "3.266.1", - "@aws-sdk/node-http-handler": "3.266.1", - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/signature-v4-multi-region": "3.266.1", - "@aws-sdk/smithy-client": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/url-parser": "3.266.1", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.266.1", - "@aws-sdk/util-defaults-mode-node": "3.266.1", - "@aws-sdk/util-endpoints": "3.266.1", - "@aws-sdk/util-retry": "3.266.1", - "@aws-sdk/util-stream-browser": "3.266.1", - "@aws-sdk/util-stream-node": "3.266.1", - "@aws-sdk/util-user-agent-browser": "3.266.1", - "@aws-sdk/util-user-agent-node": "3.266.1", - "@aws-sdk/util-utf8": "3.254.0", - "@aws-sdk/util-waiter": "3.266.1", - "@aws-sdk/xml-builder": "3.201.0", - "fast-xml-parser": "4.0.11", - "tslib": "^2.3.1" + "@aws-sdk/client-sts": "3.319.0", + "@aws-sdk/config-resolver": "3.310.0", + "@aws-sdk/credential-provider-node": "3.319.0", + "@aws-sdk/eventstream-serde-browser": "3.310.0", + "@aws-sdk/eventstream-serde-config-resolver": "3.310.0", + "@aws-sdk/eventstream-serde-node": "3.310.0", + "@aws-sdk/fetch-http-handler": "3.310.0", + "@aws-sdk/hash-blob-browser": "3.310.0", + "@aws-sdk/hash-node": "3.310.0", + "@aws-sdk/hash-stream-node": "3.310.0", + "@aws-sdk/invalid-dependency": "3.310.0", + "@aws-sdk/md5-js": "3.310.0", + "@aws-sdk/middleware-bucket-endpoint": "3.310.0", + "@aws-sdk/middleware-content-length": "3.310.0", + "@aws-sdk/middleware-endpoint": "3.310.0", + "@aws-sdk/middleware-expect-continue": "3.310.0", + "@aws-sdk/middleware-flexible-checksums": "3.310.0", + "@aws-sdk/middleware-host-header": "3.310.0", + "@aws-sdk/middleware-location-constraint": "3.310.0", + "@aws-sdk/middleware-logger": "3.310.0", + "@aws-sdk/middleware-recursion-detection": "3.310.0", + "@aws-sdk/middleware-retry": "3.310.0", + "@aws-sdk/middleware-sdk-s3": "3.310.0", + "@aws-sdk/middleware-serde": "3.310.0", + "@aws-sdk/middleware-signing": "3.310.0", + "@aws-sdk/middleware-ssec": "3.310.0", + "@aws-sdk/middleware-stack": "3.310.0", + "@aws-sdk/middleware-user-agent": "3.319.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/node-http-handler": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/signature-v4-multi-region": "3.310.0", + "@aws-sdk/smithy-client": "3.316.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", + "@aws-sdk/util-body-length-browser": "3.310.0", + "@aws-sdk/util-body-length-node": "3.310.0", + "@aws-sdk/util-defaults-mode-browser": "3.316.0", + "@aws-sdk/util-defaults-mode-node": "3.316.0", + "@aws-sdk/util-endpoints": "3.319.0", + "@aws-sdk/util-retry": "3.310.0", + "@aws-sdk/util-stream-browser": "3.310.0", + "@aws-sdk/util-stream-node": "3.310.0", + "@aws-sdk/util-user-agent-browser": "3.310.0", + "@aws-sdk/util-user-agent-node": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", + "@aws-sdk/util-waiter": "3.310.0", + "@aws-sdk/xml-builder": "3.310.0", + "fast-xml-parser": "4.1.2", + "tslib": "^2.5.0" } }, "@aws-sdk/client-sso": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.266.1.tgz", - "integrity": "sha512-mgrRfNSa7sJyBgAuMvRE5W2izHYl1n0tpxjLZ8rP+AoOp0GrZLpuj9T2XhmVwyR4ibVBNFKdr8nUHWekF4HA+w==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.319.0.tgz", + "integrity": "sha512-g46KgAjRiYBS8Oi85DPwSAQpt+Hgmw/YFgGVwZqMfTL70KNJwLFKRa5D9UocQd7t7OjPRdKF7g0Gp5peyAK9dw==", "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/config-resolver": "3.266.1", - "@aws-sdk/fetch-http-handler": "3.266.1", - "@aws-sdk/hash-node": "3.266.1", - "@aws-sdk/invalid-dependency": "3.266.1", - "@aws-sdk/middleware-content-length": "3.266.1", - "@aws-sdk/middleware-endpoint": "3.266.1", - "@aws-sdk/middleware-host-header": "3.266.1", - "@aws-sdk/middleware-logger": "3.266.1", - "@aws-sdk/middleware-recursion-detection": "3.266.1", - "@aws-sdk/middleware-retry": "3.266.1", - "@aws-sdk/middleware-serde": "3.266.1", - "@aws-sdk/middleware-stack": "3.266.1", - "@aws-sdk/middleware-user-agent": "3.266.1", - "@aws-sdk/node-config-provider": "3.266.1", - "@aws-sdk/node-http-handler": "3.266.1", - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/smithy-client": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/url-parser": "3.266.1", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.266.1", - "@aws-sdk/util-defaults-mode-node": "3.266.1", - "@aws-sdk/util-endpoints": "3.266.1", - "@aws-sdk/util-retry": "3.266.1", - "@aws-sdk/util-user-agent-browser": "3.266.1", - "@aws-sdk/util-user-agent-node": "3.266.1", - "@aws-sdk/util-utf8": "3.254.0", - "tslib": "^2.3.1" + "@aws-sdk/config-resolver": "3.310.0", + "@aws-sdk/fetch-http-handler": "3.310.0", + "@aws-sdk/hash-node": "3.310.0", + "@aws-sdk/invalid-dependency": "3.310.0", + "@aws-sdk/middleware-content-length": "3.310.0", + "@aws-sdk/middleware-endpoint": "3.310.0", + "@aws-sdk/middleware-host-header": "3.310.0", + "@aws-sdk/middleware-logger": "3.310.0", + "@aws-sdk/middleware-recursion-detection": "3.310.0", + "@aws-sdk/middleware-retry": "3.310.0", + "@aws-sdk/middleware-serde": "3.310.0", + "@aws-sdk/middleware-stack": "3.310.0", + "@aws-sdk/middleware-user-agent": "3.319.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/node-http-handler": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/smithy-client": "3.316.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", + "@aws-sdk/util-body-length-browser": "3.310.0", + "@aws-sdk/util-body-length-node": "3.310.0", + "@aws-sdk/util-defaults-mode-browser": "3.316.0", + "@aws-sdk/util-defaults-mode-node": "3.316.0", + "@aws-sdk/util-endpoints": "3.319.0", + "@aws-sdk/util-retry": "3.310.0", + "@aws-sdk/util-user-agent-browser": "3.310.0", + "@aws-sdk/util-user-agent-node": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/client-sso-oidc": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.266.1.tgz", - "integrity": "sha512-eErpowPr6etcZH25v8JfJNdSPr+jet98cFWhsCN8GSxVNkyZci6aZnx6pBsTQCQn7L/zx8i4QZuOo5LYXdzF6A==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.319.0.tgz", + "integrity": "sha512-GJBgT/tephRZY3oTbDBMv+G9taoqKUIvGPn+7shmzz2P1SerutsRSfKfDXV+VptPNRoGmjjCLPmWjMFYbFKILQ==", "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/config-resolver": "3.266.1", - "@aws-sdk/fetch-http-handler": "3.266.1", - "@aws-sdk/hash-node": "3.266.1", - "@aws-sdk/invalid-dependency": "3.266.1", - "@aws-sdk/middleware-content-length": "3.266.1", - "@aws-sdk/middleware-endpoint": "3.266.1", - "@aws-sdk/middleware-host-header": "3.266.1", - "@aws-sdk/middleware-logger": "3.266.1", - "@aws-sdk/middleware-recursion-detection": "3.266.1", - "@aws-sdk/middleware-retry": "3.266.1", - "@aws-sdk/middleware-serde": "3.266.1", - "@aws-sdk/middleware-stack": "3.266.1", - "@aws-sdk/middleware-user-agent": "3.266.1", - "@aws-sdk/node-config-provider": "3.266.1", - "@aws-sdk/node-http-handler": "3.266.1", - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/smithy-client": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/url-parser": "3.266.1", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.266.1", - "@aws-sdk/util-defaults-mode-node": "3.266.1", - "@aws-sdk/util-endpoints": "3.266.1", - "@aws-sdk/util-retry": "3.266.1", - "@aws-sdk/util-user-agent-browser": "3.266.1", - "@aws-sdk/util-user-agent-node": "3.266.1", - "@aws-sdk/util-utf8": "3.254.0", - "tslib": "^2.3.1" + "@aws-sdk/config-resolver": "3.310.0", + "@aws-sdk/fetch-http-handler": "3.310.0", + "@aws-sdk/hash-node": "3.310.0", + "@aws-sdk/invalid-dependency": "3.310.0", + "@aws-sdk/middleware-content-length": "3.310.0", + "@aws-sdk/middleware-endpoint": "3.310.0", + "@aws-sdk/middleware-host-header": "3.310.0", + "@aws-sdk/middleware-logger": "3.310.0", + "@aws-sdk/middleware-recursion-detection": "3.310.0", + "@aws-sdk/middleware-retry": "3.310.0", + "@aws-sdk/middleware-serde": "3.310.0", + "@aws-sdk/middleware-stack": "3.310.0", + "@aws-sdk/middleware-user-agent": "3.319.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/node-http-handler": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/smithy-client": "3.316.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", + "@aws-sdk/util-body-length-browser": "3.310.0", + "@aws-sdk/util-body-length-node": "3.310.0", + "@aws-sdk/util-defaults-mode-browser": "3.316.0", + "@aws-sdk/util-defaults-mode-node": "3.316.0", + "@aws-sdk/util-endpoints": "3.319.0", + "@aws-sdk/util-retry": "3.310.0", + "@aws-sdk/util-user-agent-browser": "3.310.0", + "@aws-sdk/util-user-agent-node": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/client-sts": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.266.1.tgz", - "integrity": "sha512-P1hIyJkzojIG5NHuW2u/oae36KUvTB2q4nSIWuU4BrUPDeBoHg+5+zRRavtfK88aLRohwYDumRdLegT6sQNt0g==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.319.0.tgz", + "integrity": "sha512-PRGGKCSKtyM3x629J9j4DMsH1cQT8UGW+R67u9Q5HrMK05gfjpmg+X1DQ3pgve4D8MI4R/Cm3NkYl2eUTbQHQg==", "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/config-resolver": "3.266.1", - "@aws-sdk/credential-provider-node": "3.266.1", - "@aws-sdk/fetch-http-handler": "3.266.1", - "@aws-sdk/hash-node": "3.266.1", - "@aws-sdk/invalid-dependency": "3.266.1", - "@aws-sdk/middleware-content-length": "3.266.1", - "@aws-sdk/middleware-endpoint": "3.266.1", - "@aws-sdk/middleware-host-header": "3.266.1", - "@aws-sdk/middleware-logger": "3.266.1", - "@aws-sdk/middleware-recursion-detection": "3.266.1", - "@aws-sdk/middleware-retry": "3.266.1", - "@aws-sdk/middleware-sdk-sts": "3.266.1", - "@aws-sdk/middleware-serde": "3.266.1", - "@aws-sdk/middleware-signing": "3.266.1", - "@aws-sdk/middleware-stack": "3.266.1", - "@aws-sdk/middleware-user-agent": "3.266.1", - "@aws-sdk/node-config-provider": "3.266.1", - "@aws-sdk/node-http-handler": "3.266.1", - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/smithy-client": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/url-parser": "3.266.1", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.208.0", - "@aws-sdk/util-defaults-mode-browser": "3.266.1", - "@aws-sdk/util-defaults-mode-node": "3.266.1", - "@aws-sdk/util-endpoints": "3.266.1", - "@aws-sdk/util-retry": "3.266.1", - "@aws-sdk/util-user-agent-browser": "3.266.1", - "@aws-sdk/util-user-agent-node": "3.266.1", - "@aws-sdk/util-utf8": "3.254.0", - "fast-xml-parser": "4.0.11", - "tslib": "^2.3.1" + "@aws-sdk/config-resolver": "3.310.0", + "@aws-sdk/credential-provider-node": "3.319.0", + "@aws-sdk/fetch-http-handler": "3.310.0", + "@aws-sdk/hash-node": "3.310.0", + "@aws-sdk/invalid-dependency": "3.310.0", + "@aws-sdk/middleware-content-length": "3.310.0", + "@aws-sdk/middleware-endpoint": "3.310.0", + "@aws-sdk/middleware-host-header": "3.310.0", + "@aws-sdk/middleware-logger": "3.310.0", + "@aws-sdk/middleware-recursion-detection": "3.310.0", + "@aws-sdk/middleware-retry": "3.310.0", + "@aws-sdk/middleware-sdk-sts": "3.310.0", + "@aws-sdk/middleware-serde": "3.310.0", + "@aws-sdk/middleware-signing": "3.310.0", + "@aws-sdk/middleware-stack": "3.310.0", + "@aws-sdk/middleware-user-agent": "3.319.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/node-http-handler": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/smithy-client": "3.316.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", + "@aws-sdk/util-body-length-browser": "3.310.0", + "@aws-sdk/util-body-length-node": "3.310.0", + "@aws-sdk/util-defaults-mode-browser": "3.316.0", + "@aws-sdk/util-defaults-mode-node": "3.316.0", + "@aws-sdk/util-endpoints": "3.319.0", + "@aws-sdk/util-retry": "3.310.0", + "@aws-sdk/util-user-agent-browser": "3.310.0", + "@aws-sdk/util-user-agent-node": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", + "fast-xml-parser": "4.1.2", + "tslib": "^2.5.0" } }, "@aws-sdk/config-resolver": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.266.1.tgz", - "integrity": "sha512-MqMVki/y40Ot7XWJnziYuO35zqww3JbpH9jzCRCf8vtOE9u6C8VpuiG/OHIR9WQj63Yhcr+7fohmN3kGFnNWFg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.310.0.tgz", + "integrity": "sha512-8vsT+/50lOqfDxka9m/rRt6oxv1WuGZoP8oPMk0Dt+TxXMbAzf4+rejBgiB96wshI1k3gLokYRjSQZn+dDtT8g==", "requires": { - "@aws-sdk/signature-v4": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-config-provider": "3.208.0", - "@aws-sdk/util-middleware": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-config-provider": "3.310.0", + "@aws-sdk/util-middleware": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-env": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.266.1.tgz", - "integrity": "sha512-RPq9/FV7fOv14P5DxpqpcwuCa7P6ijUrN1vhpiYaWMQNJSsJK8cIsPECI3xQ1z+oPZ5/1qA++0RpTLqIhq/ifg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.310.0.tgz", + "integrity": "sha512-vvIPQpI16fj95xwS7M3D48F7QhZJBnnCgB5lR+b7So+vsG9ibm1mZRVGzVpdxCvgyOhHFbvrby9aalNJmmIP1A==", "requires": { - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-imds": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.266.1.tgz", - "integrity": "sha512-pTJnJtKaR0JWVqyt9XgHiqlK+3GnZfd3cuKGv9IsYxumVzladm7gNKiNFw0A2KsDj9jhrCRRZwEsH9ooDzZ/Ow==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.310.0.tgz", + "integrity": "sha512-baxK7Zp6dai5AGW01FIW27xS2KAaPUmKLIXv5SvFYsUgXXvNW55im4uG3b+2gA0F7V+hXvVBH08OEqmwW6we5w==", "requires": { - "@aws-sdk/node-config-provider": "3.266.1", - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/url-parser": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-ini": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.266.1.tgz", - "integrity": "sha512-N52GNeHRJufEx+V0mWfwe5cV3ukHong75uRAB0IeapJwj+kKwxxLH1dKOUaGjd/ALx6/hsISoUE/6jm/Qf/DsA==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.319.0.tgz", + "integrity": "sha512-pzx388Fw1KlSgmIMUyRY8DJVYM3aXpwzjprD4RiQVPJeAI+t7oQmEvd2FiUZEuHDjWXcuonxgU+dk7i7HUk/HQ==", "requires": { - "@aws-sdk/credential-provider-env": "3.266.1", - "@aws-sdk/credential-provider-imds": "3.266.1", - "@aws-sdk/credential-provider-process": "3.266.1", - "@aws-sdk/credential-provider-sso": "3.266.1", - "@aws-sdk/credential-provider-web-identity": "3.266.1", - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/shared-ini-file-loader": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/credential-provider-env": "3.310.0", + "@aws-sdk/credential-provider-imds": "3.310.0", + "@aws-sdk/credential-provider-process": "3.310.0", + "@aws-sdk/credential-provider-sso": "3.319.0", + "@aws-sdk/credential-provider-web-identity": "3.310.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-node": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.266.1.tgz", - "integrity": "sha512-6/iTi/zugdvuyQDmEakYn01kiFKUArL+rIYwcMf20YguXNml6G4HVWJGbX2JklY6ovnznU5ENw6+ftzBAiw/PA==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.319.0.tgz", + "integrity": "sha512-DS4a0Rdd7ZtMshoeE+zuSgbC05YBcdzd0h89u/eX+1Yqx+HCjeb8WXkbXsz0Mwx8q9TE04aS8f6Bw9J4x4mO5g==", "requires": { - "@aws-sdk/credential-provider-env": "3.266.1", - "@aws-sdk/credential-provider-imds": "3.266.1", - "@aws-sdk/credential-provider-ini": "3.266.1", - "@aws-sdk/credential-provider-process": "3.266.1", - "@aws-sdk/credential-provider-sso": "3.266.1", - "@aws-sdk/credential-provider-web-identity": "3.266.1", - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/shared-ini-file-loader": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/credential-provider-env": "3.310.0", + "@aws-sdk/credential-provider-imds": "3.310.0", + "@aws-sdk/credential-provider-ini": "3.319.0", + "@aws-sdk/credential-provider-process": "3.310.0", + "@aws-sdk/credential-provider-sso": "3.319.0", + "@aws-sdk/credential-provider-web-identity": "3.310.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-process": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.266.1.tgz", - "integrity": "sha512-4V/7zVnaZo1IP4Is09dlwd2CkltlUdgbX4NUIb+QxZ/BlY7Ws47xyCjjyJhVVCe+y184M58bG4+HR5dHnrBfSA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.310.0.tgz", + "integrity": "sha512-h73sg6GPMUWC+3zMCbA1nZ2O03nNJt7G96JdmnantiXBwHpRKWW8nBTLzx5uhXn6hTuTaoQRP/P+oxQJKYdMmA==", "requires": { - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/shared-ini-file-loader": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-sso": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.266.1.tgz", - "integrity": "sha512-d9hcV7XV1Gh0Dkt8kADsSoB/hZPlbuTp/Vzbj0HMO7hlGxFGcTrGN1UoQc11UAp4kKeF3i2ZQlMsch0d/2gK3w==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.319.0.tgz", + "integrity": "sha512-gAUnWH41lxkIbANXu+Rz5zS0Iavjjmpf3C56vAMT7oaYZ3Cg/Ys5l2SwAucQGOCA2DdS2hDiSI8E+Yhr4F5toA==", "requires": { - "@aws-sdk/client-sso": "3.266.1", - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/shared-ini-file-loader": "3.266.1", - "@aws-sdk/token-providers": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/client-sso": "3.319.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/token-providers": "3.319.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-web-identity": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.266.1.tgz", - "integrity": "sha512-JIktczlqxIc+Gqc/99e7pPzNSgUjYX23fA2dmLt1bHRPH15p8S1Kv73lvqsgLF5EKP1H/UXDu+jVWDklYM6fVA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.310.0.tgz", + "integrity": "sha512-H4SzuZXILNhK6/IR1uVvsUDZvzc051hem7GLyYghBCu8mU+tq28YhKE8MfSroi6eL2e5Vujloij1OM2EQQkPkw==", "requires": { - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/eventstream-codec": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-codec/-/eventstream-codec-3.266.1.tgz", - "integrity": "sha512-4d39jHq8zSfhE2+aPq/fX72ZeekC5iUnqA7NDPxycYKdfULYPEVKrnMytuVon3QaTQVekxtsfHaD4cIh6VvxZg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-codec/-/eventstream-codec-3.310.0.tgz", + "integrity": "sha512-clIeSgWbZbxwtsxZ/yoedNM0/kJFSIjjHPikuDGhxhqc+vP6TN3oYyVMFrYwFaTFhk2+S5wZcWYMw8Op1pWo+A==", "requires": { "@aws-crypto/crc32": "3.0.0", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-hex-encoding": "3.201.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-hex-encoding": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/eventstream-serde-browser": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-serde-browser/-/eventstream-serde-browser-3.266.1.tgz", - "integrity": "sha512-h2UkUvlY8J9RqyXXqBNJYBlDw4TB9xZZpajvA4ZALftY/NcLFXVWbh/AkyQVgVht4SlGba/0CiG5p5se0w7udA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-serde-browser/-/eventstream-serde-browser-3.310.0.tgz", + "integrity": "sha512-3S6ziuQVALgEyz0TANGtYDVeG8ArK4Y05mcgrs8qUTmsvlDIXX37cR/DvmVbNB76M4IrsZeSAIajL9644CywkA==", "requires": { - "@aws-sdk/eventstream-serde-universal": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/eventstream-serde-universal": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/eventstream-serde-config-resolver": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.266.1.tgz", - "integrity": "sha512-ocQiyJw3rSaz+Y6SNZMI7R6yKqI3ffehNqgGoDvm/meKlvAtptj1zXGGyxsNQ+MwB1+t27+RUX/565rF9SJYjQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.310.0.tgz", + "integrity": "sha512-8s1Qdn9STj+sV75nUp9yt0W6fHS4BZ2jTm4Z/1Pcbvh2Gqs0WjH5n2StS+pDW5Y9J/HSGBl0ogmUr5lC5bXFHg==", "requires": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/eventstream-serde-node": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-serde-node/-/eventstream-serde-node-3.266.1.tgz", - "integrity": "sha512-ofMVEdu8TO4vGHXw6ozipy+JoaQB5yog9B6EYj1q/Pq1fBk5AtL9lz6Oar/2VwfYy4XzjIp+axg34XnXUPsN9g==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-serde-node/-/eventstream-serde-node-3.310.0.tgz", + "integrity": "sha512-kSnRomCgW43K9TmQYuwN9+AoYPnhyOKroanUMyZEzJk7rpCPMj4OzaUpXfDYOvznFNYn7NLaH6nHLJAr0VPlJA==", "requires": { - "@aws-sdk/eventstream-serde-universal": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/eventstream-serde-universal": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/eventstream-serde-universal": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-serde-universal/-/eventstream-serde-universal-3.266.1.tgz", - "integrity": "sha512-CftsPIKTw7WyCjoaVur3XTLShPIAy+//VavpDI19rjHL66aGE+RSKCNL5mYJ1HJs3A65Cb0BuEp8VsIT8KYnJQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-serde-universal/-/eventstream-serde-universal-3.310.0.tgz", + "integrity": "sha512-Qyjt5k/waV5cDukpgT824ISZAz5U0pwzLz5ztR409u85AGNkF/9n7MS+LSyBUBSb0WJ5pUeSD47WBk+nLq9Nhw==", "requires": { - "@aws-sdk/eventstream-codec": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/eventstream-codec": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/fetch-http-handler": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.266.1.tgz", - "integrity": "sha512-tyVMLBrJF1weMUqLU81lhuHES5QtFg7RmSysYM8mndePwBl81iQjLF5D7M8CU3aVzXY3TNU3rZBrm5xEK3xK1w==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.310.0.tgz", + "integrity": "sha512-Bi9vIwzdkw1zMcvi/zGzlWS9KfIEnAq4NNhsnCxbQ4OoIRU9wvU+WGZdBBhxg0ZxZmpp1j1aZhU53lLjA07MHw==", "requires": { - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/querystring-builder": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-base64": "3.208.0", - "tslib": "^2.3.1" + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/querystring-builder": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/hash-blob-browser": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/hash-blob-browser/-/hash-blob-browser-3.266.1.tgz", - "integrity": "sha512-VsDjFtbHL5hZkeIq9BRACqvDecfpIJf323F7o1u5q0yATCMq2A4ogL0E8S1TxvlrJAUepFufUVkZxcFL2g4N2w==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/hash-blob-browser/-/hash-blob-browser-3.310.0.tgz", + "integrity": "sha512-OoR8p0cbypToysLT0v3o2oyjy6+DKrY7GNCAzHOHJK9xmqXCt+DsjKoPeiY7o1sWX2aN6Plmvubj/zWxMKEn/A==", "requires": { - "@aws-sdk/chunked-blob-reader": "3.188.0", - "@aws-sdk/chunked-blob-reader-native": "3.208.0", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/chunked-blob-reader": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/hash-node": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.266.1.tgz", - "integrity": "sha512-2DbuY/AmtF4ORJVEAdzHfbM1p8w9ThRlu4BGdI7DXpO6/o1kgRBvNEbZc6MZkg7D2bI7TT6bI83u7AAbbMUMng==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.310.0.tgz", + "integrity": "sha512-NvE2fhRc8GRwCXBfDehxVAWCmVwVMILliAKVPAEr4yz2CkYs0tqU51S48x23dtna07H4qHtgpeNqVTthcIQOEQ==", "requires": { - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-buffer-from": "3.208.0", - "@aws-sdk/util-utf8": "3.254.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-buffer-from": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/hash-stream-node": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/hash-stream-node/-/hash-stream-node-3.266.1.tgz", - "integrity": "sha512-hdFv9pvQOdjNhi5kXEfBgfH5Z28jc0KXh+7x4eUp6dTGoDUP8BPPUTMMtnrVVPnRFVYOsC3ej5xjvuPQhTs9Cw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/hash-stream-node/-/hash-stream-node-3.310.0.tgz", + "integrity": "sha512-ZoXdybNgvMz1Hl6k/e32xVL3jmG5p2IEk5mTtLfFEuskTJ74Z+VMYKkkF1whyy7KQfH83H+TQGnsGtlRCchQKw==", "requires": { - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-utf8": "3.254.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/invalid-dependency": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.266.1.tgz", - "integrity": "sha512-rGc2Bv10eEVQW2Zwrd4/I2QBj5MOhl8qr1NA3UCHJa2501Z97/jn2BGZoX+Cc+iE55so66GKmqMYpibqdtDARw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.310.0.tgz", + "integrity": "sha512-1s5RG5rSPXoa/aZ/Kqr5U/7lqpx+Ry81GprQ2bxWqJvWQIJ0IRUwo5pk8XFxbKVr/2a+4lZT/c3OGoBOM1yRRA==", "requires": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/is-array-buffer": { - "version": "3.201.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.201.0.tgz", - "integrity": "sha512-UPez5qLh3dNgt0DYnPD/q0mVJY84rA17QE26hVNOW3fAji8W2wrwrxdacWOxyXvlxWsVRcKmr+lay1MDqpAMfg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.310.0.tgz", + "integrity": "sha512-urnbcCR+h9NWUnmOtet/s4ghvzsidFmspfhYaHAmSRdy9yDjdjBJMFjjsn85A1ODUktztm+cVncXjQ38WCMjMQ==", "requires": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" } }, "@aws-sdk/md5-js": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/md5-js/-/md5-js-3.266.1.tgz", - "integrity": "sha512-AsNAQ0/6xoWrPU6ZgNKFi7DWhTSXt9Ogp2xaZqT5jY+s5DCsQ6Ydpe1i4HwFLJiJCEAEEw1OurXLp0D8NMaJdA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/md5-js/-/md5-js-3.310.0.tgz", + "integrity": "sha512-x5sRBUrEfLWAS1EhwbbDQ7cXq6uvBxh3qR2XAsnGvFFceTeAadk7cVogWxlk3PC+OCeeym7c3/6Bv2HQ2f1YyQ==", "requires": { - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-utf8": "3.254.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/middleware-bucket-endpoint": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.266.1.tgz", - "integrity": "sha512-6wygf79/YA5ezNhHXsXKkP09jdVm1CzwVZV6Z3b/FqBZJ48FfgFXYhUF7E6mbZepGva7yRFzAwLZEhwYGj5DZw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.310.0.tgz", + "integrity": "sha512-uJJfHI7v4AgbJZRLtyI8ap2QRWkBokGc3iyUoQ+dVNT3/CE2ZCu694A6W+H0dRqg79dIE+f9CRNdtLGa/Ehhvg==", "requires": { - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-arn-parser": "3.208.0", - "@aws-sdk/util-config-provider": "3.208.0", - "tslib": "^2.3.1" + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-arn-parser": "3.310.0", + "@aws-sdk/util-config-provider": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/middleware-content-length": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.266.1.tgz", - "integrity": "sha512-Clq14Fr9WkiSg59jnIelL2F5D81HAhdE1MCZIAEEjN1ZK6bEM2kECnNT9CKJjDsuPvhdkrVGv9rjUSANWHLETw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.310.0.tgz", + "integrity": "sha512-P8tQZxgDt6CAh1wd/W6WPzjc+uWPJwQkm+F7rAwRlM+k9q17HrhnksGDKcpuuLyIhPQYdmOMIkpKVgXGa4avhQ==", "requires": { - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/middleware-endpoint": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.266.1.tgz", - "integrity": "sha512-EVnzd51U/Jhz9x68jFwqHjU4KPsLIXfuS1PSNV598OT04WLQXerBx/fvZh17Y4Dmmu6hf/JUWI9PI5To+oC3mQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.310.0.tgz", + "integrity": "sha512-Z+N2vOL8K354/lstkClxLLsr6hCpVRh+0tCMXrVj66/NtKysCEZ/0b9LmqOwD9pWHNiI2mJqXwY0gxNlKAroUg==", "requires": { - "@aws-sdk/middleware-serde": "3.266.1", - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/signature-v4": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/url-parser": "3.266.1", - "@aws-sdk/util-config-provider": "3.208.0", - "@aws-sdk/util-middleware": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/middleware-serde": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/url-parser": "3.310.0", + "@aws-sdk/util-middleware": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/middleware-expect-continue": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.266.1.tgz", - "integrity": "sha512-8vM1YY/4ub+0s+aWtwubXd2LB2VZ0aTO0X7M/Xjm+fAiCkfqNea5r+T6n2wg/sZCGGgQkBBswTg1I+c2/WbD2Q==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.310.0.tgz", + "integrity": "sha512-l3d1z2gt+gINJDnPSyu84IxfzjzPfCQrqC1sunw2cZGo/sXtEiq698Q3SiTcO2PGP4LBQAy2RHb5wVBJP708CQ==", "requires": { - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/middleware-flexible-checksums": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.266.1.tgz", - "integrity": "sha512-Z9KBIN6IDgnjyjCL7oPxS8yByRi+T7qcLqPm+1QHefLVHWYsAUSD24+0zlshgUQPz6jn8xNnfB9AqTbtuW05NQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.310.0.tgz", + "integrity": "sha512-5ndnLgzgGVpWkmHBAiYkagHqiSuow8q62J4J6E2PzaQ77+fm8W3nfdy7hK5trHokEyouCZdxT/XK/IRhgj/4PA==", "requires": { "@aws-crypto/crc32": "3.0.0", "@aws-crypto/crc32c": "3.0.0", - "@aws-sdk/is-array-buffer": "3.201.0", - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-utf8": "3.254.0", - "tslib": "^2.3.1" + "@aws-sdk/is-array-buffer": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/middleware-host-header": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.266.1.tgz", - "integrity": "sha512-3FSD8EkxOGV4O2iKgBnAwvj3PG/lABzcqmX6hABnsIusXAlUV5umh39FteipLcjnMXB04cLgmcgcG2o3cSA3tQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.310.0.tgz", + "integrity": "sha512-QWSA+46/hXorXyWa61ic2K7qZzwHTiwfk2e9mRRjeIRepUgI3qxFjsYqrWtrOGBjmFmq0pYIY8Bb/DCJuQqcoA==", "requires": { - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/middleware-location-constraint": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.266.1.tgz", - "integrity": "sha512-m3ZKtv+bfzFNe8O5cYraaSoFs2IkwELJ20ResV6RlyXfkHxML22ftCaKf+jTNQqHVFg6m0l3ECWirGfDLUvicw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.310.0.tgz", + "integrity": "sha512-LFm0JTQWwTPWL/tZU2wsQTl8J5PpDEkXjEhaXVKamtyH0xhysRqd+0n92n65dc8oztAuQkb9xUbErGn5b6gsew==", "requires": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/middleware-logger": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.266.1.tgz", - "integrity": "sha512-FbD9Hqt994PyDm7OTG8PbIuB6Mv9vYhqOM2RhqC1UGtprDmk084/cEv9Sp+qY33lFPxjZstKneQK6FhAfozIAQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.310.0.tgz", + "integrity": "sha512-Lurm8XofrASBRnAVtiSNuDSRsRqPNg27RIFLLsLp/pqog9nFJ0vz0kgdb9S5Z+zw83Mm+UlqOe6D8NTUNp4fVg==", "requires": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/middleware-recursion-detection": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.266.1.tgz", - "integrity": "sha512-rgRxdgrLOD20zIFrjFW7Bu3s4MXC1KLDbqJY6sMpc5D8mmQlxfaQiSnCQrjgUxbW0Ni+rXiatlW2q2MwCUAPzw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.310.0.tgz", + "integrity": "sha512-SuB75/xk/gyue24gkriTwO2jFd7YcUGZDClQYuRejgbXSa3CO0lWyawQtfLcSSEBp9izrEVXuFH24K1eAft5nQ==", "requires": { - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/middleware-retry": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.266.1.tgz", - "integrity": "sha512-xBiKAjAP1j8SbKhF28bk1g2iZoiVMI7XV/x5d0g6igsvI4RiqzywTsiLi2VVsYPCY6bwbn0Zgt93Mej/MFfn5w==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.310.0.tgz", + "integrity": "sha512-oTPsRy2W4s+dfxbJPW7Km+hHtv/OMsNsVfThAq8DDYKC13qlr1aAyOqGLD+dpBy2aKe7ss517Sy2HcHtHqm7/g==", "requires": { - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/service-error-classification": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-middleware": "3.266.1", - "@aws-sdk/util-retry": "3.266.1", - "tslib": "^2.3.1", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/service-error-classification": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-middleware": "3.310.0", + "@aws-sdk/util-retry": "3.310.0", + "tslib": "^2.5.0", "uuid": "^8.3.2" }, "dependencies": { @@ -17837,344 +18012,328 @@ } }, "@aws-sdk/middleware-sdk-s3": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.266.1.tgz", - "integrity": "sha512-d3Ow2YjPTIgi2WGx0lMRdoO86JOII3VwzGN4R7GViCY7Ic+Vj920IvGTz/olqSJWIA2tF9l+D2dQTNuU0btaDQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.310.0.tgz", + "integrity": "sha512-QK9x9g2ksg0hOjjYgqddeFcn5ctUEGdxJVu4OumPXceulefMcSO2jyH2qTybYSA93nqNQFdFmg5wQfvIRUWFCQ==", "requires": { - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-arn-parser": "3.208.0", - "tslib": "^2.3.1" + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-arn-parser": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/middleware-sdk-sts": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.266.1.tgz", - "integrity": "sha512-lM9t+S+PjmJ/xhoP9e/sIUS2bZyuEbobHo6a9WPk0UcdiqDWBIp+8MlTRDafKZtlN36gPDk5+qM9tXcI6P5YCA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.310.0.tgz", + "integrity": "sha512-+5PFwlYNLvLLIfw0ASAoWV/iIF8Zv6R6QGtyP0CclhRSvNjgbQDVnV0g95MC5qvh+GB/Yjlkt8qAjLSPjHfsrQ==", "requires": { - "@aws-sdk/middleware-signing": "3.266.1", - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/signature-v4": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/middleware-signing": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/middleware-serde": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.266.1.tgz", - "integrity": "sha512-UFJ4BlRG/MUOJq5afHohkDsMDPAkbuXGCkhTz93MGxbACEOJYoEvsaMjpLft88wu4D11GY1Y2PVFkfxJUYWDXA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.310.0.tgz", + "integrity": "sha512-RNeeTVWSLTaentUeCgQKZhAl+C6hxtwD78cQWS10UymWpQFwbaxztzKUu4UQS5xA2j6PxwPRRUjqa4jcFjfLsg==", "requires": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/middleware-signing": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.266.1.tgz", - "integrity": "sha512-PbVwt7xSP3xlT5x4Xdj7+2T1PgCW00bh5QrCJi2wo3dEN9UowU/IVGzGSv4/OJItLZWe4puGb1WtA+LKeWA40w==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.310.0.tgz", + "integrity": "sha512-f9mKq+XMdW207Af3hKjdTnpNhdtwqWuvFs/ZyXoOkp/g1MY1O6L23Jy6i52m29LxbT4AuNRG1oKODfXM0vYVjQ==", "requires": { - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/signature-v4": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-middleware": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/signature-v4": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-middleware": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/middleware-ssec": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.266.1.tgz", - "integrity": "sha512-HEiFZVLLzLPRKI16MvsIUGv9rZASP6dCYIldYpYj8hT2upxh2fhm4hYxHmspfIBgVo2RFK147pTpBwnfYQBeEA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.310.0.tgz", + "integrity": "sha512-CnEwNKVpd5bXnrCKPaePF8mWTA9ET21OMBb54y9b0fd8K02zoOcdBz4DWfh1SjFD4HkgCdja4egd8l2ivyvqmw==", "requires": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/middleware-stack": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.266.1.tgz", - "integrity": "sha512-liqq541u1eCDe+TCDOSrOcH6kAB6Dn1R8pbtJ23hP3fYM5/8W3V0f6VcywALVL9Pam+mkYmodWeDRQK8ieLEOg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.310.0.tgz", + "integrity": "sha512-010O1PD+UAcZVKRvqEusE1KJqN96wwrf6QsqbRM0ywsKQ21NDweaHvEDlds2VHpgmofxkRLRu/IDrlPkKRQrRg==", "requires": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" } }, "@aws-sdk/middleware-user-agent": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.266.1.tgz", - "integrity": "sha512-yoHQSP3OngZnLWeuqMrYkOifMD8FUZxyXoUO9iHPytxns1Gri/4Gn/1raNWMqdrSIlBKPorKzCEu24DX5klf0w==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.319.0.tgz", + "integrity": "sha512-ytaLx2dlR5AdMSne6FuDCISVg8hjyKj+cHU20b2CRA/E/z+XXrLrssp4JrCgizRKPPUep0psMIa22Zd6osTT5Q==", "requires": { - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-endpoints": "3.319.0", + "tslib": "^2.5.0" } }, "@aws-sdk/node-config-provider": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.266.1.tgz", - "integrity": "sha512-cDDuj64nGskZNJQdwglIRqTazfZt0f8pooT1ZJrFoydLfMmR9yi6orizQ7C0i1vMkY02HxgwqJiwXuJ73gmaqA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.310.0.tgz", + "integrity": "sha512-T/Pp6htc6hq/Cq+MLNDSyiwWCMVF6GqbBbXKVlO5L8rdHx4sq9xPdoPveZhGWrxvkanjA6eCwUp6E0riBOSVng==", "requires": { - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/shared-ini-file-loader": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/node-http-handler": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.266.1.tgz", - "integrity": "sha512-oa1cDeD+fwGFg8xMfNUZ95xAE0dxiXaTdJwSqOzCVIBz/auahHrcfXey+Oynw1zUjv8ijOH9z/SXYrqfwlZosw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.310.0.tgz", + "integrity": "sha512-irv9mbcM9xC2xYjArQF5SYmHBMu4ciMWtGsoHII1nRuFOl9FoT4ffTvEPuLlfC6pznzvKt9zvnm6xXj7gDChKg==", "requires": { - "@aws-sdk/abort-controller": "3.266.1", - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/querystring-builder": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/abort-controller": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/querystring-builder": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/property-provider": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.266.1.tgz", - "integrity": "sha512-1ZRWqc4sNFGDRZ0Tl4WaukU9jR4ghB84QEQOqc48cJIoDiwOAP9UBJTNBJXCVllmPWGNgx4/lfWJoaFcvwsrzw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.310.0.tgz", + "integrity": "sha512-3lxDb0akV6BBzmFe4nLPaoliQbAifyWJhuvuDOu7e8NzouvpQXs0275w9LePhhcgjKAEVXUIse05ZW2DLbxo/g==", "requires": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/protocol-http": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.266.1.tgz", - "integrity": "sha512-8Z1Yfkf59of1R9qRSPmDKIHDo0n5YNCh1FrRLmCRqjjiZ4Ed7FJV/W6YYnJ6VbPcVv1WK6FvwzrGPM2gg4P48Q==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.310.0.tgz", + "integrity": "sha512-fgZ1aw/irQtnrsR58pS8ThKOWo57Py3xX6giRvwSgZDEcxHfVzuQjy9yPuV++v04fdmdtgpbGf8WfvAAJ11yXQ==", "requires": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/querystring-builder": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.266.1.tgz", - "integrity": "sha512-D1LoDv3A+c6YIYq6F2T5m8V0C14vQAarSoT6romVIIYCDuMK4R5BwB1NLFRco1dczyAYmqScxdV2C26+xjXJfw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.310.0.tgz", + "integrity": "sha512-ZHH8GV/80+pWGo7DzsvwvXR5xVxUHXUvPJPFAkhr6nCf78igdoF8gR10ScFoEKbtEapoNTaZlKHPXxpD8aPG7A==", "requires": { - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-uri-escape": "3.201.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-uri-escape": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/querystring-parser": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.266.1.tgz", - "integrity": "sha512-Ck8Ahluj+/eK4FcX8IlbO7DA1MNWdnh1rKjc1qx/ZWh71G/FdZ8Sse33N+Ed/z9v7H8W695dprRT6CuRlqyAbw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.310.0.tgz", + "integrity": "sha512-YkIznoP6lsiIUHinx++/lbb3tlMURGGqMpo0Pnn32zYzGrJXA6eC3D0as2EcMjo55onTfuLcIiX4qzXes2MYOA==", "requires": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/s3-request-presigner": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.266.1.tgz", - "integrity": "sha512-bLbVQCFQ+VwGEkRfmQ+IFB8nkRZRtZW3QbsXwNYeQ7VD387gYhvV/hnNbWlOWrNjiNNaLuvwcgzlMgFR3sRHIQ==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.319.0.tgz", + "integrity": "sha512-mq/4nqr/3sHGx9iJqPXXkfBPAlXGB000u4dX4QCMPFmMupfH5sT8M+hYgcB6N/2HuZ+JNJQntwu9q97gjhwpDQ==", "requires": { - "@aws-sdk/middleware-endpoint": "3.266.1", - "@aws-sdk/middleware-sdk-s3": "3.266.1", - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/signature-v4-multi-region": "3.266.1", - "@aws-sdk/smithy-client": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-create-request": "3.266.1", - "@aws-sdk/util-format-url": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/middleware-endpoint": "3.310.0", + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/signature-v4-multi-region": "3.310.0", + "@aws-sdk/smithy-client": "3.316.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-format-url": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/service-error-classification": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.266.1.tgz", - "integrity": "sha512-c2EvUvn9XLaDjKozCcYlO4cbtbJzBgx6EuhW1eLsMGLY3EobVRo1hGT0PtRmWQNnoW0BXv6oi/8NLOV6x37fxA==" + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.310.0.tgz", + "integrity": "sha512-PuyC7k3qfIKeH2LCnDwbttMOKq3qAx4buvg0yfnJtQOz6t1AR8gsnAq0CjKXXyfkXwNKWTqCpE6lVNUIkXgsMw==" }, "@aws-sdk/shared-ini-file-loader": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.266.1.tgz", - "integrity": "sha512-yV8GY1Cgbc6pl0SRRQtx3PPcZpqYvKf/h1pz0FgkMBPHwOhp7zJYUkYmu3yvXulfORNsM5ro7wnKa0kxb5ljmg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.310.0.tgz", + "integrity": "sha512-N0q9pG0xSjQwc690YQND5bofm+4nfUviQ/Ppgan2kU6aU0WUq8KwgHJBto/YEEI+VlrME30jZJnxtOvcZJc2XA==", "requires": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/signature-v4": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.266.1.tgz", - "integrity": "sha512-kiHHA3voQKz4QYLKbR/3hKkY2n62MuGewYctvtQsh1069U/OI7FVceIE5hZnrlC5XX4jiNoF1lKdyRhXmK5GMQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.310.0.tgz", + "integrity": "sha512-1M60P1ZBNAjCFv9sYW29OF6okktaeibWyW3lMXqzoHF70lHBZh+838iUchznXUA5FLabfn4jBFWMRxlAXJUY2Q==", "requires": { - "@aws-sdk/is-array-buffer": "3.201.0", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-hex-encoding": "3.201.0", - "@aws-sdk/util-middleware": "3.266.1", - "@aws-sdk/util-uri-escape": "3.201.0", - "@aws-sdk/util-utf8": "3.254.0", - "tslib": "^2.3.1" + "@aws-sdk/is-array-buffer": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-hex-encoding": "3.310.0", + "@aws-sdk/util-middleware": "3.310.0", + "@aws-sdk/util-uri-escape": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/signature-v4-multi-region": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.266.1.tgz", - "integrity": "sha512-G94sV+RfGpYMiGEFvXNf8y4COEywoRmDJ2Dx9yVIZnhkQJgToffazwLHmfAHcDS7UUs+p1LoBEaKCzb5cW/+NA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.310.0.tgz", + "integrity": "sha512-q8W+RIomTS/q85Ntgks/CoDElwqkC9+4OCicee5YznNHjQ4gtNWhUkYIyIRWRmXa/qx/AUreW9DM8FAecCOdng==", "requires": { - "@aws-sdk/protocol-http": "3.266.1", - "@aws-sdk/signature-v4": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-arn-parser": "3.208.0", - "tslib": "^2.3.1" + "@aws-sdk/protocol-http": "3.310.0", + "@aws-sdk/signature-v4": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/smithy-client": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.266.1.tgz", - "integrity": "sha512-fg/+JzHeYPS0poVckSiaE/h1eWf5+u2Cs8/zh/4bAvVPqSA3Gg/yBrtvP+HxKLoSo+ObuPb9aXXkeCKPke6ktA==", + "version": "3.316.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.316.0.tgz", + "integrity": "sha512-6YXOKbRnXeS8r8RWzuL6JMBolDYM5Wa4fD/VY6x/wK78i2xErHOvqzHgyyeLI1MMw4uqyd4wRNJNWC9TMPduXw==", "requires": { - "@aws-sdk/middleware-stack": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/middleware-stack": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/token-providers": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.266.1.tgz", - "integrity": "sha512-N+qiLQvPvel9dFdEoffRG4Mcp2p82OMyUvS12P5iYWqPCDuPzU72rYT2PmVFKINmflqEySjsKo8vIaWx7Kl4pQ==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.319.0.tgz", + "integrity": "sha512-5utg6VL6Pl0uiLUn8ZJPYYxzCb9VRPsgJmGXktRUwq0YlTJ6ABcaxTXwZcC++sjh/qyCQDK5PPLNU5kIBttHMQ==", "requires": { - "@aws-sdk/client-sso-oidc": "3.266.1", - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/shared-ini-file-loader": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/client-sso-oidc": "3.319.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/shared-ini-file-loader": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/types": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.266.1.tgz", - "integrity": "sha512-OVg3CjHKT3/Ws33jx3TUYYkbFOv/CLb9m3P4gZQDvgKPsOagp96LOsG8ZWdcVZCvSorAUqSb5kuc1utsjJxDTw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.310.0.tgz", + "integrity": "sha512-j8eamQJ7YcIhw7fneUfs8LYl3t01k4uHi4ZDmNRgtbmbmTTG3FZc2MotStZnp3nZB6vLiPF1o5aoJxWVvkzS6A==", "requires": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" } }, "@aws-sdk/url-parser": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.266.1.tgz", - "integrity": "sha512-7IBZ8TjTWafug26CnNpz6cdrLU0TZ0G7N9LNfqjM/+69KI/Ragvv2Lsm4jhSv2uMx5OEzwlVYIEYaKMnAUiRLQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.310.0.tgz", + "integrity": "sha512-mCLnCaSB9rQvAgx33u0DujLvr4d5yEm/W5r789GblwwQnlNXedVu50QRizMLTpltYWyAUoXjJgQnJHmJMaKXhw==", "requires": { - "@aws-sdk/querystring-parser": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/querystring-parser": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/util-arn-parser": { - "version": "3.208.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.208.0.tgz", - "integrity": "sha512-QV4af+kscova9dv4VuHOgH8wEr/IIYHDGcnyVtkUEqahCejWr1Kuk+SBK0xMwnZY5LSycOtQ8aeqHOn9qOjZtA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.310.0.tgz", + "integrity": "sha512-jL8509owp/xB9+Or0pvn3Fe+b94qfklc2yPowZZIFAkFcCSIdkIglz18cPDWnYAcy9JGewpMS1COXKIUhZkJsA==", "requires": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" } }, "@aws-sdk/util-base64": { - "version": "3.208.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64/-/util-base64-3.208.0.tgz", - "integrity": "sha512-PQniZph5A6N7uuEOQi+1hnMz/FSOK/8kMFyFO+4DgA1dZ5pcKcn5wiFwHkcTb/BsgVqQa3Jx0VHNnvhlS8JyTg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64/-/util-base64-3.310.0.tgz", + "integrity": "sha512-v3+HBKQvqgdzcbL+pFswlx5HQsd9L6ZTlyPVL2LS9nNXnCcR3XgGz9jRskikRUuUvUXtkSG1J88GAOnJ/apTPg==", "requires": { - "@aws-sdk/util-buffer-from": "3.208.0", - "tslib": "^2.3.1" + "@aws-sdk/util-buffer-from": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/util-body-length-browser": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.188.0.tgz", - "integrity": "sha512-8VpnwFWXhnZ/iRSl9mTf+VKOX9wDE8QtN4bj9pBfxwf90H1X7E8T6NkiZD3k+HubYf2J94e7DbeHs7fuCPW5Qg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.310.0.tgz", + "integrity": "sha512-sxsC3lPBGfpHtNTUoGXMQXLwjmR0zVpx0rSvzTPAuoVILVsp5AU/w5FphNPxD5OVIjNbZv9KsKTuvNTiZjDp9g==", "requires": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" } }, "@aws-sdk/util-body-length-node": { - "version": "3.208.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.208.0.tgz", - "integrity": "sha512-3zj50e5g7t/MQf53SsuuSf0hEELzMtD8RX8C76f12OSRo2Bca4FLLYHe0TZbxcfQHom8/hOaeZEyTyMogMglqg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.310.0.tgz", + "integrity": "sha512-2tqGXdyKhyA6w4zz7UPoS8Ip+7sayOg9BwHNidiGm2ikbDxm1YrCfYXvCBdwaJxa4hJfRVz+aL9e+d3GqPI9pQ==", "requires": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" } }, "@aws-sdk/util-buffer-from": { - "version": "3.208.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.208.0.tgz", - "integrity": "sha512-7L0XUixNEFcLUGPeBF35enCvB9Xl+K6SQsmbrPk1P3mlV9mguWSDQqbOBwY1Ir0OVbD6H/ZOQU7hI/9RtRI0Zw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.310.0.tgz", + "integrity": "sha512-i6LVeXFtGih5Zs8enLrt+ExXY92QV25jtEnTKHsmlFqFAuL3VBeod6boeMXkN2p9lbSVVQ1sAOOYZOHYbYkntw==", "requires": { - "@aws-sdk/is-array-buffer": "3.201.0", - "tslib": "^2.3.1" + "@aws-sdk/is-array-buffer": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/util-config-provider": { - "version": "3.208.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.208.0.tgz", - "integrity": "sha512-DSRqwrERUsT34ug+anlMBIFooBEGwM8GejC7q00Y/9IPrQy50KnG5PW2NiTjuLKNi7pdEOlwTSEocJE15eDZIg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.310.0.tgz", + "integrity": "sha512-xIBaYo8dwiojCw8vnUcIL4Z5tyfb1v3yjqyJKJWV/dqKUFOOS0U591plmXbM+M/QkXyML3ypon1f8+BoaDExrg==", "requires": { - "tslib": "^2.3.1" - } - }, - "@aws-sdk/util-create-request": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-create-request/-/util-create-request-3.266.1.tgz", - "integrity": "sha512-S7Kj9AvryLYIAuHaNGdnC+eF0NqzD7DkW6n/wWRjaKg4eR36VfG5AXNCQcsXkpd8eo66OHDPv6VRjX2SaL50yA==", - "requires": { - "@aws-sdk/middleware-stack": "3.266.1", - "@aws-sdk/smithy-client": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "tslib": "^2.5.0" } }, "@aws-sdk/util-defaults-mode-browser": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.266.1.tgz", - "integrity": "sha512-4arGHXzTwLIPlNb3a2v7i2fpKFBLQfFygUDT1E6VCAbNpvPVJk+/w0foFs0Zc8BQsPQsC+ZKe20pFw0hnHZJGw==", + "version": "3.316.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.316.0.tgz", + "integrity": "sha512-6FSqLhYmaihtH2n1s4b2rlLW0ABU8N6VZIfzLfe2ING4PF0MzfaMMhnTFUHVXfKCVGoR8yP6iyFTRCyHGVEL1w==", "requires": { - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/types": "3.266.1", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", "bowser": "^2.11.0", - "tslib": "^2.3.1" + "tslib": "^2.5.0" } }, "@aws-sdk/util-defaults-mode-node": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.266.1.tgz", - "integrity": "sha512-EOo2pPtvJUd9vkwRAptBIeF4P5zHeHcvCcCw6ZuP7bLvaUNHxepKAy4iesaB4aqqRgVn6AdV7w489HnTxa8Kpw==", + "version": "3.316.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.316.0.tgz", + "integrity": "sha512-dkYy10hdjPSScXXvnjGpZpnJxllkb6ICHgLMwZ4JczLHhPM12T/4PQ758YN8HS+muiYDGX1Bl2z1jd/bMcewBQ==", "requires": { - "@aws-sdk/config-resolver": "3.266.1", - "@aws-sdk/credential-provider-imds": "3.266.1", - "@aws-sdk/node-config-provider": "3.266.1", - "@aws-sdk/property-provider": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/config-resolver": "3.310.0", + "@aws-sdk/credential-provider-imds": "3.310.0", + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/property-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/util-endpoints": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.266.1.tgz", - "integrity": "sha512-w2VjoAIvfw2gau+cVQ5vahfy5CqQJrNOnSXbH6kjpd8RVQ0wOWBDVKb8tUwF4ROD1zovx0jT9d7bsYdMyo3HJw==", + "version": "3.319.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.319.0.tgz", + "integrity": "sha512-3I64UMoYA2e2++oOUJXRcFtYLpLylnZFRltWfPo1B3dLlf+MIWat9djT+mMus+hW1ntLsvAIVu1hLVePJC0gvw==", "requires": { - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/util-format-url": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.266.1.tgz", - "integrity": "sha512-hCOgeAv1Oc4vK9VIkvbruchXXTxutFgLYFvqt43q5Tnu2jXyWinnIsenKS0PszUxuccmqy/fDcoYQWAqRML1fQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.310.0.tgz", + "integrity": "sha512-NBOvmvvVR3ydquHmznfgtakiSgDhq8Ww6fq8TUaEjM+Es6+iqY4AwZo0rZ9xTX3GpCcoZy391HUi6kiXRAFzuA==", "requires": { - "@aws-sdk/querystring-builder": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/querystring-builder": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/util-hex-encoding": { - "version": "3.201.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.201.0.tgz", - "integrity": "sha512-7t1vR1pVxKx0motd3X9rI3m/xNp78p3sHtP5yo4NP4ARpxyJ0fokBomY8ScaH2D/B+U5o9ARxldJUdMqyBlJcA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.310.0.tgz", + "integrity": "sha512-sVN7mcCCDSJ67pI1ZMtk84SKGqyix6/0A1Ab163YKn+lFBQRMKexleZzpYzNGxYzmQS6VanP/cfU7NiLQOaSfA==", "requires": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" } }, "@aws-sdk/util-locate-window": { @@ -18186,81 +18345,81 @@ } }, "@aws-sdk/util-middleware": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.266.1.tgz", - "integrity": "sha512-iZq+lq80byWZMsdII4OS7CdhgGeuBXBPd//iFWq4YmGts5W1QI1FLIFcsOuUnZtQMiaAuvLXtEO8ZrfaKTFKgw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.310.0.tgz", + "integrity": "sha512-FTSUKL/eRb9X6uEZClrTe27QFXUNNp7fxYrPndZwk1hlaOP5ix+MIHBcI7pIiiY/JPfOUmPyZOu+HetlFXjWog==", "requires": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" } }, "@aws-sdk/util-retry": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-retry/-/util-retry-3.266.1.tgz", - "integrity": "sha512-mQZshXR31iM9eV+x50pdmIFuDAjd8wDrxJ/kDnwR0H9NaeIQ3SKcNFTs0PPqtu/JUX0vb4wvm2KjIkUyO2iijg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-retry/-/util-retry-3.310.0.tgz", + "integrity": "sha512-FwWGhCBLfoivTMUHu1LIn4NjrN9JLJ/aX5aZmbcPIOhZVFJj638j0qDgZXyfvVqBuBZh7M8kGq0Oahy3dp69OA==", "requires": { - "@aws-sdk/service-error-classification": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/service-error-classification": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/util-stream-browser": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-stream-browser/-/util-stream-browser-3.266.1.tgz", - "integrity": "sha512-u1Tyb8x3PkOZfMuSugRSfyY28dKnPv8oG70jGTRwpscqFQMOjzXMB8ciwNRlPeuivwSOhX2ZWkgnQg6Sx0JuQg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-stream-browser/-/util-stream-browser-3.310.0.tgz", + "integrity": "sha512-bysXZHwFwvbqOTCScCdCnoLk1K3GCo0HRIYEZuL7O7MHrQmfaYRXcaft/p22+GUv9VeFXS/eJJZ5r4u32az94w==", "requires": { - "@aws-sdk/fetch-http-handler": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-base64": "3.208.0", - "@aws-sdk/util-hex-encoding": "3.201.0", - "@aws-sdk/util-utf8": "3.254.0", - "tslib": "^2.3.1" + "@aws-sdk/fetch-http-handler": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-base64": "3.310.0", + "@aws-sdk/util-hex-encoding": "3.310.0", + "@aws-sdk/util-utf8": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/util-stream-node": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-stream-node/-/util-stream-node-3.266.1.tgz", - "integrity": "sha512-tZm6KKf8fdv/MS3oKe9C0iK5vukQOvYdAVXSOSROuU6q3GVQXTLEl593KC/GkhjO1hjF9o72IlRZZ/QA0PvnNg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-stream-node/-/util-stream-node-3.310.0.tgz", + "integrity": "sha512-hueAXFK0GVvnfYFgqbF7587xZfMZff5jlIFZOHqx7XVU7bl7qrRUCnphHk8H6yZ7RoQbDPcfmHJgtEoAJg1T1Q==", "requires": { - "@aws-sdk/node-http-handler": "3.266.1", - "@aws-sdk/types": "3.266.1", - "@aws-sdk/util-buffer-from": "3.208.0", - "tslib": "^2.3.1" + "@aws-sdk/node-http-handler": "3.310.0", + "@aws-sdk/types": "3.310.0", + "@aws-sdk/util-buffer-from": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/util-uri-escape": { - "version": "3.201.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.201.0.tgz", - "integrity": "sha512-TeTWbGx4LU2c5rx0obHeDFeO9HvwYwQtMh1yniBz00pQb6Qt6YVOETVQikRZ+XRQwEyCg/dA375UplIpiy54mA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.310.0.tgz", + "integrity": "sha512-drzt+aB2qo2LgtDoiy/3sVG8w63cgLkqFIa2NFlGpUgHFWTXkqtbgf4L5QdjRGKWhmZsnqkbtL7vkSWEcYDJ4Q==", "requires": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" } }, "@aws-sdk/util-user-agent-browser": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.266.1.tgz", - "integrity": "sha512-zT5Sc0rNLOhBC+RhFF0FRE2y+CIf50rJZLkxRXoVRXJeFVSKPyhk3AKqe2Q6FE+yQsTV2FlwSDI98SxgaDORkQ==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.310.0.tgz", + "integrity": "sha512-yU/4QnHHuQ5z3vsUqMQVfYLbZGYwpYblPiuZx4Zo9+x0PBkNjYMqctdDcrpoH9Z2xZiDN16AmQGK1tix117ZKw==", "requires": { - "@aws-sdk/types": "3.266.1", + "@aws-sdk/types": "3.310.0", "bowser": "^2.11.0", - "tslib": "^2.3.1" + "tslib": "^2.5.0" } }, "@aws-sdk/util-user-agent-node": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.266.1.tgz", - "integrity": "sha512-o8uYR38GxaKj95acC0tIxM2K0vANVMpEpgpWcW+QTvVc4Vm4im0SBD7BvgXbQV2VW8X28ZNddVbCK7pHHEJrtg==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.310.0.tgz", + "integrity": "sha512-Ra3pEl+Gn2BpeE7KiDGpi4zj7WJXZA5GXnGo3mjbi9+Y3zrbuhJAbdZO3mO/o7xDgMC6ph4xCTbaSGzU6b6EDg==", "requires": { - "@aws-sdk/node-config-provider": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/node-config-provider": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/util-utf8": { - "version": "3.254.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8/-/util-utf8-3.254.0.tgz", - "integrity": "sha512-14Kso/eIt5/qfIBmhEL9L1IfyUqswjSTqO2mY7KOzUZ9SZbwn3rpxmtkhmATkRjD7XIlLKaxBkI7tU9Zjzj8Kw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8/-/util-utf8-3.310.0.tgz", + "integrity": "sha512-DnLfFT8uCO22uOJc0pt0DsSNau1GTisngBCDw8jQuWT5CqogMJu4b/uXmwEqfj8B3GX6Xsz8zOd6JpRlPftQoA==", "requires": { - "@aws-sdk/util-buffer-from": "3.208.0", - "tslib": "^2.3.1" + "@aws-sdk/util-buffer-from": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/util-utf8-browser": { @@ -18272,21 +18431,21 @@ } }, "@aws-sdk/util-waiter": { - "version": "3.266.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-waiter/-/util-waiter-3.266.1.tgz", - "integrity": "sha512-g3uzVouAs6LfYU7vZEy4BIEIiCXSAjZnGV4RjTagfxZRpNtAriFn29Zys4nA/cBHxUkOS3XTzbt5eTBwEdK/FA==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-waiter/-/util-waiter-3.310.0.tgz", + "integrity": "sha512-AV5j3guH/Y4REu+Qh3eXQU9igljHuU4XjX2sADAgf54C0kkhcCCkkiuzk3IsX089nyJCqIcj5idbjdvpnH88Vw==", "requires": { - "@aws-sdk/abort-controller": "3.266.1", - "@aws-sdk/types": "3.266.1", - "tslib": "^2.3.1" + "@aws-sdk/abort-controller": "3.310.0", + "@aws-sdk/types": "3.310.0", + "tslib": "^2.5.0" } }, "@aws-sdk/xml-builder": { - "version": "3.201.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.201.0.tgz", - "integrity": "sha512-brRdB1wwMgjWEnOQsv7zSUhIQuh7DEicrfslAqHop4S4FtSI3GQAShpQqgOpMTNFYcpaWKmE/Y1MJmNY7xLCnw==", + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.310.0.tgz", + "integrity": "sha512-TqELu4mOuSIKQCqj63fGVs86Yh+vBx5nHRpWKNUNhB2nPTpfbziTs5c1X358be3peVWA4wPxW7Nt53KIg1tnNw==", "requires": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" } }, "@babel/code-frame": { @@ -18336,9 +18495,9 @@ } }, "@babel/generator": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz", - "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==", + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", + "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", "dev": true, "requires": { "@babel/types": "^7.20.7", @@ -19412,9 +19571,9 @@ } }, "@babel/runtime": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz", - "integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==", + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", + "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", "dev": true, "requires": { "regenerator-runtime": "^0.13.11" @@ -19475,179 +19634,194 @@ "dev": true }, "@es-joy/jsdoccomment": { - "version": "0.36.1", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.36.1.tgz", - "integrity": "sha512-922xqFsTpHs6D0BUiG4toiyPOMc8/jafnWKxz1KWgS4XzKPy2qXf1Pe6UFuNSCQqt6tOuhAWXBNuuyUhJmw9Vg==", + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.37.0.tgz", + "integrity": "sha512-hjK0wnsPCYLlF+HHB4R/RbUjOWeLW2SlarB67+Do5WsKILOkmIZvvPJFbtWSmbypxcjpoECLAMzoao0D4Bg5ZQ==", "dev": true, "requires": { "comment-parser": "1.3.1", "esquery": "^1.4.0", - "jsdoc-type-pratt-parser": "~3.1.0" + "jsdoc-type-pratt-parser": "~4.0.0" } }, "@esbuild/android-arm": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz", - "integrity": "sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.8.tgz", + "integrity": "sha512-0/rb91GYKhrtbeglJXOhAv9RuYimgI8h623TplY2X+vA4EXnk3Zj1fXZreJ0J3OJJu1bwmb0W7g+2cT/d8/l/w==", "dev": true, "optional": true }, "@esbuild/android-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz", - "integrity": "sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.8.tgz", + "integrity": "sha512-oa/N5j6v1svZQs7EIRPqR8f+Bf8g6HBDjD/xHC02radE/NjKHK7oQmtmLxPs1iVwYyvE+Kolo6lbpfEQ9xnhxQ==", "dev": true, "optional": true }, "@esbuild/android-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz", - "integrity": "sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.8.tgz", + "integrity": "sha512-bTliMLqD7pTOoPg4zZkXqCDuzIUguEWLpeqkNfC41ODBHwoUgZ2w5JBeYimv4oP6TDVocoYmEhZrCLQTrH89bg==", "dev": true, "optional": true }, "@esbuild/darwin-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz", - "integrity": "sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.8.tgz", + "integrity": "sha512-ghAbV3ia2zybEefXRRm7+lx8J/rnupZT0gp9CaGy/3iolEXkJ6LYRq4IpQVI9zR97ID80KJVoUlo3LSeA/sMAg==", "dev": true, "optional": true }, "@esbuild/darwin-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz", - "integrity": "sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.8.tgz", + "integrity": "sha512-n5WOpyvZ9TIdv2V1K3/iIkkJeKmUpKaCTdun9buhGRWfH//osmUjlv4Z5mmWdPWind/VGcVxTHtLfLCOohsOXw==", "dev": true, "optional": true }, "@esbuild/freebsd-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz", - "integrity": "sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.8.tgz", + "integrity": "sha512-a/SATTaOhPIPFWvHZDoZYgxaZRVHn0/LX1fHLGfZ6C13JqFUZ3K6SMD6/HCtwOQ8HnsNaEeokdiDSFLuizqv5A==", "dev": true, "optional": true }, "@esbuild/freebsd-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz", - "integrity": "sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.8.tgz", + "integrity": "sha512-xpFJb08dfXr5+rZc4E+ooZmayBW6R3q59daCpKZ/cDU96/kvDM+vkYzNeTJCGd8rtO6fHWMq5Rcv/1cY6p6/0Q==", "dev": true, "optional": true }, "@esbuild/linux-arm": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz", - "integrity": "sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.8.tgz", + "integrity": "sha512-6Ij8gfuGszcEwZpi5jQIJCVIACLS8Tz2chnEBfYjlmMzVsfqBP1iGmHQPp7JSnZg5xxK9tjCc+pJ2WtAmPRFVA==", "dev": true, "optional": true }, "@esbuild/linux-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz", - "integrity": "sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.8.tgz", + "integrity": "sha512-v3iwDQuDljLTxpsqQDl3fl/yihjPAyOguxuloON9kFHYwopeJEf1BkDXODzYyXEI19gisEsQlG1bM65YqKSIww==", "dev": true, "optional": true }, "@esbuild/linux-ia32": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz", - "integrity": "sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.8.tgz", + "integrity": "sha512-8svILYKhE5XetuFk/B6raFYIyIqydQi+GngEXJgdPdI7OMKUbSd7uzR02wSY4kb53xBrClLkhH4Xs8P61Q2BaA==", "dev": true, "optional": true }, "@esbuild/linux-loong64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz", - "integrity": "sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.8.tgz", + "integrity": "sha512-B6FyMeRJeV0NpyEOYlm5qtQfxbdlgmiGdD+QsipzKfFky0K5HW5Td6dyK3L3ypu1eY4kOmo7wW0o94SBqlqBSA==", "dev": true, "optional": true }, "@esbuild/linux-mips64el": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz", - "integrity": "sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.8.tgz", + "integrity": "sha512-CCb67RKahNobjm/eeEqeD/oJfJlrWyw29fgiyB6vcgyq97YAf3gCOuP6qMShYSPXgnlZe/i4a8WFHBw6N8bYAA==", "dev": true, "optional": true }, "@esbuild/linux-ppc64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz", - "integrity": "sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.8.tgz", + "integrity": "sha512-bytLJOi55y55+mGSdgwZ5qBm0K9WOCh0rx+vavVPx+gqLLhxtSFU0XbeYy/dsAAD6xECGEv4IQeFILaSS2auXw==", "dev": true, "optional": true }, "@esbuild/linux-riscv64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz", - "integrity": "sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.8.tgz", + "integrity": "sha512-2YpRyQJmKVBEHSBLa8kBAtbhucaclb6ex4wchfY0Tj3Kg39kpjeJ9vhRU7x4mUpq8ISLXRXH1L0dBYjAeqzZAw==", "dev": true, "optional": true }, "@esbuild/linux-s390x": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz", - "integrity": "sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.8.tgz", + "integrity": "sha512-QgbNY/V3IFXvNf11SS6exkpVcX0LJcob+0RWCgV9OiDAmVElnxciHIisoSix9uzYzScPmS6dJFbZULdSAEkQVw==", "dev": true, "optional": true }, "@esbuild/linux-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz", - "integrity": "sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.8.tgz", + "integrity": "sha512-mM/9S0SbAFDBc4OPoyP6SEOo5324LpUxdpeIUUSrSTOfhHU9hEfqRngmKgqILqwx/0DVJBzeNW7HmLEWp9vcOA==", "dev": true, "optional": true }, "@esbuild/netbsd-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz", - "integrity": "sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.8.tgz", + "integrity": "sha512-eKUYcWaWTaYr9zbj8GertdVtlt1DTS1gNBWov+iQfWuWyuu59YN6gSEJvFzC5ESJ4kMcKR0uqWThKUn5o8We6Q==", "dev": true, "optional": true }, "@esbuild/openbsd-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz", - "integrity": "sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.8.tgz", + "integrity": "sha512-Vc9J4dXOboDyMXKD0eCeW0SIeEzr8K9oTHJU+Ci1mZc5njPfhKAqkRt3B/fUNU7dP+mRyralPu8QUkiaQn7iIg==", "dev": true, "optional": true }, "@esbuild/sunos-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz", - "integrity": "sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.8.tgz", + "integrity": "sha512-0xvOTNuPXI7ft1LYUgiaXtpCEjp90RuBBYovdd2lqAFxje4sEucurg30M1WIm03+3jxByd3mfo+VUmPtRSVuOw==", "dev": true, "optional": true }, "@esbuild/win32-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz", - "integrity": "sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.8.tgz", + "integrity": "sha512-G0JQwUI5WdEFEnYNKzklxtBheCPkuDdu1YrtRrjuQv30WsYbkkoixKxLLv8qhJmNI+ATEWquZe/N0d0rpr55Mg==", "dev": true, "optional": true }, "@esbuild/win32-ia32": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz", - "integrity": "sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.8.tgz", + "integrity": "sha512-Fqy63515xl20OHGFykjJsMnoIWS+38fqfg88ClvPXyDbLtgXal2DTlhb1TfTX34qWi3u4I7Cq563QcHpqgLx8w==", "dev": true, "optional": true }, "@esbuild/win32-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz", - "integrity": "sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.8.tgz", + "integrity": "sha512-1iuezdyDNngPnz8rLRDO2C/ZZ/emJLb72OsZeqQ6gL6Avko/XCXZw+NuxBSNhBAP13Hie418V7VMt9et1FMvpg==", "dev": true, "optional": true }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", + "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", + "dev": true + }, "@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", + "espree": "^9.5.1", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -19706,10 +19880,16 @@ } } }, + "@eslint/js": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", + "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", + "dev": true + }, "@fortawesome/fontawesome-free": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.3.0.tgz", - "integrity": "sha512-qVtd5i1Cc7cdrqnTWqTObKQHjPWAiRwjUPaXObaeNPcy7+WKxJumGBx66rfSFgK6LNpIasVKkEgW8oyf0tmPLA==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.4.0.tgz", + "integrity": "sha512-0NyytTlPJwB/BF5LtRV8rrABDbe3TdTXqNB3PdZ+UUUZAEIrdOJdmABqKjt4AXwIoJNaRVVZEXxpNrqvE1GAYQ==", "dev": true }, "@gar/promisify": { @@ -20587,56 +20767,56 @@ } }, "@ngrx/effects": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-15.2.1.tgz", - "integrity": "sha512-dHMXZ3jIgAJ6l5W+IxYTkWKeq0BE5RG87LVrfH6mVi1X41j7dXqXeALvjvyZ5CUSTUMHq8WiiJg5w9LeLJci0g==", + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-15.4.0.tgz", + "integrity": "sha512-/8gHhOM9aeGaw8OG2LLwi4I4p84xzG0EU9TqWrvQcW74wn8sFZONjLvUte5YOzJ5502PPFFrfXSOc+lHnVAJUA==", "requires": { "tslib": "^2.0.0" } }, "@ngrx/entity": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/@ngrx/entity/-/entity-15.2.1.tgz", - "integrity": "sha512-MtaqBK5Z8vtRULtVXOkukpnYiVYsK/aDbCMocg4GTE0sOuw2Jo6VbjUWYJmWpv4pKitO9LfiIVzE8XnC3Byp3w==", + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@ngrx/entity/-/entity-15.4.0.tgz", + "integrity": "sha512-DmfbbasV5bth9APAiwH9ovDwJ/rtEUm4pJvTd6Eds/kOJ6Ime9MZwEhtglXlk2jMwe7f08pl1jzFhYIjI277aQ==", "requires": { "tslib": "^2.0.0" } }, "@ngrx/router-store": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/@ngrx/router-store/-/router-store-15.2.1.tgz", - "integrity": "sha512-muGlunaZqu05gShZ4wO+BUc5vknBLsf0n+qOZGqMkjRNrbuwja2DNQKjZd83EUewlIRJRBuV4M1ljeiwINBR3g==", + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@ngrx/router-store/-/router-store-15.4.0.tgz", + "integrity": "sha512-uc8gx+SMr2gyly+WSBmGnpHTPsMVhenUG6skH3Qk67hrwdVG3SABjw3qdP4GibbfwwajMQ67sLaLY8PQZ5Sb2g==", "requires": { "tslib": "^2.0.0" } }, "@ngrx/schematics": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/@ngrx/schematics/-/schematics-15.2.1.tgz", - "integrity": "sha512-pNkicfq+1NdUOKf13hqXMYNoEJIDkx2M8eLS3Sor/iOE/vDDHQu59lYp+wFdF+Zf8v2BHpiRcaKkD8cmC/6qEw==", + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@ngrx/schematics/-/schematics-15.4.0.tgz", + "integrity": "sha512-vOio2+0BNuzgde8OtIR5Gbzn/+59V0V2TyDyrxxpOi8v7FuaKCPh+o525ekjU/PfVi3ZiMVRjbmrTAR4wzBmug==", "dev": true }, "@ngrx/store": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-15.2.1.tgz", - "integrity": "sha512-s4V2ylfQ/IvjVJrJaqRMNF/LkeUjHG+bkis6xl06CjpwCQ4I2FpLog9le+dfayQLSAu+OXmUOl4/OAY3ewvEtw==", + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-15.4.0.tgz", + "integrity": "sha512-OvCuNBHL8mAUnRTS6QSFm+IunspsYNu2cCwDovBNn7EGhxRuGihBeNoX47jCqWPHBFtokj4BlatDfpJ/yCh4xQ==", "requires": { "tslib": "^2.0.0" } }, "@ngrx/store-devtools": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/@ngrx/store-devtools/-/store-devtools-15.2.1.tgz", - "integrity": "sha512-mzsW2LEXY2/Qcz/VQbvst2dsR/qU5bFlnx2XgolmlCJRo00buy99Goo0umJi81V5Ii917w/TO8F2UqLMqk0s+w==", + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@ngrx/store-devtools/-/store-devtools-15.4.0.tgz", + "integrity": "sha512-AqWRprSyS3u/vZlpsBOPMW1/0TZS2LE13/KpZedEY+RMCW+mi53esqgrdNGOB3Wr4vrI82Ar9fgaIm4TQO6LPg==", "dev": true, "requires": { "tslib": "^2.0.0" } }, "@ngtools/webpack": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-15.1.4.tgz", - "integrity": "sha512-IvKXK8AvPlLkP99Uf0RL1EHlcsXNQd86II9HsLjupUtmFC/pPuDWrRFMP9bjWUMh2ZeYpgUeEAbcCH3doSrdIA==", + "version": "15.2.6", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-15.2.6.tgz", + "integrity": "sha512-I+kekKItfsCLdX+ZjjmsWqd0AyoYGTQPjlbQAiPtmdH73/rfPOF4Q/3AU4tzTdn0n0GXqZWv6VOs91w99ydi0A==", "dev": true }, "@nodelib/fs.scandir": { @@ -20675,14 +20855,13 @@ } }, "@npmcli/git": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.0.3.tgz", - "integrity": "sha512-8cXNkDIbnXPVbhXMmQ7/bklCAjtmPaXfI9aEM4iH+xSuEHINLMHhlfESvVwdqmHJRJkR48vNJTSUvoF6GRPSFA==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.0.4.tgz", + "integrity": "sha512-5yZghx+u5M47LghaybLCkdSyFzV/w4OuH12d96HO389Ik9CDsLaDZJVynSGGVJOLn6gy/k7Dz5XYcplM3uxXRg==", "dev": true, "requires": { "@npmcli/promise-spawn": "^6.0.0", "lru-cache": "^7.4.4", - "mkdirp": "^1.0.4", "npm-pick-manifest": "^8.0.0", "proc-log": "^3.0.0", "promise-inflight": "^1.0.1", @@ -20692,9 +20871,9 @@ }, "dependencies": { "lru-cache": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", - "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true }, "which": { @@ -20709,9 +20888,9 @@ } }, "@npmcli/installed-package-contents": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.1.tgz", - "integrity": "sha512-GIykAFdOVK31Q1/zAtT5MbxqQL2vyl9mvFJv+OGu01zxbhL3p0xc8gJjdNGX1mWmUT43aEKVO2L6V/2j4TOsAA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", + "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", "dev": true, "requires": { "npm-bundled": "^3.0.0", @@ -20779,30 +20958,57 @@ } }, "@schematics/angular": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-15.1.4.tgz", - "integrity": "sha512-4SV8dDGZeSvts01b8y2W6FmpDD0dQhBlGMhMJKC/tUnhfNKfYCs2VKtMBsIc3ZiGP2yoA3+nUiMmtS6hEkXYHw==", + "version": "15.2.6", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-15.2.6.tgz", + "integrity": "sha512-OcBUvVAxZEMBX+fi0ytybeAdmStra+GwtlvipS70yOxcAgJ84ZrnZGN7a072cCVQcq7AgqUfssnyqCx1wu+yCg==", "dev": true, "requires": { - "@angular-devkit/core": "15.1.4", - "@angular-devkit/schematics": "15.1.4", + "@angular-devkit/core": "15.2.6", + "@angular-devkit/schematics": "15.2.6", "jsonc-parser": "3.2.0" - }, - "dependencies": { - "jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - } } }, + "@sigstore/protobuf-specs": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.1.0.tgz", + "integrity": "sha512-a31EnjuIDSX8IXBUib3cYLDRlPMU36AWX4xS8ysLaNu4ZzUesDiPt83pgrW2X1YLMe5L2HbDyaKK5BrL4cNKaQ==", + "dev": true + }, "@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", "dev": true }, + "@tufjs/models": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.1.tgz", + "integrity": "sha512-AY0VoG/AXdlSOocuREfPoEW4SNhOPp/7fw6mpAxfVIny1uZ+0fEtMoCi7NhELSlqQIRLMu7RgfKhkxT+AJ+EXg==", + "dev": true, + "requires": { + "minimatch": "^7.4.2" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz", + "integrity": "sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, "@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -20842,9 +21048,9 @@ } }, "@types/d3-selection": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.4.tgz", - "integrity": "sha512-ZeykX7286BCyMg9sH5fIAORyCB6hcATPSRQpN47jwBA2bMbAT0s+EvtDP5r1FZYJ95R8QoEE1CKJX+n0/M5Vhg==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.5.tgz", + "integrity": "sha512-xCB0z3Hi8eFIqyja3vW8iV01+OHGYR2di/+e+AiOcXIOrY82lcvWW8Ke1DYE/EUVMsBl4Db9RppSBS3X1U6J0w==", "dev": true }, "@types/eslint": { @@ -20897,9 +21103,9 @@ } }, "@types/http-proxy": { - "version": "1.17.9", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", - "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", + "version": "1.17.10", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.10.tgz", + "integrity": "sha512-Qs5aULi+zV1bwKAg5z1PWnDXWmsn+LxIvUGv6E2+OOMYhclZMO+OXd9pYVf2gLykf2I7IV2u7oTHwChPNsvJ7g==", "dev": true, "requires": { "@types/node": "*" @@ -20924,9 +21130,9 @@ "dev": true }, "@types/lodash-es": { - "version": "4.17.6", - "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.6.tgz", - "integrity": "sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==", + "version": "4.17.7", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.7.tgz", + "integrity": "sha512-z0ptr6UI10VlU6l5MYhGwS4mC8DZyYer2mCoyysZtSF7p26zOX8UpbrV0YpNYLGS8K4PUFIyEr62IMFFjveSiQ==", "dev": true, "requires": { "@types/lodash": "*" @@ -20939,9 +21145,9 @@ "dev": true }, "@types/node": { - "version": "18.13.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", - "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==", + "version": "18.16.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.0.tgz", + "integrity": "sha512-BsAaKhB+7X+H4GnSjGhJG9Qi8Tw+inU9nJDwmD5CgOmBLEI6ArdhikpLX7DjbjDRDTbqZzU2LSQNZg8WGPiSZQ==", "dev": true }, "@types/parse-json": { @@ -20951,9 +21157,9 @@ "dev": true }, "@types/plotly.js": { - "version": "2.12.13", - "resolved": "https://registry.npmjs.org/@types/plotly.js/-/plotly.js-2.12.13.tgz", - "integrity": "sha512-p/xo8LuJMxSvT/szkjgUJVlopRu049NZ+p46MpcSlovmO6tIgyzldm8kLUo9p24XE/5iZzGSTtvIUQjLwIUQxw==", + "version": "2.12.18", + "resolved": "https://registry.npmjs.org/@types/plotly.js/-/plotly.js-2.12.18.tgz", + "integrity": "sha512-ff+CIEWnqZNjZqHtQZvkEAVuLs9fkm1f54QnPVmgoET7wMHdSqUka2hasVN4e5yfHD05YwGjsAtCseewJh/BMw==", "dev": true }, "@types/qs": { @@ -20990,9 +21196,9 @@ } }, "@types/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", + "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", "dev": true, "requires": { "@types/mime": "*", @@ -21009,9 +21215,9 @@ } }, "@types/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==", "dev": true }, "@types/ws": { @@ -21029,71 +21235,71 @@ "integrity": "sha512-Nqo3HMPFPcNyZ7HNFZJjpH+N4yXqpxBItG+41e7nL9zednovMRZMXWj36CctSznbBcbj6ucvkJDo5iZ8SKqLIw==" }, "@typescript-eslint/eslint-plugin": { - "version": "5.51.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.51.0.tgz", - "integrity": "sha512-wcAwhEWm1RgNd7dxD/o+nnLW8oH+6RK1OGnmbmkj/GGoDPV1WWMVP0FXYQBivKHdwM1pwii3bt//RC62EriIUQ==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.1.tgz", + "integrity": "sha512-AVi0uazY5quFB9hlp2Xv+ogpfpk77xzsgsIEWyVS7uK/c7MZ5tw7ZPbapa0SbfkqE0fsAMkz5UwtgMLVk2BQAg==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.51.0", - "@typescript-eslint/type-utils": "5.51.0", - "@typescript-eslint/utils": "5.51.0", + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.59.1", + "@typescript-eslint/type-utils": "5.59.1", + "@typescript-eslint/utils": "5.59.1", "debug": "^4.3.4", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", "semver": "^7.3.7", "tsutils": "^3.21.0" } }, "@typescript-eslint/parser": { - "version": "5.51.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.51.0.tgz", - "integrity": "sha512-fEV0R9gGmfpDeRzJXn+fGQKcl0inIeYobmmUWijZh9zA7bxJ8clPhV9up2ZQzATxAiFAECqPQyMDB4o4B81AaA==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.1.tgz", + "integrity": "sha512-nzjFAN8WEu6yPRDizIFyzAfgK7nybPodMNFGNH0M9tei2gYnYszRDqVA0xlnRjkl7Hkx2vYrEdb6fP2a21cG1g==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.51.0", - "@typescript-eslint/types": "5.51.0", - "@typescript-eslint/typescript-estree": "5.51.0", + "@typescript-eslint/scope-manager": "5.59.1", + "@typescript-eslint/types": "5.59.1", + "@typescript-eslint/typescript-estree": "5.59.1", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.51.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.51.0.tgz", - "integrity": "sha512-gNpxRdlx5qw3yaHA0SFuTjW4rxeYhpHxt491PEcKF8Z6zpq0kMhe0Tolxt0qjlojS+/wArSDlj/LtE69xUJphQ==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.1.tgz", + "integrity": "sha512-mau0waO5frJctPuAzcxiNWqJR5Z8V0190FTSqRw1Q4Euop6+zTwHAf8YIXNwDOT29tyUDrQ65jSg9aTU/H0omA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.51.0", - "@typescript-eslint/visitor-keys": "5.51.0" + "@typescript-eslint/types": "5.59.1", + "@typescript-eslint/visitor-keys": "5.59.1" } }, "@typescript-eslint/type-utils": { - "version": "5.51.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.51.0.tgz", - "integrity": "sha512-QHC5KKyfV8sNSyHqfNa0UbTbJ6caB8uhcx2hYcWVvJAZYJRBo5HyyZfzMdRx8nvS+GyMg56fugMzzWnojREuQQ==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.1.tgz", + "integrity": "sha512-ZMWQ+Oh82jWqWzvM3xU+9y5U7MEMVv6GLioM3R5NJk6uvP47kZ7YvlgSHJ7ERD6bOY7Q4uxWm25c76HKEwIjZw==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.51.0", - "@typescript-eslint/utils": "5.51.0", + "@typescript-eslint/typescript-estree": "5.59.1", + "@typescript-eslint/utils": "5.59.1", "debug": "^4.3.4", "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.51.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.51.0.tgz", - "integrity": "sha512-SqOn0ANn/v6hFn0kjvLwiDi4AzR++CBZz0NV5AnusT2/3y32jdc0G4woXPWHCumWtUXZKPAS27/9vziSsC9jnw==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.1.tgz", + "integrity": "sha512-dg0ICB+RZwHlysIy/Dh1SP+gnXNzwd/KS0JprD3Lmgmdq+dJAJnUPe1gNG34p0U19HvRlGX733d/KqscrGC1Pg==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.51.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.51.0.tgz", - "integrity": "sha512-TSkNupHvNRkoH9FMA3w7TazVFcBPveAAmb7Sz+kArY6sLT86PA5Vx80cKlYmd8m3Ha2SwofM1KwraF24lM9FvA==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.1.tgz", + "integrity": "sha512-lYLBBOCsFltFy7XVqzX0Ju+Lh3WPIAWxYpmH/Q7ZoqzbscLiCW00LeYCdsUnnfnj29/s1WovXKh2gwCoinHNGA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.51.0", - "@typescript-eslint/visitor-keys": "5.51.0", + "@typescript-eslint/types": "5.59.1", + "@typescript-eslint/visitor-keys": "5.59.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -21102,28 +21308,28 @@ } }, "@typescript-eslint/utils": { - "version": "5.51.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.51.0.tgz", - "integrity": "sha512-76qs+5KWcaatmwtwsDJvBk4H76RJQBFe+Gext0EfJdC3Vd2kpY2Pf//OHHzHp84Ciw0/rYoGTDnIAr3uWhhJYw==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.1.tgz", + "integrity": "sha512-MkTe7FE+K1/GxZkP5gRj3rCztg45bEhsd8HYjczBuYm+qFHP5vtZmjx3B0yUCDotceQ4sHgTyz60Ycl225njmA==", "dev": true, "requires": { + "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.51.0", - "@typescript-eslint/types": "5.51.0", - "@typescript-eslint/typescript-estree": "5.51.0", + "@typescript-eslint/scope-manager": "5.59.1", + "@typescript-eslint/types": "5.59.1", + "@typescript-eslint/typescript-estree": "5.59.1", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", "semver": "^7.3.7" } }, "@typescript-eslint/visitor-keys": { - "version": "5.51.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.51.0.tgz", - "integrity": "sha512-Oh2+eTdjHjOFjKA27sxESlA87YPSOJafGCR0md5oeMdh1ZcCfAGCIOL216uTBAkAIptvLIfKQhl7lHxMJet4GQ==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.1.tgz", + "integrity": "sha512-6waEYwBTCWryx0VJmP7JaM4FpipLsFl9CvYf2foAE8Qh/Y0s+bxWysciwOs0LTBED4JCaNxTZ5rGadB14M6dwA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/types": "5.59.1", "eslint-visitor-keys": "^3.3.0" } }, @@ -21314,9 +21520,9 @@ } }, "ace-builds": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.15.0.tgz", - "integrity": "sha512-L1RXgqxDvzbJ7H8Y2v9lb4kHaZRn5JNTECG+oZTH2EDewMmpQMLDC4GnFKIh3+xb/gk2nVPO7gGwpTYPw91QzA==" + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.18.0.tgz", + "integrity": "sha512-ETLeQ3X1XvcWckOZFR+KvTectZyEwDm2p+CckWazS+xsK3THHVxn/PkfkPr37OTNKVY/yJRx29JGERV77YQYXw==" }, "acorn": { "version": "8.8.1", @@ -21369,13 +21575,13 @@ } }, "agentkeepalive": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", - "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", + "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", "dev": true, "requires": { "debug": "^4.1.0", - "depd": "^1.1.2", + "depd": "^2.0.0", "humanize-ms": "^1.2.1" } }, @@ -21390,9 +21596,9 @@ } }, "ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -21436,9 +21642,9 @@ } }, "angular-split": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/angular-split/-/angular-split-14.1.0.tgz", - "integrity": "sha512-WJ7LUROpvuEy9r7/EHBO2TwrJXrHeB8PUeAWmM5gU1lCmfttAXcCGSCMMIuiCs/QNSsq8mR8rTMCvNs4Xeihfg==", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/angular-split/-/angular-split-15.0.0.tgz", + "integrity": "sha512-An/f0NobbxHxA9bowwYIuKHPoP2yoQldrPklpMvmQdqntExys+B92m7kkfs4K0ANuowyFIZHMeEzounC4j7ocQ==", "requires": { "tslib": "^2.0.0" } @@ -21508,6 +21714,12 @@ "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", "dev": true }, + "are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true + }, "are-we-there-yet": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", @@ -21770,12 +21982,6 @@ "ms": "2.0.0" } }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -21785,9 +21991,9 @@ } }, "bonjour-service": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.0.tgz", - "integrity": "sha512-LVRinRB3k1/K0XzZ2p58COnWvkQknIY6sf0zF2rpErvcJXpMBttEPQSxK+HEXSS9VmpZlDoDnQWv8ftJT20B0Q==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", + "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", "dev": true, "requires": { "array-flatten": "^2.1.2", @@ -21803,9 +22009,9 @@ "dev": true }, "bootstrap": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz", - "integrity": "sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ==" + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.2.3.tgz", + "integrity": "sha512-cEKPM+fwb3cT8NzQZYEu4HilJ3anCrWqh3CHAok1p9jXqMPsPTBhU25fBckEJHJ/p+tTxTFTsFQGM+gaHpi3QQ==" }, "bowser": { "version": "2.11.0", @@ -21842,15 +22048,15 @@ } }, "browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" } }, "buffer": { @@ -21967,9 +22173,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001426", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001426.tgz", - "integrity": "sha512-n7cosrHLl8AWt0wwZw/PJZgUg3lV0gk9LMI7ikGJwhyhgsd2Nb65vKvmSexCqq/J7rbH3mFG6yZZiPR5dLPW5A==", + "version": "1.0.30001477", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001477.tgz", + "integrity": "sha512-lZim4iUHhGcy5p+Ri/G7m84hJwncj+Kz7S5aD4hoQfslKZJgt0tHc/hafVbqHC5bbhHb+mrW2JOUHkI5KH7toQ==", "dev": true }, "chalk": { @@ -22932,9 +23138,9 @@ "dev": true }, "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true }, "dependency-graph": { @@ -22976,9 +23182,9 @@ "dev": true }, "dns-packet": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", - "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.0.tgz", + "integrity": "sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ==", "dev": true, "requires": { "@leichtgewicht/ip-codec": "^2.0.1" @@ -23241,40 +23447,40 @@ } }, "esbuild": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz", - "integrity": "sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.8.tgz", + "integrity": "sha512-g24ybC3fWhZddZK6R3uD2iF/RIPnRpwJAqLov6ouX3hMbY4+tKolP0VMF3zuIYCaXun+yHwS5IPQ91N2BT191g==", "dev": true, "optional": true, "requires": { - "@esbuild/android-arm": "0.16.17", - "@esbuild/android-arm64": "0.16.17", - "@esbuild/android-x64": "0.16.17", - "@esbuild/darwin-arm64": "0.16.17", - "@esbuild/darwin-x64": "0.16.17", - "@esbuild/freebsd-arm64": "0.16.17", - "@esbuild/freebsd-x64": "0.16.17", - "@esbuild/linux-arm": "0.16.17", - "@esbuild/linux-arm64": "0.16.17", - "@esbuild/linux-ia32": "0.16.17", - "@esbuild/linux-loong64": "0.16.17", - "@esbuild/linux-mips64el": "0.16.17", - "@esbuild/linux-ppc64": "0.16.17", - "@esbuild/linux-riscv64": "0.16.17", - "@esbuild/linux-s390x": "0.16.17", - "@esbuild/linux-x64": "0.16.17", - "@esbuild/netbsd-x64": "0.16.17", - "@esbuild/openbsd-x64": "0.16.17", - "@esbuild/sunos-x64": "0.16.17", - "@esbuild/win32-arm64": "0.16.17", - "@esbuild/win32-ia32": "0.16.17", - "@esbuild/win32-x64": "0.16.17" + "@esbuild/android-arm": "0.17.8", + "@esbuild/android-arm64": "0.17.8", + "@esbuild/android-x64": "0.17.8", + "@esbuild/darwin-arm64": "0.17.8", + "@esbuild/darwin-x64": "0.17.8", + "@esbuild/freebsd-arm64": "0.17.8", + "@esbuild/freebsd-x64": "0.17.8", + "@esbuild/linux-arm": "0.17.8", + "@esbuild/linux-arm64": "0.17.8", + "@esbuild/linux-ia32": "0.17.8", + "@esbuild/linux-loong64": "0.17.8", + "@esbuild/linux-mips64el": "0.17.8", + "@esbuild/linux-ppc64": "0.17.8", + "@esbuild/linux-riscv64": "0.17.8", + "@esbuild/linux-s390x": "0.17.8", + "@esbuild/linux-x64": "0.17.8", + "@esbuild/netbsd-x64": "0.17.8", + "@esbuild/openbsd-x64": "0.17.8", + "@esbuild/sunos-x64": "0.17.8", + "@esbuild/win32-arm64": "0.17.8", + "@esbuild/win32-ia32": "0.17.8", + "@esbuild/win32-x64": "0.17.8" } }, "esbuild-wasm": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.16.17.tgz", - "integrity": "sha512-Tn7NuMqRcM+T/qCOxbQRq0qrwWl1sUWp6ARfJRakE8Bepew6zata4qrKgH2YqovNC5e/2fcTa7o+VL/FAOZC1Q==", + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.17.8.tgz", + "integrity": "sha512-zCmpxv95E0FuCmvdw1K836UHnj4EdiQnFfjTby35y3LAjRPtXMj3sbHDRHjbD8Mqg5lTwq3knacr/1qIFU51CQ==", "dev": true }, "escalade": { @@ -23296,12 +23502,15 @@ "dev": true }, "eslint": { - "version": "8.33.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.33.0.tgz", - "integrity": "sha512-WjOpFQgKK8VrCnAtl8We0SUOy/oVZ5NHykyMiagV1M9r8IFpIJX7DduK6n1mpfhlG7T1NLWm2SuD8QB7KFySaA==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", + "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.4.1", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.39.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -23311,11 +23520,10 @@ "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.0", + "espree": "^9.5.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", @@ -23336,7 +23544,6 @@ "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" @@ -23401,9 +23608,9 @@ "dev": true }, "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", "dev": true, "requires": { "esrecurse": "^4.3.0", @@ -23601,16 +23808,17 @@ } }, "eslint-plugin-jsdoc": { - "version": "39.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.8.0.tgz", - "integrity": "sha512-ZwGmk0jJoJD/NILeDRBKrpq/PCgddUdATjeU5JGTqTzKsOWfeaHOnaAwZjuOh7T8EB4hSoZ/9pR4+Qns2ldQVg==", + "version": "41.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-41.1.2.tgz", + "integrity": "sha512-MePJXdGiPW7AG06CU5GbKzYtKpoHwTq1lKijjq+RwL/cQkZtBZ59Zbv5Ep0RVxSMnq6242249/n+w4XrTZ1Afg==", "dev": true, "requires": { - "@es-joy/jsdoccomment": "~0.36.1", + "@es-joy/jsdoccomment": "~0.37.0", + "are-docs-informative": "^0.0.2", "comment-parser": "1.3.1", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", - "esquery": "^1.4.0", + "esquery": "^1.5.0", "semver": "^7.3.8", "spdx-expression-parse": "^3.0.1" }, @@ -23657,20 +23865,20 @@ } }, "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", "dev": true }, "espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", "dev": true, "requires": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.0" } }, "esprima": { @@ -23680,9 +23888,9 @@ "dev": true }, "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "requires": { "estraverse": "^5.1.0" @@ -23820,12 +24028,6 @@ "ms": "2.0.0" } }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -23888,9 +24090,9 @@ "dev": true }, "fast-xml-parser": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.0.11.tgz", - "integrity": "sha512-4aUg3aNRR/WjQAcpceODG1C3x3lFANXRo8+1biqfieHmg9pyMt7qB4lQV/Ta6sJCTbA5vfD8fnA8S54JATiFUA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.1.2.tgz", + "integrity": "sha512-CDYeykkle1LiA/uqQyNwYpFbyF6Axec6YapmpUP+/RHWIoR1zKjocdvNaTsxCxZzQ6v9MLXaSYm9Qq0thv0DHg==", "requires": { "strnum": "^1.0.5" } @@ -23938,9 +24140,9 @@ } }, "filesize": { - "version": "10.0.6", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.0.6.tgz", - "integrity": "sha512-rzpOZ4C9vMFDqOa6dNpog92CoLYjD79dnjLk2TYDDtImRIyLTOzqojCb05Opd1WuiWjs+fshhCgTd8cl7y5t+g==" + "version": "10.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.0.7.tgz", + "integrity": "sha512-iMRG7Qo9nayLoU3PNCiLizYtsy4W1ClrapeCwEgtiQelOAOuRJiw4QaLI+sSr8xr901dgHv+EYP2bCusGZgoiA==" }, "fill-range": { "version": "7.0.1", @@ -24353,9 +24555,9 @@ }, "dependencies": { "lru-cache": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", - "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true } } @@ -24373,9 +24575,9 @@ }, "dependencies": { "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -24424,14 +24626,6 @@ "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" - }, - "dependencies": { - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true - } } }, "http-parser-js": { @@ -24527,12 +24721,12 @@ "dev": true }, "ignore-walk": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.1.tgz", - "integrity": "sha512-/c8MxUAqpRccq+LyDOecwF+9KqajueJHh8fz7g3YqjMZt+NSfJzx05zrKiXwa2sKwFCzaiZ5qUVfRj0pmxixEA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.2.tgz", + "integrity": "sha512-ezmQ1Dg2b3jVZh2Dh+ar6Eu2MqNSTkyb32HU2MAQQQX9tKM3q/UQ/9lf03lQ5hW+fOeoMnwxwkleZ0xcNp0/qg==", "dev": true, "requires": { - "minimatch": "^6.1.6" + "minimatch": "^7.4.2" }, "dependencies": { "brace-expansion": { @@ -24545,9 +24739,9 @@ } }, "minimatch": { - "version": "6.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-6.1.6.tgz", - "integrity": "sha512-6bR3UIeh/DF8+p6A9Spyuy67ShOq42rOkHWi7eUe3Ua99Zo5lZfGC6lJJWkeoK4k9jQFT3Pl7czhTXimG2XheA==", + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz", + "integrity": "sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -25098,9 +25292,9 @@ } }, "jsdoc-type-pratt-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz", - "integrity": "sha512-MgtD0ZiCDk9B+eI73BextfRrVQl0oyzRG8B2BjORts6jbunj4ScKPcyXGTbB6eXL4y9TzxCm6hyeLq/2ASzNdw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", "dev": true }, "jsesc": { @@ -25133,6 +25327,12 @@ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, + "jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, "jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", @@ -25399,6 +25599,15 @@ "resolved": "https://registry.npmjs.org/lucene/-/lucene-2.1.1.tgz", "integrity": "sha512-l0qCX+pgXEZh/7sYQNG+vzhOIFRPjlJJkQ/irk9n7Ak3d+1MrU6F7IV31KILwFkUn153oLK8a2AIt48DzLdVPg==" }, + "magic-string": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.29.0.tgz", + "integrity": "sha512-WcfidHrDjMY+eLjlU+8OvwREqHwpgCeKVBUpQ3OhYYuvfaYCUgcbuBzappNzZvg/v8onU3oQj+BYpkOJe9Iw4Q==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.4.13" + } + }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -25508,9 +25717,9 @@ } }, "lru-cache": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", - "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true }, "minimatch": { @@ -25667,9 +25876,9 @@ "dev": true }, "minipass": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.3.tgz", - "integrity": "sha512-OW2r4sQ0sI+z5ckEt5c1Tri4xTgZwYDxpE54eqWlQloQRoWtXjqt9udJ5Z4dSv7wK+nfFI7FRXyCpBSft+gpFw==", + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.7.tgz", + "integrity": "sha512-ScVIgqHcXRMyfflqHmEW0bm8z8rb5McHyOY3ewX9JBgZaR77G7nxq9L/mtV96/QbAAwtbCAHVVLzD1kkyfFQEw==", "dev": true }, "minipass-collect": { @@ -25910,18 +26119,18 @@ "dev": true }, "ngx-clipboard": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/ngx-clipboard/-/ngx-clipboard-15.1.0.tgz", - "integrity": "sha512-dUJl1cNtdkCqL953oAhP7wmUPFrqW2aDg5OPhwPU9R3cLEdQgU2NbsHEUz4zaPyEopTXu8SR37onVm1Ep8qOHg==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/ngx-clipboard/-/ngx-clipboard-16.0.0.tgz", + "integrity": "sha512-rZ/Eo1PqiKMiyF8tdjhmUkoUu68f7OzBJ7YH1YFeh2RAaNrerTaW8XfFOzppSckjFQqA1fwGSYuTTJlDhDag5w==", "requires": { - "ngx-window-token": ">=6.0.0", + "ngx-window-token": ">=7.0.0", "tslib": "^2.0.0" } }, "ngx-color-picker": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/ngx-color-picker/-/ngx-color-picker-13.0.0.tgz", - "integrity": "sha512-3mgMbs21KeqnmmY5p1cn71ckTH3q7gBt6Qn0fMfeF/Ql7ddTZsW4Z7Z8ga6LymMP/ugooGuLOFX+V6yx0dDxAw==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/ngx-color-picker/-/ngx-color-picker-14.0.0.tgz", + "integrity": "sha512-w28zx2DyVpIJeNsTB3T2LUI4Ed/Ujf5Uhxuh0dllputfpxXwZG9ocSJM/0L67+fxA3UnfvvXVZNUX1Ny5nZIIw==", "requires": { "tslib": "^2.3.0" } @@ -25935,9 +26144,9 @@ } }, "ngx-markdown-editor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ngx-markdown-editor/-/ngx-markdown-editor-5.1.0.tgz", - "integrity": "sha512-KE7j8apkcjncMOWIZJpkV41hOi99ki6KHOTUtLai/WrD4P6bebz9Ig/ZtdX8zhSPR8xep9tmm7hEF/9eXvePaw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ngx-markdown-editor/-/ngx-markdown-editor-5.3.0.tgz", + "integrity": "sha512-IeGqtvq+jDMjGGnFFdHhEPphx+jM27EdvcJ3IboCQlXzolpe10JUdCCe53T6TgFe2MFvegVlaVuo44Dcve5IZw==", "requires": { "tslib": "^2.3.0" } @@ -25951,9 +26160,9 @@ } }, "ngx-window-token": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ngx-window-token/-/ngx-window-token-6.0.0.tgz", - "integrity": "sha512-IeLKO1jzfzSvZ6vlAt4QSY/B5XcHEhdOwTjqvWEPt6/esWV9T3mA2ln10kj6SCc9pUSx4NybxE10gcyyYroImg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ngx-window-token/-/ngx-window-token-7.0.0.tgz", + "integrity": "sha512-5+XfRVSY7Dciu8xyCNMkOlH2UfwR9W2P1Pirz7caaZgOZDjFbL8aEO2stjfJJm2FFf1D6dlVHNzhLWGk9HGkqA==", "requires": { "tslib": "^2.0.0" } @@ -26008,9 +26217,9 @@ "optional": true }, "node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", "dev": true }, "nopt": { @@ -26056,9 +26265,9 @@ } }, "npm-install-checks": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.0.0.tgz", - "integrity": "sha512-SBU9oFglRVZnfElwAtF14NivyulDqF1VKqqwNsFW9HDcbHMAPHpRSsVFgKuwFGq/hVvWZExz62Th0kvxn/XE7Q==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.1.0.tgz", + "integrity": "sha512-udSGENih/5xKh3Ex+L0PtZcOt0Pa+6ppDLnpG5D49/EhMja3LupaY9E/DtJTxyFBwE09ot7Fc+H4DywnZNWTVA==", "dev": true, "requires": { "semver": "^7.1.1" @@ -26119,9 +26328,9 @@ }, "dependencies": { "lru-cache": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", - "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true }, "make-fetch-happen": { @@ -26281,9 +26490,9 @@ } }, "open": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.1.tgz", + "integrity": "sha512-/4b7qZNhv6Uhd7jjnREh1NjnPxlTq+XNWPG88Ydkj5AILcA5m3ajvcg57pB24EQjKv0dK62XnDqk9c/hkIG5Kg==", "dev": true, "requires": { "define-lazy-prop": "^2.0.0", @@ -26431,9 +26640,9 @@ "dev": true }, "pacote": { - "version": "15.0.8", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.0.8.tgz", - "integrity": "sha512-UlcumB/XS6xyyIMwg/WwMAyUmga+RivB5KgkRwA1hZNtrx+0Bt41KxHCvg1kr0pZ/ZeD8qjhW4fph6VaYRCbLw==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.1.0.tgz", + "integrity": "sha512-FFcjtIl+BQNfeliSm7MZz5cpdohvUV1yjGnqgVM4UnVF7JslRY0ImXAygdaCDV0jjUADEWu4y5xsDV8brtrTLg==", "dev": true, "requires": { "@npmcli/git": "^4.0.0", @@ -26451,6 +26660,7 @@ "promise-retry": "^2.0.1", "read-package-json": "^6.0.0", "read-package-json-fast": "^3.0.0", + "sigstore": "^1.0.0", "ssri": "^10.0.0", "tar": "^6.1.11" } @@ -26492,7 +26702,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "optional": true, + "devOptional": true, "requires": { "entities": "^4.4.0" }, @@ -26501,24 +26711,25 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", - "optional": true + "devOptional": true } } }, "parse5-html-rewriting-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-6.0.1.tgz", - "integrity": "sha512-vwLQzynJVEfUlURxgnf51yAJDQTtVpNyGD8tKi2Za7m+akukNHxCcUQMAa/mUGLhCeicFdpy7Tlvj8ZNKadprg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", + "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", "dev": true, "requires": { - "parse5": "^6.0.1", - "parse5-sax-parser": "^6.0.1" + "entities": "^4.3.0", + "parse5": "^7.0.0", + "parse5-sax-parser": "^7.0.0" }, "dependencies": { - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "entities": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", + "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", "dev": true } } @@ -26541,20 +26752,12 @@ } }, "parse5-sax-parser": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-6.0.1.tgz", - "integrity": "sha512-kXX+5S81lgESA0LsDuGjAlBybImAChYRMT+/uKCEXFBFOeEhS52qUCydGhU3qLRD8D9DVjaUo821WK7DM4iCeg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", + "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", "dev": true, "requires": { - "parse5": "^6.0.1" - }, - "dependencies": { - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - } + "parse5": "^7.0.0" } }, "parseurl": { @@ -26587,6 +26790,30 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "path-scurry": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.6.4.tgz", + "integrity": "sha512-Qp/9IHkdNiXJ3/Kon++At2nVpnhRiPq/aSvQN+H3U1WZbvNRK0RIQK/o4HMqPoXjpuGJUEWpHSs6Mnjxqh3TQg==", + "dev": true, + "requires": { + "lru-cache": "^9.0.0", + "minipass": "^5.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.0.0.tgz", + "integrity": "sha512-9AEKXzvOZc4BMacFnYiTOlDH/197LNnQIK9wZ6iMB5NXPzuv4bWR/Msv7iUMplkiMQ1qQL+KSv/JF1mZAB5Lrg==", + "dev": true + }, + "minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true + } + } + }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -26730,9 +26957,9 @@ "integrity": "sha512-KDeO94CbWI4pKsPnYpA1FPjo79EsY9I+M8ywoPBSf9XMXoe/0crjbUK7jcQEDHuc0ZMRIZsxH3TYLv4TUtHmAA==" }, "primeng": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/primeng/-/primeng-15.2.0.tgz", - "integrity": "sha512-CLcB4RYiI4PcQ8nwov01L5CQHbhl7n1OufA2OKIq9+C4sBEv9sLsnEN2/Cah4m1jtrRkNbsac8JJE7LdPxecaQ==", + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/primeng/-/primeng-15.4.1.tgz", + "integrity": "sha512-j2unOQZk6756l6SgkzcmlHF6JlawF0bIjKTgAPWwT+S5RYeWEjpCPg/ABV8TylwW7CTNQX2oCHbyqCAuhtr++w==", "requires": { "tslib": "^2.3.0" } @@ -26857,12 +27084,12 @@ } }, "read-package-json": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.0.tgz", - "integrity": "sha512-b/9jxWJ8EwogJPpv99ma+QwtqB7FSl3+V6UXS7Aaay8/5VwMY50oIFooY1UKXMWpfNCM6T/PoGqa5GD1g9xf9w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.1.tgz", + "integrity": "sha512-AaHqXxfAVa+fNL07x8iAghfKOds/XXsu7zoouIVsbm7PEbQ3nMWXlvjcbrNLjElnUHWQtAo4QEa0RXuvD4XlpA==", "dev": true, "requires": { - "glob": "^8.0.1", + "glob": "^9.3.0", "json-parse-even-better-errors": "^3.0.0", "normalize-package-data": "^5.0.0", "npm-normalize-package-bin": "^3.0.0" @@ -26878,16 +27105,15 @@ } }, "glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", "dev": true, "requires": { "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" } }, "json-parse-even-better-errors": { @@ -26897,9 +27123,9 @@ "dev": true }, "minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -26998,12 +27224,6 @@ "functions-have-names": "^1.2.2" } }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, "regexpu-core": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz", @@ -27200,9 +27420,9 @@ "integrity": "sha512-LRneZZRXNgjzwG4bDQdOTSbze3fHm1EAKN/8bePxnlEZiBmkYEDggaHbuvHI9/hoqHbGfsEA7tWS9GhYHZBBsw==" }, "sass": { - "version": "1.57.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.57.1.tgz", - "integrity": "sha512-O2+LwLS79op7GI0xZ8fqzF7X2m/m8WFfI02dHOdsK5R2ECeS5F62zrwg/relM1rjSLy7Vd/DiMNIvPrQGsA0jw==", + "version": "1.58.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.58.1.tgz", + "integrity": "sha512-bnINi6nPXbP1XNRaranMFEBZWUfdW/AF16Ql5+ypRxfTvCRTTKrLsMIakyDcayUt2t/RZotmL4kgJwNH5xO+bg==", "dev": true, "requires": { "chokidar": ">=3.0.0 <4.0.0", @@ -27318,12 +27538,6 @@ } } }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true - }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -27365,6 +27579,12 @@ "ms": "2.0.0" } }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true + }, "http-errors": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", @@ -27468,6 +27688,60 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "sigstore": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.2.0.tgz", + "integrity": "sha512-Fr9+W1nkBSIZCkJQR7jDn/zI0UXNsVpp+7mDQkCnZOIxG9p6yNXBx9xntHsfUyYHE55XDkkVV3+rYbrkzAeesA==", + "dev": true, + "requires": { + "@sigstore/protobuf-specs": "^0.1.0", + "make-fetch-happen": "^11.0.1", + "tuf-js": "^1.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true + }, + "make-fetch-happen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", + "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", + "dev": true, + "requires": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + } + }, + "minipass-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", + "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^4.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + } + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -27573,9 +27847,9 @@ } }, "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -27819,9 +28093,9 @@ } }, "terser": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", - "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", + "version": "5.16.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.3.tgz", + "integrity": "sha512-v8wWLaS/xt3nE9dgKEWhNUFP6q4kngO5B8eYFUuebsu7Dw/UNAnpUod6UHo04jSSkv8TzKHjZDSd7EXdDQAl8Q==", "dev": true, "requires": { "@jridgewell/source-map": "^0.3.2", @@ -28001,6 +28275,59 @@ } } }, + "tuf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.2.tgz", + "integrity": "sha512-gBfbnS6khluxjvoFCpRV0fhWT265xNfpiNXOcBX0Ze6HGbPhe93UG5V5DdKcgm/aXsMadnY76l/h6j63GmJS5g==", + "dev": true, + "requires": { + "@tufjs/models": "1.0.1", + "make-fetch-happen": "^11.0.1" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true + }, + "make-fetch-happen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", + "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", + "dev": true, + "requires": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + } + }, + "minipass-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", + "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^4.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + } + } + }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -28219,9 +28546,9 @@ } }, "webpack": { - "version": "5.75.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", - "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "version": "5.76.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", + "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", @@ -28507,9 +28834,9 @@ "dev": true }, "ws": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz", - "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "dev": true }, "xhr2": { diff --git a/package.json b/package.json index 091968cf..4cbd7190 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "clearml-webapp", - "version": "1.10.0", + "version": "1.11.0", "license": "", "scripts": { "ng": "ng", @@ -19,54 +19,54 @@ }, "private": true, "dependencies": { - "@angular/animations": "^15.1.3", - "@angular/cdk": "^15.1.3", - "@angular/common": "^15.1.3", - "@angular/compiler": "^15.1.3", - "@angular/core": "^15.1.3", - "@angular/forms": "^15.1.3", - "@angular/material": "^15.1.3", - "@angular/platform-browser": "^15.1.3", - "@angular/platform-browser-dynamic": "^15.1.3", - "@angular/platform-server": "^15.1.3", - "@angular/router": "^15.1.3", - "@angular/service-worker": "^15.1.3", - "@angular/youtube-player": "^15.1.3", - "@aws-sdk/client-s3": "^3.266.1", - "@aws-sdk/s3-request-presigner": "^3.266.1", + "@angular/animations": "^15.2.8", + "@angular/cdk": "^15.2.8", + "@angular/common": "^15.2.8", + "@angular/compiler": "^15.2.8", + "@angular/core": "^15.2.8", + "@angular/forms": "^15.2.8", + "@angular/material": "^15.2.8", + "@angular/platform-browser": "^15.2.8", + "@angular/platform-browser-dynamic": "^15.2.8", + "@angular/platform-server": "^15.2.8", + "@angular/router": "^15.2.8", + "@angular/service-worker": "^15.2.8", + "@angular/youtube-player": "^15.2.8", + "@aws-sdk/client-s3": "^3.317.0", + "@aws-sdk/s3-request-presigner": "^3.317.0", "@ctrl/ngx-github-buttons": "^8.0.0", "@ngneat/dag": "^2.0.0", - "@ngrx/effects": "^15.2.1", - "@ngrx/entity": "^15.2.1", - "@ngrx/router-store": "^15.2.1", - "@ngrx/store": "^15.2.1", - "ace-builds": "^1.15.0", + "@ngrx/effects": "^15.4.0", + "@ngrx/entity": "^15.4.0", + "@ngrx/router-store": "^15.4.0", + "@ngrx/store": "^15.4.0", + "ace-builds": "^1.18.0", "angular-google-tag-manager": "^1.7.0", "angular-resizable-element": "^7.0.2", - "angular-split": "^14.1.0", + "angular-split": "^15.0.0", "ansi-to-html": "^0.7.2", - "bootstrap": "^4.6.2", + "bootstrap": "^5.2.3", "britecharts": "^2.18.0", "curved-arrows": "^0.1.0", "d3-selection": "^3.0.0", "diff": "^5.1.0", "dom-to-image": "^2.6.0", - "filesize": "^10.0.6", + "filesize": "^10.0.7", "has-ansi": "^5.0.1", "hocon-parser": "^1.0.1", "jwt-decode": "^3.1.2", "localforage": "^1.10.0", "lodash-es": "^4.17.21", "lucene": "^2.1.1", - "ngx-clipboard": "^15.1.0", - "ngx-color-picker": "^13.0.0", + "ngx-clipboard": "^16.0.0", + "ngx-color-picker": "^14.0.0", "ngx-device-detector": "^5.0.1", - "ngx-markdown-editor": "^5.1.0", + "ngx-markdown-editor": "^5.3.0", "ngx-print": "^1.3.1", - "ngx-window-token": "^6.0.0", + "ngx-window-token": "^7.0.0", "object-hash": "^3.0.0", "primeicons": "^6.0.1", - "primeng": "^15.2.0", + "primeng": "^15.4.1", "process": "^0.11.10", "rxjs": "^7.8.0", "string-to-color": "^2.2.2", @@ -74,36 +74,36 @@ "tslib": "^2.5.0", "url": "^0.11.0", "uuid": "^9.0.0", - "zone.js": "~0.12.0" + "zone.js": "^0.12.0" }, "devDependencies": { - "@angular-devkit/build-angular": "^15.1.4", - "@angular-devkit/core": "^15.1.4", - "@angular-devkit/schematics": "^15.1.4", - "@angular-devkit/schematics-cli": "^15.1.4", - "@angular-eslint/builder": "^15.2.0", - "@angular-eslint/eslint-plugin": "^15.2.0", - "@angular-eslint/eslint-plugin-template": "^15.2.0", - "@angular-eslint/schematics": "15.2.0", - "@angular-eslint/template-parser": "^15.2.0", - "@angular/cli": "^15.1.4", - "@angular/compiler-cli": "^15.1.3", - "@angular/language-service": "^15.1.3", - "@fortawesome/fontawesome-free": "^6.3.0", - "@ngrx/schematics": "^15.2.1", - "@ngrx/store-devtools": "^15.2.1", - "@types/d3-selection": "^3.0.4", - "@types/lodash-es": "^4.17.6", - "@types/node": "^18.13.0", - "@types/plotly.js": "^2.12.13", - "@types/uuid": "^9.0.0", - "@typescript-eslint/eslint-plugin": "^5.51.0", - "@typescript-eslint/parser": "^5.51.0", + "@angular-devkit/build-angular": "^15.2.6", + "@angular-devkit/core": "^15.2.6", + "@angular-devkit/schematics": "^15.2.6", + "@angular-devkit/schematics-cli": "^15.2.5", + "@angular-eslint/builder": "^15.2.1", + "@angular-eslint/eslint-plugin": "^15.2.1", + "@angular-eslint/eslint-plugin-template": "^15.2.1", + "@angular-eslint/schematics": "15.2.1", + "@angular-eslint/template-parser": "^15.2.1", + "@angular/cli": "^15.2.6", + "@angular/compiler-cli": "^15.2.8", + "@angular/language-service": "^15.2.8", + "@fortawesome/fontawesome-free": "^6.4.0", + "@ngrx/schematics": "^15.4.0", + "@ngrx/store-devtools": "^15.4.0", + "@types/d3-selection": "^3.0.5", + "@types/lodash-es": "^4.17.7", + "@types/node": "^18.16.0", + "@types/plotly.js": "^2.12.18", + "@types/uuid": "^9.0.1", + "@typescript-eslint/eslint-plugin": "^5.59.1", + "@typescript-eslint/parser": "^5.59.1", "codelyzer": "^6.0.2", - "eslint": "^8.33.0", + "eslint": "^8.39.0", "eslint-plugin-import": "2.27.5", - "eslint-plugin-jsdoc": "39.8.0", + "eslint-plugin-jsdoc": "41.1.2", "eslint-plugin-prefer-arrow": "1.2.3", "typescript": "~4.9.5" } -} +} \ No newline at end of file diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 20fd1aa1..3a9d5a42 100755 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -3,22 +3,19 @@ import {selectCurrentUser} from '@common/core/reducers/users-reducer'; import {Component, OnDestroy, OnInit, ViewEncapsulation, HostListener, Renderer2, Injector} from '@angular/core'; import {ActivatedRoute, NavigationEnd, Router, Params, RouterEvent} from '@angular/router'; import {Title} from '@angular/platform-browser'; -import {selectLoggedOut} from '@common/core/reducers/view.reducer'; +import {selectBreadcrumbs, selectLoggedOut} from '@common/core/reducers/view.reducer'; import {Store} from '@ngrx/store'; -import {selectRouterConfig, selectRouterParams, selectRouterUrl} from '@common/core/reducers/router-reducer'; +import {selectRouterParams, selectRouterUrl} from '@common/core/reducers/router-reducer'; import {ApiProjectsService} from './business-logic/api-services/projects.service'; import {Project} from './business-logic/model/projects/project'; import {getAllSystemProjects, setSelectedProjectId, updateProject} from '@common/core/actions/projects.actions'; import {selectSelectedProject} from '@common/core/reducers/projects.reducer'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {getTutorialBucketCredentials} from '@common/core/actions/common-auth.actions'; import {termsOfUseAccepted} from '@common/core/actions/users.actions'; -import {distinctUntilChanged, filter, map, tap, withLatestFrom} from 'rxjs/operators'; +import {distinctUntilChanged, filter, map, tap} from 'rxjs/operators'; import * as routerActions from './webapp-common/core/actions/router.actions'; import {combineLatest, Observable, Subscription} from 'rxjs'; -import {selectBreadcrumbsStrings} from '@common/layout/layout.reducer'; -import {NestedProjectTypeUrlEnum, prepareNames} from './layout/breadcrumbs/breadcrumbs.utils'; -import {formatStaticCrumb} from '@common/layout/breadcrumbs/breadcrumbs-common.utils'; import {ServerUpdatesService} from '@common/shared/services/server-updates.service'; import {selectAvailableUpdates} from './core/reducers/view.reducer'; import {UPDATE_SERVER_PATH} from './app.constants'; @@ -53,10 +50,8 @@ export class AppComponent implements OnInit, OnDestroy { private selectedProjectFromUrl$: Observable; private breadcrumbsSubscription: Subscription; private selectedCurrentUserSubscription: Subscription; - private breadcrumbsStrings; private selectedCurrentUser$: Observable; public showNotification: boolean = true; - public showSurvey$: Observable; public demo = ConfigurationService.globalEnvironment.demo; public isLoginContext: boolean; public currentUser: User; @@ -67,6 +62,7 @@ export class AppComponent implements OnInit, OnDestroy { public showSurvey: boolean; private plotlyURL: string; private environment: Environment; + private title = 'ClearML'; @HostListener('document:visibilitychange') onVisibilityChange() { this.store.dispatch(visibilityChanged({visible: !document.hidden})); @@ -140,7 +136,6 @@ export class AppComponent implements OnInit, OnDestroy { }; this.gtmService?.pushTag(gtmTag); this.store.dispatch(new routerActions.NavigationEnd()); - this.updateTitle(); }); this.selectedCurrentUserSubscription = this.selectedCurrentUser$.pipe( @@ -181,16 +176,10 @@ export class AppComponent implements OnInit, OnDestroy { } }); - this.breadcrumbsSubscription = this.store.select(selectBreadcrumbsStrings).pipe( - filter(names => !!names), - withLatestFrom(this.store.select(selectRouterConfig)) - ).subscribe( - ([names, routeConf]) => { - const projectType = `${routeConf?.[0]}${routeConf?.[1] === 'simple' ? '/' + routeConf?.[1] : ''}`; - this.breadcrumbsStrings = prepareNames(names, projectType as NestedProjectTypeUrlEnum); - this.updateTitle(); - } - ); + this.breadcrumbsSubscription = this.store.select(selectBreadcrumbs).subscribe(breadcrumbs => { + const crumbs = breadcrumbs.flat().map(breadcrumb=> breadcrumb.name); + this.titleService.setTitle(`${this.title ? this.title + '-' : ''} ${crumbs.join(' / ')}`); + }); if (window.localStorage.getItem('disableHidpi') !== 'true') { this.setScale(); @@ -228,26 +217,6 @@ export class AppComponent implements OnInit, OnDestroy { return this.router.navigateByUrl('projects'); } - updateTitle() { - let route = this.route.snapshot.firstChild; - let routeConfig = []; - - while (route) { - const path = route.routeConfig.path.split('/').filter((item) => !!item); - routeConfig = routeConfig.concat(path); - route = route.firstChild; - } - const crumbs = routeConfig - .reduce((acc, config) => { - const dynamicCrumb = this.breadcrumbsStrings[config]; - let crumb = dynamicCrumb ? dynamicCrumb : formatStaticCrumb(config); - crumb = Array.isArray(crumb) ? crumb.at(-1) : crumb; - return acc.concat(crumb.name); - }, ['']) - .filter(name => !!name && name !== ':project'); - this.titleService.setTitle(`ClearML - ${crumbs.join(' / ')}`); - } - versionDismissed(version: string) { this.serverUpdatesService.setDismissedVersion(version); } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index b4f64ed5..53fa089d 100755 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -20,7 +20,7 @@ import {ColorHashService} from '@common/shared/services/color-hash/color-hash.se import {SharedModule} from './shared/shared.module'; import {ConfigurationService} from '@common/shared/services/configuration.service'; import {ProjectsSharedModule} from './features/projects/shared/projects-shared.module'; -import {MAT_LEGACY_FORM_FIELD_DEFAULT_OPTIONS as MAT_FORM_FIELD_DEFAULT_OPTIONS} from '@angular/material/legacy-form-field'; +import {MAT_FORM_FIELD_DEFAULT_OPTIONS} from '@angular/material/form-field'; import {LoginService} from '~/shared/services/login.service'; import {ExperimentSharedModule} from '~/features/experiments/shared/experiment-shared.module'; diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 2046a0b5..9dfbd21b 100755 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -1,7 +1,4 @@ import {Routes} from '@angular/router'; -/* -import {AdminComponent} from '@common/settings/admin/admin.component'; -*/ import {ProjectRedirectGuardGuard} from '@common/shared/guards/project-redirect.guard'; import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; @@ -45,6 +42,11 @@ export const routes: Routes = [ loadChildren: () => import('./webapp-common/experiments-compare/experiments-compare.module').then(m => m.ExperimentsCompareModule), data: {entityType: EntityTypeEnum.experiment}, }, + { + path: 'compare-models', + data: {entityType: EntityTypeEnum.model}, + loadChildren: () => import('./webapp-common/experiments-compare/experiments-compare.module').then(m => m.ExperimentsCompareModule) + }, ] }, ] diff --git a/src/app/business-logic/model/events/eventsGetMultiTaskPlotsRequest.ts b/src/app/business-logic/model/events/eventsGetMultiTaskPlotsRequest.ts index a41d330e..904e8369 100644 --- a/src/app/business-logic/model/events/eventsGetMultiTaskPlotsRequest.ts +++ b/src/app/business-logic/model/events/eventsGetMultiTaskPlotsRequest.ts @@ -26,4 +26,5 @@ export interface EventsGetMultiTaskPlotsRequest { */ scroll_id?: string; no_scroll?: boolean; + model_events?: boolean; } diff --git a/src/app/business-logic/model/events/eventsMultiTaskScalarMetricsIterHistogramRequest.ts b/src/app/business-logic/model/events/eventsMultiTaskScalarMetricsIterHistogramRequest.ts index 0de76592..bddd3f21 100644 --- a/src/app/business-logic/model/events/eventsMultiTaskScalarMetricsIterHistogramRequest.ts +++ b/src/app/business-logic/model/events/eventsMultiTaskScalarMetricsIterHistogramRequest.ts @@ -23,4 +23,5 @@ export interface EventsMultiTaskScalarMetricsIterHistogramRequest { */ samples?: number; key?: ScalarKeyEnum; + model_events?: boolean; } diff --git a/src/app/business-logic/model/events/metricsPlotEvent.ts b/src/app/business-logic/model/events/metricsPlotEvent.ts index 404d00a4..b512ee51 100644 --- a/src/app/business-logic/model/events/metricsPlotEvent.ts +++ b/src/app/business-logic/model/events/metricsPlotEvent.ts @@ -23,7 +23,7 @@ export interface MetricsPlotEvent { /** * \'plot\' */ - type: object; + type: any; /** * Task ID (required) */ @@ -41,7 +41,7 @@ export interface MetricsPlotEvent { */ variant?: string; /** - * An entire plot (not single datapoint) and it\'s layout. Used for plotting ROC curves, confidence matrices, etc. when evaluating the net. + * An entire plot (not single datapoint) and it\'s layout. Used for plotting ROC curves, confidence matrices, etc. when evaluating the net. */ plot_str?: string; /** diff --git a/src/app/business-logic/model/models/lastMetricsEvent.ts b/src/app/business-logic/model/models/lastMetricsEvent.ts new file mode 100644 index 00000000..184bbc8c --- /dev/null +++ b/src/app/business-logic/model/models/lastMetricsEvent.ts @@ -0,0 +1,44 @@ +/** + * models + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * OpenAPI spec version: 999.0 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + + + +export interface LastMetricsEvent { + /** + * Metric name + */ + metric?: string; + /** + * Variant name + */ + variant?: string; + /** + * Last value reported + */ + value?: number; + /** + * Minimum value reported + */ + min_value?: number; + /** + * The iteration at which the minimum value was reported + */ + min_value_iteration?: number; + /** + * Maximum value reported + */ + max_value?: number; + /** + * The iteration at which the maximum value was reported + */ + max_value_iteration?: number; +} diff --git a/src/app/business-logic/model/models/model.ts b/src/app/business-logic/model/models/model.ts index a159428b..ec84c967 100644 --- a/src/app/business-logic/model/models/model.ts +++ b/src/app/business-logic/model/models/model.ts @@ -10,6 +10,8 @@ * Do not edit the class manually. */ +import { ModelStats } from '././modelStats'; +import { LastMetricsEvent } from '././lastMetricsEvent'; import { MetadataItem } from '././metadataItem'; @@ -55,11 +57,11 @@ export interface Model { */ comment?: string; /** - * User-defined tags list + * User-defined tags */ tags?: Array; /** - * System tags list. This field is reserved for system use, please don\'t use it. + * System tags. This field is reserved for system use, please don\'t use it. */ system_tags?: Array; /** @@ -89,5 +91,14 @@ export interface Model { /** * Model metadata */ - metadata?: Array; + metadata?: { [key: string]: MetadataItem; }; + /** + * Last iteration reported for this model + */ + last_iteration?: number; + /** + * Last metric variants (hash to events), one for each metric hash + */ + last_metrics?: { [key: string]: { [key: string]: LastMetricsEvent; }; }; + stats?: ModelStats; } diff --git a/src/app/business-logic/model/models/modelStats.ts b/src/app/business-logic/model/models/modelStats.ts new file mode 100644 index 00000000..550b0ab0 --- /dev/null +++ b/src/app/business-logic/model/models/modelStats.ts @@ -0,0 +1,23 @@ +/** + * models + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * OpenAPI spec version: 999.0 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + + + +/** + * Model statistics + */ +export interface ModelStats { + /** + * Number of the model labels + */ + labels_count?: number; +} diff --git a/src/app/business-logic/model/projects/projectsGetUniqueMetricVariantsRequest.ts b/src/app/business-logic/model/projects/projectsGetUniqueMetricVariantsRequest.ts index f221bb6d..60e5c3c6 100644 --- a/src/app/business-logic/model/projects/projectsGetUniqueMetricVariantsRequest.ts +++ b/src/app/business-logic/model/projects/projectsGetUniqueMetricVariantsRequest.ts @@ -21,4 +21,8 @@ export interface ProjectsGetUniqueMetricVariantsRequest { * If set to \'true\' and the project field is set then the result includes metrics/variants from the subproject tasks */ include_subprojects?: boolean; + /** + * If set to Truethen bring unique metric and variant names from the project models otherwise from the project tasks + */ + model_metrics?: boolean; } diff --git a/src/app/business-logic/model/reports/reportsGetTaskDataResponse.ts b/src/app/business-logic/model/reports/reportsGetTaskDataResponse.ts index 7bfb8948..fed0e34e 100644 --- a/src/app/business-logic/model/reports/reportsGetTaskDataResponse.ts +++ b/src/app/business-logic/model/reports/reportsGetTaskDataResponse.ts @@ -12,20 +12,25 @@ import { Task } from '././task'; import { DebugImagesResponseTaskMetrics } from '././debugImagesResponseTaskMetrics'; +import { SingleValueTaskMetrics } from '././singleValueTaskMetrics'; export interface ReportsGetTaskDataResponse { - /** - * List of tasks - */ - tasks?: Array; - /** - * Plot events grouped by tasks and iterations - */ - plots?: object; - /** - * Debug image events grouped by tasks and iterations - */ - debug_images?: Array; - scalar_metrics_iter_histogram?: object; + /** + * List of tasks + */ + tasks?: Array; + /** + * Plots mapped by metric, variant, task and iteration + */ + plots?: object; + /** + * Debug image events grouped by tasks and iterations + */ + debug_images?: Array; + scalar_metrics_iter_histogram?: object; + /** + * Single value metrics grouped by task + */ + single_value_metrics?: Array; } diff --git a/src/app/business-logic/model/reports/singleValueTaskMetrics.ts b/src/app/business-logic/model/reports/singleValueTaskMetrics.ts new file mode 100644 index 00000000..46669ff3 --- /dev/null +++ b/src/app/business-logic/model/reports/singleValueTaskMetrics.ts @@ -0,0 +1,22 @@ +/** + * reports + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * OpenAPI spec version: 999.0 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +import { SingleValueTaskMetricsValues } from '././singleValueTaskMetricsValues'; + + +export interface SingleValueTaskMetrics { + /** + * Task ID + */ + task?: string; + values?: Array; +} diff --git a/src/app/business-logic/model/reports/singleValueTaskMetricsValues.ts b/src/app/business-logic/model/reports/singleValueTaskMetricsValues.ts new file mode 100644 index 00000000..c8baf8fc --- /dev/null +++ b/src/app/business-logic/model/reports/singleValueTaskMetricsValues.ts @@ -0,0 +1,20 @@ +/** + * reports + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * OpenAPI spec version: 999.0 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + + + +export interface SingleValueTaskMetricsValues { + metric?: string; + variant?: string; + value?: number; + timestamp?: number; +} diff --git a/src/app/business-logic/model/tasks/tasksDequeueManyRequest.ts b/src/app/business-logic/model/tasks/tasksDequeueManyRequest.ts index 94b2d259..f2eff648 100644 --- a/src/app/business-logic/model/tasks/tasksDequeueManyRequest.ts +++ b/src/app/business-logic/model/tasks/tasksDequeueManyRequest.ts @@ -25,4 +25,5 @@ export interface TasksDequeueManyRequest { * Extra information regarding status change */ status_message?: string; + remove_from_all_queues?: boolean; } diff --git a/src/app/business-logic/model/tasks/tasksDequeueRequest.ts b/src/app/business-logic/model/tasks/tasksDequeueRequest.ts index 098a8040..a1b2ab9f 100644 --- a/src/app/business-logic/model/tasks/tasksDequeueRequest.ts +++ b/src/app/business-logic/model/tasks/tasksDequeueRequest.ts @@ -25,4 +25,5 @@ export interface TasksDequeueRequest { * Extra information regarding status change */ status_message?: string; + remove_from_all_queues?: boolean; } diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts index 3b42092d..ee56cbce 100755 --- a/src/app/core/core.module.ts +++ b/src/app/core/core.module.ts @@ -60,6 +60,7 @@ const syncedKeys = [ 'projects.selectedProject', 'rootProjects.showHidden', 'rootProjects.hideExamples', + 'rootProjects.defaultNestedModeForFeature', 'views.availableUpdates', 'views.showSurvey', 'views.neverShowPopupAgain' @@ -94,7 +95,7 @@ const userPrefMetaFactory = (userPreferences: UserPreferences): MetaReducer (reducer: ActionReducer) => createUserPrefReducer('users', ['activeWorkspace', 'showOnlyUserWork'], [USERS_PREFIX], userPreferences, reducer), (reducer: ActionReducer) => - createUserPrefReducer('rootProjects', ['tagsColors', 'graphVariant', 'showHidden', 'hideExamples', 'aa'] as (keyof RootProjects)[], [ROOT_PROJECTS_PREFIX], userPreferences, reducer), + createUserPrefReducer('rootProjects', ['tagsColors', 'graphVariant', 'showHidden', 'hideExamples', 'defaultNestedModeForFeature'], [ROOT_PROJECTS_PREFIX], userPreferences, reducer), (reducer: ActionReducer) => createUserPrefReducer('views', ['autoRefresh', 'neverShowPopupAgain', 'redactedArguments', 'hideRedactedArguments'], [VIEW_PREFIX], userPreferences, reducer), localStorageReducer, diff --git a/src/app/core/reducers/users.reducer.ts b/src/app/core/reducers/users.reducer.ts index 5d7a8520..c2b736d8 100644 --- a/src/app/core/reducers/users.reducer.ts +++ b/src/app/core/reducers/users.reducer.ts @@ -18,7 +18,7 @@ export const usersReducer = createReducer(initUsers, })) ); -export const selectFeatures = createSelector(users, (state) => []); +export const selectFeatures = createSelector(users, (state) => null); // eslint-disable-next-line @typescript-eslint/naming-convention export const selectTermsOfUse = createSelector(users, state => ({accept_required: null})); export const selectInvitesPending = createSelector(users, state => []); diff --git a/src/app/core/services/usage-stats.service.ts b/src/app/core/services/usage-stats.service.ts index 4726c7fb..21d1d145 100644 --- a/src/app/core/services/usage-stats.service.ts +++ b/src/app/core/services/usage-stats.service.ts @@ -3,7 +3,7 @@ import {Store} from '@ngrx/store'; import {filter} from 'rxjs/operators'; import {updateUsageStats} from '../actions/usage-stats.actions'; import {selectPromptUser} from '../reducers/usage-stats.reducer'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {ConfirmDialogComponent} from '@common/shared/ui-components/overlay/confirm-dialog/confirm-dialog.component'; import {ConfigurationService} from '@common/shared/services/configuration.service'; diff --git a/src/app/features/dashboard/dashboard-routing.module.ts b/src/app/features/dashboard/dashboard-routing.module.ts index 55b584cd..311d22f1 100755 --- a/src/app/features/dashboard/dashboard-routing.module.ts +++ b/src/app/features/dashboard/dashboard-routing.module.ts @@ -1,9 +1,14 @@ import {RouterModule, Routes} from '@angular/router'; import {NgModule} from '@angular/core'; import {DashboardComponent} from './dashboard.component'; +import {CrumbTypeEnum} from '@common/layout/breadcrumbs/breadcrumbs.component'; export const routes: Routes = [ - {path: '', component: DashboardComponent} + {path: '', component: DashboardComponent, data:{staticBreadcrumb:[[{ + name: 'DASHBOARD', + type: CrumbTypeEnum.Feature + }]]} + } ]; @NgModule({ diff --git a/src/app/features/dashboard/dashboard.component.html b/src/app/features/dashboard/dashboard.component.html index d11d8500..f052a4b6 100755 --- a/src/app/features/dashboard/dashboard.component.html +++ b/src/app/features/dashboard/dashboard.component.html @@ -9,9 +9,9 @@
+ >MANAGE WORKERS AND QUEUES
diff --git a/src/app/features/dashboard/dashboard.component.ts b/src/app/features/dashboard/dashboard.component.ts index ba2e3eb9..a812b75c 100755 --- a/src/app/features/dashboard/dashboard.component.ts +++ b/src/app/features/dashboard/dashboard.component.ts @@ -8,7 +8,7 @@ import {filter, skip, take} from 'rxjs/operators'; import {setDeep} from '@common/core/actions/projects.actions'; import {getRecentProjects, getRecentExperiments} from '@common/dashboard/common-dashboard.actions'; import {selectFirstLogin} from '@common/core/reducers/view.reducer'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {WelcomeMessageComponent} from '@common/layout/welcome-message/welcome-message.component'; import {firstLogin} from '@common/core/actions/layout.actions'; import {IRecentTask, selectRecentTasks} from '@common/dashboard/common-dashboard.reducer'; diff --git a/src/app/features/datasets/datasets-routing.module.ts b/src/app/features/datasets/datasets-routing.module.ts index 47613ecd..e948f083 100644 --- a/src/app/features/datasets/datasets-routing.module.ts +++ b/src/app/features/datasets/datasets-routing.module.ts @@ -4,13 +4,17 @@ import {SimpleDatasetsComponent} from '@common/datasets/simple-datasets/simple-d import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; import { NestedProjectViewPageComponent -} from "@common/nested-project-view/nested-project-view-page/nested-project-view-page.component"; +} from '@common/nested-project-view/nested-project-view-page/nested-project-view-page.component'; +import {CrumbTypeEnum} from '@common/layout/breadcrumbs/breadcrumbs.component'; const routes: Routes = [ { path : '', component: SimpleDatasetsComponent, - data : {search: true} + data: {search: true, staticBreadcrumb:[[{ + name: 'DATASETS', + type: CrumbTypeEnum.Feature + }]]} }, { path: 'simple/:projectId', diff --git a/src/app/features/datasets/datasets.module.ts b/src/app/features/datasets/datasets.module.ts index 4de6253c..c33139f1 100644 --- a/src/app/features/datasets/datasets.module.ts +++ b/src/app/features/datasets/datasets.module.ts @@ -6,7 +6,8 @@ import {DatasetsRoutingModule} from '~/features/datasets/datasets-routing.module import {DatasetsSharedModule} from '~/features/datasets/shared/datasets-shared.module'; import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module'; import {SMSharedModule} from '@common/shared/shared.module'; -import {FeatureNestedProjectViewModule} from "~/features/nested-project-view/feature-nested-project-view.module"; +import {FeatureNestedProjectViewModule} from '~/features/nested-project-view/feature-nested-project-view.module'; +import {LabeledFormFieldDirective} from '@common/shared/directive/labeled-form-field.directive'; @NgModule({ @@ -18,6 +19,7 @@ import {FeatureNestedProjectViewModule} from "~/features/nested-project-view/fea DatasetsSharedModule, SharedPipesModule, FeatureNestedProjectViewModule, + LabeledFormFieldDirective, ], declarations: [ SimpleDatasetsComponent, diff --git a/src/app/features/experiments/containers/experiment-info-navbar/experiment-info-navbar.component.html b/src/app/features/experiments/containers/experiment-info-navbar/experiment-info-navbar.component.html index 795a8783..f02c9e65 100644 --- a/src/app/features/experiments/containers/experiment-info-navbar/experiment-info-navbar.component.html +++ b/src/app/features/experiments/containers/experiment-info-navbar/experiment-info-navbar.component.html @@ -1,58 +1,8 @@ - + \ No newline at end of file diff --git a/src/app/features/experiments/containers/experiment-info-navbar/experiment-info-navbar.component.scss b/src/app/features/experiments/containers/experiment-info-navbar/experiment-info-navbar.component.scss index dd79aba2..2d43f913 100644 --- a/src/app/features/experiments/containers/experiment-info-navbar/experiment-info-navbar.component.scss +++ b/src/app/features/experiments/containers/experiment-info-navbar/experiment-info-navbar.component.scss @@ -1,31 +1,17 @@ -@import "variables"; -$output-tabs-height: 40px; - -nav { - height: $output-tabs-height; - position: relative; - text-align: center; +.tab-nav { + display: grid; + grid-template-columns: 200px 1fr 200px; border-bottom: 1px solid #efefef; - padding: 0 48px 0 24px; - .refresh-position { - position: absolute; - right: 16px; - top: 6px; - display: flex; - align-items: center; + &.minimized { + grid-template-columns: 0 1fr 60px; } - .refreshIcon{ - margin-right: 10px; - } - span.disabled { - pointer-events: none; - } -} -.mat-menu-item { - padding-left: 22px; - &.active { - border-left: 6px solid $purple; - padding-left: 16px; + + @media(max-width: 1200px) { + grid-template-columns: 0 1fr 200px; } } + +sm-router-tab-nav-bar { + overflow: hidden; +} \ No newline at end of file diff --git a/src/app/features/experiments/containers/experiment-info-navbar/experiment-info-navbar.component.ts b/src/app/features/experiments/containers/experiment-info-navbar/experiment-info-navbar.component.ts index f313366c..616b0003 100644 --- a/src/app/features/experiments/containers/experiment-info-navbar/experiment-info-navbar.component.ts +++ b/src/app/features/experiments/containers/experiment-info-navbar/experiment-info-navbar.component.ts @@ -1,38 +1,38 @@ -import {Component, Input} from '@angular/core'; -import {FeaturesEnum} from '~/business-logic/model/users/featuresEnum'; -import {selectRouterConfig} from '@common/core/reducers/router-reducer'; -import {Store} from '@ngrx/store'; -import {ExperimentInfoState} from '../../reducers/experiment-info.reducer'; -import {Observable} from 'rxjs'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; +import {Link} from '@common/shared/components/router-tab-nav-bar/router-tab-nav-bar.component'; @Component({ selector: 'sm-experiment-info-navbar', templateUrl: './experiment-info-navbar.component.html', - styleUrls: ['./experiment-info-navbar.component.scss'] + styleUrls: ['./experiment-info-navbar.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush }) export class ExperimentInfoNavbarComponent { - public featuresEnum = FeaturesEnum; - public routerConfig$: Observable; public baseInfoRoute: string[]; - public overflow: boolean; private _minimized: boolean; + links = [ + {name: 'execution', url: ['execution']}, + {name: 'configuration', url: ['hyper-params', 'hyper-param', '_empty_'], activeBy: 'hyper-params'}, + {name: 'artifacts', url: ['artifacts']}, + {name: 'info', url: ['general']}, + {name: 'console', url: ['log'], output: true}, + {name: 'scalars', url: ['metrics','scalar'], output: true}, + {name: 'plots', url: ['metrics','plots'], output: true}, + {name: 'debug samples', url: ['debugImages'], output: true}, + ] as Link[]; @Input() set minimized(minimized: boolean) { this.baseInfoRoute = minimized ? ['info-output'] : []; + this.links = this.links.map(link => ({ + ...link, + url: (link as any).output ? this.baseInfoRoute.concat(link.url) : link.url + })); this._minimized = minimized; } - get minimized() { + get minimized(){ return this._minimized; } @Input() splitSize: number; - - - constructor(private store: Store) { - this.routerConfig$ = this.store.select(selectRouterConfig); - } - navbarOverflowed($event: boolean) { - this.overflow = $event; - } } diff --git a/src/app/features/experiments/experiments.module.ts b/src/app/features/experiments/experiments.module.ts index 72238a02..2e0e052f 100755 --- a/src/app/features/experiments/experiments.module.ts +++ b/src/app/features/experiments/experiments.module.ts @@ -16,7 +16,7 @@ import {CommonLayoutModule} from '@common/layout/layout.module'; import {DebugImagesModule} from '@common/debug-images/debug-images.module'; import {ExperimentInfoExecutionComponent} from '@common/experiments/containers/experiment-info-execution/experiment-info-execution.component'; import {MatSidenavModule} from '@angular/material/sidenav'; -import {MatLegacyListModule as MatListModule} from '@angular/material/legacy-list'; +import {MatListModule} from '@angular/material/list'; import {ExperimentOutputComponent} from './containers/experiment-ouptut/experiment-output.component'; import {ExperimentInfoNavbarComponent} from './containers/experiment-info-navbar/experiment-info-navbar.component'; import {ExperimentInfoHyperParametersComponent} from '@common/experiments/containers/experiment-info-hyper-parameters/experiment-info-hyper-parameters.component'; @@ -34,7 +34,6 @@ import {ExperimentArtifactsNavbarComponent} from '@common/experiments/dumb/exper import {ExperimentInfoArtifactsComponent} from '@common/experiments/containers/experiment-info-aritfacts/experiment-info-artifacts.component'; import {ExperimentInfoHeaderComponent} from '@common/experiments/dumb/experiment-info-header/experiment-info-header.component'; import {ExperimentInfoTaskModelComponent} from '@common/experiments/containers/experiment-info-task-model/experiment-info-task-model.component'; -import {ModelAutoPopulateDialogComponent} from '@common/experiments/dumb/model-auto-populate-dialog/model-auto-populate-dialog.component'; import {ExperimentOutputScalarsComponent} from '@common/experiments/containers/experiment-output-scalars/experiment-output-scalars.component'; import {ExperimentInfoModelComponent} from '@common/experiments/containers/experiment-info-model/experiment-info-model.component'; import {ExperimentInfoHyperParametersFormContainerComponent} from '@common/experiments/containers/experiment-info-hyper-parameters-form-container/experiment-info-hyper-parameters-form-container.component'; @@ -50,6 +49,8 @@ import {MAT_AUTOCOMPLETE_SCROLL_STRATEGY} from '@angular/material/autocomplete'; import {scrollFactory} from '@common/shared/utils/scroll-factory'; import {Overlay} from '@angular/cdk/overlay'; import {ExperimentsComponent} from '@common/experiments/experiments.component'; +import {RouterTabNavBarComponent} from '@common/shared/components/router-tab-nav-bar/router-tab-nav-bar.component'; +import {MatTabsModule} from '@angular/material/tabs'; @NgModule({ @@ -80,6 +81,9 @@ import {ExperimentsComponent} from '@common/experiments/experiments.component'; MatProgressSpinnerModule, MatRadioModule, ExperimentSharedModule, + RouterTabNavBarComponent, + MatTabsModule, + RouterTabNavBarComponent, ], declarations: [ ExperimentsComponent, @@ -97,7 +101,6 @@ import {ExperimentsComponent} from '@common/experiments/experiments.component'; ExperimentOutputModelViewComponent, ExperimentExecutionSourceCodeComponent, ExperimentOutputScalarsComponent, - ModelAutoPopulateDialogComponent, ExperimentInfoHyperParametersComponent, ExperimentInfoHyperParametersFormContainerComponent, ExperimentArtifactsNavbarComponent, diff --git a/src/app/features/experiments/reducers/index.ts b/src/app/features/experiments/reducers/index.ts index 6d55b929..59d8c0ad 100755 --- a/src/app/features/experiments/reducers/index.ts +++ b/src/app/features/experiments/reducers/index.ts @@ -1,6 +1,6 @@ import {ActionReducerMap, createSelector} from '@ngrx/store'; import {experimentInfoReducer, ExperimentInfoState, initialState as infoInitialState} from './experiment-info.reducer'; -import {experimentOutputReducer, ExperimentOutputState, experimentOutputInitState} from '@common/experiments/reducers/experiment-output.reducer'; +import {experimentOutputReducer, ExperimentOutputState, experimentOutputInitState, ExperimentSettings} from '@common/experiments/reducers/experiment-output.reducer'; import {experimentsViewReducer, ExperimentsViewState, experimentsViewInitialState} from '@common/experiments/reducers/experiments-view.reducer'; import {IExperimentInfo} from '../shared/experiment-info.model'; import {TaskStatusEnum} from '~/business-logic/model/tasks/taskStatusEnum'; @@ -59,3 +59,7 @@ export const selectExperimentFormValidity = createSelector(selectExperimentInfoD return !error; }); + +export const selectSelectedModelSettings = createSelector(experimentOutput, selectSelectedModel, + (output, currentModel): ExperimentSettings => + output.settingsList && output.settingsList.find((setting) => currentModel && setting.id === currentModel.id)); diff --git a/src/app/features/experiments/shared/experiment-shared.module.ts b/src/app/features/experiments/shared/experiment-shared.module.ts index f773ff6b..8a4cba92 100755 --- a/src/app/features/experiments/shared/experiment-shared.module.ts +++ b/src/app/features/experiments/shared/experiment-shared.module.ts @@ -4,16 +4,13 @@ import {SMSharedModule} from '@common/shared/shared.module'; import {ExperimentConverterService} from './services/experiment-converter.service'; import { ExperimentMenuComponent } from '@common/experiments/shared/components/experiment-menu/experiment-menu.component'; import {ExperimentMenuExtendedComponent} from '../containers/experiment-menu-extended/experiment-menu-extended.component'; -import {GetParamMetricValuePipe} from '@common/experiments/dumb/experiments-table/hyper-param-metric-column/get-param-metric-value.pipe'; import {ExperimentHeaderComponent} from '@common/experiments/dumb/experiment-header/experiment-header.component'; import {SelectHyperParamsForCustomColComponent} from '@common/experiments/dumb/select-hyper-params-for-custom-col/select-hyper-params-for-custom-col.component'; import {ExperimentExecutionParametersComponent} from '@common/experiments/dumb/experiment-execution-parameters/experiment-execution-parameters.component'; import {CloneDialogComponent} from '@common/experiments/shared/components/clone-dialog/clone-dialog.component'; -import {HyperParamMetricColumnComponent} from '@common/experiments/dumb/experiments-table/hyper-param-metric-column/hyper-param-metric-column.component'; import {ExperimentSystemTagsComponent} from '@common/experiments/shared/components/experiments-system-tags/experiment-system-tags.component'; import {AbortAllChildrenDialogComponent} from '@common/experiments/shared/components/abort-all-children-dialog/abort-all-children-dialog.component'; import {ExperimentsTableComponent} from '@common/experiments/dumb/experiments-table/experiments-table.component'; -import {GetVariantWithoutRoundPipe} from '@common/experiments/dumb/experiments-table/hyper-param-metric-column/get-variant-without-round.pipe'; import {ChangeProjectDialogComponent} from '@common/experiments/shared/components/change-project-dialog/change-project-dialog.component'; import {ExperimentOutputPlotsComponent} from '@common/experiments/containers/experiment-output-plots/experiment-output-plots.component'; import {ExperimentCustomColsMenuComponent} from '@common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component'; @@ -41,6 +38,8 @@ import {EXPERIMENTS_OUTPUT_PREFIX} from '@common/experiments/actions/common-expe import {EXPERIMENTS_INFO_PREFIX} from '@common/experiments/actions/common-experiments-info.actions'; import {experimentsReducers} from '~/features/experiments/reducers'; import {CommonExperimentConverterService} from '@common/experiments/shared/services/common-experiment-converter.service'; +import {HyperParamMetricColumnComponent} from '@common/experiments/shared/components/hyper-param-metric-column/hyper-param-metric-column.component'; +import {LabeledFormFieldDirective} from '@common/shared/directive/labeled-form-field.directive'; export const experimentSyncedKeys = [ 'view.projectColumnsSortOrder', @@ -89,9 +88,6 @@ const DECLARATIONS = [ AbortAllChildrenDialogComponent, ExperimentExecutionParametersComponent, ExperimentsTableComponent, - HyperParamMetricColumnComponent, - GetParamMetricValuePipe, - GetVariantWithoutRoundPipe, ExperimentHeaderComponent, ExperimentCustomColsMenuComponent, SelectHyperParamsForCustomColComponent, @@ -117,6 +113,8 @@ const DECLARATIONS = [ MatProgressSpinnerModule, ScrollingModule, CommonLayoutModule, + HyperParamMetricColumnComponent, + LabeledFormFieldDirective, ], declarations : [...DECLARATIONS], providers : [ diff --git a/src/app/features/login/login.module.ts b/src/app/features/login/login.module.ts index 898952b2..12fc2c94 100644 --- a/src/app/features/login/login.module.ts +++ b/src/app/features/login/login.module.ts @@ -5,14 +5,14 @@ import { CommonModule } from '@angular/common'; import { LoginRoutingModule } from './login-routing.module'; -import { MatLegacyAutocompleteModule as MatAutocompleteModule } from '@angular/material/legacy-autocomplete'; -import {MatLegacyProgressSpinnerModule as MatProgressSpinnerModule} from '@angular/material/legacy-progress-spinner'; -import {MatLegacyCheckboxModule as MatCheckboxModule} from '@angular/material/legacy-checkbox'; +import { MatAutocompleteModule } from '@angular/material/autocomplete'; +import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; +import {MatCheckboxModule} from '@angular/material/checkbox'; import {SignupComponent} from './signup/signup.component'; -import {MatLegacyFormFieldModule as MatFormFieldModule} from '@angular/material/legacy-form-field'; -import {MatLegacySelectModule as MatSelectModule} from '@angular/material/legacy-select'; -import {MatLegacyInputModule as MatInputModule} from '@angular/material/legacy-input'; -import {MatLegacyRadioModule as MatRadioModule} from '@angular/material/legacy-radio'; +import {MatFormFieldModule} from '@angular/material/form-field'; +import {MatSelectModule} from '@angular/material/select'; +import {MatInputModule} from '@angular/material/input'; +import {MatRadioModule} from '@angular/material/radio'; import {LoginComponent} from '@common/login/login/login.component'; import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module'; import {NtkmeButtonModule} from '@ctrl/ngx-github-buttons'; diff --git a/src/app/features/nested-project-view/nested-project-view-page-extended/nested-project-view-page-extended.component.spec.ts b/src/app/features/nested-project-view/nested-project-view-page-extended/nested-project-view-page-extended.component.spec.ts index 14acbbbf..299932ab 100644 --- a/src/app/features/nested-project-view/nested-project-view-page-extended/nested-project-view-page-extended.component.spec.ts +++ b/src/app/features/nested-project-view/nested-project-view-page-extended/nested-project-view-page-extended.component.spec.ts @@ -3,7 +3,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { NestedProjectViewPageExtendedComponent } from './nested-project-view-page-extended.component'; import {StoreModule} from '@ngrx/store'; import {RouterTestingModule} from '@angular/router/testing'; -import {MatLegacyDialogModule as MatDialogModule} from '@angular/material/legacy-dialog'; +import {MatDialogModule} from '@angular/material/dialog'; describe('PipelinesPageComponent', () => { let component: NestedProjectViewPageExtendedComponent; diff --git a/src/app/features/nested-project-view/nested-project-view-utils.ts b/src/app/features/nested-project-view/nested-project-view-utils.ts index 4a4f099a..981152b3 100644 --- a/src/app/features/nested-project-view/nested-project-view-utils.ts +++ b/src/app/features/nested-project-view/nested-project-view-utils.ts @@ -1,4 +1,4 @@ -import {EntityTypeEnum} from "~/shared/constants/non-common-consts"; +import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; export enum EntityTypePluralEnum { pipelines = 'pipelines', @@ -6,13 +6,13 @@ export enum EntityTypePluralEnum { reports = 'reports', } -export const getEntityTypeFromUrlConf = (conf: string[]): string => { - return conf[0]; -}; +export const getEntityTypeFromUrlConf = (conf: string[]) => conf[0] as EntityTypePluralEnum; +// eslint-disable-next-line @typescript-eslint/no-unused-vars export const getDatasetUrlPrefix = (entityType)=> 'simple'; export const getNestedEntityBaseUrl = (entityType) => entityType; export const isDatasetType = (entityType) => entityType === EntityTypePluralEnum.datasets ; +// eslint-disable-next-line @typescript-eslint/no-unused-vars export const datasetLabel = (entityType) => 'DATASETS' ; export const getNestedEntityName = (entityType: string): EntityTypeEnum => { diff --git a/src/app/features/projects/projects-routing.module.ts b/src/app/features/projects/projects-routing.module.ts index 87fa51c1..cdb407ea 100644 --- a/src/app/features/projects/projects-routing.module.ts +++ b/src/app/features/projects/projects-routing.module.ts @@ -1,9 +1,15 @@ import {RouterModule, Routes} from '@angular/router'; import {NgModule} from '@angular/core'; -import {CommonProjectsPageComponent} from '../../webapp-common/projects/containers/projects-page/common-projects-page.component'; +import {CommonProjectsPageComponent} from '@common/projects/containers/projects-page/common-projects-page.component'; +import {CrumbTypeEnum} from '@common/layout/breadcrumbs/breadcrumbs.component'; export const routes: Routes = [ - {path: '', component: CommonProjectsPageComponent} + {path: '', component: CommonProjectsPageComponent, data: { + staticBreadcrumb: [[{ + name: 'PROJECTS', + type: CrumbTypeEnum.Feature + }]] + }} ]; diff --git a/src/app/features/settings/containers/admin/create-credential-dialog/create-credential-dialog.component.ts b/src/app/features/settings/containers/admin/create-credential-dialog/create-credential-dialog.component.ts index 639a5be8..dc16b23e 100644 --- a/src/app/features/settings/containers/admin/create-credential-dialog/create-credential-dialog.component.ts +++ b/src/app/features/settings/containers/admin/create-credential-dialog/create-credential-dialog.component.ts @@ -1,5 +1,5 @@ import {Component, Inject} from '@angular/core'; -import { MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA } from '@angular/material/legacy-dialog'; +import { MAT_DIALOG_DATA } from '@angular/material/dialog'; import {Store} from '@ngrx/store'; import {updateCredentialLabel} from '@common/core/actions/common-auth.actions'; import {OrganizationGetUserCompaniesResponseCompanies} from '~/business-logic/model/organization/organizationGetUserCompaniesResponseCompanies'; diff --git a/src/app/features/settings/containers/admin/usage-stats/usage-stats.component.ts b/src/app/features/settings/containers/admin/usage-stats/usage-stats.component.ts index b390e238..8a51ba51 100644 --- a/src/app/features/settings/containers/admin/usage-stats/usage-stats.component.ts +++ b/src/app/features/settings/containers/admin/usage-stats/usage-stats.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { MatLegacySlideToggleChange as MatSlideToggleChange } from '@angular/material/legacy-slide-toggle'; +import { MatSlideToggleChange } from '@angular/material/slide-toggle'; import {Store} from '@ngrx/store'; import {selectAllowed} from '~/core/reducers/usage-stats.reducer'; import {Observable} from 'rxjs'; diff --git a/src/app/features/settings/containers/admin/user-credentials/user-credentials.component.ts b/src/app/features/settings/containers/admin/user-credentials/user-credentials.component.ts index 38ae0ee1..c0177c9a 100644 --- a/src/app/features/settings/containers/admin/user-credentials/user-credentials.component.ts +++ b/src/app/features/settings/containers/admin/user-credentials/user-credentials.component.ts @@ -6,7 +6,7 @@ import {filter, take} from 'rxjs/operators'; import {createCredential, credentialRevoked, getAllCredentials, resetCredential, updateCredentialLabel} from '@common/core/actions/common-auth.actions'; import {Store} from '@ngrx/store'; import {GetCurrentUserResponseUserObject} from '~/business-logic/model/users/getCurrentUserResponseUserObject'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {CreateCredentialDialogComponent} from '~/features/settings/containers/admin/create-credential-dialog/create-credential-dialog.component'; @Component({ diff --git a/src/app/features/settings/settings-routing.module.ts b/src/app/features/settings/settings-routing.module.ts index 9591fe6e..24e419ce 100644 --- a/src/app/features/settings/settings-routing.module.ts +++ b/src/app/features/settings/settings-routing.module.ts @@ -4,6 +4,13 @@ import {ProfileNameComponent} from '@common/settings/admin/profile-name/profile- import {WebappConfigurationComponent} from '@common/settings/webapp-configuration/webapp-configuration.component'; import {WorkspaceConfigurationComponent} from '@common/settings/workspace-configuration/workspace-configuration.component'; import {SettingsComponent} from './settings.component'; +import {CrumbTypeEnum} from '@common/layout/breadcrumbs/breadcrumbs.component'; + +const settingsBreadcrumb = { + name: 'Settings', + url: 'settings', + type: CrumbTypeEnum.Feature +}; const routes: Routes = [ { @@ -17,14 +24,27 @@ const routes: Routes = [ }, {path: 'profile', component: ProfileNameComponent, + data: { + staticBreadcrumb:[[settingsBreadcrumb, { + name: 'Profile', + type: CrumbTypeEnum.SubFeature + }]]}, }, { path: 'webapp-configuration', component: WebappConfigurationComponent, + data: {workspaceNeutral: true, staticBreadcrumb:[[settingsBreadcrumb, { + name: 'Configuration', + type: CrumbTypeEnum.SubFeature + }]]}, }, { path: 'workspace-configuration', component: WorkspaceConfigurationComponent, + data: {workspaceNeutral: true, staticBreadcrumb:[[settingsBreadcrumb, { + name: 'Workspace', + type: CrumbTypeEnum.SubFeature + }]]}, } ] } diff --git a/src/app/features/settings/settings.module.ts b/src/app/features/settings/settings.module.ts index 86ba32b6..95666c50 100644 --- a/src/app/features/settings/settings.module.ts +++ b/src/app/features/settings/settings.module.ts @@ -24,6 +24,7 @@ import {CreateCredentialDialogComponent} from '~/features/settings/containers/ad import {RedactedArgumentsDialogComponent} from '@common/settings/admin/redacted-arguments-dialog/redacted-arguments-dialog.component'; import {LayoutModule} from '~/layout/layout.module'; import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module'; +import {LabeledFormFieldDirective} from '@common/shared/directive/labeled-form-field.directive'; @@ -56,6 +57,7 @@ import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module'; MatExpansionModule, FormsModule, LayoutModule, + LabeledFormFieldDirective, SharedPipesModule ], exports: [ diff --git a/src/app/webapp-common/workers-and-queues/workers-and-queues.component.html b/src/app/features/workers-and-queues/orchestration.component.html old mode 100755 new mode 100644 similarity index 72% rename from src/app/webapp-common/workers-and-queues/workers-and-queues.component.html rename to src/app/features/workers-and-queues/orchestration.component.html index eeb7b37d..c30637dc --- a/src/app/webapp-common/workers-and-queues/workers-and-queues.component.html +++ b/src/app/features/workers-and-queues/orchestration.component.html @@ -1,10 +1,10 @@ - + diff --git a/src/app/features/workers-and-queues/workers-and-queues-routing.module.ts b/src/app/features/workers-and-queues/workers-and-queues-routing.module.ts new file mode 100644 index 00000000..ff212e07 --- /dev/null +++ b/src/app/features/workers-and-queues/workers-and-queues-routing.module.ts @@ -0,0 +1,39 @@ +import {RouterModule, Routes} from '@angular/router'; +import {NgModule} from '@angular/core'; +import {OrchestrationComponent} from '@common/workers-and-queues/orchestration.component'; +import {WorkersComponent} from '@common/workers-and-queues/containers/workers/workers.component'; +import {QueuesComponent} from '@common/workers-and-queues/containers/queues/queues.component'; +import {WorkersAndQueuesResolver} from '~/shared/resolvers/workers-and-queues.resolver'; +import {CrumbTypeEnum} from '@common/layout/breadcrumbs/breadcrumbs.component'; + +const wQBreadcrumb = [[{ + name: 'WORKERS AND QUEUES', + type: CrumbTypeEnum.Feature +}]]; +export const routes: Routes = [ + { + path: '', + component: OrchestrationComponent, + resolve: { + queuesManager: WorkersAndQueuesResolver + }, + children: [ + {path: '', redirectTo: 'workers', pathMatch: 'full'}, + {path: 'workers', component: WorkersComponent, data: {staticBreadcrumb: wQBreadcrumb}}, + { + path: 'queues', + component: QueuesComponent, + data: {staticBreadcrumb: wQBreadcrumb, queuesManager: true} + }, + ] + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(routes) + ], + exports: [RouterModule] +}) +export class WorkersAndQueuesRoutingModule { +} diff --git a/src/app/features/workers-and-queues/workers-and-queues.module.ts b/src/app/features/workers-and-queues/workers-and-queues.module.ts index 10451d9d..9384db60 100644 --- a/src/app/features/workers-and-queues/workers-and-queues.module.ts +++ b/src/app/features/workers-and-queues/workers-and-queues.module.ts @@ -1,8 +1,8 @@ import {NgModule} from '@angular/core'; import {FormsModule} from '@angular/forms'; import {CommonModule} from '@angular/common'; -import {WorkersAndQueuesRoutingModule} from '@common/workers-and-queues/workers-and-queues-routing.module'; -import {WorkersAndQueuesComponent} from '@common/workers-and-queues/workers-and-queues.component'; +import {WorkersAndQueuesRoutingModule} from './workers-and-queues-routing.module'; +import {OrchestrationComponent} from '@common/workers-and-queues/orchestration.component'; import {WorkersComponent} from '@common/workers-and-queues/containers/workers/workers.component'; import {QueuesComponent} from '@common/workers-and-queues/containers/queues/queues.component'; import {SMSharedModule} from '@common/shared/shared.module'; @@ -41,7 +41,7 @@ import {QueuesMenuExtendedComponent} from './queues-menu-extended/queues-menu-ex FormsModule, ], declarations: [ - WorkersAndQueuesComponent, + OrchestrationComponent, WorkersComponent, WorkersTableComponent, WorkersStatsComponent, diff --git a/src/app/layout/side-nav/side-nav.component.html b/src/app/layout/side-nav/side-nav.component.html index c5a95393..c24d3bb9 100755 --- a/src/app/layout/side-nav/side-nav.component.html +++ b/src/app/layout/side-nav/side-nav.component.html @@ -20,22 +20,22 @@ routerLinkActive="active"> diff --git a/src/app/layout/side-nav/side-nav.component.ts b/src/app/layout/side-nav/side-nav.component.ts index 6467b958..7b5c4f7d 100755 --- a/src/app/layout/side-nav/side-nav.component.ts +++ b/src/app/layout/side-nav/side-nav.component.ts @@ -1,10 +1,12 @@ import {selectCurrentUser} from '@common/core/reducers/users-reducer'; import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, ViewChild} from '@angular/core'; import {Store} from '@ngrx/store'; -import {selectSelectedProjectId} from '@common/core/reducers/projects.reducer'; +import {selectDefaultNestedModeForFeature, selectSelectedProjectId} from '@common/core/reducers/projects.reducer'; import {fromEvent, Observable} from 'rxjs'; import {ConfigurationService} from '@common/shared/services/configuration.service'; import {searchDeactivate} from '@common/dashboard-search/dashboard-search.actions'; +import {selectRouterConfig} from '@common/core/reducers/router-reducer'; +import {map} from 'rxjs/operators'; @Component({ selector : 'sm-side-nav', @@ -17,13 +19,17 @@ export class SideNavComponent implements AfterViewInit { currentUser: any; environment = ConfigurationService.globalEnvironment; public scrolling: boolean; + public defaultNestedModeForFeature$: Observable<{ [p: string]: boolean }>; + public baseRouteConfig$: Observable; @ViewChild('container') container: ElementRef; constructor(public store: Store, private cdr: ChangeDetectorRef) { this.selectedProjectId$ = this.store.select(selectSelectedProjectId); + this.defaultNestedModeForFeature$ = this.store.select(selectDefaultNestedModeForFeature); this.store.select(selectCurrentUser).subscribe((res) => this.currentUser = res); + this.baseRouteConfig$ = this.store.select(selectRouterConfig).pipe(map(conf => conf?.[0])); fromEvent(window, 'resize').subscribe(() => { const scrolling = this.container.nativeElement.scrollHeight > this.container.nativeElement.clientHeight; diff --git a/src/app/shared/constants/non-common-consts.ts b/src/app/shared/constants/non-common-consts.ts index b431356d..4ab6e395 100644 --- a/src/app/shared/constants/non-common-consts.ts +++ b/src/app/shared/constants/non-common-consts.ts @@ -43,3 +43,5 @@ export const EXPERIMENTS_STATUS_LABELS = { [TaskTypeEnum.Qc] : 'Qc', [TaskTypeEnum.Custom] : 'Custom' }; + +export const hideDeleteArtifactsEntities = [EntityTypeEnum.model]; diff --git a/src/app/shared/utils/url.ts b/src/app/shared/utils/url.ts index b6b210fe..cae87240 100644 --- a/src/app/shared/utils/url.ts +++ b/src/app/shared/utils/url.ts @@ -3,4 +3,15 @@ import {HTTP} from '~/app.constants'; export const isFileserverUrl = (url: string) => url.startsWith(HTTP.FILE_BASE_URL); -export const convertToReverseProxy = (url: string) => url; +export const convertToReverseProxy = (url: string) => { + try { + const u = new URL(url); + if (!u.pathname.startsWith('/files')) { + u.protocol = window.location.protocol; + u.host = window.location.host; + u.pathname = 'files' + u.pathname; + return u.toString(); + } + } catch {} + return url; +}; diff --git a/src/app/webapp-common/angular-notifier/src/notifier.module.ts b/src/app/webapp-common/angular-notifier/src/notifier.module.ts index 2c09f515..cef8529c 100644 --- a/src/app/webapp-common/angular-notifier/src/notifier.module.ts +++ b/src/app/webapp-common/angular-notifier/src/notifier.module.ts @@ -12,11 +12,10 @@ import {NotifierConfigToken, NotifierService} from './services/notifier.service' /** * Injection Token for notifier options */ -export const NotifierOptionsToken: InjectionToken +export const notifierOptionsToken: InjectionToken = new InjectionToken('[angular-notifier] Notifier Options'); - /** * Factory for a notifier configuration with custom options * @@ -26,9 +25,7 @@ export const NotifierOptionsToken: InjectionToken * @param options - Custom notifier options * @returns - Notifier configuration as result */ -export function notifierCustomConfigFactory(options: NotifierOptions): NotifierConfig { - return new NotifierConfig(options); -} +export const notifierCustomConfigFactory = (options: NotifierOptions): NotifierConfig => new NotifierConfig(options); /** * Factory for a notifier configuration with default options @@ -38,9 +35,7 @@ export function notifierCustomConfigFactory(options: NotifierOptions): NotifierC * * @returns - Notifier configuration as result */ -export function notifierDefaultConfigFactory(): NotifierConfig { - return new NotifierConfig({}); -} +export const notifierDefaultConfigFactory = (): NotifierConfig => new NotifierConfig({}); /** * Notifier module @@ -84,14 +79,14 @@ export class NotifierModule { // Provide the options itself upfront (as we need to inject them as dependencies -- see below) { - provide: NotifierOptionsToken, + provide: notifierOptionsToken, useValue: options }, // Provide a custom notifier configuration, based on the given notifier options { deps: [ - NotifierOptionsToken + notifierOptionsToken ], provide: NotifierConfigToken, useFactory: notifierCustomConfigFactory diff --git a/src/app/webapp-common/angular-notifier/styles/themes/theme-material.scss b/src/app/webapp-common/angular-notifier/styles/themes/theme-material.scss index b815684d..cdae85ca 100644 --- a/src/app/webapp-common/angular-notifier/styles/themes/theme-material.scss +++ b/src/app/webapp-common/angular-notifier/styles/themes/theme-material.scss @@ -19,7 +19,6 @@ $notifier-shadow-color: rgba(0, 0, 0, .2) !default; } .notifier__notification { - &-message { display: inline-block; margin: { // Reset paragraph default styles @@ -31,6 +30,8 @@ $notifier-shadow-color: rgba(0, 0, 0, .2) !default; font-size: 15px; .message{ white-space: pre-line; + overflow: hidden; + text-overflow: ellipsis; } .user-action { diff --git a/src/app/webapp-common/assets/fonts/trains-icons.scss b/src/app/webapp-common/assets/fonts/trains-icons.scss index fe72fd4d..4f07fd33 100644 --- a/src/app/webapp-common/assets/fonts/trains-icons.scss +++ b/src/app/webapp-common/assets/fonts/trains-icons.scss @@ -3,7 +3,7 @@ @font-face { font-family: '#{$icomoon-font-family}'; - src: url('./#{$icomoon-font-family}.ttf?i5mliw') format('truetype'); + src: url('./#{$icomoon-font-family}.ttf?s0lnuq') format('truetype'); font-weight: normal; font-style: normal; font-display: block; @@ -24,6 +24,11 @@ -moz-osx-font-smoothing: grayscale; } +.al-ico-info-circle-outline { + &:before { + content: $al-ico-info-circle-outline; + } +} .al-ico-ghost { &:before { content: $al-ico-ghost; diff --git a/src/app/webapp-common/assets/fonts/trains.ttf b/src/app/webapp-common/assets/fonts/trains.ttf index 0fb6652b..d4617e4d 100644 Binary files a/src/app/webapp-common/assets/fonts/trains.ttf and b/src/app/webapp-common/assets/fonts/trains.ttf differ diff --git a/src/app/webapp-common/assets/fonts/variables.scss b/src/app/webapp-common/assets/fonts/variables.scss index 107d325e..a1dad46f 100755 --- a/src/app/webapp-common/assets/fonts/variables.scss +++ b/src/app/webapp-common/assets/fonts/variables.scss @@ -1,6 +1,7 @@ $icomoon-font-family: "trains" !default; $icomoon-font-path: "fonts" !default; +$al-ico-info-circle-outline: "\e9f0"; $al-ico-ghost: "\e9ef"; $al-ico-flat-view: "\e9ee"; $al-ico-camera: "\e9ed"; diff --git a/src/app/webapp-common/assets/icons/filter-off.svg b/src/app/webapp-common/assets/icons/filter-off.svg index b03147f2..eaf1024d 100644 --- a/src/app/webapp-common/assets/icons/filter-off.svg +++ b/src/app/webapp-common/assets/icons/filter-off.svg @@ -1,14 +1,3 @@ - - - background - - - - Layer 1 - - - - - + \ No newline at end of file diff --git a/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.actions.ts b/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.actions.ts index f9f8dfe1..2fec8f8a 100644 --- a/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.actions.ts +++ b/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.actions.ts @@ -3,6 +3,7 @@ import {ExtFrame} from '@common/shared/single-graph/plotly-graph-base'; import {DebugSample} from '@common/shared/debug-sample/debug-sample.reducer'; import {ReportsApiMultiplotsResponse} from '@common/clearml-applications/report-widgets/src/app/app.reducer'; import {Task} from '~/business-logic/model/tasks/task'; +import {SingleValueTaskMetrics} from '~/business-logic/model/reports/singleValueTaskMetrics'; export const getPlot = createAction('[App] getPlot', props<{ tasks: string[]; @@ -10,6 +11,7 @@ export const getPlot = createAction('[App] getPlot', props<{ metrics: string[]; variants: string[]; company: string; + models: boolean; otherSearchParams?: URLSearchParams; }>()); @@ -19,6 +21,7 @@ export const getScalar = createAction('[App] getScalar', props<{ metrics: string[]; variants: string[]; company: string; + models: boolean; otherSearchParams?: URLSearchParams; }>()); export const getSample = createAction('[App] getSample', props<{ @@ -37,11 +40,23 @@ export const getParcoords = createAction('[App] getParcoords', props<{ company: string; otherSearchParams?: URLSearchParams; }>()); +export const getSingleValues = createAction('[App] getSingleValues', props<{ + tasks: string[]; + company: string; + models: boolean; + otherSearchParams?: URLSearchParams; +}>()); export const setPlotData = createAction('[App] setPlot', props<{ data: ReportsApiMultiplotsResponse }>()); export const setScalarData = createAction('[App] setScalar', props<{ data: ExtFrame[] }>()); export const setSampleData = createAction('[App] setSample', props<{ data: DebugSample }>()); +export const setSingleValues = createAction('[App] setSingleValues', props<{ data: SingleValueTaskMetrics }>()); export const setParallelCoordinateExperiments = createAction('[App] setParcoor', props<{ data: Task[] }>()); export const reportsPlotlyReady = createAction('[App] plotly ready'); export const setSignIsNeeded = createAction('[App] set sign is needed'); export const setNoPermissions = createAction('[App] set no permissions'); +export const setTaskData = createAction('[App] set task data', props<{ + sourceProject: string; + sourceTasks: string[]; + appId?: string; +}>()); diff --git a/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.component.html b/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.component.html index 7e2981bc..21d0b2f8 100644 --- a/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.component.html +++ b/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.component.html @@ -2,6 +2,12 @@ + + + + + View original resource + + + + + + diff --git a/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.component.scss b/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.component.scss index c3c7cf6a..b091bc2a 100644 --- a/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.component.scss +++ b/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.component.scss @@ -67,3 +67,59 @@ padding: 24px; // min-height: 150px; } + +.webapp-link { + position: absolute; + display: block; + width: 16px; + height: 16px; + top: 26px; + left: 21px; + cursor: pointer; + z-index: 2; + visibility: hidden; + + &:hover { + svg path { + fill: $blue-100; + } + } +} + +:host { + &:hover .webapp-link { + visibility: visible; + } +} + + +.webapp-link_tooltip { + display:none; + position: absolute; + left: 0; + top: 24px; + z-index: 1; + padding: 6px 8px; + font-size: 12px; + text-align: left; + color: white; + background-color: #6B7488; + text-decoration: none; + border-radius: 3px; + white-space: nowrap; +} + +a.webapp-link:hover .webapp-link_tooltip { + display: block; +} + +.webapp-link.dark-theme { + svg path { + fill: $blue-300; + } + &:hover { + svg path { + fill: $blue-400; + } + } +} diff --git a/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.component.ts b/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.component.ts index 3a12247d..a48f43bf 100644 --- a/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.component.ts +++ b/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.component.ts @@ -1,10 +1,10 @@ import {ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, OnInit, ViewChild} from '@angular/core'; import {Store} from '@ngrx/store'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; -import {Observable} from 'rxjs'; +import {MatDialog} from '@angular/material/dialog'; +import {Observable, withLatestFrom} from 'rxjs'; import {filter, map, switchMap, take} from 'rxjs/operators'; import {Environment} from '../environments/base'; -import {getParcoords, getPlot, getSample, getScalar, reportsPlotlyReady} from './app.actions'; +import {getParcoords, getPlot, getSample, getScalar, getSingleValues, reportsPlotlyReady} from './app.actions'; import { ReportsApiMultiplotsResponse, selectNoPermissions, @@ -13,6 +13,8 @@ import { selectReportsPlotlyReady, selectSampleData, selectSignIsNeeded, + selectSingleValuesData, + selectTaskData, State } from './app.reducer'; import {ExtFrame} from '@common/shared/single-graph/plotly-graph-base'; @@ -30,9 +32,10 @@ import {setCurrentDebugImage} from '@common/shared/debug-sample/debug-sample.act import {isFileserverUrl} from '~/shared/utils/url'; import {MetricValueType, SelectedMetric} from '@common/experiments-compare/experiments-compare.constants'; import {ExtraTask} from '@common/experiments-compare/dumbs/parallel-coordinates-graph/parallel-coordinates-graph.component'; +import {EventsGetTaskSingleValueMetricsResponseValues} from '~/business-logic/model/events/eventsGetTaskSingleValueMetricsResponseValues'; -type WidgetTypes = 'plot' | 'scalar' | 'sample' | 'parcoords'; +type WidgetTypes = 'plot' | 'scalar' | 'sample' | 'parcoords' | 'single'; @Component({ selector: 'sm-app-root', @@ -59,6 +62,8 @@ export class AppComponent implements OnInit { public externalTool: boolean = false; public parcoordsData: { experiments: ExtraTask[]; params: string[]; metric: SelectedMetric; valueType: MetricValueType }; @ViewChild(SingleGraphComponent) 'singleGraph': SingleGraphComponent; + public singleValueData: EventsGetTaskSingleValueMetricsResponseValues[]; + public webappLink: string; @HostListener('window:resize') onResize() { @@ -77,6 +82,7 @@ export class AppComponent implements OnInit { this.noPermissions$ = store.select(selectNoPermissions); this.searchParams = new URLSearchParams(window.location.search); this.type = this.searchParams.get('type') as WidgetTypes; + this.webappLink = this.buildSourceLink(this.searchParams, '*', null); this.singleGraphHeight = window.innerHeight; this.otherSearchParams = this.getOtherSearchParams(); this.isDarkTheme = !this.searchParams.get('light'); @@ -91,7 +97,7 @@ export class AppComponent implements OnInit { } private getOtherSearchParams() { - const paramsToRemove = ['light', 'type', 'tasks', 'metrics', 'variants', 'iterations', 'company', 'value_type']; + const paramsToRemove = ['light', 'type', 'tasks', 'models', 'objects', 'objectType', 'metrics', 'variants', 'iterations', 'company', 'value_type']; const otherSearchParams = new URLSearchParams(window.location.search); paramsToRemove.forEach(key => { otherSearchParams.delete(key); @@ -123,6 +129,9 @@ export class AppComponent implements OnInit { break; case 'parcoords': this.getParallelCoordinate(); + break; + case 'single': + this.getSingleValues(); } window.addEventListener('message', (e) => { @@ -134,6 +143,15 @@ export class AppComponent implements OnInit { this.hideMaximize = 'disabled'; } }); + + this.store.select(selectTaskData) + .pipe( + filter(taskData => !!taskData), + take(1)) + .subscribe(({sourceProject, sourceTasks, appId}) => { + this.webappLink = appId ? this.buildAppLink(sourceTasks, appId) : this.buildSourceLink(this.searchParams, sourceProject, sourceTasks); + this.cdr.detectChanges(); + }); } /// Merging all variants of same metric to same graph. (single experiment) @@ -169,7 +187,7 @@ export class AppComponent implements OnInit { const merged = this.mergeVariants(metricsPlots as ReportsApiMultiplotsResponse); this.plotData = Object.values(merged)[0].plotParsed; } else { - const {merged, } = prepareMultiPlots(metricsPlots); + const {merged,} = prepareMultiPlots(metricsPlots); const newGraphs = convertMultiPlots(merged); this.plotData = Object.values(newGraphs)[0]?.[0]; } @@ -264,14 +282,31 @@ export class AppComponent implements OnInit { }); } - activate = () => { - this.type !== 'sample' && loadExternalLibrary(this.store, this.environment.plotlyURL, reportsPlotlyReady); + private getSingleValues() { + this.store.select(selectSingleValuesData) + .pipe( + filter(singleValueData => !!singleValueData), + take(1) + ).subscribe(singleValueData => { + this.singleValueData = singleValueData.values; + this.cdr.detectChanges(); + }); + } + + activate = async () => { + this.activated = true; + await this.waitForVisibility(); + this.singleGraphHeight = window.innerHeight; + !['sample', 'single'].includes(this.type) && loadExternalLibrary(this.store, this.environment.plotlyURL, reportsPlotlyReady); + const models = this.searchParams.has('models') || this.searchParams.get('objectType') === 'model'; + const objects = this.searchParams.getAll('objects'); const queryParams = { - tasks: this.searchParams.getAll('tasks'), + tasks: objects.length > 0 ? objects : this.searchParams.getAll('tasks'), metrics: this.searchParams.getAll('metrics'), variants: this.searchParams.getAll('variants'), iterations: this.searchParams.getAll('iterations').map(iteration => parseInt(iteration, 10)), company: this.searchParams.get('company') || '', + models }; switch (this.type) { @@ -286,8 +321,11 @@ export class AppComponent implements OnInit { break; case 'parcoords': this.store.dispatch(getParcoords({...queryParams, otherSearchParams: this.otherSearchParams})); + break; + case 'single': + this.store.dispatch(getSingleValues({...queryParams, otherSearchParams: this.otherSearchParams})); + break; } - this.activated = true; }; @@ -339,4 +377,80 @@ export class AppComponent implements OnInit { const lastMetric = get(experimentWithCurrentMetric.last_metrics, metric) as ExtraTask['last_metrics']; return `${lastMetric.metric}/${lastMetric.variant}`; } + + private buildSourceLink(searchParams: URLSearchParams, project: string, tasks: string[]): string { + const isModels = searchParams.has('models') || this.searchParams.get('objectType') === 'model'; + const objects = searchParams.getAll('objects'); + let entityIds = objects.length > 0? objects : searchParams.getAll(isModels ? 'models' : 'tasks'); + if (entityIds.length === 0 && tasks?.length > 0) { + entityIds = tasks; + } + const isCompare = entityIds.length > 1; + let url = `${window.location.origin.replace('4201', '4200')}/projects/${project ?? '*'}/`; + if (isCompare) { + url += `${isModels ? 'compare-models;ids=' : 'compare-experiments;ids='}${entityIds.join(',')}/${this.getComparePath(this.type)}`; + } else { + url += `${isModels ? 'models/' : 'experiments/'}${entityIds}/${this.getOutputPath(isModels, this.type)}`; + } + return url; + } + + private getOutputPath(isModels: boolean, type: WidgetTypes) { + if (isModels) { + switch (type) { + case 'single': + case 'scalar': + return 'scalars'; + case 'plot': + return 'plots'; + } + } else { + switch (type) { + case 'single': + case 'scalar': + return 'info-output/metrics/scalar'; + case 'plot': + return 'info-output/metrics/plots'; + case 'sample': + return 'info-output/debugImages'; + } + } + } + + private getComparePath(type: WidgetTypes) { + switch (type) { + case 'single': + case 'scalar': + return 'scalars/graph'; + case 'plot': + return 'metrics-plots'; + case 'parcoords': + return 'hyper-params/graph'; + case 'sample': + return 'debug-images'; + } + } + + private buildAppLink(sourceTasks: string[], appId) { + const isAutoscaler = appId.includes('autoscaler'); + return `${window.location.origin.replace('4201', '4200')}/${isAutoscaler ? 'workers-and-queues/autoscalers' : 'applications'}/${appId}/info;experimentId=${sourceTasks[0]}?instancesFilter=All`; + } + + private waitForVisibility(): Promise { + return new Promise(resolve => { + if (window.innerHeight > 0) { + return resolve(true); + } + + const observer = new IntersectionObserver(entities => { + if (entities[0].intersectionRatio > 0) { + resolve(true); + observer.disconnect(); + } + }); + + observer.observe(document.body); + }); + } } + diff --git a/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.effects.ts b/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.effects.ts index 779d8921..08c48244 100644 --- a/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.effects.ts +++ b/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.effects.ts @@ -4,11 +4,11 @@ import { getParcoords, getPlot, getSample, - getScalar, + getScalar, getSingleValues, setNoPermissions, setParallelCoordinateExperiments, setPlotData, setSampleData, - setSignIsNeeded + setSignIsNeeded, setSingleValues, setTaskData } from './app.actions'; import {EMPTY, mergeMap, of, switchMap} from 'rxjs'; import {Store} from '@ngrx/store'; @@ -50,6 +50,8 @@ export class AppEffects { switchMap(action => this.httpClient.post<{ data: ReportsGetTaskDataResponse }>(`${this.basePath}/reports.get_task_data?${action.otherSearchParams.toString()}`, { id: action.tasks, + // eslint-disable-next-line @typescript-eslint/naming-convention + model_events: action.models, plots: { iters: 1, metrics: action.metrics.map(metric => ({metric, variants: action.variants})) @@ -57,7 +59,13 @@ export class AppEffects { }, {headers: this.getHeaders(action.company)} )), - mergeMap((res) => [setPlotData({data: res.data.plots as unknown as ReportsApiMultiplotsResponse})]), + mergeMap((res) => [ + setPlotData({data: res.data.plots as unknown as ReportsApiMultiplotsResponse}), + setTaskData({ + sourceProject: (res.data.tasks[0]?.project as any).id, + sourceTasks: res.data.tasks.map(t => t.id), + appId: (res.data.tasks[0] as any)?.application?.app_id?.id + })]), catchError(error => [requestFailed(error), ...(error.status === 403 ? [setNoPermissions()] : [])]) )); @@ -67,6 +75,8 @@ export class AppEffects { { id: action.tasks, // eslint-disable-next-line @typescript-eslint/naming-convention + model_events: action.models, + // eslint-disable-next-line @typescript-eslint/naming-convention scalar_metrics_iter_histogram: { metrics: action.metrics.map(metric => ({metric, variants: action.variants})) } @@ -74,7 +84,12 @@ export class AppEffects { {headers: this.getHeaders(action.company)} ).pipe( mergeMap(res => [ - setPlotData({data: res.data.scalar_metrics_iter_histogram as ReportsApiMultiplotsResponse})] + setPlotData({data: res.data.scalar_metrics_iter_histogram as ReportsApiMultiplotsResponse}), + setTaskData({ + sourceProject: (res.data.tasks[0]?.project as any).id, + sourceTasks: res.data.tasks.map(t => t.id), + appId: (res.data.tasks[0] as any)?.application?.app_id?.id + })] ), catchError(error => [requestFailed(error), ...(error.status === 403 ? [setNoPermissions()] : [])]) ) ) @@ -94,26 +109,46 @@ export class AppEffects { {headers: this.getHeaders(action.company)} ).pipe( mergeMap(res => [ - setSampleData({data: res.data.debug_images?.[0]?.iterations?.[0]?.events[0] as DebugSample}) - ]), + setSampleData({data: res.data.debug_images?.[0]?.iterations?.[0]?.events[0] as DebugSample}), + setTaskData({sourceProject: (res.data.tasks[0]?.project as any).id, sourceTasks: res.data.tasks.map(t => t.id)})]), catchError(error => [requestFailed(error), ...(error.status === 403 ? [setNoPermissions()] : [])]) ) )) ); - getExperiments$ = createEffect(() => this.actions$.pipe( + getParcoords$ = createEffect(() => this.actions$.pipe( ofType(getParcoords), - mergeMap((action) => this.httpClient.post<{data: ReportsGetTaskDataResponse}>(`${this.basePath}/reports.get_task_data?${action.otherSearchParams.toString()}`, { + mergeMap((action) => this.httpClient.post<{ data: ReportsGetTaskDataResponse }>(`${this.basePath}/reports.get_task_data?${action.otherSearchParams.toString()}`, { id: action.tasks, // eslint-disable-next-line @typescript-eslint/naming-convention only_fields: ['last_metrics', 'name', 'last_iteration', ...action.variants.map(variant => `hyperparams.${variant}`)] }) .pipe( - mergeMap(res => [setParallelCoordinateExperiments({data: res.data.tasks as unknown as Task[]})]) + mergeMap(res => [ + setParallelCoordinateExperiments({data: res.data.tasks as unknown as Task[]}), + setTaskData({sourceProject: (res.data.tasks[0]?.project as any).id, sourceTasks: res.data.tasks.map(t => t.id)}) + ]) ) )) ); + getScalarSingleValue$ = createEffect(() => this.actions$.pipe( + ofType(getSingleValues), + switchMap((action) => this.httpClient.post<{ data: ReportsGetTaskDataResponse }>(`${this.basePath}/reports.get_task_data?${action.otherSearchParams.toString()}`, { + id: action.tasks, + // eslint-disable-next-line @typescript-eslint/naming-convention + model_events: action.models, + // eslint-disable-next-line @typescript-eslint/naming-convention + single_value_metrics: {} + }) + ), + mergeMap((res: { data: ReportsGetTaskDataResponse }) => [ + setSingleValues({data: res.data.single_value_metrics[0]}), + setTaskData({sourceProject: (res.data.tasks[0]?.project as any).id, sourceTasks: res.data.tasks.map(t => t.id)}) + ] + ) + )); + signUrl = createEffect(() => this.actions$.pipe( ofType(getSignedUrl), filter(action => !!action.url), diff --git a/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.module.ts b/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.module.ts index 4ecf3c8e..56db2e92 100644 --- a/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.module.ts +++ b/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.module.ts @@ -8,7 +8,7 @@ import {AppEffects} from './app.effects'; import {StoreModule} from '@ngrx/store'; import {appReducer} from './app.reducer'; import {HttpClientModule} from '@angular/common/http'; -import {MatLegacyDialogModule as MatDialogModule} from '@angular/material/legacy-dialog'; +import {MatDialogModule} from '@angular/material/dialog'; import {ChooseColorModule} from '@common/shared/ui-components/directives/choose-color/choose-color.module'; import {SingleGraphModule} from '@common/shared/single-graph/single-graph.module'; import {DebugSampleModule} from '@common/shared/debug-sample/debug-sample.module'; @@ -20,6 +20,7 @@ import {authReducer} from '~/features/settings/containers/admin/auth.reducers'; import {extCoreModules} from '~/build-specifics'; import {SmApiRequestsService} from '~/business-logic/api-services/api-requests.service'; import {ParallelCoordinatesGraphComponent} from '@common/experiments-compare/dumbs/parallel-coordinates-graph/parallel-coordinates-graph.component'; +import {SingleValueSummaryTableComponent} from '@common/shared/single-value-summary-table/single-value-summary-table.component'; if (!localStorage.getItem('_saved_state_')) { localStorage.setItem('_saved_state_', '{}'); @@ -29,19 +30,20 @@ if (!localStorage.getItem('_saved_state_')) { declarations: [ AppComponent ], - imports: [ - BrowserAnimationsModule, - BrowserModule, - HttpClientModule, - MatDialogModule, - ChooseColorModule, - SingleGraphModule, - DebugSampleModule, - ParallelCoordinatesGraphComponent, - StoreModule.forRoot({appReducer, auth: authReducer}), - EffectsModule.forRoot([AppEffects]), - ...extCoreModules - ], + imports: [ + BrowserAnimationsModule, + BrowserModule, + HttpClientModule, + MatDialogModule, + ChooseColorModule, + SingleGraphModule, + DebugSampleModule, + ParallelCoordinatesGraphComponent, + StoreModule.forRoot({appReducer, auth: authReducer}), + EffectsModule.forRoot([AppEffects]), + ...extCoreModules, + SingleValueSummaryTableComponent + ], providers: [ApiEventsService, ApiReportsService, SmApiRequestsService, ColorHashService, BaseAdminService], bootstrap: [AppComponent] }) diff --git a/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.reducer.ts b/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.reducer.ts index dcdfe1ef..1f0b0904 100644 --- a/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.reducer.ts +++ b/src/app/webapp-common/clearml-applications/report-widgets/src/app/app.reducer.ts @@ -1,11 +1,17 @@ import {createReducer, createSelector, on} from '@ngrx/store'; -import {reportsPlotlyReady, setNoPermissions, setParallelCoordinateExperiments, setPlotData, setSampleData, setSignIsNeeded} from './app.actions'; +import {reportsPlotlyReady, setNoPermissions, setParallelCoordinateExperiments, setPlotData, setSampleData, setSignIsNeeded, setSingleValues, setTaskData} from './app.actions'; import {DebugSample} from '@common/shared/debug-sample/debug-sample.reducer'; import {MetricsPlotEvent} from '~/business-logic/model/events/metricsPlotEvent'; import {MetricValueType, SelectedMetric} from '@common/experiments-compare/experiments-compare.constants'; import {Task} from '~/business-logic/model/tasks/task'; +import {SingleValueTaskMetrics} from '~/business-logic/model/reports/singleValueTaskMetrics'; + +export interface ParCoords { + metric: SelectedMetric; + valueType: MetricValueType; + parameters: string[]; +} -export interface ParCoords {metric: SelectedMetric; valueType: MetricValueType; parameters: string[]} export interface ReportsApiMultiplotsResponse { [metric: string]: { [variant: string]: { @@ -25,21 +31,29 @@ export const appFeatureKey = 'app'; export interface State { plotData: MetricsPlotEvent[] | ReportsApiMultiplotsResponse; sampleData: DebugSample; + singleValuesData: SingleValueTaskMetrics; parallelCoordinateData: Task[]; scaleFactor: number; plotlyReady: boolean; signIsNeeded: boolean; noPermissions: boolean; + taskData: { + sourceProject: string; + sourceTasks: string[]; + appId: string; + }; } export const initialState: State = { plotData: null, sampleData: null, + singleValuesData: null, parallelCoordinateData: null, scaleFactor: 100, plotlyReady: false, signIsNeeded: false, - noPermissions: false + noPermissions: false, + taskData: null }; export const appReducer = createReducer( @@ -47,9 +61,13 @@ export const appReducer = createReducer( on(reportsPlotlyReady, (state) => ({...state, plotlyReady: true})), on(setPlotData, (state, action) => ({...state, plotData: action.data as ReportsApiMultiplotsResponse})), on(setSampleData, (state, action) => ({...state, sampleData: action.data})), + on(setSingleValues, (state, action) => ({...state, singleValuesData: action.data})), on(setParallelCoordinateExperiments, (state, action) => ({...state, parallelCoordinateData: action.data})), on(setSignIsNeeded, (state) => ({...state, signIsNeeded: true})), on(setNoPermissions, (state) => ({...state, noPermissions: true})), + on(setTaskData, (state, action) => ({...state, taskData: + {appId: action.appId, sourceTasks: action.sourceTasks, sourceProject: action.sourceProject}}) + ), ); export const selectFeature = state => state.appReducer as State; @@ -58,6 +76,12 @@ export const selectScaleFactor = createSelector(selectFeature, state => state.sc export const selectReportsPlotlyReady = createSelector(selectFeature, state => state.plotlyReady); export const selectPlotData = createSelector(selectFeature, state => state.plotData); export const selectSampleData = createSelector(selectFeature, state => state.sampleData); +export const selectSingleValuesData = createSelector(selectFeature, state => state.singleValuesData); export const selectParallelCoordinateExperiments = createSelector(selectFeature, state => state.parallelCoordinateData); export const selectSignIsNeeded = createSelector(selectFeature, state => state.signIsNeeded); export const selectNoPermissions = createSelector(selectFeature, state => state.noPermissions); +export const selectTaskData = createSelector(selectFeature, (state): { + sourceProject: string; + sourceTasks: string[]; + appId: string; +} => state.taskData); diff --git a/src/app/webapp-common/clearml-applications/report-widgets/src/styles.scss b/src/app/webapp-common/clearml-applications/report-widgets/src/styles.scss index 4597a431..414345cd 100644 --- a/src/app/webapp-common/clearml-applications/report-widgets/src/styles.scss +++ b/src/app/webapp-common/clearml-applications/report-widgets/src/styles.scss @@ -2,7 +2,40 @@ // For more information: https://material.angular.io/guide/theming @use '../../../../../../node_modules/@angular/material/index' as mat; // Plus imports for other components in your app. - +$neon-yellow: #d3ff00; +$white-primary-text: rgba(white, 0.87); +$sm-neon: ( + 50: lighten($neon-yellow, 30%), + 100: lighten($neon-yellow, 25%), + 200: lighten($neon-yellow, 20%), + 300: lighten($neon-yellow, 15%), + 400: lighten($neon-yellow, 10%), + 500: $neon-yellow, + 600: darken($neon-yellow, 10%), + 700: darken($neon-yellow, 15%), + 800: darken($neon-yellow, 20%), + 900: darken($neon-yellow, 25%), + A100: $neon-yellow, + A200: darken($neon-yellow, 5%), + A400: darken($neon-yellow, 10%), + A700: darken($neon-yellow, 15%), + contrast: ( + 50: $white-primary-text, + 100: $white-primary-text, + 200: $white-primary-text, + 300: $white-primary-text, + 400: white, + 500: white, + 600: white, + 700: white, + 800: white, + 900: white, + A100: white, + A200: white, + A400: white, + A700: white, + ) +); // Include the common styles for Angular Material. We include this here so that you only // have to load a single css file for Angular Material in your app. // Be sure that you only ever include this mixin once! @@ -14,9 +47,14 @@ $theme-primary: mat.define-palette(mat.$indigo-palette); $theme-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400); +$sm-neon-palette-primary: mat.define-palette($sm-neon); +$sm-neon-palette-accent: mat.define-palette($sm-neon, A200, A100, A400); // The warn palette is optional (defaults to red). $theme-warn: mat.define-palette(mat.$red-palette); - +$font-family-base: 'Heebo', sans-serif; // Assumes the browser default, typically `16px` +$custom-typography: mat.define-typography-config( + $font-family: $font-family-base +); // Create the theme object. A theme consists of configurations for individual // theming systems such as "color" or "typography". $theme: mat.define-light-theme(( @@ -24,13 +62,26 @@ $theme: mat.define-light-theme(( primary: $theme-primary, accent: $theme-accent, warn: $theme-warn, - ) + ), + typography: $custom-typography, + density: -2 +)); + +$sm-neon-theme: mat.define-dark-theme(( + color: ( + primary: $sm-neon-palette-primary, + accent: $sm-neon-palette-accent, + ), + typography: $custom-typography, + density: -2 )); // Include theme styles for core and each component used in your app. // Alternatively, you can import and @include the theme mixins for each component // that you are using. @include mat.dialog-theme($theme); +@include mat.slider-theme($sm-neon-theme); +@include mat.form-field-theme($theme); @import "src/app/webapp-common/shared/ui-components/styles/variables"; @@ -68,7 +119,7 @@ body { } } -.mat-dialog-container { +.mat-mdc-dialog-container { padding: 0 !important; } @@ -76,6 +127,10 @@ body { display: flex; } +.align-items-center { + align-items: center; +} + .h-100 { height: 100%; } @@ -182,6 +237,107 @@ body { cursor: default !important; } +sm-debug-image-snippet { + .image-var { + top: 8px; + bottom: unset; + } +} + + +.dark-theme .mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input { + color: rgba(255, 255, 255, 0.87); +} + .dark-theme { + .mdc-text-field--outlined:not(.mdc-text-field--disabled) { + .mdc-notched-outline__leading, .mdc-notched-outline__notch, .mdc-notched-outline__trailing { + border-color: $blue-500; + border-width: 1px; + } + + &:not(.mdc-text-field--focused):hover .mdc-notched-outline { + .mdc-notched-outline__leading, .mdc-notched-outline__notch, .mdc-notched-outline__trailing { + border-color: $blue-450; + } + } + + &.mdc-text-field--focused { + .mdc-notched-outline__leading, .mdc-notched-outline__notch, .mdc-notched-outline__trailing { + border-color: $blue-400; + } + } + } + } + +.dark-theme, .light-theme { + .mat-mdc-form-field { + --mdc-typography-body1-font-size: 14px; + --mdc-typography-body1-line-height: 16px; + + &.mat-form-field-appearance-outline { + &.black { + background-color: #000; + + .mat-mdc-select-value, .mat-mdc-select-arrow { + color: $blue-200; + } + } + + .mat-mdc-text-field-wrapper { + .mat-mdc-form-field-flex { + height: 100%; + + .mat-mdc-form-field-infix { + min-height: 100%; + padding: 5px 0; + + .mat-mdc-input-element { + height: 26px; + } + } + + .mat-mdc-form-field-icon-suffix { + line-height: 24px; + } + } + } + } + &.mat-form-field-appearance-fill { + .mdc-text-field--filled:not(.mdc-text-field--disabled) { + background-color: transparent; + + .mat-mdc-input-element { + background-color: transparent; + } + } + + &.mat-focused { + .mat-mdc-form-field-focus-overlay { + opacity: 5%; + } + } + } + } +} + +.mat-mdc-form-field.smooth-input { + height: 36px; +} + +.label-text.smoothing-text { + color: $blue-200; +} +// hide arrows for number inputs +input[type=number]::-webkit-inner-spin-button, +input[type=number]::-webkit-outer-spin-button { + -webkit-appearance: none !important; + margin: 0 !important; +} + +// hide arrows for number inputs (FireFox) +input[type=number] { + -moz-appearance: textfield !important; +} /* width */ ::-webkit-scrollbar { diff --git a/src/app/webapp-common/common-styles.scss b/src/app/webapp-common/common-styles.scss index 018b2bbf..7479dab9 100644 --- a/src/app/webapp-common/common-styles.scss +++ b/src/app/webapp-common/common-styles.scss @@ -12,94 +12,104 @@ @import "shared/ui-components/styles/material-palette"; @import "assets/fonts/trains-icons.scss"; @import "layout/layout"; -@import "shared/ui-components/styles/overrides/viewer-iterations-slider"; -// TODO(v15): As of v15 mat.legacy-core no longer includes default typography styles. -// The following line adds: -// 1. Default typography styles for all components -// 2. Styles for typography hierarchy classes (e.g. .mat-headline-1) -// If you specify typography styles for the components you use elsewhere, you should delete this line. -// If you don't need the default component typographies but still want the hierarchy styles, -// you can delete this line and instead use: -// `@include mat.legacy-typography-hierarchy(mat.define-legacy-typography-config());` -@include mat.all-legacy-component-typographies(); -@include mat.legacy-core(); -//@import "../webapp-common/shared/ui-components/styles/material-theme.scss"; - -$custom-typography: mat.define-legacy-typography-config( - $font-family: $font-family-base +@include mat.core(); +$custom-typography: mat.define-typography-config( + $font-family: $font-family-base ); -@include mat.all-legacy-component-typographies($custom-typography); +@include mat.typography-hierarchy($custom-typography); +@include mat.all-component-typographies($custom-typography); -$allegro-theme-primary: mat.define-palette($mat-allegro); -$allegro-theme-accent: mat.define-palette($mat-allegro, A400, A100, A400); -$custom-theme-primary: mat.define-palette(mat.$green-palette); -$custom-theme-accent: mat.define-palette(mat.$lime-palette, A400, A100, A400); -$custom-theme-warn: mat.define-palette(mat.$purple-palette); +$allegro-palette-primary: mat.define-palette($mat-allegro); +$allegro-palette-accent: mat.define-palette($mat-allegro, A400, A100, A400); -$sm-theme-primary: mat.define-palette($sm-purple); -$sm-theme-accent: mat.define-palette($sm-purple, A400, A100, A400); -$sm-theme-warn: mat.define-palette(mat.$purple-palette); +$sm-palette-primary: mat.define-palette($sm-purple); +$sm-palette-accent: mat.define-palette($sm-purple, A100, A200, A400); +$sm-palette-warn: mat.define-palette(mat.$purple-palette); -$green-theme: mat.define-light-theme((color: ( - primary: $custom-theme-primary, - accent: $custom-theme-accent, - warn: $custom-theme-warn -))); -$dark-theme: mat.define-dark-theme((color: ( - primary: $allegro-theme-primary, - accent: $allegro-theme-accent -))); -$light-theme: mat.define-light-theme(( +$sm-neon-palette-primary: mat.define-palette($sm-neon); +$sm-neon-palette-accent: mat.define-palette($sm-neon, A200, A100, A400); + +$dark-theme: mat.define-dark-theme(( color: ( - primary: $allegro-theme-primary, - accent: $allegro-theme-accent + primary: $allegro-palette-primary, + accent: $allegro-palette-accent ), + typography: $custom-typography, + density: -2 )); -$sm-theme: mat.define-light-theme((color: ( - primary: $sm-theme-primary, - accent: $sm-theme-accent, - warn: $sm-theme-warn -))); +$light-theme: mat.define-light-theme(( + color: ( + primary: $allegro-palette-primary, + accent: $allegro-palette-accent + ), + typography: $custom-typography, +)); -@include mat.legacy-form-field-color($light-theme); -@include mat.legacy-progress-spinner-theme($light-theme); -@include mat.legacy-progress-bar-theme($light-theme); +$sm-theme: mat.define-light-theme(( + color: ( + primary: $sm-palette-primary, + accent: $sm-palette-accent, + warn: $sm-palette-warn + ), + typography: $custom-typography +)); + +$sm-neon-theme: mat.define-dark-theme(( + color: ( + primary: $sm-neon-palette-primary, + accent: $sm-neon-palette-accent, + ), + typography: $custom-typography +)); + +//@include mat.form-field-theme($light-theme); +@include mat.progress-spinner-theme($light-theme); +@include mat.progress-bar-theme($light-theme); @include mat.datepicker-color($light-theme); +@include mat.tooltip-theme($sm-theme); +@include mat.menu-theme($light-theme); +@include mat.autocomplete-theme($light-theme); +@include mat.select-theme($light-theme); + +.dark-outline { + @include mat.menu-color($dark-theme); + @include mat.autocomplete-color($dark-theme); + @include mat.select-color($dark-theme); +} .dark-theme { - @include mat.legacy-core-theme($dark-theme); - @include mat.legacy-button-theme($dark-theme); - @include mat.legacy-slide-toggle-color($green-theme); - @include mat.legacy-radio-color($green-theme); - @include mat.legacy-select-color($dark-theme); - @include mat.legacy-menu-color($light-theme); - @include mat.legacy-autocomplete-color($light-theme); - @include mat.pseudo-checkbox-color($light-theme); - @include mat.divider-color($light-theme); + // @include mat.all-component-themes($dark-theme); + @include mat.core-theme($dark-theme); + @include mat.form-field-theme($dark-theme); + @include mat.input-theme($dark-theme); + @include mat.dialog-theme($dark-theme); + @include mat.chips-theme($dark-theme); + @include mat.button-theme($dark-theme); + @include mat.fab-theme($dark-theme); + @include mat.icon-button-theme($dark-theme); + @include mat.slide-toggle-theme($sm-neon-theme); + @include mat.slider-theme($sm-neon-theme); + @include mat.radio-color($dark-theme); + @include mat.divider-color($dark-theme); + @include mat.checkbox-theme($dark-theme); + @include mat.list-theme($dark-theme); + --mdc-typography-body1-letter-spacing: 0; + --mdc-typography-button-letter-spacing: 0; - .mat-checkbox-frame, - .mat-radio-outer-circle { - border-color: $blue-400; + .mat-mdc-checkbox .mdc-checkbox { + --mdc-checkbox-selected-icon-color: #{$purple}; + --mdc-checkbox-selected-hover-icon-color: #{$purple}; + --mdc-checkbox-selected-focus-icon-color: #{$purple}; } .mat-expansion-panel-header-description, .mat-expansion-indicator:after { color: $white; } - .light-theme .mat-radio-button.mat-radio-disabled .mat-radio-outer-circle, - .light-theme .mat-radio-button.mat-radio-disabled .mat-radio-label-content { - border-color: $blue-200 !important; - color: $blue-200 !important; - } - - .light-theme .mat-radio-button.mat-radio-disabled .mat-radio-inner-circle { - background-color: transparent !important; - } - .link { &:hover { text-decoration: underline; @@ -109,50 +119,34 @@ $sm-theme: mat.define-light-theme((color: ( } .light-theme { - @include mat.legacy-core-color($light-theme); - @include mat.legacy-button-color($light-theme); - @include mat.legacy-slide-toggle-color($sm-theme); - // @include mat.radio-color($sm-theme); - @include mat.legacy-radio-theme($sm-theme); - // @include mat.select-color($light-theme); - @include mat.legacy-select-theme($light-theme); - @include mat.legacy-menu-color($light-theme); - @include mat.legacy-autocomplete-color($light-theme); - @include mat.pseudo-checkbox-color($light-theme); + @include mat.core-color($light-theme); + @include mat.form-field-color($light-theme); + @include mat.input-color($light-theme); + @include mat.dialog-color($light-theme); + @include mat.chips-color($light-theme); + @include mat.button-color($light-theme); + @include mat.fab-color($light-theme); + @include mat.icon-button-color($light-theme); + @include mat.slide-toggle-color($sm-theme); + @include mat.slider-color($sm-theme); + @include mat.radio-color($sm-theme); @include mat.divider-color($light-theme); + @include mat.checkbox-color($sm-theme); + @include mat.list-color($light-theme); + + --mdc-typography-body1-letter-spacing: 0; + --mdc-typography-button-letter-spacing: 0; mat-progress-bar { border-radius: 4px; box-shadow: 0 0 0 1px $white, 0 0 0 3px lighten($purple, 30%); + --mdc-linear-progress-active-indicator-color: #{lighten($purple, 10%)}; + --mdc-linear-progress-track-height: 12px; } - .mat-progress-bar-fill::after { - background-color: lighten($purple, 10%); - } - - .mat-checkbox-frame, - .mat-radio-outer-circle { - border-color: $purple; - } - - .mat-radio-button.mat-accent.disabled, .mat-radio-button.mat-accent.disabled.mat-radio-checked { - .mat-radio-outer-circle, .mat-radio-inner-circle { - border-color: $blue-300; - } - - .mat-radio-inner-circle { - background-color: $blue-300; - } - } - - .light-theme .mat-radio-button.mat-radio-disabled .mat-radio-outer-circle, - .light-theme .mat-radio-button.mat-radio-disabled .mat-radio-label-content { - border-color: $blue-200 !important; - color: $blue-200 !important; - } - - .light-theme .mat-radio-button.mat-radio-disabled .mat-radio-inner-circle { - background-color: transparent !important; + .mat-mdc-radio-button, .mat-mdc-radio-button.mat-accent { + --mdc-radio-disabled-selected-icon-color: #{$blue-300}; + --mdc-radio-disabled-unselected-icon-color: #{$blue-300}; } .mat-drawer { @@ -163,6 +157,18 @@ $sm-theme: mat.define-light-theme((color: ( color: $blue-300; } + .mat-mdc-nav-list { + --mdc-list-list-item-label-text-size: 13px; + --mdc-list-list-item-label-text-weight: 500; + --mdc-list-list-item-label-text-color: #{$blue-400}; + --mdc-list-list-item-selected-label-text-color: white; + + .mat-mdc-list-item.selected { + .mdc-list-item__primary-text { + color: white; + } + } + } } * { @@ -249,33 +255,33 @@ hr { } } -// fix for calendar v15 mix with v14 -.dark-theme, .light-theme { - .mat-datepicker-content { - .mat-mdc-icon-button.mat-mdc-button-base { - width: 40px; - height: 40px; - padding: 8px; - } - - .mat-calendar-body-selected { - background-color: $blue-200; - } - - .mat-mdc-button:not(:disabled) { - color: $blue-700; - } - - .mat-calendar-body-label, .mat-calendar-period-button { - font-size: 14px; - font-weight: 500; - } - - .mat-calendar-hidden-label { - display: none; - } - } -} +//// fix for calendar v15 mix with v14 +//.dark-theme, .light-theme { +// .mat-datepicker-content { +// .mat-mdc-icon-button.mat-mdc-button-base { +// width: 40px; +// height: 40px; +// padding: 8px; +// } +// +// .mat-calendar-body-selected { +// background-color: $blue-200; +// } +// +// .mat-mdc-button:not(:disabled) { +// color: $blue-700; +// } +// +// .mat-calendar-body-label, .mat-calendar-period-button { +// font-size: 14px; +// font-weight: 500; +// } +// +// .mat-calendar-hidden-label { +// display: none; +// } +// } +//} mat-expansion-panel { box-shadow: unset; @@ -309,31 +315,28 @@ mat-expansion-panel { background: $faint-gray !important; } -.mat-slide-toggle-label { - display: flex !important; -} +.mat-mdc-radio-button.sm { + --mdc-radio-state-layer-size: 16px; -// Cancel bootstrap css on material component -mat-radio-group mat-radio-button label.mat-radio-label { - display: inline-flex; - margin-bottom: 0; -} - -mat-radio-button.sm { - .mat-radio-container, - .mat-radio-outer-circle, - .mat-radio-inner-circle { - width: 16px; + .mdc-radio { height: 16px; } - .mat-radio-input { - height: auto; + + .mdc-radio__background { + width: 16px; + height: 16px; + + .mdc-radio__inner-circle { + top: -2px; + left: -2px; + } } - .mat-radio-ripple{ + + .mat-radio-ripple { height: 32px; width: 32px; - left: calc(50% - 16px); - top: calc(50% - 16px); + left: calc(50% - 18px); + top: calc(50% - 18px); border-radius: 100%; } } @@ -357,12 +360,10 @@ button { .background-neon-green { background-color: $neon-green !important; - background: $neon-green !important; } .background-neon-yellow { background-color: $neon-yellow !important; - background: $neon-yellow !important; } .color-neon-green { @@ -388,6 +389,7 @@ button { justify-content: center; height: 100%; width: 100%; + margin-top: 50px; } .empty-menu { @@ -510,24 +512,27 @@ body .clean-list { list-style-type: none; } -.mat-tooltip { +.mat-mdc-tooltip { &.sm-tooltip { - background-color: $purple; - box-shadow: 0 -2px 8px 0 rgba(0, 0, 0, 0.2); - font-family: 'Heebo', sans-serif; - font-size: 11px; - line-height: 1.55; - letter-spacing: 0.3px; - color: #ffffff; - word-break: break-word; - max-width: 400px; + --mdc-plain-tooltip-container-color: #{$purple}; + + .mdc-tooltip__surface { + max-width: 400px; + font-size: 11px; + line-height: 1.55; + letter-spacing: 0.3px; + } &.validation { - background-color: #ff001f; + .mdc-tooltip__surface { + --mdc-plain-tooltip-container-color: #{$strong-red}; + } } &.break-line { - white-space: pre-line; + .mdc-tooltip__surface { + white-space: pre-line; + } } } @@ -539,7 +544,7 @@ body .clean-list { // --------------------------------old------------------------------------------ @import "shared/ui-components/styles/index"; -.mat-dialog-container { +.mat-mdc-dialog-container { box-shadow: none !important; background-color: transparent !important; } @@ -561,15 +566,21 @@ html { overflow: hidden; } - .mat-menu-panel { - max-width: none; + .mat-mdc-menu-panel.mat-mdc-menu-panel { + max-width: 450px; min-width: 114px; min-height: 32px; &.custom-columns { width: 370px; } + + sm-checkbox-three-state-list { + min-width: 160px; + display: block; + } } + .ico-chk { width: 24px; display: inline-block; @@ -583,24 +594,55 @@ html { background: $blue-25; color: $blue-400; border-bottom: 1px solid $blue-200; + font-size: 14px; } -.mat-menu-content { - .mat-menu-item { +.light-theme { + .mat-mdc-menu-content { + .mat-mdc-menu-item { + .mdc-list-item__primary-text { + --mdc-list-list-item-label-text-color: rgba(0, 0, 0, 0.87); + } + } + } +} + +.mat-mdc-menu-content { + padding: 4px 0 !important; + + .mat-mdc-menu-item { + margin: 0 4px; + width: calc(100% - 8px); height: 40px; + min-height: 40px; + --mdc-typography-body1-line-height: 20px; font-size: 14px; + --mdc-typography-body1-font-size: 14px; padding: 0 32px 0 12px; border-radius: 4px; - > .al-icon { - margin-right: 12px; + + .mdc-list-item__primary-text { + --mdc-typography-body1-line-height: 20px; + display: flex; + align-items: center; + gap: 0 12px; + flex-grow: 1; + overflow: hidden; + text-overflow: ellipsis; } } hr { - margin: 4px -4px; + margin: 4px 0; } } +.mat-mdc-list-item { + --mdc-list-list-item-label-text-size: 14px; + --mdc-list-list-item-label-text-line-height: 40px; + --mdc-list-list-item-one-line-container-height: 40px; +} + // hide arrows for number inputs input[type=number]::-webkit-inner-spin-button, input[type=number]::-webkit-outer-spin-button { @@ -641,6 +683,21 @@ as-split { } } +.dark-theme .light-theme .as-horizontal > .as-split-gutter { + background-color: transparent !important; + + .as-split-gutter-icon { + background-color: transparent !important; + border-left: solid 1px #DEE1E9; + border-right: none; + background-image: none !important; + + &:hover { + border-left: $purple solid 2px; + } + } +} + .notifier__container { ul { margin: 0; @@ -648,10 +705,10 @@ as-split { } $type-colors: ( - string: #ff8400, - number: $neon-yellow, - boolean: #b938a4, - date: #05668D, + string: #ff8400, + number: $neon-yellow, + boolean: #b938a4, + date: #05668D, ); @@ -688,25 +745,17 @@ $type-colors: ( } } -.mat-checkbox label { - margin: 0; - display: inline-flex; -} - .image-viewer-dialog { - .mat-dialog-container { + .mat-mdc-dialog-container { padding: 0; border-radius: 0; } } //material menu -body .mat-menu-content:not(:empty) { - padding: 4px; - +body .mat-mdc-menu-content:not(:empty) { .search-results { overflow: auto; - max-width: 222px; } .fixed-options-subheader { @@ -717,29 +766,6 @@ body .mat-menu-content:not(:empty) { } } -body .mat-menu-panel .mat-form-field.tags-menu-input { - .mat-form-field-wrapper { - padding: 0; - - .mat-form-field-flex { - padding: 0 14px; - align-items: center; - - .mat-form-field-infix, .mat-form-field-suffix { - display: flex; - align-items: center; - padding: 10px 0; - border: 0; - font-size: 14px; - } - } - - .mat-form-field-underline { - bottom: unset; - } - } -} - .hyper-parameters-tooltip { white-space: pre-line; text-align: left !important; @@ -823,7 +849,7 @@ button.btn.button-outline-dark { .cdk-drag-preview.form-group-drag { padding: 8px 16px 32px 16px; border-radius: 4px; - border: solid 1px #d4d6e0; + border: solid 1px $cloudy-blue; background-color: white; } @@ -885,3 +911,22 @@ button.btn.button-outline-dark { padding: 0 !important; } } + +.cml-dialog { + border-radius: 4px; + + .mdc-dialog .mdc-dialog__content { + padding: 0 32px; + max-height: 90vh; + } + + .mdc-dialog__actions { + padding: 24px 0; + justify-content: center; + } +} + +.select-panel-width { + min-width: fit-content; + max-width: 50vw !important; +} diff --git a/src/app/webapp-common/constants.ts b/src/app/webapp-common/constants.ts index de78f68e..7bec6d19 100644 --- a/src/app/webapp-common/constants.ts +++ b/src/app/webapp-common/constants.ts @@ -108,3 +108,5 @@ export const MESSAGES_SEVERITY = { INFO: 'info' as MessageSeverityEnum, WARN: 'warn' as MessageSeverityEnum }; + +export const rootProjectsPageSize = 50; diff --git a/src/app/webapp-common/core/actions/projects.actions.ts b/src/app/webapp-common/core/actions/projects.actions.ts index 462a792a..83a849d2 100755 --- a/src/app/webapp-common/core/actions/projects.actions.ts +++ b/src/app/webapp-common/core/actions/projects.actions.ts @@ -4,7 +4,7 @@ import {ProjectsUpdateRequest} from '~/business-logic/model/projects/projectsUpd import {ModelsPublishManyResponse} from '~/business-logic/model/models/modelsPublishManyResponse'; import {ModelsArchiveManyResponse} from '~/business-logic/model/models/modelsArchiveManyResponse'; import {ModelsDeleteManyResponse} from '~/business-logic/model/models/modelsDeleteManyResponse'; -import {archivedSelectedModels} from '@common/models/actions/models-menu.actions'; +import {archiveSelectedModels} from '@common/models/actions/models-menu.actions'; import {TasksResetManyResponse} from '~/business-logic/model/tasks/tasksResetManyResponse'; import {TasksEnqueueManyResponse} from '~/business-logic/model/tasks/tasksEnqueueManyResponse'; import {TasksArchiveManyResponse} from '~/business-logic/model/tasks/tasksArchiveManyResponse'; @@ -14,6 +14,8 @@ import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; import {MetricColumn} from '@common/shared/utils/tableParamEncode'; import {ProjectStatsGraphData} from '@common/core/reducers/projects.reducer'; import {User} from '~/business-logic/model/users/user'; +import {ProjectsGetAllResponseSingle} from '~/business-logic/model/projects/projectsGetAllResponseSingle'; +import {TaskStatusEnum} from '~/business-logic/model/tasks/taskStatusEnum'; export const PROJECTS_PREFIX = '[ROOT_PROJECTS] '; @@ -31,11 +33,6 @@ export const updateProject = createAction( props<{ id: string; changes: Partial }>() ); -export const setAllProjects = createAction( - PROJECTS_PREFIX + 'SET_PROJECTS', - props<{ projects: Project[]; updating?: boolean }>() -); - export const resetProjects = createAction(PROJECTS_PREFIX + 'RESET_PROJECTS'); export const refetchProjects = createAction(PROJECTS_PREFIX + 'REFETCH_PROJECTS'); @@ -56,15 +53,16 @@ export const setSelectedProjectId = createAction( PROJECTS_PREFIX + 'SET_SELECTED_PROJECT_ID', props<{ projectId: string; example?: boolean }>() ); -export const deletedProjectFromRoot = createAction( - PROJECTS_PREFIX + 'DELETE_PROJECT_FROM_ROOT', - props<{ project: Project }>() -); export const setSelectedProject = createAction( PROJECTS_PREFIX + 'SET_SELECTED_PROJECT', props<{ project: Project }>() ); +export const setProjectAncestors = createAction( + PROJECTS_PREFIX + 'SET_PROJECT_ANCESTORS', + props<{ projects: Project[] }>() +); + export const setSelectedProjectStats = createAction( PROJECTS_PREFIX + '[set selected project statistics]', props<{ project: Project }>() @@ -99,7 +97,7 @@ export const getCompanyTags = createAction( export const getProjectsTags = createAction( PROJECTS_PREFIX + '[get projects tags]', - props<{entity: string}>() + props<{ entity: string }>() ); export const setTagsFilterByProject = createAction( @@ -119,7 +117,7 @@ export const setCompanyTags = createAction( export const setMainPageTagsFilter = createAction( PROJECTS_PREFIX + '[set main page tags filters]', - props<{ tags: string[] }>() + props<{ tags: string[]; feature: string }>() ); export const setMainPageTagsFilterMatchMode = createAction( @@ -134,7 +132,7 @@ export const addProjectTags = createAction( export const openTagColorsMenu = createAction( PROJECTS_PREFIX + '[open tag colors]', - props<{tags: string[]}>() + props<{ tags: string[] }>() ); export const setTagColors = createAction( @@ -144,7 +142,12 @@ export const setTagColors = createAction( export const openMoreInfoPopup = createAction( PROJECTS_PREFIX + '[open more info popup]', - props<{ parentAction: ReturnType; operationName: string; entityType: EntityTypeEnum; res: ModelsPublishManyResponse | ModelsArchiveManyResponse | ModelsDeleteManyResponse | TasksResetManyResponse | TasksEnqueueManyResponse | TasksArchiveManyResponse | TasksPublishManyResponse | TasksStopManyResponse }>() + props<{ + parentAction: ReturnType; + operationName: string; + entityType: EntityTypeEnum; + res: ModelsPublishManyResponse | ModelsArchiveManyResponse | ModelsDeleteManyResponse | TasksResetManyResponse | TasksEnqueueManyResponse | TasksArchiveManyResponse | TasksPublishManyResponse | TasksStopManyResponse + }>() ); export const setMetricVariant = createAction( @@ -153,6 +156,11 @@ export const setMetricVariant = createAction( ); export const fetchGraphData = createAction(PROJECTS_PREFIX + '[fetch stats for project graph]'); +export const toggleState = createAction( + PROJECTS_PREFIX + '[toggle state]', + props<{ state: TaskStatusEnum }>() +); + export const setGraphData = createAction( PROJECTS_PREFIX + '[set project stats]', props<{ stats: ProjectStatsGraphData[] }>() @@ -193,4 +201,16 @@ export const setDefaultNestedModeForFeature = createAction( props<{ feature: string; isNested: boolean }>() ); +export const resetTablesFilterProjectsOptions = createAction( + PROJECTS_PREFIX + ' [reset tables filter projects options]' +); +export const getTablesFilterProjectsOptions = createAction( + PROJECTS_PREFIX + ' [get tables filter projects options]', + props<{ searchString: string; loadMore: boolean }>() +); + +export const setTablesFilterProjectsOptions = createAction( + PROJECTS_PREFIX + ' [set tables filter projects options]', + props<{ projects: Partial[]; scrollId: string; loadMore?: boolean }>() +); diff --git a/src/app/webapp-common/core/actions/router.actions.ts b/src/app/webapp-common/core/actions/router.actions.ts index a0bb8c34..611c7825 100755 --- a/src/app/webapp-common/core/actions/router.actions.ts +++ b/src/app/webapp-common/core/actions/router.actions.ts @@ -1,9 +1,12 @@ import {ISmAction} from '../models/actions'; -import {NAVIGATION_PREFIX, NAVIGATION_ACTIONS} from '~/app.constants'; +import {NAVIGATION_ACTIONS, NAVIGATION_PREFIX} from '~/app.constants'; import {Action, createAction, props} from '@ngrx/store'; import {Params} from '@angular/router'; import {FilterMetadata} from 'primeng/api/filtermetadata'; import {SortMeta} from 'primeng/api'; +import {CrumbTypeEnum, IBreadcrumbsLink} from "@common/layout/breadcrumbs/breadcrumbs.component"; + +export const BREADCRUMBS_PREFIX = 'BREADCRUMBS_'; // TODO: remove this action... @@ -14,23 +17,21 @@ export class NavigateTo implements ISmAction { url: string; params?: Params; unGuard?: boolean; - }) {} + }) { + } } export class NavigationEnd implements Action { readonly type = NAVIGATION_ACTIONS.NAVIGATION_END; } -export class SetRouterSegments implements Action { - readonly type = NAVIGATION_ACTIONS.SET_ROUTER_SEGMENT; - - constructor(public payload: { +export const setRouterSegments = createAction( + NAVIGATION_ACTIONS.SET_ROUTER_SEGMENT, props<{ url: string; params: Params; queryParams: Params; config: string[]; - }) {} -} + }>()); export const setURLParams = createAction( NAVIGATION_PREFIX + 'SET_URL_PARAMS', @@ -44,3 +45,14 @@ export const setURLParams = createAction( version?: string; }>() ); + +export const setBreadcrumbs = createAction( + BREADCRUMBS_PREFIX + 'SET_BREADCRUMBS', + props<{ breadcrumbs: IBreadcrumbsLink[][]}>() +); + +export const setTypeBreadcrumbs = createAction( + BREADCRUMBS_PREFIX + 'SET_TYPE_BREADCRUMBS', + props<{ breadcrumb: IBreadcrumbsLink; type?: CrumbTypeEnum }>() +); + diff --git a/src/app/webapp-common/core/effects/common-auth.effects.ts b/src/app/webapp-common/core/effects/common-auth.effects.ts index 8c98942a..592bb72e 100644 --- a/src/app/webapp-common/core/effects/common-auth.effects.ts +++ b/src/app/webapp-common/core/effects/common-auth.effects.ts @@ -13,7 +13,7 @@ import {AdminService} from '~/shared/services/admin.service'; import {selectDontShowAgainForBucketEndpoint, selectS3BucketCredentialsBucketCredentials, selectSignedUrl} from '@common/core/reducers/common-auth-reducer'; import {EMPTY, of} from 'rxjs'; import {S3AccessResolverComponent} from '@common/layout/s3-access-resolver/s3-access-resolver.component'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {setCredentialLabel} from '../actions/common-auth.actions'; import {SignResponse} from '@common/settings/admin/base-admin-utils'; diff --git a/src/app/webapp-common/core/effects/layout.effects.ts b/src/app/webapp-common/core/effects/layout.effects.ts index 9d252210..6ac18208 100755 --- a/src/app/webapp-common/core/effects/layout.effects.ts +++ b/src/app/webapp-common/core/effects/layout.effects.ts @@ -7,7 +7,7 @@ import {bufferTime, filter, map, mergeMap, switchMap, take} from 'rxjs/operators import {ApiTasksService} from '~/business-logic/api-services/tasks.service'; import {EMPTY, Observable, of} from 'rxjs'; import {ApiModelsService} from '~/business-logic/api-services/models.service'; -import {MatLegacyDialog as MatDialog, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MatDialog, MatDialogRef} from '@angular/material/dialog'; import {AlertDialogComponent} from '../../shared/ui-components/overlay/alert-dialog/alert-dialog.component'; import {NotifierService} from '../../angular-notifier'; import {requestFailed} from '@common/core/actions/http.actions'; diff --git a/src/app/webapp-common/core/effects/projects.effects.ts b/src/app/webapp-common/core/effects/projects.effects.ts index bec15471..6063a895 100755 --- a/src/app/webapp-common/core/effects/projects.effects.ts +++ b/src/app/webapp-common/core/effects/projects.effects.ts @@ -3,26 +3,23 @@ import {Store} from '@ngrx/store'; import {Actions, createEffect, ofType} from '@ngrx/effects'; import {ApiProjectsService} from '~/business-logic/api-services/projects.service'; import * as actions from '../actions/projects.actions'; -import {setShowHidden} from '../actions/projects.actions'; -import {catchError, expand, filter, map, mergeMap, reduce, switchMap, withLatestFrom} from 'rxjs/operators'; +import {setProjectAncestors, setShowHidden, setTablesFilterProjectsOptions} from '../actions/projects.actions'; +import {catchError, debounceTime, filter, map, mergeMap, switchMap, withLatestFrom} from 'rxjs/operators'; import {requestFailed} from '../actions/http.actions'; import {activeLoader, deactivateLoader, setServerError} from '../actions/layout.actions'; import {setSelectedModels} from '../../models/actions/models-view.actions'; import {TagColorMenuComponent} from '../../shared/ui-components/tags/tag-color-menu/tag-color-menu.component'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {ApiOrganizationService} from '~/business-logic/api-services/organization.service'; import {OrganizationGetTagsResponse} from '~/business-logic/model/organization/organizationGetTagsResponse'; import {selectRouterParams} from '../reducers/router-reducer'; -import {EMPTY, forkJoin, from, of} from 'rxjs'; +import {EMPTY, forkJoin, of} from 'rxjs'; import {ProjectsGetTaskTagsResponse} from '~/business-logic/model/projects/projectsGetTaskTagsResponse'; import {ProjectsGetModelTagsResponse} from '~/business-logic/model/projects/projectsGetModelTagsResponse'; import { - selectAllProjectsUsers, - selectLastUpdate, - selectRootProjects, + selectAllProjectsUsers, selectProjectsOptionsScrollId, selectSelectedMetricVariantForCurrProject, - selectSelectedProjectId, - selectShowHidden + selectSelectedProjectId, selectShowHidden, } from '../reducers/projects.reducer'; import { OperationErrorDialogComponent @@ -33,30 +30,25 @@ import {ITask} from '~/business-logic/model/al-task'; import {TasksGetAllExRequest} from '~/business-logic/model/tasks/tasksGetAllExRequest'; import {setSelectedExperiments} from '../../experiments/actions/common-experiments-view.actions'; import {setActiveWorkspace} from '@common/core/actions/users.actions'; -import {ProjectsGetAllExResponse} from '~/business-logic/model/projects/projectsGetAllExResponse'; -import {Project} from '~/business-logic/model/projects/project'; import {ApiUsersService} from '~/business-logic/api-services/users.service'; -import {get} from 'lodash-es'; +import {escapeRegExp, get} from 'lodash-es'; +import {escapeRegex} from '@common/shared/utils/escape-regex'; import {ProjectsGetAllExRequest} from '~/business-logic/model/projects/projectsGetAllExRequest'; -import localForage from 'localforage'; -import {TIME_IN_MILLI} from '@common/shared/utils/time-util'; +import {ProjectsGetAllResponseSingle} from '~/business-logic/model/projects/projectsGetAllResponseSingle'; +import {rootProjectsPageSize} from '@common/constants'; export const ALL_PROJECTS_OBJECT = {id: '*', name: 'All Experiments'}; -interface RootCache { - time: string; - hidden: boolean; - projects: Project[]; -} + @Injectable() export class ProjectsEffects { - private pageSize: number = 1000; constructor( private actions$: Actions, private projectsApi: ApiProjectsService, private orgApi: ApiOrganizationService, private store: Store, private dialog: MatDialog, private tasksApi: ApiTasksService, private usersApi: ApiUsersService, - ) {} + ) { + } activeLoader = createEffect(() => this.actions$.pipe( ofType(actions.setSelectedProjectId), @@ -64,83 +56,92 @@ export class ProjectsEffects { map(action => activeLoader(action.type)) )); - getProjects$ = createEffect(() => this.actions$.pipe( - ofType(actions.getAllSystemProjects), - withLatestFrom( - this.store.select(selectShowHidden), - this.store.select(selectLastUpdate), - ), - switchMap(([, showHidden, lastUpdate]) => !lastUpdate ? from(localForage.getItem('rootProjects')) - .pipe( - map((cache: RootCache) => - [showHidden, lastUpdate, - (new Date(cache?.time)).getTime() > (new Date()).getTime() - TIME_IN_MILLI.ONE_HOUR && - cache.projects?.length > 0 && - showHidden === cache.hidden ? cache : null - ]) - ) : of([showHidden, lastUpdate, null]) - ), - switchMap(([showHidden, lastUpdate, cache]: [boolean, string, RootCache]) => { - if (cache) { - return [ - actions.setAllProjects({projects: cache.projects, updating: false}), - actions.setLastUpdate({lastUpdate: cache.time}), - actions.getAllSystemProjects() - ]; - } - const cacheTime = (new Date()).toISOString(); - const query = { - /* eslint-disable @typescript-eslint/naming-convention */ - scroll_id: null, - size: this.pageSize, - order_by: ['last_update'], - ...(lastUpdate && {last_update: [lastUpdate, null]}), - only_fields: ['name', 'company', 'last_update'], - search_hidden: showHidden - /* eslint-enable @typescript-eslint/naming-convention */ - } as ProjectsGetAllExRequest; - return this.projectsApi.projectsGetAllEx(query) - .pipe( - expand((res: ProjectsGetAllExResponse) => res.scroll_id && res.projects.length >= this.pageSize ? - this.projectsApi.projectsGetAllEx({ - ...query, - // eslint-disable-next-line @typescript-eslint/naming-convention - scroll_id: res.scroll_id, - }) : - EMPTY - ), - reduce((acc, res: ProjectsGetAllExResponse) => acc.concat(res.projects), []), - withLatestFrom(this.store.select(selectRootProjects)), - mergeMap(([projects, rootProjects]) => [ - actions.setLastUpdate({lastUpdate: cacheTime}), - actions.setAllProjects({ - projects: projects as Project[], - updating: rootProjects?.length > 0 - }), - ]) - ); - }), - )); - updateProjectsCache$ = createEffect(() => this.actions$.pipe( - ofType(actions.setAllProjects, actions.deletedProjectFromRoot, actions.updateProjectCompleted), - withLatestFrom( - this.store.select(selectRootProjects), - this.store.select(selectLastUpdate), - this.store.select(selectShowHidden), - ), - map(([, projects, lastUpdate, hidden]) => localForage.setItem('rootProjects', { - time: lastUpdate, - hidden, - projects - })) - ), {dispatch: false}); + getTablesFilterProjectsOptions$ = createEffect(() => this.actions$.pipe( + ofType(actions.getTablesFilterProjectsOptions), + debounceTime(300), + withLatestFrom( + this.store.select(selectShowHidden), + this.store.select(selectProjectsOptionsScrollId), + ), + switchMap(([action, showHidden, scrollId]) => forkJoin([ + this.projectsApi.projectsGetAllEx({ + /* eslint-disable @typescript-eslint/naming-convention */ + page_size: rootProjectsPageSize, + size: rootProjectsPageSize, + order_by: ['name'], + only_fields: ['name', 'company'], + search_hidden: showHidden, + _any_: {pattern: escapeRegex(action.searchString), fields: ['name']}, + scroll_id: !!action.loadMore && scrollId + } as ProjectsGetAllExRequest), + !action.loadMore && action.searchString?.length > 2 ? + this.projectsApi.projectsGetAllEx({ + page_size: 1, + only_fields: ['name', 'company'], + search_hidden: showHidden, + _any_: {pattern: `^${escapeRegex(action.searchString)}$`, fields: ['name', 'id']}, + /* eslint-enable @typescript-eslint/naming-convention */ + } as ProjectsGetAllExRequest).pipe(map(res => res.projects)) : + of([]) + ]) + .pipe(map(([allProjects, specificProjects]) => ({ + projects: [ + ...(specificProjects.length > 0 && allProjects.projects.some(project => project.id === specificProjects[0]?.id) ? [] : specificProjects), + ...allProjects.projects + ], + scrollId: allProjects.scroll_id, + loadMore: action.loadMore + }) + )) + ), + mergeMap((projects: { projects: ProjectsGetAllResponseSingle[]; scrollId: string }) => [setTablesFilterProjectsOptions({...projects})]) + ) + ); + resetProjects$ = createEffect(() => this.actions$.pipe( ofType(actions.resetSelectedProject), mergeMap(() => [actions.resetProjectSelection()]) )); + resetAncestorProjects$ = createEffect(() => this.actions$.pipe( + ofType(actions.setSelectedProjectId), + withLatestFrom(this.store.select(selectSelectedProjectId)), + filter(([action, prevProjectId]) => action.projectId !== prevProjectId), + mergeMap(() => [setProjectAncestors({projects: null})]) + )); + + getAncestorProjects$ = createEffect(() => this.actions$.pipe( + ofType(actions.setSelectedProject), + filter(action => !!action.project), + switchMap(action => { + const parts = action.project.name?.split('/'); + if (!action.project.id || action.project.id === ALL_PROJECTS_OBJECT.id || parts.length === 1) { + return of([{projects: []}, []]); + } + parts.pop(); + const escapedParts = parts.map(escapeRegExp); + const [simpleProjectNames, projectsNames] = parts.reduce( + ([simpleNames, names], part, index) => [ + [...simpleNames, parts.slice(0, index + 1).join('/')], + [...names, escapedParts.slice(0, index + 1).join('\\/')], + ], + [[], []] + ); + return this.projectsApi.projectsGetAllEx({ + /* eslint-disable @typescript-eslint/naming-convention */ + _any_: {fields: ['name'], pattern: projectsNames.map(name => `^${name}$`).join('|')}, + search_hidden: true + /* eslint-enable @typescript-eslint/naming-convention */ + }).pipe(map(res => [res, simpleProjectNames])); + }), + switchMap(([res, projectsNames]) => [actions.setProjectAncestors({ + projects: res?.projects?.filter(project => projectsNames.includes(project.name)) + .sort((projectA, projectB) => (projectA.name?.split('/').length >= projectB.name?.split('/').length) ? 1 : -1) + })] + ))); + resetProjectSelections$ = createEffect(() => this.actions$.pipe( ofType(actions.resetProjectSelection), mergeMap(() => [setSelectedExperiments({experiments: []}), setSelectedModels({models: []})]) @@ -176,13 +177,16 @@ export class ProjectsEffects { // eslint-disable-next-line @typescript-eslint/naming-convention switchMap(() => this.orgApi.organizationGetTags({include_system: true}) .pipe( - map((res: OrganizationGetTagsResponse) => actions.setCompanyTags({tags: res.tags, systemTags: res.system_tags})), + map((res: OrganizationGetTagsResponse) => actions.setCompanyTags({ + tags: res.tags, + systemTags: res.system_tags + })), catchError(error => [requestFailed(error)]) ) ) )); - getProjectsTags = createEffect(() => this.actions$.pipe( + getProjectsTags = createEffect(() => this.actions$.pipe( ofType(actions.getProjectsTags), // eslint-disable-next-line @typescript-eslint/naming-convention switchMap(action => this.projectsApi.projectsGetProjectTags({filter: {system_tags: [action.entity]}}) @@ -197,7 +201,7 @@ export class ProjectsEffects { ofType(actions.getTags), withLatestFrom(this.store.select(selectRouterParams).pipe( map(params => (params === null || params?.projectId === '*') ? [] : [params.projectId]))), - mergeMap(([action, projects]) => { + mergeMap(([action, projects]) => { const ids = action?.projectId ? [action.projectId] : projects; if (ids.length === 0 || !ids[0]) { return EMPTY; @@ -237,7 +241,7 @@ export class ProjectsEffects { ofType(actions.fetchGraphData), withLatestFrom( this.store.select(selectSelectedProjectId), - this.store.select(selectSelectedMetricVariantForCurrProject) + this.store.select(selectSelectedMetricVariantForCurrProject), ), filter(([, , variant]) => !!variant), switchMap(([, projectId, variant]) => { @@ -278,7 +282,6 @@ export class ProjectsEffects { resetRootProjects = createEffect(() => this.actions$.pipe( ofType(setActiveWorkspace, actions.refetchProjects, setShowHidden), - switchMap(() => from(localForage.removeItem('rootProjects'))), mergeMap(() => [ actions.resetProjects(), actions.getAllSystemProjects() diff --git a/src/app/webapp-common/core/effects/router.effects.ts b/src/app/webapp-common/core/effects/router.effects.ts index d1b5562f..19d2c952 100755 --- a/src/app/webapp-common/core/effects/router.effects.ts +++ b/src/app/webapp-common/core/effects/router.effects.ts @@ -5,7 +5,7 @@ import {uniq} from 'lodash-es'; import {map, tap} from 'rxjs/operators'; import {NAVIGATION_ACTIONS} from '~/app.constants'; import {encodeFilters, encodeOrder} from '../../shared/utils/tableParamEncode'; -import {NavigateTo, NavigationEnd, SetRouterSegments, setURLParams} from '../actions/router.actions'; +import {NavigateTo, NavigationEnd, setRouterSegments, setURLParams} from '../actions/router.actions'; @Injectable() @@ -29,7 +29,7 @@ export class RouterEffects { routerNavigationEnd = createEffect(() => this.actions$.pipe( ofType(NAVIGATION_ACTIONS.NAVIGATION_END), - map(() => new SetRouterSegments({url: this.getRouterUrl(), params: this.getRouterParams(), config: this.getRouterConfig(), queryParams: this.route.snapshot.queryParams})) + map(() => setRouterSegments({url: this.getRouterUrl(), params: this.getRouterParams(), config: this.getRouterConfig(), queryParams: this.route.snapshot.queryParams})) )); setTableParams = createEffect(() => this.actions$.pipe( diff --git a/src/app/webapp-common/core/reducers/projects.reducer.ts b/src/app/webapp-common/core/reducers/projects.reducer.ts index 3db30348..ced1c757 100755 --- a/src/app/webapp-common/core/reducers/projects.reducer.ts +++ b/src/app/webapp-common/core/reducers/projects.reducer.ts @@ -5,9 +5,9 @@ import {Project} from '~/business-logic/model/projects/project'; import {getSystemTags} from '~/features/experiments/shared/experiments.utils'; import {ITableExperiment} from '../../experiments/shared/common-experiment-model.model'; import {MetricColumn} from '@common/shared/utils/tableParamEncode'; -import {sortByField} from '@common/tasks/tasks.utils'; -import {ProjectsGetAllResponseSingle} from '~/business-logic/model/projects/projectsGetAllResponseSingle'; import {User} from '~/business-logic/model/users/user'; +import {ProjectsGetAllResponseSingle} from '~/business-logic/model/projects/projectsGetAllResponseSingle'; +import {selectRouterConfig} from "@common/core/reducers/router-reducer"; export interface ProjectStatsGraphData { @@ -23,6 +23,7 @@ export interface ProjectStatsGraphData { export interface RootProjects { projects: Project[]; selectedProject: Project; + projectAncestors: Project[]; archive: boolean; deep: boolean; projectTags: string[]; @@ -32,22 +33,26 @@ export interface RootProjects { tagsFilterByProject: boolean; graphVariant: { [project: string]: MetricColumn }; graphData: ProjectStatsGraphData[]; + hiddenStates: { [state: string]: boolean }; lastUpdate: string; users: User[]; allUsers: User[]; extraUsers: User[]; showHidden: boolean; hideExamples: boolean; - mainPageTagsFilter: string[]; + mainPageTagsFilter: { [Feature: string]: string[] }; mainPageTagsFilterMatchMode: string; defaultNestedModeForFeature: { [feature: string]: boolean }; + tablesFilterProjectsOptions: Partial[]; + projectsOptionsScrollId: string; } const initRootProjects: RootProjects = { - mainPageTagsFilter: [], + mainPageTagsFilter: {}, mainPageTagsFilterMatchMode: 'AND', projects: null, selectedProject: null, + projectAncestors: null, archive: false, deep: false, projectTags: [], @@ -57,25 +62,30 @@ const initRootProjects: RootProjects = { tagsFilterByProject: true, graphVariant: {}, graphData: null, + hiddenStates: {}, lastUpdate: null, users: [], allUsers: [], extraUsers: [], showHidden: false, hideExamples: false, - defaultNestedModeForFeature: {} + defaultNestedModeForFeature: {}, + tablesFilterProjectsOptions: null, + projectsOptionsScrollId: null }; export const projects = state => state.rootProjects as RootProjects; export const selectRootProjects = createSelector(projects, (state): Project[] => state.projects); -export const selectSelectedProject = createSelector(projects, (state): ProjectsGetAllResponseSingle => state.selectedProject); +export const selectSelectedProject = createSelector(projects, state => state.selectedProject); +export const selectProjectAncestors = createSelector(projects, state => state.projectAncestors); export const selectSelectedProjectDescription = createSelector(projects, state => state.selectedProject?.description); export const selectSelectedProjectId = createSelector(selectSelectedProject, (selectedProject): string => selectedProject ? selectedProject.id : ''); export const selectIsArchivedMode = createSelector(projects, state => state.archive); export const selectIsDeepMode = createSelector(projects, state => state.deep); -export const selectTagsFilterByProject = createSelector(projects, state => state.tagsFilterByProject); +export const selectTagsFilterByProject = createSelector(projects, selectSelectedProjectId, + (state, projectId) => projectId !== '*' && state.tagsFilterByProject); export const selectProjectTags = createSelector(projects, state => state.projectTags); -export const selectMainPageTagsFilter = createSelector(projects, state => state.mainPageTagsFilter); +export const selectMainPageTagsFilter = createSelector(projects, selectRouterConfig, (state, config) => config?.[0] ? state.mainPageTagsFilter[config?.[0]] : []); export const selectMainPageTagsFilterMatchMode = createSelector(projects, state => state.mainPageTagsFilterMatchMode); export const selectCompanyTags = createSelector(projects, state => state.companyTags); // eslint-disable-next-line @typescript-eslint/naming-convention @@ -91,32 +101,17 @@ export const selectSelectedMetricVariantForCurrProject = createSelector( selectSelectedProjectsMetricVariant, selectSelectedProjectId, (projectsVariant, projectId) => projectsVariant[projectId]); export const selectGraphData = createSelector(projects, state => state.graphData); +export const selectGraphHiddenStates = createSelector(projects, state => state.hiddenStates); export const selectProjectUsers = createSelector(projects, state => state.extraUsers.length ? Array.from(new Set([...state.users, ...state.extraUsers])) : state.users ); export const selectAllProjectsUsers = createSelector(projects, state => state.allUsers); +export const selectTablesFilterProjectsOptions = createSelector(projects, state => state.tablesFilterProjectsOptions); export const projectsReducer = createReducer( initRootProjects, on(projectsActions.resetProjects, state => ({...state, projects: [], lastUpdate: null})), - on(projectsActions.setAllProjects, (state, action) => { - let newProjects = state.projects; - if (action.updating) { - action.projects.forEach(proj => { - const index = state.projects.findIndex(stateProject => stateProject.id === proj.id); - if (index > -1) { - newProjects = [...newProjects.slice(0, index), proj, ...newProjects.slice(index + 1)]; - } else { - newProjects = [...newProjects, proj]; - } - }); - } else { - newProjects = [...(newProjects || []), ...action.projects]; - } - return {...state, projects: sortByField(newProjects, 'name')}; - - }), on(projectsActions.setSelectedProjectId, (state, action) => { const projectId = action.projectId; return { @@ -130,6 +125,7 @@ export const projectsReducer = createReducer( selectedProject: action.project, extraUsers: [] })), + on(projectsActions.setProjectAncestors, (state, action) => ({...state, projectAncestors: action.projects})), on(projectsActions.setSelectedProjectStats, (state, action) => ({ ...state, selectedProject: { @@ -137,10 +133,6 @@ export const projectsReducer = createReducer( stats: action.project?.stats } })), - on(projectsActions.deletedProjectFromRoot, (state, action) => { - const projectIdsToDelete = [action.project.id].concat(action.project.sub_projects.map(project => project.id)); - return {...state, projects: state.projects.filter(project => !projectIdsToDelete.includes(project.id))}; - }), on(projectsActions.resetSelectedProject, state => ({ ...state, selectedProject: initRootProjects.selectedProject, @@ -168,7 +160,9 @@ export const projectsReducer = createReducer( ...state, projectTags: Array.from(new Set(state.projectTags.concat(action.tags))).sort() })), - on(projectsActions.setMainPageTagsFilter, (state, action) => ({...state, mainPageTagsFilter: action.tags})), + on(projectsActions.setMainPageTagsFilter, (state, action) => ({ + ...state, + mainPageTagsFilter: {...state.mainPageTagsFilter, [action.feature] : action.tags }})), on(projectsActions.setMainPageTagsFilterMatchMode, (state, action) => ({ ...state, mainPageTagsFilterMatchMode: action.matchMode @@ -181,13 +175,26 @@ export const projectsReducer = createReducer( ...state, graphVariant: {...state.graphVariant, [action.projectId]: action.col} })), on(projectsActions.setGraphData, (state, action) => ({...state, graphData: action.stats})), + on(projectsActions.toggleState, (state, action) => ({ + ...state, + hiddenStates: {...state.hiddenStates, [action.state]: !state.hiddenStates?.[action.state]} + })), on(projectsActions.setLastUpdate, (state, action) => ({...state, lastUpdate: action.lastUpdate})), on(projectsActions.setProjectUsers, (state, action) => ({...state, users: action.users, extraUsers: []})), on(projectsActions.setAllProjectUsers, (state, action) => ({...state, allUsers: action.users})), on(projectsActions.setProjectExtraUsers, (state, action) => ({...state, extraUsers: action.users})), on(projectsActions.setShowHidden, (state, action) => ({...state, showHidden: action.show})), on(projectsActions.setHideExamples, (state, action) => ({...state, hideExamples: action.hide})), - on(projectsActions.setDefaultNestedModeForFeature, (state, action) => ({...state, defaultNestedModeForFeature: {...state.defaultNestedModeForFeature, [action.feature]:action.isNested}})) + on(projectsActions.setDefaultNestedModeForFeature, (state, action) => ({ + ...state, + defaultNestedModeForFeature: {...state.defaultNestedModeForFeature, [action.feature]: action.isNested} + })), + on(projectsActions.resetTablesFilterProjectsOptions, (state) => ({...state, tablesFilterProjectsOptions: null})), + on(projectsActions.setTablesFilterProjectsOptions, (state, action) => ({ + ...state, + tablesFilterProjectsOptions: action.loadMore ? (state.tablesFilterProjectsOptions || []).concat(action.projects) : action.projects, + projectsOptionsScrollId: action.scrollId + })) ); export const selectShowHiddenUserSelection = createSelector(projects, state => state.showHidden); export const selectShowHidden = createSelector(projects, selectSelectedProject, @@ -195,3 +202,4 @@ export const selectShowHidden = createSelector(projects, selectSelectedProject, export const selectHideExamples = createSelector(projects, state => state?.hideExamples); export const selectDefaultNestedModeForFeature = createSelector(projects, state => state?.defaultNestedModeForFeature); +export const selectProjectsOptionsScrollId = createSelector(projects, state => state?.projectsOptionsScrollId); diff --git a/src/app/webapp-common/core/reducers/router-reducer.ts b/src/app/webapp-common/core/reducers/router-reducer.ts index cfb9e9b3..27570ad2 100755 --- a/src/app/webapp-common/core/reducers/router-reducer.ts +++ b/src/app/webapp-common/core/reducers/router-reducer.ts @@ -1,7 +1,6 @@ -import {createSelector, Action} from '@ngrx/store'; -import {NAVIGATION_ACTIONS} from '../../../app.constants'; -import {SetRouterSegments} from '../actions/router.actions'; +import {createReducer, createSelector, on} from '@ngrx/store'; import {Params} from '@angular/router'; +import {setRouterSegments} from '@common/core/actions/router.actions'; export interface RouterState { url: string; @@ -11,29 +10,23 @@ export interface RouterState { skipNextNavigation: boolean; } -const initRouter = { - url : window.location.pathname, - params : null, - queryParams : null, - config : null, - skipNextNavigation: false +const initRouter: RouterState = { + url: window.location.pathname, + params: null, + queryParams: null, + config: null, + skipNextNavigation: false, }; -export const selectRouter = state => state.router as RouterState; -export const selectRouterUrl = createSelector(selectRouter, router => router && router.url); -export const selectRouterParams = createSelector(selectRouter, router => router && router.params); +export const selectRouter = state => state.router as RouterState; +export const selectRouterUrl = createSelector(selectRouter, router => router && router.url); +export const selectRouterParams = createSelector(selectRouter, router => router && router?.params); export const selectRouterQueryParams = createSelector(selectRouter, router => router && router.queryParams); export const selectRouterConfig = createSelector(selectRouter, router => router && router.config); -export function routerReducer(state: RouterState = initRouter, action: Action): RouterState { - switch (action.type) { - case NAVIGATION_ACTIONS.SET_ROUTER_SEGMENT: { - const payload = (action as SetRouterSegments).payload; - return {...state, params: payload.params, queryParams: payload.queryParams, - url: payload.url, config: payload.config}; - } - default: - return state; - } - -} +export const routerReducer = createReducer(initRouter, + on(setRouterSegments, (state, action) => ({ + ...state, params: action.params, queryParams: action.queryParams, + url: action.url, config: action.config + })), +); diff --git a/src/app/webapp-common/core/reducers/view.reducer.ts b/src/app/webapp-common/core/reducers/view.reducer.ts index 36fc2bf4..7c248148 100644 --- a/src/app/webapp-common/core/reducers/view.reducer.ts +++ b/src/app/webapp-common/core/reducers/view.reducer.ts @@ -2,6 +2,8 @@ import {createReducer, createSelector, on, ReducerTypes} from '@ngrx/store'; import * as layoutActions from '../actions/layout.actions'; import {apiRequest, requestFailed} from '@common/core/actions/http.actions'; import {Ace} from 'ace-builds'; +import {IBreadcrumbsLink} from '@common/layout/breadcrumbs/breadcrumbs.component'; +import {setBreadcrumbs, setTypeBreadcrumbs} from '@common/core/actions/router.actions'; export interface ViewState { loading: { [endpoint: string]: boolean }; @@ -24,6 +26,7 @@ export interface ViewState { redactedArguments: { key: string }[]; hideRedactedArguments: boolean; showEmbedReportMenu: { show: boolean; position: { x: number; y: number } }; + breadcrumbs: IBreadcrumbsLink[][]; } export const initViewState: ViewState = { @@ -49,7 +52,8 @@ export const initViewState: ViewState = { {key: 'AWS_SECRET_ACCESS_KEY'}, {key: 'AZURE_STORAGE_KEY'}], hideRedactedArguments: false, - showEmbedReportMenu: {show: null, position: null} + showEmbedReportMenu: {show: null, position: null}, + breadcrumbs: [[{}]], }; export const views = state => state.views as ViewState; @@ -75,6 +79,8 @@ export const selectNeverShowPopups = createSelector(views, (state): string[] => export const selectRedactedArguments = createSelector(views, (state): { key: string }[] => state.redactedArguments); export const selectHideRedactedArguments = createSelector(views, (state): { key: string }[] => state.hideRedactedArguments ? state.redactedArguments : null); export const selectShowEmbedReportMenu = createSelector(views, state => state.showEmbedReportMenu); +export const selectBreadcrumbs = createSelector(views, state => state && state.breadcrumbs); + export const viewReducers = [ @@ -124,6 +130,14 @@ export const viewReducers = [ ...state, neverShowPopupAgain: action.reset ? state.neverShowPopupAgain.filter(popups => popups !== action.popupId) : Array.from(new Set([...state.neverShowPopupAgain, action.popupId])) })), + on(setBreadcrumbs, (state, action) => ({ + ...state, breadcrumbs: action.breadcrumbs + })), + on(setTypeBreadcrumbs, (state, action) => ({ + ...state, + breadcrumbs: [...state.breadcrumbs?.map(breadcrumbGroup => [...breadcrumbGroup?.map(breadcrumb => breadcrumb.type === action.type ? action.breadcrumb : breadcrumb) + ])] + })), ] as ReducerTypes[]; export const viewReducer = createReducer( diff --git a/src/app/webapp-common/dashboard/containers/dashboard-projects/dashboard-projects.component.html b/src/app/webapp-common/dashboard/containers/dashboard-projects/dashboard-projects.component.html index d748bbf1..2fac4630 100644 --- a/src/app/webapp-common/dashboard/containers/dashboard-projects/dashboard-projects.component.html +++ b/src/app/webapp-common/dashboard/containers/dashboard-projects/dashboard-projects.component.html @@ -8,7 +8,7 @@ class="btn btn-cml-primary d-flex align-items-center" data-id="New Project" (click)="openCreateProjectDialog()"> - NEW PROJECT + NEW PROJECT diff --git a/src/app/webapp-common/dashboard/containers/dashboard-projects/dashboard-projects.component.ts b/src/app/webapp-common/dashboard/containers/dashboard-projects/dashboard-projects.component.ts index f8fa4cd7..5e2871bb 100644 --- a/src/app/webapp-common/dashboard/containers/dashboard-projects/dashboard-projects.component.ts +++ b/src/app/webapp-common/dashboard/containers/dashboard-projects/dashboard-projects.component.ts @@ -1,6 +1,6 @@ -import {Component, Output, EventEmitter, AfterViewInit, ViewChild, ElementRef, OnDestroy} from '@angular/core'; +import {Component, OnInit, Output, EventEmitter, AfterViewInit, ViewChild, ElementRef, OnDestroy} from '@angular/core'; import {Router} from '@angular/router'; -import {MatLegacyDialog as MatDialog, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MatDialog, MatDialogRef} from '@angular/material/dialog'; import {fromEvent, Observable, Subscription} from 'rxjs'; import {Store} from '@ngrx/store'; import {Project} from '~/business-logic/model/projects/project'; @@ -19,7 +19,7 @@ import {trackById} from '@common/shared/utils/forms-track-by'; templateUrl: './dashboard-projects.component.html', styleUrls : ['./dashboard-projects.component.scss'] }) -export class DashboardProjectsComponent implements AfterViewInit, OnDestroy { +export class DashboardProjectsComponent implements OnInit, AfterViewInit, OnDestroy { public recentProjectsList$: Observable>; private dialog: MatDialogRef; private sub: Subscription; @@ -34,15 +34,18 @@ export class DashboardProjectsComponent implements AfterViewInit, OnDestroy { public router: Router, private matDialog: MatDialog ) { - this.store.dispatch(resetSelectedProject()); - this.store.select(selectCurrentUser) - .pipe(filter(user => !!user), take(1)) - .subscribe(() => this.store.dispatch(getRecentProjects())); this.recentProjectsList$ = this.store.select(selectRecentProjects); } @ViewChild('header') header: ElementRef; + ngOnInit() { + this.store.dispatch(resetSelectedProject()); + this.store.select(selectCurrentUser) + .pipe(filter(user => !!user), take(1)) + .subscribe(() => this.store.dispatch(getRecentProjects())); + } + ngAfterViewInit() { window.setTimeout(() => this.width.emit(this.header.nativeElement.getBoundingClientRect().width)); this.sub = fromEvent(window, 'resize') @@ -56,6 +59,7 @@ export class DashboardProjectsComponent implements AfterViewInit, OnDestroy { public openCreateProjectDialog() { this.dialog = this.matDialog.open(ProjectDialogComponent, { + panelClass: 'light-theme', data: { mode: 'create', } diff --git a/src/app/webapp-common/dataset-version/dataset-version-step/dataset-version-step.component.html b/src/app/webapp-common/dataset-version/dataset-version-step/dataset-version-step.component.html index 8456c431..dcf7ba96 100644 --- a/src/app/webapp-common/dataset-version/dataset-version-step/dataset-version-step.component.html +++ b/src/app/webapp-common/dataset-version/dataset-version-step/dataset-version-step.component.html @@ -12,7 +12,7 @@ diff --git a/src/app/webapp-common/dataset-version/dataset-version.module.ts b/src/app/webapp-common/dataset-version/dataset-version.module.ts index a2465f6f..d0397b28 100644 --- a/src/app/webapp-common/dataset-version/dataset-version.module.ts +++ b/src/app/webapp-common/dataset-version/dataset-version.module.ts @@ -50,10 +50,10 @@ export const routes: Routes = [ SimpleDatasetVersionInfoComponent, SimpleDatasetVersionDetailsComponent, SimpleDatasetVersionContentComponent, - SimpleDatasetVersionPreviewComponent, DatasetVersionStepComponent, ], imports: [ + SimpleDatasetVersionPreviewComponent, CommonModule, SMSharedModule, AngularSplitModule, @@ -63,6 +63,9 @@ export const routes: Routes = [ ExperimentOutputLogModule, DebugImagesModule, RouterModule.forChild(routes), + ], + exports: [ + SimpleDatasetVersionPreviewComponent, ] }) export class DatasetVersionModule { } diff --git a/src/app/webapp-common/dataset-version/simple-dataset-version-content/simple-dataset-version-content.component.html b/src/app/webapp-common/dataset-version/simple-dataset-version-content/simple-dataset-version-content.component.html index 1880bac5..775e3997 100644 --- a/src/app/webapp-common/dataset-version/simple-dataset-version-content/simple-dataset-version-content.component.html +++ b/src/app/webapp-common/dataset-version/simple-dataset-version-content/simple-dataset-version-content.component.html @@ -13,7 +13,7 @@ ngxClipboard [cbContent]="command" (cbOnSuccess)="$event.event.stopPropagation(); copied()" - >Copy command + >Copy command diff --git a/src/app/webapp-common/dataset-version/simple-dataset-version-content/simple-dataset-version-content.component.ts b/src/app/webapp-common/dataset-version/simple-dataset-version-content/simple-dataset-version-content.component.ts index 900861ea..c9ae511b 100644 --- a/src/app/webapp-common/dataset-version/simple-dataset-version-content/simple-dataset-version-content.component.ts +++ b/src/app/webapp-common/dataset-version/simple-dataset-version-content/simple-dataset-version-content.component.ts @@ -1,5 +1,5 @@ import {ChangeDetectionStrategy, Component, Input, ViewChild} from '@angular/core'; -import {MatLegacyMenuTrigger as MatMenuTrigger} from '@angular/material/legacy-menu'; +import {MatMenuTrigger} from '@angular/material/menu'; import {ISmCol} from '@common/shared/ui-components/data/table/table.consts'; import {fileSizeConfigStorage, FileSizePipe} from '@common/shared/pipes/filesize.pipe'; diff --git a/src/app/webapp-common/dataset-version/simple-dataset-version-details/simple-dataset-version-details.component.html b/src/app/webapp-common/dataset-version/simple-dataset-version-details/simple-dataset-version-details.component.html index d0f3d29c..ec927818 100644 --- a/src/app/webapp-common/dataset-version/simple-dataset-version-details/simple-dataset-version-details.component.html +++ b/src/app/webapp-common/dataset-version/simple-dataset-version-details/simple-dataset-version-details.component.html @@ -20,6 +20,21 @@ > +
Size
{{($any(entity?.runtime?.ds_total_size) | filesize : fileSizeConfigStorage) || '-'}}(original)
diff --git a/src/app/webapp-common/dataset-version/simple-dataset-version-info/simple-dataset-version-info.component.html b/src/app/webapp-common/dataset-version/simple-dataset-version-info/simple-dataset-version-info.component.html index 7030121e..481db9f9 100644 --- a/src/app/webapp-common/dataset-version/simple-dataset-version-info/simple-dataset-version-info.component.html +++ b/src/app/webapp-common/dataset-version/simple-dataset-version-info/simple-dataset-version-info.component.html @@ -6,7 +6,7 @@ >
- + {{selected?.name}} v{{selected.runtime.version}} @@ -64,7 +64,7 @@ >
- +
diff --git a/src/app/webapp-common/dataset-version/simple-dataset-version-info/simple-dataset-version-info.component.ts b/src/app/webapp-common/dataset-version/simple-dataset-version-info/simple-dataset-version-info.component.ts index b5872019..cf6ccde2 100644 --- a/src/app/webapp-common/dataset-version/simple-dataset-version-info/simple-dataset-version-info.component.ts +++ b/src/app/webapp-common/dataset-version/simple-dataset-version-info/simple-dataset-version-info.component.ts @@ -4,8 +4,8 @@ import {DagManagerUnsortedService} from '@common/shared/services/dag-manager-uns import {experimentDetailsUpdated, getSelectedPipelineStep, setSelectedPipelineStep} from '@common/experiments/actions/common-experiments-info.actions'; import {last} from 'lodash-es'; import {Store} from '@ngrx/store'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; -import {EditJsonComponent} from '@common/shared/ui-components/overlay/edit-json/edit-json.component'; +import {MatDialog} from '@angular/material/dialog'; +import {EditJsonComponent, EditJsonData} from '@common/shared/ui-components/overlay/edit-json/edit-json.component'; import {Task} from '~/business-logic/model/tasks/task'; import {CommonExperimentsInfoEffects} from '@common/experiments/effects/common-experiments-info.effects'; import {tap} from 'rxjs/operators'; @@ -93,8 +93,7 @@ export class SimpleDatasetVersionInfoComponent extends PipelineControllerInfoCom data: { textData: dataset.comment, title: 'EDIT DESCRIPTION', - typeJson: false, - } + } as EditJsonData }); editJsonComponent.afterClosed().subscribe(res => { if (res !== undefined) { diff --git a/src/app/webapp-common/dataset-version/simple-dataset-version-preview/simple-dataset-version-preview.component.ts b/src/app/webapp-common/dataset-version/simple-dataset-version-preview/simple-dataset-version-preview.component.ts index 2dc208a1..e9d7b661 100644 --- a/src/app/webapp-common/dataset-version/simple-dataset-version-preview/simple-dataset-version-preview.component.ts +++ b/src/app/webapp-common/dataset-version/simple-dataset-version-preview/simple-dataset-version-preview.component.ts @@ -1,9 +1,18 @@ import {Component, Input} from '@angular/core'; +import {ExperimentSharedModule} from "~/features/experiments/shared/experiment-shared.module"; +import {DebugImagesModule} from "@common/debug-images/debug-images.module"; +import {NgIf} from "@angular/common"; @Component({ selector: 'sm-simple-dataset-version-preview', templateUrl: './simple-dataset-version-preview.component.html', - styleUrls: ['./simple-dataset-version-preview.component.scss'] + styleUrls: ['./simple-dataset-version-preview.component.scss'], + imports: [ + ExperimentSharedModule, + DebugImagesModule, + NgIf + ], + standalone: true }) export class SimpleDatasetVersionPreviewComponent { @Input() selected; diff --git a/src/app/webapp-common/dataset-version/simple-dataset-versions/simple-dataset-versions.component.html b/src/app/webapp-common/dataset-version/simple-dataset-versions/simple-dataset-versions.component.html index 0b4fbc4e..c5987424 100644 --- a/src/app/webapp-common/dataset-version/simple-dataset-versions/simple-dataset-versions.component.html +++ b/src/app/webapp-common/dataset-version/simple-dataset-versions/simple-dataset-versions.component.html @@ -47,7 +47,7 @@ [users]="users$ | async" [hyperParamsOptions]="hyperParamsOptions$ | async" [activeParentsFilter]="activeParentsFilter$ | async" - [parents]="parent$ | async" + [parents]="parents$ | async" [experimentTypes]="types$ | async" [tags]="tags$ | async" [systemTags]="systemTags$ | async" @@ -107,7 +107,7 @@ [selectedDisableAvailable]="singleRowContext ? getSingleSelectedDisableAvailable(contextExperiment) : (selectedExperimentsDisableAvailable$ | async)" [numSelected]="singleRowContext ? 1 : selectedExperiments.length" [tagsFilterByProject]="tagsFilterByProject$ | async" - [projectTags]="projectTags$ | async" + [projectTags]="tags$ | async" [companyTags]="companyTags$ | async" [activateFromMenuButton]="false" [minimizedView]="true" diff --git a/src/app/webapp-common/dataset-version/simple-dataset-versions/simple-dataset-versions.component.ts b/src/app/webapp-common/dataset-version/simple-dataset-versions/simple-dataset-versions.component.ts index 2c5d3201..e497008d 100644 --- a/src/app/webapp-common/dataset-version/simple-dataset-versions/simple-dataset-versions.component.ts +++ b/src/app/webapp-common/dataset-version/simple-dataset-versions/simple-dataset-versions.component.ts @@ -9,7 +9,7 @@ import {EXPERIMENTS_TABLE_COL_FIELDS} from '~/features/experiments/shared/experi import {Store} from '@ngrx/store'; import {SmSyncStateSelectorService} from '@common/core/services/sync-state-selector.service'; import {ActivatedRoute, Router} from '@angular/router'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {RefreshService} from '@common/core/services/refresh.service'; import {take} from 'rxjs/operators'; import {ExperimentsViewState} from '@common/experiments/reducers/experiments-view.reducer'; @@ -50,7 +50,7 @@ export class SimpleDatasetVersionsComponent extends ControllersComponent impleme if (!this.route.snapshot.firstChild?.params.versionId) { this.store.dispatch(experimentsActions.experimentSelectionChanged({ experiment: this.firstExperiment, - project: this.selectedProject, + project: this.selectedProjectId, replaceURL: true })); } diff --git a/src/app/webapp-common/datasets/dataset-empty/dataset-empty.component.html b/src/app/webapp-common/datasets/dataset-empty/dataset-empty.component.html index 834d3180..843e2350 100644 --- a/src/app/webapp-common/datasets/dataset-empty/dataset-empty.component.html +++ b/src/app/webapp-common/datasets/dataset-empty/dataset-empty.component.html @@ -12,7 +12,7 @@
Use ClearML Data from CLI or in your Python code.
Run these code snippets for a quick example (Requires ClearML 1.7 or above).
- For more details see the documentation + For more details see the documentation
- \ No newline at end of file + diff --git a/src/app/webapp-common/datasets/simple-dataset-card/simple-dataset-card.component.html b/src/app/webapp-common/datasets/simple-dataset-card/simple-dataset-card.component.html index eb1a6f0f..1a76697a 100644 --- a/src/app/webapp-common/datasets/simple-dataset-card/simple-dataset-card.component.html +++ b/src/app/webapp-common/datasets/simple-dataset-card/simple-dataset-card.component.html @@ -24,7 +24,7 @@ >{{project.name | shortProjectName}} + class="al-icon al-ico-project-path sm ms-2"> - NEW DATASET + NEW DATASET - + ()); export const setExperimentsUpdateTime = createAction(SET_EXPERIMENTS_UPDATE_TIME, props<{ payload: {[key: string]: Date}}>()); -export const refreshIfNeeded = createAction(REFRESH_IF_NEEDED, props<{ payload: boolean; autoRefresh?: boolean }>()); +export const refreshIfNeeded = createAction(REFRESH_IF_NEEDED, props<{ payload: boolean; autoRefresh?: boolean; entityType: string }>()); export const toggleShowScalarOptions = createAction(TOGGLE_SHOW_SACLARS_OPTIONS); export const setSearchExperimentsForCompareResults = createAction(SET_SELECT_EXPERIMENTS_FOR_COMPARE, props<{ payload: Array }>()); export const setShowSearchExperimentsForCompare = createAction(SET_SHOW_SEARCH_EXPERIMENTS_FOR_COMPARE, props<{ payload: boolean }>()); @@ -50,7 +51,7 @@ export const compareAddDialogSetTableSort = createAction( EXPERIMENTS_COMPARE_SELECT_EXPERIMENT_ + ' [set table sort]', props<{ orders: SortMeta[]; projectId: string; colIds: string[] }>() ); -export const refetchExperimentRequested = createAction(REFETCH_EXPERIMENT_REQUESTED, props<{ autoRefresh: boolean }>()); +export const refetchExperimentRequested = createAction(REFETCH_EXPERIMENT_REQUESTED, props<{ autoRefresh: boolean; entity: EntityTypeEnum }>()); export const setNavigationPreferences = createAction(SET_NAVIGATION_PREFERENCES, props<{ navigationPreferences: Params }>()); export const setAddTableViewArchived = createAction( EXPERIMENTS_COMPARE_SELECT_EXPERIMENT_ + '[show archived in add table]', diff --git a/src/app/webapp-common/experiments-compare/actions/experiments-compare-charts.actions.ts b/src/app/webapp-common/experiments-compare/actions/experiments-compare-charts.actions.ts index c6b5f45b..40f73798 100644 --- a/src/app/webapp-common/experiments-compare/actions/experiments-compare-charts.actions.ts +++ b/src/app/webapp-common/experiments-compare/actions/experiments-compare-charts.actions.ts @@ -2,6 +2,7 @@ import {createAction, props} from '@ngrx/store'; import {ScalarKeyEnum} from '~/business-logic/model/events/scalarKeyEnum'; import {EventsGetMultiTaskPlotsResponse} from '~/business-logic/model/events/eventsGetMultiTaskPlotsResponse'; import {ExperimentCompareSettings} from '@common/experiments-compare/reducers/experiments-compare-charts.reducer'; +import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; export const EXPERIMENTS_COMPARE_METRICS_CHARTS_ = 'EXPERIMENTS_COMPARE_METRICS_CHARTS_'; @@ -14,12 +15,12 @@ export const SET_EXPERIMENT_PLOTS = EXPERIMENTS_COMPARE_METRICS_CH export const getMultiScalarCharts = createAction( EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'GET_MULTI_SCALAR_CHARTS', - props<{ taskIds: string[]; autoRefresh?: boolean; cached?: boolean }>() + props<{ taskIds: string[]; entity: EntityTypeEnum; autoRefresh?: boolean; cached?: boolean }>() ); export const getMultiPlotCharts = createAction( EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'GET_MULTI_PLOT_CHARTS', - props<{ taskIds: Array; autoRefresh?: boolean }>() + props<{ taskIds: Array; entity: EntityTypeEnum; autoRefresh?: boolean }>() ); export const setSelectedExperiments = createAction( diff --git a/src/app/webapp-common/experiments-compare/actions/experiments-compare-details.actions.ts b/src/app/webapp-common/experiments-compare/actions/experiments-compare-details.actions.ts index 150ee9d3..a9bb2598 100644 --- a/src/app/webapp-common/experiments-compare/actions/experiments-compare-details.actions.ts +++ b/src/app/webapp-common/experiments-compare/actions/experiments-compare-details.actions.ts @@ -1,6 +1,9 @@ import {createAction, props} from '@ngrx/store'; import {IExperimentDetail} from '~/features/experiments-compare/experiments-compare-models'; +import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; +import {ModelDetail, ModelDetails} from '@common/experiments-compare/shared/experiments-compare-details.model'; export const resetState = createAction('[experiment compare details] RESET_STATE'); export const setExperiments = createAction('[experiment compare details] SET_EXPERIMENTS', props<{experiments: IExperimentDetail[]}>()); -export const experimentListUpdated = createAction('[experiment compare details] EXPERIMENT_LIST_UPDATED', props<{ids: string[]}>()); +export const setModels = createAction('[experiment compare details] SET_MODELS', props<{models: ModelDetail[]}>()); +export const experimentListUpdated = createAction('[experiment compare details] EXPERIMENT_LIST_UPDATED', props<{ids: string[]; entity: EntityTypeEnum}>()); diff --git a/src/app/webapp-common/experiments-compare/actions/experiments-compare-metrics-values.actions.ts b/src/app/webapp-common/experiments-compare/actions/experiments-compare-metrics-values.actions.ts index 14849161..53f8e507 100644 --- a/src/app/webapp-common/experiments-compare/actions/experiments-compare-metrics-values.actions.ts +++ b/src/app/webapp-common/experiments-compare/actions/experiments-compare-metrics-values.actions.ts @@ -1,11 +1,12 @@ import {createAction, props} from '@ngrx/store'; import {Task} from '~/business-logic/model/tasks/task'; +import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; export const EXPERIMENTS_COMPARE_METRICS_VALUES_ = 'EXPERIMENTS_COMPARE_METRICS_VALUES_'; export const getComparedExperimentsMetricsValues = createAction( EXPERIMENTS_COMPARE_METRICS_VALUES_ + 'GET_COMPARED_EXPERIMENTS_METRICS_VALUES', - props<{ taskIds: string[]; autoRefresh?: boolean }>() + props<{ taskIds: string[]; entity: EntityTypeEnum; autoRefresh?: boolean }>() ); export const setComparedExperiments = createAction( EXPERIMENTS_COMPARE_METRICS_VALUES_ + 'SET_COMPARED_EXPERIMENTS', diff --git a/src/app/webapp-common/experiments-compare/actions/experiments-compare-params.actions.ts b/src/app/webapp-common/experiments-compare/actions/experiments-compare-params.actions.ts index 713bf022..e746817e 100644 --- a/src/app/webapp-common/experiments-compare/actions/experiments-compare-params.actions.ts +++ b/src/app/webapp-common/experiments-compare/actions/experiments-compare-params.actions.ts @@ -1,6 +1,7 @@ import {createAction, props} from '@ngrx/store'; import {ExperimentParams} from '../shared/experiments-compare-details.model'; +import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; export const resetState = createAction('[experiment compare params] RESET_STATE'); export const setExperiments = createAction('[experiment compare params] SET_EXPERIMENTS', props<{experiments: ExperimentParams[]}>()); -export const experimentListUpdated = createAction('[experiment compare params] EXPERIMENT_LIST_UPDATED', props<{ids: string[]}>()); +export const experimentListUpdated = createAction('[experiment compare params] EXPERIMENT_LIST_UPDATED', props<{ids: string[]; entity: EntityTypeEnum}>()); diff --git a/src/app/webapp-common/experiments-compare/containers/experiment-compare-base.ts b/src/app/webapp-common/experiments-compare/containers/experiment-compare-base.ts index 8580ddda..459de85c 100644 --- a/src/app/webapp-common/experiments-compare/containers/experiment-compare-base.ts +++ b/src/app/webapp-common/experiments-compare/containers/experiment-compare-base.ts @@ -1,10 +1,6 @@ import * as detailsActions from '../actions/experiments-compare-details.actions'; import * as paramsActions from '../actions/experiments-compare-params.actions'; -import { - ExperimentCompareTree, - ExperimentCompareTreeSection, - IExperimentDetail -} from '~/features/experiments-compare/experiments-compare-models'; +import {ExperimentCompareTree, ExperimentCompareTreeSection, IExperimentDetail} from '~/features/experiments-compare/experiments-compare-models'; import {get, has, isEmpty, isEqual} from 'lodash-es'; import {treeBuilderService} from '../services/tree-builder.service'; import {isArrayOrderNotImportant} from '../jsonToDiffConvertor'; @@ -20,13 +16,14 @@ import {Observable, Subscription} from 'rxjs'; import {FlatTreeControl} from '@angular/cdk/tree'; import {CdkVirtualScrollViewport} from '@angular/cdk/scrolling'; import {selectRouterParams} from '../../core/reducers/router-reducer'; -import {distinctUntilChanged, filter, map, take, tap} from 'rxjs/operators'; +import {distinctUntilChanged, filter, map, take} from 'rxjs/operators'; import {selectHideIdenticalFields} from '../reducers'; import {refetchExperimentRequested} from '../actions/compare-header.actions'; import {RENAME_MAP} from '../experiments-compare.constants'; import {selectHasDataFeature} from '~/core/reducers/users.reducer'; import {ListRange} from '@angular/cdk/collections'; import {RefreshService} from '@common/core/services/refresh.service'; +import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; export type NextDiffDirectionEnum = 'down' | 'up'; @@ -76,8 +73,8 @@ export abstract class ExperimentCompareBase extends ExperimentCompareDetailsBase public experimentTags: { [experimentId: string]: string[] } = {}; private timeoutIndex: number; private originalScrolledElement: EventTarget; - private taskIds: string; private treeCardBody: HTMLDivElement; + protected entityType = EntityTypeEnum.experiment; @ViewChildren('treeCardBody') treeCardBodies: QueryList>; get baseExperiment(): IExperimentDetail { @@ -89,7 +86,7 @@ export abstract class ExperimentCompareBase extends ExperimentCompareDetailsBase @HostListener('window:resize') afterResize() { window.setTimeout(() => { - this.nativeWidth = Math.max(this.treeCardBody.getBoundingClientRect().width, 410); + this.nativeWidth = Math.max(this.treeCardBody?.getBoundingClientRect().width, 410); this.cdr.detectChanges(); }); } @@ -130,7 +127,7 @@ export abstract class ExperimentCompareBase extends ExperimentCompareDetailsBase this.refreshingSubscription = this.refresh.tick .pipe(filter(auto => auto !== null)) - .subscribe(auto => this.store.dispatch(refetchExperimentRequested({autoRefresh: auto}))); + .subscribe(auto => this.store.dispatch(refetchExperimentRequested({autoRefresh: auto, entity: this.entityType}))); this.hideIdenticalFieldsSub.add(this.hasDataFeature$.subscribe(hasData => this.hasDataFeature = hasData)); @@ -141,7 +138,7 @@ export abstract class ExperimentCompareBase extends ExperimentCompareDetailsBase .pipe(filter(list => list.first), take(1)) .subscribe((list: QueryList>) => { this.treeCardBody = list.first.nativeElement; - this.nativeWidth = Math.max(this.treeCardBody.getBoundingClientRect().width, 410); + this.afterResize(); }); } diff --git a/src/app/webapp-common/experiments-compare/containers/experiment-compare-details/experiment-compare-details.component.html b/src/app/webapp-common/experiments-compare/containers/experiment-compare-details/experiment-compare-details.component.html index 8b28e10a..6662c22c 100644 --- a/src/app/webapp-common/experiments-compare/containers/experiment-compare-details/experiment-compare-details.component.html +++ b/src/app/webapp-common/experiments-compare/containers/experiment-compare-details/experiment-compare-details.component.html @@ -96,7 +96,7 @@ - diff --git a/src/app/webapp-common/experiments-compare/containers/experiment-compare-details/experiment-compare-details.component.ts b/src/app/webapp-common/experiments-compare/containers/experiment-compare-details/experiment-compare-details.component.ts index a8f080ff..5f1a6998 100644 --- a/src/app/webapp-common/experiments-compare/containers/experiment-compare-details/experiment-compare-details.component.ts +++ b/src/app/webapp-common/experiments-compare/containers/experiment-compare-details/experiment-compare-details.component.ts @@ -1,26 +1,11 @@ -import { - AfterViewInit, - ChangeDetectionStrategy, - ChangeDetectorRef, - Component, - ElementRef, - HostListener, - OnInit, - QueryList, - ViewChildren -} from '@angular/core'; +import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit} from '@angular/core'; import {select, Store} from '@ngrx/store'; import {experimentListUpdated} from '../../actions/experiments-compare-details.actions'; import {selectExperimentsDetails} from '../../reducers'; -import {filter, take, tap} from 'rxjs/operators'; +import {filter, tap} from 'rxjs/operators'; import {ExperimentCompareTree, IExperimentDetail} from '~/features/experiments-compare/experiments-compare-models'; import { - convertConfigurationFromExperiments, - convertContainerScriptFromExperiments, - convertExperimentsArrays, - convertNetworkDesignFromExperiments, - getAllKeysEmptyObject, - isDetailsConverted + convertConfigurationFromExperiments, convertContainerScriptFromExperiments, convertExperimentsArrays, convertNetworkDesignFromExperiments, getAllKeysEmptyObject, isDetailsConverted } from '../../jsonToDiffConvertor'; import {ExperimentCompareBase} from '../experiment-compare-base'; import {ActivatedRoute, Router} from '@angular/router'; @@ -28,6 +13,7 @@ import {ExperimentInfoState} from '~/features/experiments/reducers/experiment-in import {ConfigurationItem} from '~/business-logic/model/tasks/configurationItem'; import {RefreshService} from '@common/core/services/refresh.service'; import {LIMITED_VIEW_LIMIT} from '@common/experiments-compare/experiments-compare.constants'; +import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; @Component({ selector: 'sm-experiment-compare-details', @@ -54,7 +40,7 @@ export class ExperimentCompareDetailsComponent extends ExperimentCompareBase imp ngOnInit() { this.onInit(); this.routerParamsSubscription = this.taskIds$.subscribe((experimentIds) => { - this.store.dispatch(experimentListUpdated({ids: experimentIds.slice(0, LIMITED_VIEW_LIMIT)})); + this.store.dispatch(experimentListUpdated({ids: experimentIds.slice(0, LIMITED_VIEW_LIMIT), entity: EntityTypeEnum.experiment})); } ); diff --git a/src/app/webapp-common/experiments-compare/containers/experiment-compare-hyper-params-graph/experiment-compare-hyper-params-graph.component.html b/src/app/webapp-common/experiments-compare/containers/experiment-compare-hyper-params-graph/experiment-compare-hyper-params-graph.component.html index f05bda13..db6aff0d 100644 --- a/src/app/webapp-common/experiments-compare/containers/experiment-compare-hyper-params-graph/experiment-compare-hyper-params-graph.component.html +++ b/src/app/webapp-common/experiments-compare/containers/experiment-compare-hyper-params-graph/experiment-compare-hyper-params-graph.component.html @@ -14,8 +14,8 @@ [value]="(!metrics || listOpen) ? '' : selectedMetric?.name" (input)="updateMetricsList($event)" > - - + +
{ @@ -86,7 +87,10 @@ export class ExperimentCompareHyperParamsGraphComponent implements OnInit, OnDes } } - constructor(private store: Store, private refresh: RefreshService, private reportEmbed: ReportCodeEmbedService) { + constructor(private store: Store, + private route: ActivatedRoute, + private refresh: RefreshService, + private reportEmbed: ReportCodeEmbedService) { this.metrics$ = this.store.pipe(select(selectScalarsGraphMetrics)); this.hyperParams$ = this.store.pipe(select(selectScalarsGraphHyperParams)); this.selectedHyperParams$ = this.store.pipe(select(selectSelectedSettingsHyperParams)); @@ -239,6 +243,8 @@ export class ExperimentCompareHyperParamsGraphComponent implements OnInit, OnDes createEmbedCode(event: { tasks: string[]; valueType: MetricValueType; metrics?: string[]; variants?: string[]; domRect: DOMRect }) { this.reportEmbed.createCode({ type: 'parcoords', + objects: event.tasks, + objectType: 'task', ...event }); } diff --git a/src/app/webapp-common/experiments-compare/containers/experiment-compare-metric-charts/experiment-compare-scalar-charts.component.ts b/src/app/webapp-common/experiments-compare/containers/experiment-compare-metric-charts/experiment-compare-scalar-charts.component.ts index 4dfd5d8e..9a0d418a 100644 --- a/src/app/webapp-common/experiments-compare/containers/experiment-compare-metric-charts/experiment-compare-scalar-charts.component.ts +++ b/src/app/webapp-common/experiments-compare/containers/experiment-compare-metric-charts/experiment-compare-scalar-charts.component.ts @@ -1,25 +1,14 @@ -import {ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild} from '@angular/core'; +import {AfterViewInit, ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild} from '@angular/core'; import {Observable, Subscription} from 'rxjs'; import {select, Store} from '@ngrx/store'; import {ExperimentInfoState} from '~/features/experiments/reducers/experiment-info.reducer'; import {distinctUntilChanged, filter, map} from 'rxjs/operators'; import {isEqual} from 'lodash-es'; import {GroupedList, mergeMultiMetrics, mergeMultiMetricsGroupedVariant} from '@common/tasks/tasks.utils'; +import {getMultiScalarCharts, resetExperimentMetrics, setExperimentMetricsSearchTerm, setExperimentSettings, setSelectedExperiments} from '../../actions/experiments-compare-charts.actions'; import { - getMultiScalarCharts, - resetExperimentMetrics, setExperimentHistogram, - setExperimentMetricsSearchTerm, - setExperimentSettings, - setSelectedExperiments -} from '../../actions/experiments-compare-charts.actions'; -import { - selectCompareSelectedSettingsGroupBy, - selectCompareSelectedSettingsSmoothWeight, - selectCompareSelectedSettingsxAxisType, - selectCompareTasksScalarCharts, - selectExperimentMetricsSearchTerm, - selectSelectedExperimentSettings, - selectSelectedSettingsHiddenScalar + selectCompareSelectedSettingsGroupBy, selectCompareSelectedSettingsSmoothWeight, selectCompareSelectedSettingsxAxisType, selectCompareTasksScalarCharts, selectExperimentMetricsSearchTerm, + selectSelectedExperimentSettings, selectSelectedSettingsHiddenScalar } from '../../reducers'; import {ScalarKeyEnum} from '~/business-logic/model/events/scalarKeyEnum'; import {toggleShowScalarOptions} from '../../actions/compare-header.actions'; @@ -31,7 +20,9 @@ import {ExperimentGraphsComponent} from '@common/shared/experiment-graphs/experi import {selectScalarsHoverMode} from '@common/experiments/reducers'; import {setScalarsHoverMode} from '@common/experiments/actions/common-experiment-output.actions'; import {ChartHoverModeEnum} from '@common/experiments/shared/common-experiments.const'; -import { ReportCodeEmbedService } from '~/shared/services/report-code-embed.service'; +import {ReportCodeEmbedService} from '~/shared/services/report-code-embed.service'; +import {ActivatedRoute} from '@angular/router'; +import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; @Component({ @@ -39,7 +30,7 @@ import { ReportCodeEmbedService } from '~/shared/services/report-code-embed.serv templateUrl: './experiment-compare-scalar-charts.component.html', styleUrls: ['./experiment-compare-scalar-charts.component.scss'] }) -export class ExperimentCompareScalarChartsComponent implements OnInit, OnDestroy { +export class ExperimentCompareScalarChartsComponent implements OnInit, OnDestroy, AfterViewInit { public smoothWeight$: Observable; public xAxisType$: Observable; @@ -77,10 +68,12 @@ export class ExperimentCompareScalarChartsComponent implements OnInit, OnDestroy @ViewChild(ExperimentGraphsComponent) graphsComponent: ExperimentGraphsComponent; public hoverMode$: Observable; + private entityType: EntityTypeEnum; constructor( private store: Store, private changeDetection: ChangeDetectorRef, + private route: ActivatedRoute, private refresh: RefreshService, private reportEmbed: ReportCodeEmbedService, ) { @@ -111,7 +104,7 @@ export class ExperimentCompareScalarChartsComponent implements OnInit, OnDestroy this.xAxisSub = this.xAxisType$ .pipe(filter(axis => !!axis && this.taskIds?.length > 0)) - .subscribe(() => this.store.dispatch(getMultiScalarCharts({taskIds: this.taskIds, cached: true}))); + .subscribe(() => this.store.dispatch(getMultiScalarCharts({taskIds: this.taskIds, entity: this.entityType, cached: true}))); this.groupBySub = this.groupBy$ .subscribe(groupBy => { @@ -121,6 +114,7 @@ export class ExperimentCompareScalarChartsComponent implements OnInit, OnDestroy } ngOnInit() { + this.entityType = this.route.snapshot.parent.parent.data.entityType; this.metricsSubscription = this.metrics$ .subscribe((metricsWrapped) => { const metrics = metricsWrapped.metrics || {}; @@ -128,24 +122,18 @@ export class ExperimentCompareScalarChartsComponent implements OnInit, OnDestroy this.prepareGraphsAndUpdate(metrics); }); - this.settingsSubscription = this.experimentSettings$ - .subscribe((selectedMetric) => { - this.selectedGraph = selectedMetric; - this.graphsComponent.scrollToGraph(selectedMetric); - }); - this.routerParamsSubscription = this.routerParams$ .subscribe((params) => { if (!this.taskIds || this.taskIds.join(',') !== params.ids) { this.taskIds = params.ids.split(','); this.store.dispatch(setSelectedExperiments({selectedExperiments: this.taskIds})); - this.store.dispatch(getMultiScalarCharts({taskIds: this.taskIds})); + this.store.dispatch(getMultiScalarCharts({taskIds: this.taskIds, entity: this.entityType})); } }); this.refreshingSubscription = this.refresh.tick .pipe(filter(auto => auto !== null && this.graphs !== null)) - .subscribe(autoRefresh => this.store.dispatch(getMultiScalarCharts({taskIds: this.taskIds, autoRefresh}))); + .subscribe(autoRefresh => this.store.dispatch(getMultiScalarCharts({taskIds: this.taskIds, entity: this.entityType, autoRefresh}))); } private prepareGraphsAndUpdate(metrics) { @@ -212,10 +200,21 @@ export class ExperimentCompareScalarChartsComponent implements OnInit, OnDestroy } createEmbedCode(event: { metrics?: string[]; variants?: string[]; domRect: DOMRect }) { + const entityType = this.entityType === EntityTypeEnum.model ? 'model' : 'task'; this.reportEmbed.createCode({ type: 'scalar', - tasks: this.taskIds, + objects: this.taskIds, + objectType: entityType, ...event }); } + + ngAfterViewInit(): void { + this.settingsSubscription = this.experimentSettings$ + .pipe(filter(metric => !!metric)) + .subscribe(selectedMetric => { + this.selectedGraph = selectedMetric; + this.graphsComponent.scrollToGraph(selectedMetric); + }); + } } diff --git a/src/app/webapp-common/experiments-compare/containers/experiment-compare-metric-values/experiment-compare-metric-values.component.ts b/src/app/webapp-common/experiments-compare/containers/experiment-compare-metric-values/experiment-compare-metric-values.component.ts index a90b321a..cf9c22ae 100644 --- a/src/app/webapp-common/experiments-compare/containers/experiment-compare-metric-values/experiment-compare-metric-values.component.ts +++ b/src/app/webapp-common/experiments-compare/containers/experiment-compare-metric-values/experiment-compare-metric-values.component.ts @@ -6,12 +6,13 @@ import {has} from 'lodash-es'; import {Observable, Subscription} from 'rxjs'; import * as metricsValuesActions from '../../actions/experiments-compare-metrics-values.actions'; import {selectCompareMetricsValuesExperiments, selectCompareMetricsValuesSortConfig} from '../../reducers'; -import {Router} from '@angular/router'; +import {ActivatedRoute, Router} from '@angular/router'; import {addMessage} from '@common/core/actions/layout.actions'; import {TreeNode} from '../../shared/experiments-compare-details.model'; import {createDiffObjectScalars, getAllKeysEmptyObject} from '../../jsonToDiffConvertor'; import {RefreshService} from '@common/core/services/refresh.service'; import {LIMITED_VIEW_LIMIT} from '@common/experiments-compare/experiments-compare.constants'; +import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; interface ValueMode { key: string; @@ -59,9 +60,11 @@ export class ExperimentCompareMetricValuesComponent implements OnInit, OnDestroy public hoveredRow: string; public hoveredTable: string; public experimentTags: { [experimentId: string]: string[] } = {}; + private entityType: EntityTypeEnum; constructor( private router: Router, + private route: ActivatedRoute, public store: Store, private changeDetection: ChangeDetectorRef, private refresh: RefreshService @@ -71,6 +74,7 @@ export class ExperimentCompareMetricValuesComponent implements OnInit, OnDestroy } ngOnInit() { + this.entityType = this.route.snapshot.parent.parent.data.entityType; this.queryParamsSubscription = this.store.pipe( select(selectRouterQueryParams), map(params => params?.scalars), @@ -87,7 +91,10 @@ export class ExperimentCompareMetricValuesComponent implements OnInit, OnDestroy filter(taskIds => !!taskIds && taskIds !== this.getExperimentIdsParams(this.experiments)) ) .subscribe((experimentIds: string[]) => { - this.store.dispatch(metricsValuesActions.getComparedExperimentsMetricsValues({taskIds: experimentIds.slice(0, LIMITED_VIEW_LIMIT)})); + this.store.dispatch(metricsValuesActions.getComparedExperimentsMetricsValues({ + taskIds: experimentIds.slice(0, LIMITED_VIEW_LIMIT), + entity: this.entityType + })); }); this.comparedTasksSubscription = this.comparedTasks$ @@ -107,7 +114,7 @@ export class ExperimentCompareMetricValuesComponent implements OnInit, OnDestroy this.refreshingSubscription = this.refresh.tick .pipe(filter(auto => auto !== null)) .subscribe((autoRefresh) => this.store.dispatch( - metricsValuesActions.getComparedExperimentsMetricsValues({taskIds: this.taskIds, autoRefresh}) + metricsValuesActions.getComparedExperimentsMetricsValues({taskIds: this.taskIds, entity: this.entityType, autoRefresh}) )); } diff --git a/src/app/webapp-common/experiments-compare/containers/experiment-compare-params/experiment-compare-params.component.html b/src/app/webapp-common/experiments-compare/containers/experiment-compare-params/experiment-compare-params.component.html index 9c3fbccf..42182aa9 100644 --- a/src/app/webapp-common/experiments-compare/containers/experiment-compare-params/experiment-compare-params.component.html +++ b/src/app/webapp-common/experiments-compare/containers/experiment-compare-params/experiment-compare-params.component.html @@ -99,7 +99,7 @@ - diff --git a/src/app/webapp-common/experiments-compare/containers/experiment-compare-params/experiment-compare-params.component.ts b/src/app/webapp-common/experiments-compare/containers/experiment-compare-params/experiment-compare-params.component.ts index d2bf6e14..7b4670a3 100644 --- a/src/app/webapp-common/experiments-compare/containers/experiment-compare-params/experiment-compare-params.component.ts +++ b/src/app/webapp-common/experiments-compare/containers/experiment-compare-params/experiment-compare-params.component.ts @@ -1,4 +1,4 @@ -import {ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit} from '@angular/core'; import {select, Store} from '@ngrx/store'; import {selectExperimentsParams} from '../../reducers'; import {filter, tap} from 'rxjs/operators'; @@ -11,6 +11,7 @@ import {ExperimentInfoState} from '~/features/experiments/reducers/experiment-in import {experimentListUpdated} from '../../actions/experiments-compare-params.actions'; import {RefreshService} from '@common/core/services/refresh.service'; import {LIMITED_VIEW_LIMIT} from '@common/experiments-compare/experiments-compare.constants'; +import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; @Component({ selector: 'sm-experiment-compare-params', @@ -20,6 +21,7 @@ import {LIMITED_VIEW_LIMIT} from '@common/experiments-compare/experiments-compar }) export class ExperimentCompareParamsComponent extends ExperimentCompareBase implements OnInit { public showEllipsis: boolean = true; + protected entityType: EntityTypeEnum; constructor( public router: Router, @@ -35,11 +37,12 @@ export class ExperimentCompareParamsComponent extends ExperimentCompareBase impl experiments$ = this.store.pipe(select(selectExperimentsParams)); ngOnInit() { + this.entityType = this.activeRoute.snapshot.parent.parent.data.entityType; this.onInit(); this.compareTabPage = this.activeRoute?.snapshot?.routeConfig?.data?.mode; this.routerParamsSubscription = this.taskIds$.subscribe( (experimentIds) => { - this.store.dispatch(experimentListUpdated({ids: experimentIds.slice(0, LIMITED_VIEW_LIMIT)})); + this.store.dispatch(experimentListUpdated({ids: experimentIds.slice(0, LIMITED_VIEW_LIMIT), entity: this.entityType})); }); this.experimentsSubscription = this.experiments$.pipe( @@ -64,7 +67,7 @@ export class ExperimentCompareParamsComponent extends ExperimentCompareBase impl .reduce((acc, cur) => { acc[cur.id] = { // eslint-disable-next-line @typescript-eslint/naming-convention - 'hyper-params': this.buildSectionTree(cur, 'hyperparams', mergedExperiment) + 'hyper-params': this.buildSectionTree(cur, this.entityType === EntityTypeEnum.model? 'design': 'hyperparams', mergedExperiment) }; return acc; diff --git a/src/app/webapp-common/experiments-compare/containers/experiment-compare-plots/experiment-compare-plots.component.ts b/src/app/webapp-common/experiments-compare/containers/experiment-compare-plots/experiment-compare-plots.component.ts index a672bba9..db88eb0f 100644 --- a/src/app/webapp-common/experiments-compare/containers/experiment-compare-plots/experiment-compare-plots.component.ts +++ b/src/app/webapp-common/experiments-compare/containers/experiment-compare-plots/experiment-compare-plots.component.ts @@ -25,6 +25,8 @@ import {RefreshService} from '@common/core/services/refresh.service'; import {addMessage} from '@common/core/actions/layout.actions'; import {ExperimentGraphsComponent} from '@common/shared/experiment-graphs/experiment-graphs.component'; import { ReportCodeEmbedService } from '~/shared/services/report-code-embed.service'; +import {ActivatedRoute} from '@angular/router'; +import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; @Component({ selector: 'sm-experiment-compare-plots', @@ -51,10 +53,12 @@ export class ExperimentComparePlotsComponent implements OnInit, OnDestroy { public refreshDisabled: boolean; @ViewChild(ExperimentGraphsComponent) graphsComponent: ExperimentGraphsComponent; + private entityType: EntityTypeEnum; constructor( private store: Store, private changeDetection: ChangeDetectorRef, + private route: ActivatedRoute, private refresh: RefreshService, private reportEmbed: ReportCodeEmbedService, ) { @@ -82,6 +86,7 @@ export class ExperimentComparePlotsComponent implements OnInit, OnDestroy { } ngOnInit() { + this.entityType = this.route.snapshot.parent.parent.data.entityType; this.plotsSubscription = this.plots$ .subscribe((metricsPlots) => { this.refreshDisabled = false; @@ -106,14 +111,14 @@ export class ExperimentComparePlotsComponent implements OnInit, OnDestroy { if (!this.taskIds || this.taskIds.join(',') !== params.ids) { this.taskIds = params.ids.split(','); this.store.dispatch(setSelectedExperiments({selectedExperiments: this.taskIds})); - this.store.dispatch(getMultiPlotCharts({taskIds: this.taskIds})); + this.store.dispatch(getMultiPlotCharts({taskIds: this.taskIds, entity: this.entityType})); } }); this.refreshingSubscription = this.refresh.tick .pipe(filter(auto => auto !== null)) .subscribe(autoRefresh => - this.store.dispatch(getMultiPlotCharts({taskIds: this.taskIds, autoRefresh})) + this.store.dispatch(getMultiPlotCharts({taskIds: this.taskIds, entity: this.entityType, autoRefresh})) ); } @@ -149,9 +154,11 @@ export class ExperimentComparePlotsComponent implements OnInit, OnDestroy { } createEmbedCode(event: { metrics?: string[]; variants?: string[]; domRect: DOMRect }) { + const entityType = this.entityType === EntityTypeEnum.model ? 'model' : 'task'; this.reportEmbed.createCode({ type: 'plot', - tasks: this.taskIds, + objects: this.taskIds, + objectType: entityType, ...event }); } diff --git a/src/app/webapp-common/experiments-compare/containers/model-compare-details/model-compare-details.component.html b/src/app/webapp-common/experiments-compare/containers/model-compare-details/model-compare-details.component.html new file mode 100644 index 00000000..6662c22c --- /dev/null +++ b/src/app/webapp-common/experiments-compare/containers/model-compare-details/model-compare-details.component.html @@ -0,0 +1,106 @@ + +
+ + +
+
+
+ + + + +
+
+
+ + {{(renameMap[node.data.key] || node.data.key) | hideHashTitle}} + +
+
+
+
+
+
{{node.data.key | hideHash}}{{node.data.value}}
+                    
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + diff --git a/src/app/webapp-common/experiments-compare/containers/model-compare-details/model-compare-details.component.scss b/src/app/webapp-common/experiments-compare/containers/model-compare-details/model-compare-details.component.scss new file mode 100644 index 00000000..fe0237c5 --- /dev/null +++ b/src/app/webapp-common/experiments-compare/containers/model-compare-details/model-compare-details.component.scss @@ -0,0 +1,44 @@ +@import "../experiment-compare-base.component"; + +:host { + display: block; + height: 100%; + padding-top: 12px; + + .section { + pre { + display: inline-block; + position: relative; + overflow: visible; + + &.with-ellipsis { + overflow: hidden; + text-overflow: ellipsis; + } + + &:hover { + .extend-toggle { + visibility: visible; + } + } + + &.no-ellipsis { + + .extend-toggle { + visibility: hidden !important; + } + } + } + + .title-key { + width: 100%; + + &.ellipsis { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + width: 339px; + } + } + } +} diff --git a/src/app/webapp-common/experiments-compare/containers/model-compare-details/model-compare-details.component.ts b/src/app/webapp-common/experiments-compare/containers/model-compare-details/model-compare-details.component.ts new file mode 100644 index 00000000..e0ed6eee --- /dev/null +++ b/src/app/webapp-common/experiments-compare/containers/model-compare-details/model-compare-details.component.ts @@ -0,0 +1,85 @@ +import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit,} from '@angular/core'; +import {select, Store} from '@ngrx/store'; +import {experimentListUpdated} from '../../actions/experiments-compare-details.actions'; +import {selectModelsDetails} from '../../reducers'; +import {filter, tap} from 'rxjs/operators'; +import {ExperimentCompareTree,} from '~/features/experiments-compare/experiments-compare-models'; +import {convertmodelsArrays, getAllKeysEmptyObject, isDetailsConverted} from '../../jsonToDiffConvertor'; +import {ExperimentCompareBase} from '../experiment-compare-base'; +import {ActivatedRoute, Router} from '@angular/router'; +import {ExperimentInfoState} from '~/features/experiments/reducers/experiment-info.reducer'; +import {ConfigurationItem} from '~/business-logic/model/tasks/configurationItem'; +import {RefreshService} from '@common/core/services/refresh.service'; +import {LIMITED_VIEW_LIMIT} from '@common/experiments-compare/experiments-compare.constants'; +import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; +import {ModelDetail} from '@common/experiments-compare/shared/experiments-compare-details.model'; + +@Component({ + selector: 'sm-model-compare-details', + templateUrl: './model-compare-details.component.html', + styleUrls: ['./model-compare-details.component.scss', '../../cdk-drag.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ModelCompareDetailsComponent extends ExperimentCompareBase implements OnInit, AfterViewInit { + public showEllipsis: boolean = true; + + constructor( + public router: Router, + public store: Store, + public changeDetection: ChangeDetectorRef, + public activeRoute: ActivatedRoute, + public cdr: ChangeDetectorRef, + public refresh: RefreshService + ) { + super(router, store, changeDetection, activeRoute, refresh, cdr); + this.entityType = EntityTypeEnum.model; + } + + experiments$ = this.store.pipe(select(selectModelsDetails)); + + ngOnInit() { + this.onInit(); + this.routerParamsSubscription = this.taskIds$.subscribe((experimentIds) => { + this.store.dispatch(experimentListUpdated({ids: experimentIds.slice(0, LIMITED_VIEW_LIMIT), entity: EntityTypeEnum.model})); + } + ); + + this.experimentsSubscription = this.experiments$.pipe( + filter(experiments => !!experiments && experiments.length > 0), + tap(experiments => { + this.extractTags(experiments); + }), + ).subscribe(models => { + this.originalExperiments = models.reduce((acc, exp) => { + acc[exp.id] = isDetailsConverted(exp) ? this.originalExperiments[exp.id] : exp; + return acc; + }, {} as { [id: string]: ConfigurationItem }); + models = Object.values(this.originalExperiments).map(experiment => convertmodelsArrays(experiment, this.originalExperiments[models[0].id], models)); + + this.resetComponentState(models); + this.calculateTree(models); + }); + } + + buildCompareTree(experiments: Array): ExperimentCompareTree { + const mergedExperiment = getAllKeysEmptyObject(experiments); + return experiments + .reduce((acc, cur) => { + acc[cur.id] = this.buildExperimentTree(cur, this.baseExperiment, mergedExperiment); + + return acc; + }, {} as ExperimentCompareTree); + } + + toggleEllipsis() { + this.showEllipsis = !this.showEllipsis; + } + + public buildExperimentTree(experiment, baseExperiment, mergedExperiment): any { + return { + general: this.buildSectionTree(experiment, 'general', mergedExperiment), + labels: this.buildSectionTree(experiment, 'labels', mergedExperiment), + metadata: this.buildSectionTree(experiment, 'metadata', mergedExperiment), + }; + } +} diff --git a/src/app/webapp-common/experiments-compare/containers/select-experiments-for-compare/select-experiments-for-compare.component.html b/src/app/webapp-common/experiments-compare/containers/select-experiments-for-compare/select-experiments-for-compare.component.html index 70008d39..2fd65338 100644 --- a/src/app/webapp-common/experiments-compare/containers/select-experiments-for-compare/select-experiments-for-compare.component.html +++ b/src/app/webapp-common/experiments-compare/containers/select-experiments-for-compare/select-experiments-for-compare.component.html @@ -1,7 +1,7 @@ - +
-
- +
+ -
- Include Archived +
+ Include Archived diff --git a/src/app/webapp-common/experiments-compare/containers/select-experiments-for-compare/select-experiments-for-compare.component.ts b/src/app/webapp-common/experiments-compare/containers/select-experiments-for-compare/select-experiments-for-compare.component.ts index 980e454d..62ec014a 100644 --- a/src/app/webapp-common/experiments-compare/containers/select-experiments-for-compare/select-experiments-for-compare.component.ts +++ b/src/app/webapp-common/experiments-compare/containers/select-experiments-for-compare/select-experiments-for-compare.component.ts @@ -27,9 +27,9 @@ import {BehaviorSubject, combineLatest, Observable, Subscription} from 'rxjs'; import {Task} from '~/business-logic/model/tasks/task'; import {Params} from '@angular/router'; import {selectRouterParams} from '@common/core/reducers/router-reducer'; -import {distinctUntilChanged, distinctUntilKeyChanged, filter, map} from 'rxjs/operators'; +import {distinctUntilChanged, distinctUntilKeyChanged, filter, map, tap} from 'rxjs/operators'; import {compareLimitations} from '@common/shared/entity-page/footer-items/compare-footer-item'; -import {MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {ITableExperiment} from '@common/experiments/shared/common-experiment-model.model'; import { selectActiveParentsFilter, @@ -51,7 +51,7 @@ import {initSearch} from '@common/common-search/common-search.actions'; import * as experimentsActions from '../../../experiments/actions/common-experiments-view.actions'; import {resetExperiments, resetGlobalFilter} from '@common/experiments/actions/common-experiments-view.actions'; import {User} from '~/business-logic/model/users/user'; -import {selectProjectSystemTags, selectProjectUsers, selectRootProjects} from '@common/core/reducers/projects.reducer'; +import {selectProjectSystemTags, selectProjectUsers, selectTablesFilterProjectsOptions} from '@common/core/reducers/projects.reducer'; import {SortMeta} from 'primeng/api'; import {Project} from '~/business-logic/model/projects/project'; import {addMessage} from '@common/core/actions/layout.actions'; @@ -63,7 +63,10 @@ import {INITIAL_EXPERIMENT_TABLE_COLS} from '@common/experiments/experiment.cons import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; import {ExperimentsTableComponent} from '@common/experiments/dumb/experiments-table/experiments-table.component'; import {MESSAGES_SEVERITY} from '@common/constants'; -import {MatLegacySlideToggleChange as MatSlideToggleChange} from '@angular/material/legacy-slide-toggle'; +import {MatSlideToggleChange} from '@angular/material/slide-toggle'; +import {getTablesFilterProjectsOptions, resetTablesFilterProjectsOptions} from '@common/core/actions/projects.actions'; +import {EXPERIMENTS_PAGE_SIZE} from '@common/experiments/shared/common-experiments.const'; +import {setParents} from '../../../experiments/actions/common-experiments-view.actions'; export const allowAddExperiment$ = (selectRouterParams$: Observable) => selectRouterParams$.pipe( distinctUntilKeyChanged('ids'), @@ -109,8 +112,10 @@ export class SelectExperimentsForCompareComponent implements OnInit, OnDestroy { public showArchived$: Observable; private _resizedCols = {} as { [colId: string]: string }; private resizedCols$ = new BehaviorSubject<{ [colId: string]: string }>(this._resizedCols); + private loadMoreCount = 0; @ViewChild('searchExperiments', {static: true}) searchExperiments; @ViewChild(ExperimentsTableComponent) table: ExperimentsTableComponent; + private parents: ProjectsGetTaskParentsResponseParents[]; constructor( private store: Store, @@ -125,15 +130,23 @@ export class SelectExperimentsForCompareComponent implements OnInit, OnDestroy { this.experiments$ = combineLatest([ this.store.select(selectExperimentsList), this.store.select(selectSelectedExperimentsForCompareAdd), - ]).pipe(map(([experiments, selectedExperiments]) => unionBy(selectedExperiments, experiments, 'id'))); + ]).pipe( + map(([experiments, selectedExperiments]) => { + const union = unionBy(selectedExperiments, experiments, 'id'); + if (experiments?.length >= EXPERIMENTS_PAGE_SIZE && (union.length - (selectedExperiments?.length ?? 0) <= EXPERIMENTS_PAGE_SIZE * (this.loadMoreCount + 1))) { + this.store.dispatch(experimentsActions.getNextExperiments()); + } + return union; + }) + ); this.searchTerm$ = this.store.pipe(select(selectExperimentsForCompareSearchTerm)); this.tableColsOrder$ = this.store.select(selectExperimentsTableColsOrder); this.columns$ = this.store.select(selectExperimentsTableCols); this.metricTableCols$ = this.store.select(selectExperimentsMetricsColsForProject); this.users$ = this.store.select(selectProjectUsers); this.tableFilters$ = this.store.select(selectTableFilters); - this.parent$ = this.store.select(selectExperimentsParents); - this.projects$ = this.store.select(selectRootProjects); + this.parent$ = this.store.select(selectExperimentsParents).pipe(tap(parents => this.parents = parents)); + this.projects$ = this.store.select(selectTablesFilterProjectsOptions); this.tags$ = this.store.select(selectExperimentsTags); this.types$ = this.store.select(selectExperimentsTypes); @@ -198,6 +211,7 @@ export class SelectExperimentsForCompareComponent implements OnInit, OnDestroy { ngOnInit() { this.store.dispatch(setShowSearchExperimentsForCompare({payload: true})); + this.store.dispatch(getTablesFilterProjectsOptions({searchString: '', loadMore: false})); window.setTimeout(() => this.table.table.rowRightClick = new EventEmitter()); this.paramsSubscription = this.store.pipe( select(selectRouterParams), @@ -205,8 +219,8 @@ export class SelectExperimentsForCompareComponent implements OnInit, OnDestroy { filter(([experimentIds,]) => !!experimentIds), ).subscribe(([experimentIds, projectId]) => { if (this.selectedExperimentsIds.length === 0) { - this.selectedExperimentsIds = experimentIds.split(','); - this.syncSelectedExperiments(); + this.selectedExperimentsIds = experimentIds.split(','); + this.syncSelectedExperiments(); } if (!this.projectId && projectId !== '*') { this.store.dispatch(compareAddTableFilterInit({projectId})); @@ -217,7 +231,7 @@ export class SelectExperimentsForCompareComponent implements OnInit, OnDestroy { this.allowAddExperiment$ = allowAddExperiment$(this.store.select(selectRouterParams)); this.store.dispatch(experimentsActions.getTags()); this.store.dispatch(experimentsActions.getProjectTypes()); - this.store.dispatch(experimentsActions.getParents()); + this.store.dispatch(experimentsActions.getParents({searchValue: null})); this.store.dispatch(getSelectedExperimentsForCompareAddDialog(null)); this.syncAppSearch(); } @@ -245,6 +259,7 @@ export class SelectExperimentsForCompareComponent implements OnInit, OnDestroy { } getNextExperiments() { + this.loadMoreCount++; this.syncSelectedExperiments(); this.store.dispatch(experimentsActions.getNextExperiments()); } @@ -285,4 +300,22 @@ export class SelectExperimentsForCompareComponent implements OnInit, OnDestroy { showArchived(event: MatSlideToggleChange) { this.store.dispatch(setAddTableViewArchived({show: event.checked})); } + + filterSearchChanged({colId, value}: { colId: string; value: {value: string; loadMore?: boolean} }) { + switch (colId) { + case 'project.name': + if (this.projectId === '*' && !value.loadMore) { + this.store.dispatch(resetTablesFilterProjectsOptions()); + } + this.store.dispatch(getTablesFilterProjectsOptions({searchString: value.value || '', loadMore: value.loadMore})); + break; + case 'parent.name': + if (value.loadMore) { + this.store.dispatch(setParents({parents: [...this.parents]})); + } else { + this.store.dispatch(experimentsActions.resetTablesFilterParentsOptions()); + this.store.dispatch(experimentsActions.getParents({searchValue: value.value || ''})); + } + } + } } diff --git a/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-general-data/experiment-compare-general-data.component.html b/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-general-data/experiment-compare-general-data.component.html index 0d23ef4d..3953463f 100644 --- a/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-general-data/experiment-compare-general-data.component.html +++ b/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-general-data/experiment-compare-general-data.component.html @@ -3,15 +3,17 @@
- - {{experimentsStatusLabels[experiment.status]}} - - {{experiment.last_iteration | number | NA}} iterations + + {{experimentsStatusLabels[experiment.status] ?? experiment.status}} + + + {{experiment.last_iteration | number | NA}} iterations + Last updated {{experiment.last_update | timeAgo | NA}}
diff --git a/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-general-data/experiment-compare-general-data.component.ts b/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-general-data/experiment-compare-general-data.component.ts index 5dcc4c8d..a399af7a 100644 --- a/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-general-data/experiment-compare-general-data.component.ts +++ b/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-general-data/experiment-compare-general-data.component.ts @@ -3,6 +3,7 @@ import {EXPERIMENTS_STATUS_LABELS} from '~/features/experiments/shared/experimen import {IExperimentDetail} from '~/features/experiments-compare/experiments-compare-models'; import {TIME_FORMAT_STRING} from '@common/constants'; import {ActivatedRoute} from '@angular/router'; +import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; @Component({ selector: 'sm-experiment-compare-general-data', @@ -29,6 +30,7 @@ export class ExperimentCompareGeneralDataComponent { buildUrl() { const projectOrPipeline = this.route.root.firstChild.routeConfig.path.replace('datasets', 'datasets/simple/'); - return [`/${projectOrPipeline}`, this.experiment.project?.id || '*', 'experiments', this.experiment.id]; + const targetEntity = this.route.snapshot.parent.data.entityType === EntityTypeEnum.model ? EntityTypeEnum.model : EntityTypeEnum.experiment; + return [`/${projectOrPipeline}`, this.experiment.project?.id || '*', `${targetEntity}s`, this.experiment.id]; } } diff --git a/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-header/experiment-compare-header.component.html b/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-header/experiment-compare-header.component.html index 944a43f0..650c9456 100644 --- a/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-header/experiment-compare-header.component.html +++ b/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-header/experiment-compare-header.component.html @@ -3,7 +3,7 @@ - - - - - Parallel Coordinates - Graph - Last Values - {{queryParamsViewMode || viewMode | noUnderscore | titlecase}} - - - - - Last Values - Values - - - - Min Values - - - - Max Values - - - - Parallel Coordinates - Graph - - + + + + + + Parallel Coordinates + Graph + Last Values + {{(queryParamsViewMode$ | async) || viewMode | noUnderscore | titlecase}} + + + + + {{currentPage === 'scalars' ? 'Last Values' : 'Values'}} + + + Min Values + + + Max Values + + + {{currentPage === 'hyper-params' ? 'Parallel Coordinates' : 'Graph'}} + + +
Hide Identical Fields diff --git a/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-header/experiment-compare-header.component.scss b/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-header/experiment-compare-header.component.scss index d0d8f746..19b97f49 100644 --- a/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-header/experiment-compare-header.component.scss +++ b/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-header/experiment-compare-header.component.scss @@ -48,26 +48,6 @@ margin: 0 5px; } - - ::ng-deep mat-select.view-mode { - width: 142px; - - .mat-select-trigger { - width: 142px; - border: 1px solid $blue-250; - border-radius: 4px; - height: 32px; - padding: 5px 14px; - - mat-select-trigger { - color: $blue-400; - } - } - - .mat-select-arrow { - color: $blue-400; - } - } } .header-container { @@ -110,7 +90,7 @@ .btn-add-experiment { display: flex; align-items: center; - gap: 12px; + gap: 6px; background-color: $blue-50; } @@ -132,6 +112,6 @@ */ } -::ng-deep .mat-menu-content { +::ng-deep .mat-mdc-menu-content { height: 100%; } diff --git a/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-header/experiment-compare-header.component.ts b/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-header/experiment-compare-header.component.ts index e59fba9e..84619fc1 100644 --- a/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-header/experiment-compare-header.component.ts +++ b/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-header/experiment-compare-header.component.ts @@ -1,37 +1,20 @@ -import { - ChangeDetectionStrategy, - ChangeDetectorRef, - Component, - EventEmitter, - Input, - OnDestroy, - OnInit, - Output -} from '@angular/core'; -import {MatLegacySelectChange as MatSelectChange} from '@angular/material/legacy-select'; +import {ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnDestroy, OnInit, Output} from '@angular/core'; +import {MatSelectChange} from '@angular/material/select'; import {Store} from '@ngrx/store'; import {selectHideIdenticalFields} from '../../reducers'; import {Observable, Subscription} from 'rxjs'; -import { - refreshIfNeeded, - setHideIdenticalFields, - setNavigationPreferences, - setShowSearchExperimentsForCompare, - toggleShowScalarOptions -} from '../../actions/compare-header.actions'; +import {refreshIfNeeded, setHideIdenticalFields, setNavigationPreferences, setShowSearchExperimentsForCompare, toggleShowScalarOptions} from '../../actions/compare-header.actions'; import {ActivatedRoute, Router} from '@angular/router'; import {selectRouterParams, selectRouterQueryParams, selectRouterUrl} from '@common/core/reducers/router-reducer'; import {setAutoRefresh} from '@common/core/actions/layout.actions'; -import {filter} from 'rxjs/operators'; -import {MatLegacySlideToggleChange as MatSlideToggleChange} from '@angular/material/legacy-slide-toggle'; +import {filter, map} from 'rxjs/operators'; +import {MatSlideToggleChange} from '@angular/material/slide-toggle'; import {compareLimitations} from '@common/shared/entity-page/footer-items/compare-footer-item'; -import { - allowAddExperiment$, - SelectExperimentsForCompareComponent -} from '../../containers/select-experiments-for-compare/select-experiments-for-compare.component'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {allowAddExperiment$, SelectExperimentsForCompareComponent} from '../../containers/select-experiments-for-compare/select-experiments-for-compare.component'; +import {MatDialog} from '@angular/material/dialog'; import {RefreshService} from '@common/core/services/refresh.service'; import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; +import {SelectModelComponent} from '@common/select-model/select-model.component'; @Component({ selector: 'sm-experiment-compare-header', @@ -41,17 +24,18 @@ import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; }) export class ExperimentCompareHeaderComponent implements OnInit, OnDestroy { private routerSubscription: Subscription; - private queryParamsSubscription: Subscription; public selectHideIdenticalFields$: Observable; public viewMode: string; public currentPage: string; - public queryParamsViewMode: string; public compareLimitations = compareLimitations; public allowAddExperiment$: Observable; + public queryParamsViewMode$: Observable; private autorRefreshSub: Subscription; private showMenuSub: Subscription; + private selectedIds: string; + @Input() entityType: EntityTypeEnum; @Output() selectionChanged = new EventEmitter(); @@ -64,12 +48,14 @@ export class ExperimentCompareHeaderComponent implements OnInit, OnDestroy { private refresh: RefreshService ) { this.selectHideIdenticalFields$ = this.store.select(selectHideIdenticalFields); + this.queryParamsViewMode$ = this.store.select(selectRouterQueryParams) + .pipe(map(params => params[this.currentPage])); } ngOnInit() { this.autorRefreshSub = this.refresh.tick .pipe(filter(auto => auto === null)) - .subscribe(() => this.store.dispatch(refreshIfNeeded({payload: true, autoRefresh: true}))); + .subscribe(() => this.store.dispatch(refreshIfNeeded({payload: true, autoRefresh: true, entityType: this.entityType}))); this.routerSubscription = this.store.select(selectRouterUrl).subscribe(() => { this.currentPage = this.route?.snapshot?.firstChild?.url?.[0]?.path; @@ -77,10 +63,11 @@ export class ExperimentCompareHeaderComponent implements OnInit, OnDestroy { this.cdr.detectChanges(); }); - this.allowAddExperiment$ = allowAddExperiment$(this.store.select(selectRouterParams)); + this.routerSubscription = this.store.select(selectRouterParams).subscribe((params) => { + this.selectedIds = params.ids; + }) - this.queryParamsSubscription = this.store.select(selectRouterQueryParams) - .subscribe((queryParams) => this.queryParamsViewMode = queryParams[this.currentPage]); + this.allowAddExperiment$ = allowAddExperiment$(this.store.select(selectRouterParams)); } ngOnDestroy(): void { @@ -101,12 +88,25 @@ export class ExperimentCompareHeaderComponent implements OnInit, OnDestroy { } openAddExperimentSearch() { - this.dialog.open(SelectExperimentsForCompareComponent, { - data: {entityType: this.entityType}, - height: '100vh', - width: '100%', - maxWidth: '100%' - }).afterClosed().pipe(filter(ids => !!ids)).subscribe(ids => this.selectionChanged.emit(ids)); + if (this.entityType === EntityTypeEnum.model) { + const selectedIds = this.selectedIds?.split(',') ?? []; + this.dialog.open(SelectModelComponent, { + data: { + selectionMode: 'multiple', + selectedModels: selectedIds, + header: 'Select compared model'}, + height: '94vh', + width: '98%', + maxWidth: '100%' + }).afterClosed().pipe(filter(ids => !!ids)).subscribe(ids => this.selectionChanged.emit(ids)); + } else { + this.dialog.open(SelectExperimentsForCompareComponent, { + data: {entityType: this.entityType}, + height: '94vh', + width: '98%', + maxWidth: '100%' + }).afterClosed().pipe(filter(ids => !!ids)).subscribe(ids => this.selectionChanged.emit(ids)); + } } hideIdenticalFieldsToggled(event: MatSlideToggleChange) { diff --git a/src/app/webapp-common/experiments-compare/dumbs/parallel-coordinates-graph/parallel-coordinates-graph.component.ts b/src/app/webapp-common/experiments-compare/dumbs/parallel-coordinates-graph/parallel-coordinates-graph.component.ts index c13c988d..4d3d6e45 100644 --- a/src/app/webapp-common/experiments-compare/dumbs/parallel-coordinates-graph/parallel-coordinates-graph.component.ts +++ b/src/app/webapp-common/experiments-compare/dumbs/parallel-coordinates-graph/parallel-coordinates-graph.component.ts @@ -22,7 +22,7 @@ import {MetricValueType, SelectedMetric} from '@common/experiments-compare/exper import {TooltipDirective} from '@common/shared/ui-components/indicators/tooltip/tooltip.directive'; import {trackById} from '@common/shared/utils/forms-track-by'; import {GraphViewerComponent, GraphViewerData} from '@common/shared/single-graph/graph-viewer/graph-viewer.component'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; // eslint-disable-next-line @typescript-eslint/naming-convention declare let Plotly; diff --git a/src/app/webapp-common/experiments-compare/effects/experiments-compare-charts.effects.ts b/src/app/webapp-common/experiments-compare/effects/experiments-compare-charts.effects.ts index c82a5d12..ebffe4ac 100644 --- a/src/app/webapp-common/experiments-compare/effects/experiments-compare-charts.effects.ts +++ b/src/app/webapp-common/experiments-compare/effects/experiments-compare-charts.effects.ts @@ -13,6 +13,7 @@ import {requestFailed} from '../../core/actions/http.actions'; import {selectCompareHistogramCacheAxisType, selectCompareSelectedSettingsxAxisType} from '../reducers'; import {ScalarKeyEnum} from '~/business-logic/model/events/scalarKeyEnum'; import {selectActiveWorkspaceReady} from '~/core/reducers/view.reducer'; +import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; @Injectable() @@ -44,6 +45,8 @@ export class ExperimentsCompareChartsEffects { } return this.eventsApi.eventsMultiTaskScalarMetricsIterHistogram({ tasks: action.taskIds, + // eslint-disable-next-line @typescript-eslint/naming-convention + model_events: action.entity === EntityTypeEnum.model, key: !axisType || axisType === ScalarKeyEnum.IsoTime ? ScalarKeyEnum.Timestamp : axisType }).pipe( mergeMap(res => [ @@ -63,8 +66,14 @@ export class ExperimentsCompareChartsEffects { ofType(chartActions.getMultiPlotCharts), debounceTime(200), mergeMap((action) => - // eslint-disable-next-line @typescript-eslint/naming-convention - this.eventsApi.eventsGetMultiTaskPlots({tasks: action.taskIds, iters: 1, no_scroll: true}) + this.eventsApi.eventsGetMultiTaskPlots({ + tasks: action.taskIds, + // eslint-disable-next-line @typescript-eslint/naming-convention + model_events: action.entity === EntityTypeEnum.model, + // eslint-disable-next-line @typescript-eslint/naming-convention + no_scroll: true, + iters: 1 + }) .pipe( map(res => res.plots), mergeMap(plots => [ diff --git a/src/app/webapp-common/experiments-compare/effects/experiments-compare-details.effects.ts b/src/app/webapp-common/experiments-compare/effects/experiments-compare-details.effects.ts index 84be10f2..81f39bf2 100644 --- a/src/app/webapp-common/experiments-compare/effects/experiments-compare-details.effects.ts +++ b/src/app/webapp-common/experiments-compare/effects/experiments-compare-details.effects.ts @@ -6,21 +6,29 @@ import {catchError, mergeMap, map, switchMap, withLatestFrom, filter} from 'rxjs import {ApiTasksService} from '~/business-logic/api-services/tasks.service'; import {ExperimentDetailsReverterService} from '../services/experiment-details-reverter.service'; import {requestFailed} from '../../core/actions/http.actions'; -import {selectExperimentIdsDetails, selectExperimentsDetails} from '../reducers'; +import {selectExperimentIdsDetails, selectExperimentsDetails, selectModelIdsDetails} from '../reducers'; import {Observable, of} from 'rxjs'; import {IExperimentDetail} from '~/features/experiments-compare/experiments-compare-models'; import {REFETCH_EXPERIMENT_REQUESTED, refetchExperimentRequested} from '../actions/compare-header.actions'; import {ExperimentCompareDetailsState} from '../reducers/experiments-compare-details.reducer'; -import {experimentListUpdated, setExperiments} from '../actions/experiments-compare-details.actions'; +import {experimentListUpdated, setExperiments, setModels} from '../actions/experiments-compare-details.actions'; import {getCompareDetailsOnlyFields} from '~/features/experiments-compare/experiments-compare-consts'; import {selectHasDataFeature} from '~/core/reducers/users.reducer'; import {selectActiveWorkspaceReady} from '~/core/reducers/view.reducer'; +import {ApiModelsService} from '~/business-logic/api-services/models.service'; +import {ModelDetailsReverterService} from '@common/experiments-compare/services/model-details-reverter.service'; +import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; +import {ModelDetail} from '@common/experiments-compare/shared/experiments-compare-details.model'; @Injectable() export class ExperimentsCompareDetailsEffects { - constructor(private actions$: Actions, private tasksApi: ApiTasksService, private store: Store, - private experimentDetailsReverter: ExperimentDetailsReverterService + constructor(private actions$: Actions, + private tasksApi: ApiTasksService, + private modelsApi: ApiModelsService, + private store: Store, + private experimentDetailsReverter: ExperimentDetailsReverterService, + private modelDetailsReverter: ModelDetailsReverterService, ) { } @@ -41,20 +49,20 @@ export class ExperimentsCompareDetailsEffects { ), switchMap(([action, oldExperimentIds, hasDataFeature]) => { const newExperimentIds = action.ids.filter(id => !oldExperimentIds.includes(id)); - return this.fetchExperimentDetails$(newExperimentIds, hasDataFeature) + return this.fetchEntity$(newExperimentIds, action.entity, hasDataFeature) .pipe( withLatestFrom(this.store.pipe(select(selectExperimentsDetails))), // get only the relevant experiments map(([experiments, oldExperiments]) => oldExperiments.filter(exp => action.ids.includes(exp.id)).concat(experiments)), - map(experiments=> action.ids.map(id=> experiments.find(experiment=> experiment.id===id))), - mergeMap(experiments => [ + map(experiments => action.ids.map(id => experiments.find(experiment => experiment.id === id))), + mergeMap((experiments: IExperimentDetail[] | ModelDetail[]) => [ deactivateLoader(action.type), - setExperiments({experiments}) + this.setEntities(action, experiments) ]), catchError(error => [ requestFailed(error), deactivateLoader(action.type), - setServerError(error, null, 'The attempt to retrieve your experiment data failed. Refresh your browser and try again.') + setServerError(error, null, 'The attempt to retrieve your data failed. Refresh your browser and try again.') ]) ); }) @@ -62,24 +70,29 @@ export class ExperimentsCompareDetailsEffects { refetchExperimentEffect$ = createEffect(() => this.actions$.pipe( ofType(refetchExperimentRequested), - withLatestFrom(this.store.select(selectExperimentIdsDetails), this.store.select(selectHasDataFeature)), - switchMap(([action, newExperimentIds, hasDataFeature]) => this.fetchExperimentDetails$(newExperimentIds, hasDataFeature).pipe( - mergeMap(experiments => [ - deactivateLoader(action.type), - setExperiments({experiments}) - ]), - catchError(error => [ - requestFailed(error), - deactivateLoader(action.type), - setServerError( - error, null, - 'The attempt to retrieve your experiment data failed. Refresh your browser and try again.', - action.autoRefresh - ) - ]) - )), + withLatestFrom(this.store.select(selectExperimentIdsDetails), this.store.select(selectModelIdsDetails), this.store.select(selectHasDataFeature)), + map(([action, expIds, modelIds, hasDataFeature]: [any, string[], string[], boolean]) => [action, action.entity === EntityTypeEnum.experiment ? expIds : modelIds, hasDataFeature]), + switchMap(([action, newExperimentIds, hasDataFeature]) => this.fetchEntity$(newExperimentIds, action.entity, hasDataFeature).pipe( + mergeMap(experiments => [ + deactivateLoader(action.type), + this.setEntities(action, experiments) + ]), + catchError(error => [ + requestFailed(error), + deactivateLoader(action.type), + setServerError( + error, null, + 'The attempt to retrieve your data failed. Refresh your browser and try again.', + action.autoRefresh + ) + ]) + )), )); + fetchEntity$(ids, entity, hasDataFeature) { + return entity === EntityTypeEnum.model ? this.fetchModelDetails$(ids) : this.fetchExperimentDetails$(ids, hasDataFeature); + } + fetchExperimentDetails$(ids, hasDataFeature: boolean): Observable> { return ids.length > 0 ? this.tasksApi.tasksGetAllEx({ @@ -91,5 +104,22 @@ export class ExperimentsCompareDetailsEffects { ) : of([]); } + + fetchModelDetails$(ids): Observable> { + return ids.length > 0 ? + this.modelsApi.modelsGetAllEx({ + id: ids, + // eslint-disable-next-line @typescript-eslint/naming-convention + only_fields: ['company', 'created', 'last_update', 'last_iteration', 'framework', 'id', 'labels', 'name', 'ready', 'tags', 'system_tags', 'task.name', 'task.project', 'uri', 'user.name', 'parent', 'project.name', 'metadata'] + }).pipe( + map(res => this.modelDetailsReverter.revertModels(ids, res.models)) + ) + : of([]); + } + + private setEntities(action, experiments: IExperimentDetail[] | ModelDetail[]) { + return action.entity === EntityTypeEnum.model ? + setModels({models: experiments as ModelDetail[]}) : setExperiments({experiments: experiments as IExperimentDetail[]}); + } } diff --git a/src/app/webapp-common/experiments-compare/effects/experiments-compare-metrics-values.effects.ts b/src/app/webapp-common/experiments-compare/effects/experiments-compare-metrics-values.effects.ts index bdebe652..a74c187d 100644 --- a/src/app/webapp-common/experiments-compare/effects/experiments-compare-metrics-values.effects.ts +++ b/src/app/webapp-common/experiments-compare/effects/experiments-compare-metrics-values.effects.ts @@ -5,12 +5,14 @@ import {activeLoader, deactivateLoader, setServerError} from '@common/core/actio import {catchError, mergeMap, map} from 'rxjs/operators'; import {requestFailed} from '../../core/actions/http.actions'; import {ApiTasksService} from '~/business-logic/api-services/tasks.service'; +import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; +import {ApiModelsService} from '~/business-logic/api-services/models.service'; @Injectable() export class ExperimentsCompareMetricsValuesEffects { - constructor(private actions$: Actions, public tasksApiService: ApiTasksService) { + constructor(private actions$: Actions, public tasksApiService: ApiTasksService, private modelsApi: ApiModelsService) { } activeLoader = createEffect(() => this.actions$.pipe( @@ -20,13 +22,9 @@ export class ExperimentsCompareMetricsValuesEffects { getComparedExperimentsMetricsValues = createEffect(() => this.actions$.pipe( ofType(metricsValuesActions.getComparedExperimentsMetricsValues), - mergeMap((action) => this.tasksApiService.tasksGetAllEx({ - id: action.taskIds, - // eslint-disable-next-line @typescript-eslint/naming-convention - only_fields: ['last_metrics', 'name', 'status', 'completed', 'last_update', 'last_iteration', 'project.name', 'tags'] - }) + mergeMap((action) => this.fetchEntities$(action) .pipe( - map(res => action.taskIds.map(id => res.tasks.find(ex => ex.id === id))), + map(res => action.taskIds.map(id => res[action.entity === EntityTypeEnum.model ? 'models' : 'tasks'].find(ex => ex.id === id))), mergeMap(experiments => [ metricsValuesActions.setComparedExperiments({experiments}), deactivateLoader(action.type)]), @@ -37,4 +35,17 @@ export class ExperimentsCompareMetricsValuesEffects { ) ) )); + + fetchEntities$(action) { + return action.entity === EntityTypeEnum.model ? this.modelsApi.modelsGetAllEx({ + id: action.taskIds, + // eslint-disable-next-line @typescript-eslint/naming-convention + only_fields: ['last_metrics', 'name', 'last_update', 'last_iteration', 'last_iteration', 'project.name', 'tags', 'ready'] + }).pipe(map(res => ({models: res.models.map( model => ({...model, status: model.ready? 'Ready' : 'Draft'}))}))) + : this.tasksApiService.tasksGetAllEx({ + id: action.taskIds, + // eslint-disable-next-line @typescript-eslint/naming-convention + only_fields: ['last_metrics', 'name', 'status', 'completed', 'last_update', 'last_iteration', 'project.name', 'tags'] + }); + } } diff --git a/src/app/webapp-common/experiments-compare/effects/experiments-compare-params.effects.ts b/src/app/webapp-common/experiments-compare/effects/experiments-compare-params.effects.ts index a35d4438..254cbb0c 100644 --- a/src/app/webapp-common/experiments-compare/effects/experiments-compare-params.effects.ts +++ b/src/app/webapp-common/experiments-compare/effects/experiments-compare-params.effects.ts @@ -16,12 +16,19 @@ import {ExperimentCompareParamsState} from '../reducers/experiments-compare-para import {setExperiments} from '../actions/experiments-compare-params.actions'; import {ExperimentDetailBase, ExperimentParams} from '../shared/experiments-compare-details.model'; import {selectActiveWorkspaceReady} from '~/core/reducers/view.reducer'; +import {ApiModelsService} from '~/business-logic/api-services/models.service'; +import {ModelDetailsReverterService} from '@common/experiments-compare/services/model-details-reverter.service'; +import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; @Injectable() export class ExperimentsCompareParamsEffects { - constructor(private actions$: Actions, private tasksApi: ApiTasksService, private store: Store, - private experimentParamsReverter: ExperimentParamsReverterService + constructor(private actions$: Actions, + private store: Store, + private tasksApi: ApiTasksService, + private modelsApi: ApiModelsService, + private experimentParamsReverter: ExperimentParamsReverterService, + private modelDetailsReverter: ModelDetailsReverterService, ) { } @@ -37,26 +44,26 @@ export class ExperimentsCompareParamsEffects { map(() => action))), withLatestFrom(this.store.pipe(select(selectExperimentIdsParams))), switchMap(([action, oldExperimentIds]) => { - const newExperimentIds = action.ids.filter(id => !oldExperimentIds.includes(id)); - return this.fetchExperimentParams$(newExperimentIds) - .pipe( - withLatestFrom(this.store.pipe(select(selectExperimentsParams))), - // get only the relevant experiments - map(([experiments, oldExperiments]: [ExperimentDetailBase[], ExperimentParams[]]) => - oldExperiments.filter(exp => action.ids.includes(exp.id)).concat(experiments as ExperimentParams[])), - map(experiments=> action.ids.map(id=> experiments.find(experiment=> experiment.id===id))), - mergeMap(experiments => [ - deactivateLoader(action.type), - setExperiments({experiments}) - ]), - catchError(error => [ - requestFailed(error), - deactivateLoader(action.type), - setServerError(error, null, 'The attempt to retrieve your experiment data failed. Refresh your browser and try again.') - ] - ) - ); - } + const newExperimentIds = action.ids.filter(id => !oldExperimentIds.includes(id)); + return this.fetchEntity$(newExperimentIds, action.entity) + .pipe( + withLatestFrom(this.store.pipe(select(selectExperimentsParams))), + // get only the relevant experiments + map(([experiments, oldExperiments]: [ExperimentDetailBase[], ExperimentParams[]]) => + oldExperiments.filter(exp => action.ids.includes(exp.id)).concat(experiments as ExperimentParams[])), + map(experiments => action.ids.map(id => experiments.find(experiment => experiment.id === id))), + mergeMap(experiments => [ + deactivateLoader(action.type), + setExperiments({experiments}) + ]), + catchError(error => [ + requestFailed(error), + deactivateLoader(action.type), + setServerError(error, null, 'The attempt to retrieve your experiment data failed. Refresh your browser and try again.') + ] + ) + ); + } ) )); @@ -64,10 +71,10 @@ export class ExperimentsCompareParamsEffects { ofType(refetchExperimentRequested), withLatestFrom(this.store.select(selectExperimentIdsParams)), switchMap(([action, newExperimentIds]) => - this.fetchExperimentParams$(newExperimentIds).pipe( + this.fetchEntity$(newExperimentIds, action.entity).pipe( mergeMap(experiments => [ deactivateLoader(action.type), - setExperiments({experiments : experiments as ExperimentParams[]}) + setExperiments({experiments: experiments as ExperimentParams[]}) ]), catchError(error => [ requestFailed(error), @@ -81,6 +88,10 @@ export class ExperimentsCompareParamsEffects { )), )); + fetchEntity$(ids, entity) { + return entity === EntityTypeEnum.model ? this.fetchModelParams$(ids) : this.fetchExperimentParams$(ids); + } + fetchExperimentParams$(ids): Observable> { return ids.length > 0 ? this.tasksApi.tasksGetAllEx({ @@ -91,5 +102,22 @@ export class ExperimentsCompareParamsEffects { .pipe(map(res => this.experimentParamsReverter.revertExperiments(ids, res.tasks))) : of([]); } + + fetchModelParams$(ids): Observable> { + return ids.length > 0 ? + this.modelsApi.modelsGetAllEx({ + id: ids, + // eslint-disable-next-line @typescript-eslint/naming-convention + only_fields: ['company', 'id', 'labels', 'name', 'ready', 'tags', 'system_tags', 'user.name', 'parent', 'project.name', 'design', 'last_iteration', 'last_update'] + }) + .pipe(map(res => { + try { + return this.modelDetailsReverter.revertModelsDesign(ids, res.models, false); + } catch (e) { + return this.modelDetailsReverter.revertModelsDesign(ids, res.models, true); + } + })) + : of([]); + } } diff --git a/src/app/webapp-common/experiments-compare/effects/select-experiment-for-compare-effects.service.ts b/src/app/webapp-common/experiments-compare/effects/select-experiment-for-compare-effects.service.ts index 50238713..65ffa1dd 100644 --- a/src/app/webapp-common/experiments-compare/effects/select-experiment-for-compare-effects.service.ts +++ b/src/app/webapp-common/experiments-compare/effects/select-experiment-for-compare-effects.service.ts @@ -28,6 +28,9 @@ import {addMultipleSortColumns} from '../../shared/utils/shared-utils'; import {RefreshService} from '@common/core/services/refresh.service'; import {LIMITED_VIEW_LIMIT} from '@common/experiments-compare/experiments-compare.constants'; import {ActivatedRoute} from '@angular/router'; +import {ApiModelsService} from '~/business-logic/api-services/models.service'; +import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; +import {encodeHyperParameter} from '@common/experiments/shared/common-experiments.utils'; @Injectable() export class SelectCompareHeaderEffects { @@ -35,6 +38,7 @@ export class SelectCompareHeaderEffects { constructor( private actions: Actions, public experimentsApi: ApiTasksService, + public modelsApi: ApiModelsService, private store: Store, private refresh: RefreshService, private route: ActivatedRoute @@ -67,14 +71,18 @@ export class SelectCompareHeaderEffects { }), switchMap(([action, , experimentsIds, experimentsUpdateTime, isLimitedView]) => // eslint-disable-next-line @typescript-eslint/naming-convention - this.experimentsApi.tasksGetAllEx({ + (action.entityType === EntityTypeEnum.experiment ? this.experimentsApi.tasksGetAllEx({ id: isLimitedView ? experimentsIds.slice(0, LIMITED_VIEW_LIMIT) : experimentsIds, // eslint-disable-next-line @typescript-eslint/naming-convention only_fields: ['last_change'] - }).pipe( + }) : this.modelsApi.modelsGetAllEx({ + id: isLimitedView ? experimentsIds.slice(0, LIMITED_VIEW_LIMIT) : experimentsIds, + // eslint-disable-next-line @typescript-eslint/naming-convention + only_fields: ['last_update'] + })).pipe( mergeMap((res) => { const updatedExperimentsUpdateTime: { [key: string]: Date } = {}; - res.tasks.forEach(task => { + res[action.entityType === EntityTypeEnum.experiment ? 'tasks' : 'models'].forEach(task => { updatedExperimentsUpdateTime[task.id] = task.last_change; }); const experimentsWhereUpdated = experimentsIds.some(id => @@ -115,7 +123,7 @@ export class SelectCompareHeaderEffects { // eslint-disable-next-line @typescript-eslint/naming-convention only_fields: [...new Set([...MINIMUM_ONLY_FIELDS, ...flatten(cols.filter(col => col.id !== 'selected' && !col.hidden).map(col => col.getter || col.id)), - ...(metricCols ? flatten(metricCols.map(col => col.getter || col.id)) : [])])] as string[] + ...(metricCols ? flatten(metricCols.map(col => (col?.isParam && typeof col.getter === 'string') ? encodeHyperParameter(col.getter) : col.getter || col.id)) : [])])] as string[] }).pipe( mergeMap((res) => [setSearchExperimentsForCompareResults({payload: [...res?.tasks]}), deactivateLoader(action.type)]), ) diff --git a/src/app/webapp-common/experiments-compare/experiments-compare-routing.module.ts b/src/app/webapp-common/experiments-compare/experiments-compare-routing.module.ts index 05c39518..80d5ff9c 100755 --- a/src/app/webapp-common/experiments-compare/experiments-compare-routing.module.ts +++ b/src/app/webapp-common/experiments-compare/experiments-compare-routing.module.ts @@ -10,6 +10,7 @@ import {DebugImagesComponent} from '../debug-images/debug-images.component'; import {ExperimentCompareHyperParamsGraphComponent} from './containers/experiment-compare-hyper-params-graph/experiment-compare-hyper-params-graph.component'; import {RouterHelperGuard} from './experiment-compare-router-helper.guard'; import {ExperimentCompareParamsComponent} from './containers/experiment-compare-params/experiment-compare-params.component'; +import {ModelCompareDetailsComponent} from '@common/experiments-compare/containers/model-compare-details/model-compare-details.component'; export const routes: Routes = [ @@ -22,6 +23,8 @@ export const routes: Routes = [ {path: 'metrics-values', redirectTo: 'scalars/values', pathMatch: 'full', data: {limit: true}}, {path: 'metrics-charts', redirectTo: 'scalars/graph', pathMatch: 'full'}, {path: 'details', component: ExperimentCompareDetailsComponent, data: {mode: 'details', limit: true}}, + {path: 'models-details', component: ModelCompareDetailsComponent, data: {mode: 'details', limit: true}}, + {path: 'network', component: ExperimentCompareParamsComponent, data: {mode: 'hyper-params', limit: true}}, {path: 'hyper-params/values', component: ExperimentCompareParamsComponent, canActivate: [RouterHelperGuard], data: {mode: 'hyper-params', limit: true}}, {path: 'hyper-params/graph', component: ExperimentCompareHyperParamsGraphComponent}, {path: 'scalars/values', component: ExperimentCompareMetricValuesComponent, canActivate: [RouterHelperGuard], data: {limit: true}}, diff --git a/src/app/webapp-common/experiments-compare/experiments-compare.component.html b/src/app/webapp-common/experiments-compare/experiments-compare.component.html index 7673e64f..eeb39454 100644 --- a/src/app/webapp-common/experiments-compare/experiments-compare.component.html +++ b/src/app/webapp-common/experiments-compare/experiments-compare.component.html @@ -1,12 +1,22 @@
diff --git a/src/app/webapp-common/experiments-compare/experiments-compare.component.ts b/src/app/webapp-common/experiments-compare/experiments-compare.component.ts index 86148a24..4537845a 100644 --- a/src/app/webapp-common/experiments-compare/experiments-compare.component.ts +++ b/src/app/webapp-common/experiments-compare/experiments-compare.component.ts @@ -19,6 +19,7 @@ export class ExperimentsCompareComponent implements OnInit, OnDestroy { private navigationPreferences$: Subscription; private queryParams: Params; public entityType: EntityTypeEnum; + public entityTypeEnum = EntityTypeEnum; constructor(private store: Store, private router: Router, private activatedRoute: ActivatedRoute) { // updating URL with store query params diff --git a/src/app/webapp-common/experiments-compare/experiments-compare.module.ts b/src/app/webapp-common/experiments-compare/experiments-compare.module.ts index 06305949..28f6ffdf 100644 --- a/src/app/webapp-common/experiments-compare/experiments-compare.module.ts +++ b/src/app/webapp-common/experiments-compare/experiments-compare.module.ts @@ -48,7 +48,7 @@ import { } from './containers/experiment-compare-hyper-params-graph/experiment-compare-hyper-params-graph.component'; import {ExperimentsCompareScalarsGraphEffects} from './effects/experiments-compare-scalars-graph.effects'; import {ScrollingModule} from '@angular/cdk/scrolling'; -import {MatLegacyRadioModule as MatRadioModule} from '@angular/material/legacy-radio'; +import {MatRadioModule} from '@angular/material/radio'; import { ExperimentCompareParamsComponent } from './containers/experiment-compare-params/experiment-compare-params.component'; @@ -57,6 +57,7 @@ import {FormsModule} from '@angular/forms'; import {UiComponentsModule} from '../shared/ui-components/ui-components.module'; import {SMMaterialModule} from '../shared/material/material.module'; import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module'; +import {ModelCompareDetailsComponent} from '@common/experiments-compare/containers/model-compare-details/model-compare-details.component'; export const compareSyncedKeys = [ 'charts.settingsList', @@ -67,6 +68,7 @@ export const compareSyncedKeys = [ declarations: [ ExperimentsCompareComponent, ExperimentCompareDetailsComponent, + ModelCompareDetailsComponent, ExperimentCompareParamsComponent, ExperimentCompareMetricValuesComponent, ExperimentCompareScalarChartsComponent, diff --git a/src/app/webapp-common/experiments-compare/jsonToDiffConvertor.ts b/src/app/webapp-common/experiments-compare/jsonToDiffConvertor.ts index ff772ce1..df07c3c3 100644 --- a/src/app/webapp-common/experiments-compare/jsonToDiffConvertor.ts +++ b/src/app/webapp-common/experiments-compare/jsonToDiffConvertor.ts @@ -1,7 +1,7 @@ import {get, has, isArray, isEqual, mergeWith, isUndefined} from 'lodash-es'; import {IExperimentDetail} from '../../features/experiments-compare/experiments-compare-models'; import {treeBuilderService} from './services/tree-builder.service'; -import {TreeNode} from './shared/experiments-compare-details.model'; +import {ModelDetail, TreeNode} from './shared/experiments-compare-details.model'; import { getAlternativeConvertedExperiment, getDisplayTextForTitles @@ -24,7 +24,7 @@ export interface TreeNodeJsonData { function arrayOrderIsNotImportant(key) { // List of fields with order important - return !['augmentation', 'mapping', 'network_design', 'file content', 'preview'].includes(key); + return !['augmentation', 'mapping', 'network_design', 'file content', 'preview', 'design', 'hyper-params'].includes(key); } export function isArrayOrderNotImportant(val, key, allExperiments = []) { @@ -433,7 +433,7 @@ export function convertExperimentsArrays(experiment, origin, experiments, path = const hashedObj = {}; const currentIndex = path.split(/\.([0-9]+)$/)[1]; experiment[key].forEach(item => { - let convertedItemHash = convertToHashItem(item, origin && (Array.isArray(origin) ? (origin.map(item => item[key]) as any).flat() : origin[key][currentIndex]), newPath); + let convertedItemHash = convertToHashItem(item, origin && (Array.isArray(origin) ? (origin.map(item => item[key]) as any).flat() : origin[key]?.[currentIndex]), newPath); if (hashedObj[convertedItemHash]) { convertedItemHash = `${counter}${convertedItemHash}`; counter--; @@ -521,3 +521,46 @@ export function createDiffObjectScalars(AllKeysObject, originObject?, comparedOb }; }, metaTransformerFunction || null, {comparedObject, originPath, originObject}).children; } + +/////// MODELS ///////// + +export function convertmodelsArrays(experiment, origin, experiments, path = ''): ModelDetail { + const convertedModel: ModelDetail = {}; + let counter = 9999; + Object.keys(experiment).forEach(key => { + const newPath = `${path}.${key}`; + switch (key) { + default: + if (isObject(experiment[key]) && (!isArrayOrderNotImportant(experiment[key], key, experiments))) { + let newKey = getDisplayTextForTitles(experiment[key], newPath) || key; + + // Makes base/origin rows first + if (origin && Array.isArray(origin) && origin.map(item => getDisplayTextForTitles(item, newPath)).includes(newKey)) { + newKey = `0${newKey}`; + } + convertedModel[newKey] = convertExperimentsArrays(experiment[key], origin ? origin[key] : null, experiments.map(exp => exp ? exp[key] : null), newPath); + } else if (isArrayOrderNotImportant(experiment[key], key, experiments)) { + const hashedObj = {}; + const currentIndex = path.split(/\.([0-9]+)$/)[1]; + experiment[key].forEach(item => { + let convertedItemHash = convertToHashItem(item, origin && (Array.isArray(origin) ? (origin.map(item => item[key]) as any).flat() : origin[key]?.[currentIndex]), newPath); + if (hashedObj[convertedItemHash]) { + convertedItemHash = `${counter}${convertedItemHash}`; + counter--; + } + if (isObject(item)) { + hashedObj[convertedItemHash] = + convertExperimentsArrays(item, origin ? origin[key] : null, experiments.map(exp => exp ? exp[key] : null), newPath); + } else { + hashedObj[convertedItemHash] = item; + } + }); + convertedModel[key] = hashedObj; + } else { + convertedModel[key] = experiment[key]; + } + } + } + ); + return convertedModel; +} diff --git a/src/app/webapp-common/experiments-compare/reducers/experiments-compare-details.reducer.ts b/src/app/webapp-common/experiments-compare/reducers/experiments-compare-details.reducer.ts index 24512f80..b53a1e31 100644 --- a/src/app/webapp-common/experiments-compare/reducers/experiments-compare-details.reducer.ts +++ b/src/app/webapp-common/experiments-compare/reducers/experiments-compare-details.reducer.ts @@ -1,16 +1,20 @@ -import {resetState, setExperiments} from '../actions/experiments-compare-details.actions'; +import {resetState, setExperiments, setModels} from '../actions/experiments-compare-details.actions'; import {IExperimentDetail} from '~/features/experiments-compare/experiments-compare-models'; import {createReducer, on} from '@ngrx/store'; +import {ModelDetail} from '@common/experiments-compare/shared/experiments-compare-details.model'; export interface ExperimentCompareDetailsState { experiments: Array; + models: Array; } export const initialState: ExperimentCompareDetailsState = { - experiments : [] + experiments: [], + models: [] }; export const experimentsCompareDetailsReducer = createReducer(initialState, on(setExperiments, (state: ExperimentCompareDetailsState, {experiments}) => ({...state, experiments})), + on(setModels, (state: ExperimentCompareDetailsState, {models}) => ({...state, models})), on(resetState, () => ({...initialState})) ); diff --git a/src/app/webapp-common/experiments-compare/reducers/index.ts b/src/app/webapp-common/experiments-compare/reducers/index.ts index a10dda43..e4ef2700 100644 --- a/src/app/webapp-common/experiments-compare/reducers/index.ts +++ b/src/app/webapp-common/experiments-compare/reducers/index.ts @@ -17,7 +17,7 @@ import {compareHeader, CompareHeaderState} from './compare-header.reducer'; import {IExperimentDetail} from '~/features/experiments-compare/experiments-compare-models'; import {ScalarKeyEnum} from '~/business-logic/model/events/scalarKeyEnum'; import {scalarsGraphReducer, ScalarsGraphState} from './experiments-compare-scalars-graph.reducer'; -import {ExperimentParams} from '../shared/experiments-compare-details.model'; +import {ExperimentParams, ModelDetail} from '../shared/experiments-compare-details.model'; import {ExperimentCompareParamsState, experimentsCompareParamsReducer} from './experiments-compare-params.reducer'; import {groupByCharts, GroupByCharts} from '../../experiments/reducers/experiment-output.reducer'; import {selectSelectedProjectId} from '../../core/reducers/projects.reducer'; @@ -38,8 +38,11 @@ export const experimentsCompare = state => state.experimentsCompare; // Details export const experimentsDetails = createSelector(experimentsCompare, (state): ExperimentCompareDetailsState => state ? state.details : {}); export const selectExperimentsDetails = createSelector(experimentsDetails, (state): Array => state.experiments); +export const selectModelsDetails = createSelector(experimentsDetails, (state): Array => state.models); export const selectExperimentIdsDetails = createSelector(selectExperimentsDetails, (experiments): Array => experiments.map(exp => exp.id)); +export const selectModelIdsDetails = createSelector(selectModelsDetails, + (models): Array => models.map(model => model.id)); // Params export const experimentsParams = createSelector(experimentsCompare, (state): ExperimentCompareParamsState => state ? state.params : {}); @@ -54,6 +57,7 @@ export const selectIsCompare = createSelector(selectRouterConfig, (config): bool export const selectIsModels = createSelector(selectRouterConfig, (config): boolean => config?.includes('models')); export const selectIsPipelines = createSelector(selectRouterConfig, (config): boolean => config?.[0] === 'pipelines'); export const selectIsDatasets = createSelector(selectRouterConfig, (config): boolean => config?.[0] === 'datasets'); +export const selectSelectedFeature = createSelector(selectRouterConfig, (config): string => config?.[0]); export const selectCustomProject = createSelector(selectRouterConfig, (config): boolean => ['pipelines', 'datasets'].includes(config?.[0])); export const selectCompareAddTableSortFields = createSelector(selectCompareHeader, selectSelectedProjectId, diff --git a/src/app/webapp-common/experiments-compare/services/model-details-reverter.service.ts b/src/app/webapp-common/experiments-compare/services/model-details-reverter.service.ts new file mode 100644 index 00000000..4ba45f1f --- /dev/null +++ b/src/app/webapp-common/experiments-compare/services/model-details-reverter.service.ts @@ -0,0 +1,87 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import {Inject, Injectable, LOCALE_ID} from '@angular/core'; +import {TAGS} from '../../tasks/tasks.constants'; +import {IModelInfo} from '../../experiments/shared/common-experiment-model.model'; +import {ITask} from '~/business-logic/model/al-task'; +import {formatDate} from '@angular/common'; +import {TIME_FORMAT_STRING} from '@common/constants'; +import {NA} from '~/app.constants'; +import {DurationPipe} from '@common/shared/pipes/duration.pipe'; +import {ModelDetail} from '@common/experiments-compare/shared/experiments-compare-details.model'; +import parseHocon from 'hocon-parser'; + +@Injectable({ + providedIn: 'root' +}) +export class ModelDetailsReverterService { + + private durationPipe: DurationPipe; + + constructor(@Inject(LOCALE_ID) public locale: string) { + this.durationPipe = new DurationPipe(); + this.locale = locale; + } + + revertModels(modelIds: Array, models: Array): ModelDetail[] { + // map the experiment ids to keep the user order. + return modelIds.map(id => { + const model = models.find(ex => ex.id === id); + return { + id: model.id, + name: model.name, + status: model.ready ? 'Ready' : 'Draft', + last_update: model.last_update, + last_iteration: model.last_iteration, + project: model?.project, + tags: model.tags, + general: this.revertGeneral(model), + labels: this.revertLabels(model), + metadata: this.revertMetadata(model), + }; + }); + } + + revertModelsDesign(modelIds: Array, models: Array, safeMode: boolean): ModelDetail[] { + // map the experiment ids to keep the user order. + return modelIds.map(id => { + const model = models.find(ex => ex.id === id); + return { + id: model.id, + name: model.name, + status: model.ready ? 'Ready' : 'Draft', + last_update: model.last_update, + last_iteration: model.last_iteration, + project: model?.project, + tags: model.tags, + design: this.revertNetworkDesign(model, safeMode) + }; + }); + } + public revertGeneral(model: IModelInfo) { + return { + 'created at': model.created && formatDate(model.created, TIME_FORMAT_STRING, this.locale) || NA, + 'update at': model.last_update && formatDate(model.last_update, TIME_FORMAT_STRING, this.locale) || NA, + framework: model.framework, + 'model url': model.uri, + user: model.user.name || NA, + 'creating experiment': (model.parent as unknown as ITask)?.name || NA, + archive: model.system_tags.includes(TAGS.HIDDEN) ? 'Yes' : 'No', + project: model.project?.name || NA, + }; + } + + + revertNetworkDesign(model, safeMode: boolean): any { + let networkDesign = model?.design?.design || model?.design; + networkDesign = typeof networkDesign === 'string' ? (safeMode? networkDesign.split('\n'): parseHocon(networkDesign)) : {}; + return networkDesign; + } + + private revertLabels(model: IModelInfo) { + return model.labels; + } + + private revertMetadata(model: IModelInfo) { + return model.metadata; + } +} diff --git a/src/app/webapp-common/experiments-compare/shared/experiment-compare-shared.module.ts b/src/app/webapp-common/experiments-compare/shared/experiment-compare-shared.module.ts index 40624cab..24482a86 100755 --- a/src/app/webapp-common/experiments-compare/shared/experiment-compare-shared.module.ts +++ b/src/app/webapp-common/experiments-compare/shared/experiment-compare-shared.module.ts @@ -5,9 +5,10 @@ import {SMSharedModule} from '../../shared/shared.module'; import { SelectMetricForCustomColComponent } from '@common/experiments/dumb/select-metric-for-custom-col/select-metric-for-custom-col.component'; -import {MatLegacyRadioModule} from '@angular/material/legacy-radio'; +import {MatRadioModule} from '@angular/material/radio'; import {FormsModule} from '@angular/forms'; import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module'; +import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; const declarations = [ ExperimentSettingsComponent, @@ -15,13 +16,14 @@ const declarations = [ ]; @NgModule({ - imports: [ - CommonModule, - SMSharedModule, - MatLegacyRadioModule, - FormsModule, - SharedPipesModule - ], + imports: [ + CommonModule, + SMSharedModule, + MatRadioModule, + FormsModule, + SharedPipesModule, + MatProgressSpinnerModule + ], declarations : [declarations], exports : [...declarations] }) diff --git a/src/app/webapp-common/experiments-compare/shared/experiments-compare-details.model.ts b/src/app/webapp-common/experiments-compare/shared/experiments-compare-details.model.ts index 59cd7bbf..9675bcdf 100644 --- a/src/app/webapp-common/experiments-compare/shared/experiments-compare-details.model.ts +++ b/src/app/webapp-common/experiments-compare/shared/experiments-compare-details.model.ts @@ -9,11 +9,18 @@ import {Artifact} from '../../../business-logic/model/tasks/artifact'; export type ExperimentCompareTrees = Array; -export interface ExperimentDetailBase extends Omit{ +export interface ModelDetail extends Omit { + project?: Project; + info?: any; + labels?: Model['labels']; + metadata?: Model['design']; +} + +export interface ExperimentDetailBase extends Omit { project?: Project; model?: ModelDetails; execution?: ExecutionDetails; - artifacts?: {[key: string]: Artifact}; + artifacts?: { [key: string]: Artifact }; } export interface ExperimentParams { @@ -38,7 +45,7 @@ export interface ModelDetailsInput { framework?: Model['framework']; uri?: Model['uri']; name?: Model['name']; - taskName?: string + taskName?: string; } export interface ModelDetailsSource { diff --git a/src/app/webapp-common/experiments/actions/common-experiments-view.actions.ts b/src/app/webapp-common/experiments/actions/common-experiments-view.actions.ts index 8a8ee9a4..7469c9e1 100755 --- a/src/app/webapp-common/experiments/actions/common-experiments-view.actions.ts +++ b/src/app/webapp-common/experiments/actions/common-experiments-view.actions.ts @@ -108,12 +108,18 @@ export const setParents = createAction( props<{ parents: ProjectsGetTaskParentsResponseParents[] }>() ); +export const resetTablesFilterParentsOptions = createAction( + EXPERIMENTS_PREFIX + '[reset project experiment parents]' +); + export const setActiveParentsFilter = createAction( EXPERIMENTS_PREFIX + '[set active parents filter]', props<{ parents: ProjectsGetTaskParentsResponseParents[] }>() ); -export const getParents = createAction(EXPERIMENTS_PREFIX + '[get project experiments parents]'); +export const getParents = createAction( + EXPERIMENTS_PREFIX + '[get project experiments parents]', + props<{searchValue: string}>()); export const tableFilterChanged = createAction( EXPERIMENTS_PREFIX + '[table filter changed]', @@ -222,9 +228,13 @@ export const hyperParamSelectedExperiments = createAction( export const getTags = createAction(EXPERIMENTS_PREFIX + ' [get experiments tags]'); export const setTags = createAction( - EXPERIMENTS_PREFIX + 'SET_TAGS', + EXPERIMENTS_PREFIX + '[set experiment tags]', props<{ tags: string[] }>() ); +export const addProjectsTag = createAction( + EXPERIMENTS_PREFIX + '[add experiment tag]', + props<{tag: string}>() +); export const setSelectedExperimentsDisableAvailable = createAction( EXPERIMENTS_PREFIX + 'setSelectedExperimentsDisableAvailable', props<{ selectedExperimentsDisableAvailable: Record }>() diff --git a/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-aritfacts.component.scss b/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-aritfacts.component.scss index 9042cb1d..327f51bf 100755 --- a/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-aritfacts.component.scss +++ b/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-aritfacts.component.scss @@ -29,13 +29,6 @@ padding: 0; } - .artifacts-col { - flex: 1; - overflow: auto; - height: 100%; - padding: 0; - } - ::ng-deep sm-labeled-row { border-bottom: none !important; } diff --git a/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-artifacts.component.html b/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-artifacts.component.html index 6f0701ba..a2e0ea40 100755 --- a/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-artifacts.component.html +++ b/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-artifacts.component.html @@ -6,24 +6,25 @@ editable: editable$ | async }" [ngTemplateOutlet]="selfie" #selfie> -
- -
+ + + + + -
-
+ +
diff --git a/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-artifacts.component.ts b/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-artifacts.component.ts index 9ba87342..c36edcec 100755 --- a/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-artifacts.component.ts +++ b/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-artifacts.component.ts @@ -1,7 +1,7 @@ import {Component, OnDestroy} from '@angular/core'; import {Store} from '@ngrx/store'; import {selectBackdropActive} from '@common/core/reducers/view.reducer'; -import {combineLatest, Observable, Subscription} from 'rxjs'; +import {combineLatest, Observable, pairwise, Subscription} from 'rxjs'; import {ExperimentInfoState} from '~/features/experiments/reducers/experiment-info.reducer'; import {selectCurrentArtifactExperimentId, selectExperimentModelInfoData} from '../../reducers'; import { @@ -11,7 +11,7 @@ import { } from '~/features/experiments/reducers'; import {IExperimentInfo} from '~/features/experiments/shared/experiment-info.model'; import {selectRouterConfig, selectRouterParams} from '@common/core/reducers/router-reducer'; -import {debounceTime, distinctUntilChanged, filter, map} from 'rxjs/operators'; +import {debounceTime, distinctUntilChanged, filter, map, startWith} from 'rxjs/operators'; import {ActivatedRoute, Router} from '@angular/router'; import {IExperimentModelInfo} from '../../shared/common-experiment-model.model'; import { @@ -64,10 +64,14 @@ export class ExperimentInfoArtifactsComponent implements OnDestroy { .pipe( debounceTime(0), filter(([project, selectedExperiment]) => !!project?.id && !!selectedExperiment), - map(([, selectedExperiment]) => selectedExperiment.id) + map(([, selectedExperiment]) => selectedExperiment.id), + startWith(null), // emitting first empty value to fill-in the buffer + pairwise() ) - .subscribe(experimentId => { - this.store.dispatch(setExperimentArtifacts({model: null, experimentId: null})); + .subscribe(([previousId, experimentId]) => { + if (previousId !== experimentId) { + this.store.dispatch(setExperimentArtifacts({model: null, experimentId: null})); + } this.store.dispatch(getExperimentArtifacts({experimentId})); }) ); diff --git a/src/app/webapp-common/experiments/containers/experiment-info-execution/experiment-info-execution.component.html b/src/app/webapp-common/experiments/containers/experiment-info-execution/experiment-info-execution.component.html index acd7db94..b224913d 100755 --- a/src/app/webapp-common/experiments/containers/experiment-info-execution/experiment-info-execution.component.html +++ b/src/app/webapp-common/experiments/containers/experiment-info-execution/experiment-info-execution.component.html @@ -59,11 +59,11 @@ > @@ -89,11 +89,11 @@ [formData]="formData.requirements?.pip"> @@ -111,13 +111,13 @@
{{formData.container?.image}}
- +
{{formData.container?.arguments | hideRedactedArguments: (redactedArguments$| async) }}
- +
@@ -142,11 +142,11 @@ [formData]="formData?.container?.setup_shell_script"> @@ -164,14 +164,14 @@
{{formData.output?.destination}}
- +
{{formData.output?.logLevel}}
- +
diff --git a/src/app/webapp-common/experiments/containers/experiment-info-execution/experiment-info-execution.component.ts b/src/app/webapp-common/experiments/containers/experiment-info-execution/experiment-info-execution.component.ts index 4bc81846..d25b4246 100755 --- a/src/app/webapp-common/experiments/containers/experiment-info-execution/experiment-info-execution.component.ts +++ b/src/app/webapp-common/experiments/containers/experiment-info-execution/experiment-info-execution.component.ts @@ -16,9 +16,9 @@ import { selectIsSelectedExperimentInDev } from '../../reducers'; import {selectBackdropActive, selectHideRedactedArguments} from '@common/core/reducers/view.reducer'; -import {EditJsonComponent} from '@common/shared/ui-components/overlay/edit-json/edit-json.component'; +import {EditJsonComponent, EditJsonData} from '@common/shared/ui-components/overlay/edit-json/edit-json.component'; import {filter, take} from 'rxjs/operators'; -import {MatLegacyDialog as MatDialog, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MatDialog, MatDialogRef} from '@angular/material/dialog'; import {ConfirmDialogComponent} from '@common/shared/ui-components/overlay/confirm-dialog/confirm-dialog.component'; import {EditableSectionComponent} from '@common/shared/ui-components/panel/editable-section/editable-section.component'; import { @@ -187,8 +187,7 @@ export class ExperimentInfoExecutionComponent implements OnInit, OnDestroy { textData: this.formData?.requirements?.pip, readOnly: false, title: 'EDIT INSTALLED PACKAGES', - typeJson: false - } + } as EditJsonData }); editInstallPackagesDialog.afterClosed().pipe(take(1)).subscribe((data) => { @@ -213,7 +212,6 @@ export class ExperimentInfoExecutionComponent implements OnInit, OnDestroy { textData: this.formData?.diff, readOnly: false, title: 'EDIT UNCOMMITTED CHANGES', - typeJson: false }, this.diffSection) .afterClosed() .pipe(take(1)) @@ -262,7 +260,7 @@ export class ExperimentInfoExecutionComponent implements OnInit, OnDestroy { } - private openEditJsonDialog(data: { textData: string; readOnly?: boolean; title?: string; typeJson?: boolean }, editableSectionComponent?: EditableSectionComponent): MatDialogRef { + private openEditJsonDialog(data: { textData: string; readOnly?: boolean; title?: string; format?: string }, editableSectionComponent?: EditableSectionComponent): MatDialogRef { const editJsonComponent = this.dialog.open(EditJsonComponent, { data }); diff --git a/src/app/webapp-common/experiments/containers/experiment-info-general/experiment-info-general.component.html b/src/app/webapp-common/experiments/containers/experiment-info-general/experiment-info-general.component.html index 8a8ebb85..49b4064f 100755 --- a/src/app/webapp-common/experiments/containers/experiment-info-general/experiment-info-general.component.html +++ b/src/app/webapp-common/experiments/containers/experiment-info-general/experiment-info-general.component.html @@ -1,4 +1,5 @@ -
- -
- -
-
+ + + + + + diff --git a/src/app/webapp-common/experiments/containers/experiment-info-hyper-parameters/experiment-info-hyper-parameters.component.scss b/src/app/webapp-common/experiments/containers/experiment-info-hyper-parameters/experiment-info-hyper-parameters.component.scss index 3378f36a..32710413 100755 --- a/src/app/webapp-common/experiments/containers/experiment-info-hyper-parameters/experiment-info-hyper-parameters.component.scss +++ b/src/app/webapp-common/experiments/containers/experiment-info-hyper-parameters/experiment-info-hyper-parameters.component.scss @@ -3,13 +3,6 @@ position: relative; height: 100%; - .hyper-col { - flex: 1; - overflow: auto; - height: 100%; - padding: 0; - } - ::ng-deep sm-labeled-row { border-bottom: none !important; } @@ -17,12 +10,4 @@ ::ng-deep hr { margin: 0 26px; } - - sm-experiment-hyper-params-navbar { - border-right: 1px solid #dee1e9; - flex: 0 0 300px; - &.minimized { - flex: 0 0 250px; - } - } } diff --git a/src/app/webapp-common/experiments/containers/experiment-info-model/experiment-info-model.component.html b/src/app/webapp-common/experiments/containers/experiment-info-model/experiment-info-model.component.html index efde6fd0..9e98d569 100755 --- a/src/app/webapp-common/experiments/containers/experiment-info-model/experiment-info-model.component.html +++ b/src/app/webapp-common/experiments/containers/experiment-info-model/experiment-info-model.component.html @@ -22,7 +22,7 @@ [modelLabels]="modelLabels" [source]="source" [showCreatedExperiment]="!outputMode" - (modelSelected)="onModelSelected($event); modelSection.unsubscribeToEventListener()"> + (modelSelectedId)="onModelSelected($event); modelSection.unsubscribeToEventListener()"> model.id === this.modelId); - if (this.orgModels.map(m => m.id).includes(selectedModel.id)) { + if (this.orgModels.map(m => m.id).includes(selectedModelId)) { this.store.dispatch(addMessage('warn', 'Selected model is already an input-model')); } else { let newModels: { model: string; name: string }[]; if (modelFoundIndex >= 0) { newModels = this.orgModels.map(model => model.id !== this.modelId ? {model: model.id, name: model.taskName} : - {model: selectedModel.id, name: model.taskName} + {model: selectedModelId, name: model.taskName} ).filter(model => model.model); } else { newModels = [ ...this.orgModels.map(model => ({model: model.id, name: model.taskName})), - {model: selectedModel.id, name: 'Input Model'} + {model: selectedModelId, name: 'Input Model'} ]; } this.store.dispatch(commonInfoActions.saveExperimentSection({models: {input: newModels as any}})); - return this.router.navigate([{modelId: selectedModel.id || ''}], {relativeTo: this.route, replaceUrl: true}); + return this.router.navigate([{modelId: selectedModelId || ''}], {relativeTo: this.route, replaceUrl: true}); } } diff --git a/src/app/webapp-common/experiments/containers/experiment-info-task-model/experiment-info-task-model.component.html b/src/app/webapp-common/experiments/containers/experiment-info-task-model/experiment-info-task-model.component.html index f1741760..83439beb 100755 --- a/src/app/webapp-common/experiments/containers/experiment-info-task-model/experiment-info-task-model.component.html +++ b/src/app/webapp-common/experiments/containers/experiment-info-task-model/experiment-info-task-model.component.html @@ -29,11 +29,11 @@ > diff --git a/src/app/webapp-common/experiments/containers/experiment-info-task-model/experiment-info-task-model.component.ts b/src/app/webapp-common/experiments/containers/experiment-info-task-model/experiment-info-task-model.component.ts index 2096dbe2..056b0633 100755 --- a/src/app/webapp-common/experiments/containers/experiment-info-task-model/experiment-info-task-model.component.ts +++ b/src/app/webapp-common/experiments/containers/experiment-info-task-model/experiment-info-task-model.component.ts @@ -9,9 +9,9 @@ import {experimentSectionsEnum} from '~/features/experiments/shared/experiments. import {selectIsExperimentEditable, selectSelectedExperiment} from '~/features/experiments/reducers'; import {activateEdit, cancelExperimentEdit, deactivateEdit, getExperimentConfigurationObj, saveExperimentConfigObj, setExperimentErrors, setExperimentFormErrors} from '../../actions/common-experiments-info.actions'; import {ConfigurationItem} from '~/business-logic/model/tasks/configurationItem'; -import {EditJsonComponent} from '@common/shared/ui-components/overlay/edit-json/edit-json.component'; +import {EditJsonComponent, EditJsonData} from '@common/shared/ui-components/overlay/edit-json/edit-json.component'; import {take} from 'rxjs/operators'; -import {MatLegacyDialog as MatDialog, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MatDialog, MatDialogRef} from '@angular/material/dialog'; import {ConfirmDialogComponent} from '@common/shared/ui-components/overlay/confirm-dialog/confirm-dialog.component'; import {EditableSectionComponent} from '@common/shared/ui-components/panel/editable-section/editable-section.component'; @@ -72,10 +72,6 @@ export class ExperimentInfoTaskModelComponent implements OnInit, OnDestroy { this.selectedConfigObjSubscription.unsubscribe(); } - onFormValuesChanged(event: { field: string; value: any }) { - // this.store.dispatch(new infoActions.ExperimentDataUpdated({id: this.selectedExperiment.id, changes: {[event.field]: event.value}})); - } - onFormErrorsChanged(event: { field: string; errors: any }) { this.store.dispatch(setExperimentErrors({[event.field]: event.errors})); } @@ -96,7 +92,7 @@ export class ExperimentInfoTaskModelComponent implements OnInit, OnDestroy { editPrototext() { const editPrototextDialog = this.dialog.open(EditJsonComponent, { - data: {textData: this.formData?.value, readOnly: false, title: 'EDIT CONFIGURATION', typeJson: false} + data: {textData: this.formData?.value, readOnly: false, title: 'EDIT CONFIGURATION'} as EditJsonData }); editPrototextDialog.afterClosed().pipe(take(1)).subscribe((data) => { diff --git a/src/app/webapp-common/experiments/containers/experiment-ouptut/base-experiment-output.component.scss b/src/app/webapp-common/experiments/containers/experiment-ouptut/base-experiment-output.component.scss index 37851c42..5269aefb 100644 --- a/src/app/webapp-common/experiments/containers/experiment-ouptut/base-experiment-output.component.scss +++ b/src/app/webapp-common/experiments/containers/experiment-ouptut/base-experiment-output.component.scss @@ -36,11 +36,10 @@ $output-tabs-height: 64px; } .refresh-position { - position: absolute; - right: 26px; - top: 2px; display: flex; align-items: center; + margin-right: 30px; + margin-left: auto; } .refreshIcon { @@ -49,11 +48,13 @@ $output-tabs-height: 64px; .output-body { position: relative; - height: calc(100% - #{$output-tabs-height + $experiment-info-header-height + 36px}); + height: calc(100% - #{$output-tabs-height + $experiment-info-header-height + 48px}); &.minimized { - height: calc(100% - #{$experiment-info-header-height + $experiment-info-tabs-height + 5px}); + height: calc(100% - #{$experiment-info-header-height + $experiment-info-tabs-height + 15px}); } } + + sm-experiment-info-header { + margin-bottom: 12px; + } } - - diff --git a/src/app/webapp-common/experiments/containers/experiment-ouptut/base-experiment-output.component.ts b/src/app/webapp-common/experiments/containers/experiment-ouptut/base-experiment-output.component.ts index 8bb0dac0..cee72c11 100644 --- a/src/app/webapp-common/experiments/containers/experiment-ouptut/base-experiment-output.component.ts +++ b/src/app/webapp-common/experiments/containers/experiment-ouptut/base-experiment-output.component.ts @@ -134,6 +134,7 @@ export abstract class BaseExperimentOutputComponent implements OnInit, OnDestroy toggleSettingsBar() { this.store.dispatch(toggleSettings()); } + updateExperimentName(name) { if (name.trim().length > 2) { this.store.dispatch(experimentDetailsUpdated({id: this.selectedExperiment.id, changes: {name}})); @@ -141,6 +142,7 @@ export abstract class BaseExperimentOutputComponent implements OnInit, OnDestroy this.store.dispatch(addMessage(MESSAGES_SEVERITY.ERROR, 'Name must be more than three letters long')); } } + maximize() { if (window.location.pathname.includes('info-output')) { const resultsPath = this.route.firstChild?.firstChild?.routeConfig?.path || this.route.firstChild.routeConfig.path; diff --git a/src/app/webapp-common/experiments/containers/experiment-output-log/experiment-output-log.component.html b/src/app/webapp-common/experiments/containers/experiment-output-log/experiment-output-log.component.html index 06cc125a..d8a1b466 100755 --- a/src/app/webapp-common/experiments/containers/experiment-output-log/experiment-output-log.component.html +++ b/src/app/webapp-common/experiments/containers/experiment-output-log/experiment-output-log.component.html @@ -1,10 +1,10 @@ -
-
+
+
Hostname: {{creator}}
- diff --git a/src/app/webapp-common/experiments/containers/experiment-output-plots/experiment-output-plots.component.ts b/src/app/webapp-common/experiments/containers/experiment-output-plots/experiment-output-plots.component.ts index ab8b5f07..3b37321a 100644 --- a/src/app/webapp-common/experiments/containers/experiment-output-plots/experiment-output-plots.component.ts +++ b/src/app/webapp-common/experiments/containers/experiment-output-plots/experiment-output-plots.component.ts @@ -108,7 +108,7 @@ export class ExperimentOutputPlotsComponent implements OnInit, OnDestroy, OnChan .pipe( distinctUntilChanged(), filter(metrics => !!metrics), - map(plots => this.isDatasetVersionPreview ? plots.filter(plot => !plot.metric.startsWith('_')) : plots), + map(plots => this.isDatasetVersionPreview ? plots.filter(plot => !plot.metric.startsWith('_')).filter(plot=> !['Execution Flow', 'Execution Details'].includes(plot.variant)) : plots), ) .subscribe(metricsPlots => { this.refreshDisabled = false; @@ -187,7 +187,8 @@ export class ExperimentOutputPlotsComponent implements OnInit, OnDestroy, OnChan createEmbedCode(event: { metrics?: string[]; variants?: string[]; domRect: DOMRect }) { this.reportEmbed.createCode({ type: 'plot', - tasks: [this.experimentId], + objects: [this.experimentId], + objectType: 'task', ...event }); } diff --git a/src/app/webapp-common/experiments/containers/experiment-output-scalars/experiment-output-scalars.component.html b/src/app/webapp-common/experiments/containers/experiment-output-scalars/experiment-output-scalars.component.html index 2b87e776..437f717e 100644 --- a/src/app/webapp-common/experiments/containers/experiment-output-scalars/experiment-output-scalars.component.html +++ b/src/app/webapp-common/experiments/containers/experiment-output-scalars/experiment-output-scalars.component.html @@ -18,7 +18,7 @@ ; + protected routerParams$: Observable; public refreshDisabled: boolean; - public listOfHidden: Observable>; + public listOfHidden$: Observable>; public scalars$: any; - public experimentSettings$: Observable; + public settings$: Observable; public searchTerm$: Observable; public minimized: boolean = false; public graphs: { [key: string]: ExtFrame[] }; @@ -69,6 +69,7 @@ export class ExperimentOutputScalarsComponent implements OnInit, OnDestroy { public splitSize$: Observable; public groupBy: GroupByCharts; protected entitySelector = this.store.select(selectSelectedExperiment) as Observable<{id?: string; name?: string}>; + protected entityType: 'task' | 'model' = 'task'; protected exportForReport = true; private scalars: any; @@ -85,6 +86,7 @@ export class ExperimentOutputScalarsComponent implements OnInit, OnDestroy { ]; public singleValueData$: Observable>; public experimentName: string; + private singleValueExists: boolean; constructor( protected store: Store, @@ -93,24 +95,27 @@ export class ExperimentOutputScalarsComponent implements OnInit, OnDestroy { protected changeDetection: ChangeDetectorRef, protected reportEmbed: ReportCodeEmbedService ) { - this.searchTerm$ = this.store.pipe(select(selectExperimentMetricsSearchTerm)); - this.splitSize$ = this.store.pipe(select(selectSplitSize)); + this.searchTerm$ = this.store.select(selectExperimentMetricsSearchTerm); + this.splitSize$ = this.store.select(selectSplitSize); this.scalars$ = this.store.select(selectExperimentInfoHistograms) .pipe( filter((metrics) => !!metrics), ); - this.experimentSettings$ = this.store.pipe( - select(selectSelectedExperimentSettings), - filter(settings => !!settings), - map(settings => settings ? settings.selectedScalar : null), - distinctUntilChanged() - ); + this.settings$ = this.store.select(selectSelectedExperimentSettings) + .pipe( + filter(settings => !!settings), + map(settings => settings ? settings.selectedScalar : null) + ); this.smoothWeight$ = this.store.select(selectSelectedSettingsSmoothWeight); this.xAxisType$ = this.store.select(selectSelectedSettingsxAxisType); this.groupBy$ = this.store.select(selectSelectedSettingsGroupBy); - this.singleValueData$ = this.store.select(selectScalarSingleValue); + this.singleValueData$ = this.store.select(selectScalarSingleValue) + .pipe(tap( data => this.singleValueExists = data?.length > 0)); + this.listOfHidden$ = this.store.select(selectSelectedSettingsHiddenScalar) + .pipe(distinctUntilChanged(isEqual)); + this.routerParams$ = this.store.select(selectRouterParams) .pipe( @@ -121,10 +126,13 @@ export class ExperimentOutputScalarsComponent implements OnInit, OnDestroy { this.selectIsExperimentPendingRunning = this.store.select(selectIsExperimentInProgress); - this.subs.add(this.xAxisType$ - .pipe(filter(axis => !!axis && !!this.experimentId)) - .subscribe(() => this.axisChanged()) + this.subs.add(this.store.select(selectShowSettings) + .subscribe((show) => this.showSettingsBar = show) ); + } + + ngOnInit() { + this.minimized = this.activeRoute.snapshot.routeConfig.data.minimized; this.subs.add(this.groupBy$ .pipe(filter((groupBy) => !!groupBy)) @@ -134,26 +142,11 @@ export class ExperimentOutputScalarsComponent implements OnInit, OnDestroy { }) ); - this.subs.add(this.singleValueData$ - .subscribe(data => { - if(data?.length>0 && !this.scalarList['Summary']){ - this.scalarList['Summary'] = {}; - } - }) + this.subs.add(this.xAxisType$ + .pipe(filter(axis => !!axis && !!this.experimentId)) + .subscribe(() => this.axisChanged()) ); - this.subs.add(this.store.select(selectShowSettings) - .subscribe((show) => this.showSettingsBar = show) - ); - - - } - - ngOnInit() { - this.minimized = this.activeRoute.snapshot.routeConfig.data.minimized; - this.listOfHidden = this.store.select(selectSelectedSettingsHiddenScalar) - .pipe(distinctUntilChanged(isEqual)); - this.subs.add(this.entitySelector .pipe( filter(experiment => !!experiment?.id), @@ -175,7 +168,7 @@ export class ExperimentOutputScalarsComponent implements OnInit, OnDestroy { }) ); - this.subs.add(this.experimentSettings$ + this.subs.add(this.settings$ .subscribe((selectedScalar) => { this.selectedGraph = selectedScalar; this.experimentGraphs?.scrollToGraph(selectedScalar); @@ -184,7 +177,7 @@ export class ExperimentOutputScalarsComponent implements OnInit, OnDestroy { this.subs.add(this.routerParams$ .subscribe(params => { - if (!this.experimentId || this.experimentId !== params.experimentId) { + if (!this.experimentId || ![params.experimentId, params.modelId].includes(this.experimentId)) { this.graphs = undefined; this.resetMetrics(); // this.store.dispatch(new ExperimentScalarRequested(params.experimentId)); @@ -197,7 +190,8 @@ export class ExperimentOutputScalarsComponent implements OnInit, OnDestroy { private prepareGraphsAndUpdate(scalars: GroupedList) { if (scalars) { const splittedScalars = this.groupBy === 'metric' ? scalars : this.splitScalars(scalars); - this.scalarList = {...this.scalarList, ...prepareScalarList(splittedScalars)}; + // eslint-disable-next-line @typescript-eslint/naming-convention + this.scalarList = {...(this.singleValueExists && {Summary: {}}), ...prepareScalarList(splittedScalars)}; this.graphs = convertScalars(splittedScalars, this.experimentId); this.changeDetection.detectChanges(); } @@ -259,8 +253,9 @@ export class ExperimentOutputScalarsComponent implements OnInit, OnDestroy { createEmbedCode(event: { metrics?: string[]; variants?: string[]; domRect: DOMRect}) { this.reportEmbed.createCode({ - type: 'scalar', - tasks: [this.experimentId], + type: (!event.metrics && !event.variants) ? 'single' : 'scalar', + objects: [this.experimentId], + objectType: this.entityType, ...event }); } diff --git a/src/app/webapp-common/experiments/dumb/experiment-artifact-item-view/experiment-artifact-item-view.component.html b/src/app/webapp-common/experiments/dumb/experiment-artifact-item-view/experiment-artifact-item-view.component.html index d98b2a7f..12f1edca 100755 --- a/src/app/webapp-common/experiments/dumb/experiment-artifact-item-view/experiment-artifact-item-view.component.html +++ b/src/app/webapp-common/experiments/dumb/experiment-artifact-item-view/experiment-artifact-item-view.component.html @@ -4,12 +4,12 @@ {{artifact?.uri}} {{artifact?.uri}} diff --git a/src/app/webapp-common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component.html b/src/app/webapp-common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component.html index 4bf2a99d..8b424b66 100644 --- a/src/app/webapp-common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component.html +++ b/src/app/webapp-common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component.html @@ -5,7 +5,7 @@ buttonTooltip="Customize table" [showButton]="false" (click)="!disabled && getMetricsToDisplay.emit()" - (menuClosed)="setMode(CustomColumnMode.Standard)" + (menuClosed)="setMode(customColumnModeEnum.Standard)" [style.pointer-events]="disabled ? 'none' : 'initial'" >
@@ -22,30 +22,30 @@
METRIC + [ngClass]="{disabled: !metricVariants?.length}" + (click)="$event.stopPropagation(); metricVariants?.length && setMode(customColumnModeEnum.Metrics)" + >METRIC
HYPERPARAMETERS + (click)="$event.stopPropagation(); hasHyperParams && setMode(customColumnModeEnum.HyperParams)" + >HYPERPARAMETERS
- - diff --git a/src/app/webapp-common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component.scss b/src/app/webapp-common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component.scss index 168ceafb..ac7a72fb 100644 --- a/src/app/webapp-common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component.scss +++ b/src/app/webapp-common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component.scss @@ -4,7 +4,7 @@ display: flex; justify-content: center; align-items: center; - padding: 15px 15px; + padding: 15px; } .custom-column-buttons { @@ -13,6 +13,7 @@ color: $blue-400; background: $faint-gray; cursor: pointer; + font-size: 14px; div:not(.disabled):hover { color: $blue-300; @@ -24,7 +25,7 @@ white-space: nowrap; .caption { - margin-top: 2px; + margin-top: 4px; } &:first-child { border-right: 1px solid $blue-200; diff --git a/src/app/webapp-common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component.ts b/src/app/webapp-common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component.ts index 3c6a1900..2f13ba5a 100644 --- a/src/app/webapp-common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component.ts +++ b/src/app/webapp-common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component.ts @@ -40,7 +40,7 @@ export class ExperimentCustomColsMenuComponent { @Output() clearSelection = new EventEmitter(); customColumnMode = CustomColumnMode.Standard as CustomColumnMode; - public CustomColumnMode = CustomColumnMode; + public customColumnModeEnum = CustomColumnMode; setMode(mode: CustomColumnMode) { this.customColumnMode = mode; diff --git a/src/app/webapp-common/experiments/dumb/experiment-execution-parameters/experiment-execution-parameters.component.html b/src/app/webapp-common/experiments/dumb/experiment-execution-parameters/experiment-execution-parameters.component.html index bc808f0d..fdb42e17 100755 --- a/src/app/webapp-common/experiments/dumb/experiment-execution-parameters/experiment-execution-parameters.component.html +++ b/src/app/webapp-common/experiments/dumb/experiment-execution-parameters/experiment-execution-parameters.component.html @@ -45,7 +45,7 @@ - +
- + {{part}}{{searchedText}} diff --git a/src/app/webapp-common/experiments/dumb/experiment-execution-parameters/experiment-execution-parameters.component.scss b/src/app/webapp-common/experiments/dumb/experiment-execution-parameters/experiment-execution-parameters.component.scss index df41fa51..824d8769 100755 --- a/src/app/webapp-common/experiments/dumb/experiment-execution-parameters/experiment-execution-parameters.component.scss +++ b/src/app/webapp-common/experiments/dumb/experiment-execution-parameters/experiment-execution-parameters.component.scss @@ -38,11 +38,7 @@ } .remove-step { - margin: .25em 0; - padding-bottom: 1.34375em; - padding-top: 7px; - display: flex; - align-items: center; + line-height: 42px; } .param-row { diff --git a/src/app/webapp-common/experiments/dumb/experiment-header/experiment-header.component.html b/src/app/webapp-common/experiments/dumb/experiment-header/experiment-header.component.html index cecacef4..a738e4d8 100755 --- a/src/app/webapp-common/experiments/dumb/experiment-header/experiment-header.component.html +++ b/src/app/webapp-common/experiments/dumb/experiment-header/experiment-header.component.html @@ -11,7 +11,7 @@ > {{hyperParameter.key | replaceViaMapPipe:sectionReplaceMap}} + >{{hyperParameter.key | replaceViaMapPipe:sectionReplaceMap}}
@@ -43,10 +45,10 @@ queryParamsHandling="preserve" [routerLink]="'configuration/' + (confObj.key | safeUrlParameter)" [class.selected]="selectedObject === confObj.key" - class="hyper-container pointer ellipsis" + class="hyper-container pointer" routerLink="configuration" > - {{confObj.key | replaceViaMapPipe:sectionReplaceMap}} + + {{confObj.key | replaceViaMapPipe:sectionReplaceMap}}
- diff --git a/src/app/webapp-common/experiments/dumb/experiment-info-edit-description/experiment-info-edit-description.component.scss b/src/app/webapp-common/experiments/dumb/experiment-info-edit-description/experiment-info-edit-description.component.scss index 78b41c78..ba338265 100644 --- a/src/app/webapp-common/experiments/dumb/experiment-info-edit-description/experiment-info-edit-description.component.scss +++ b/src/app/webapp-common/experiments/dumb/experiment-info-edit-description/experiment-info-edit-description.component.scss @@ -2,13 +2,14 @@ :host { .description-tooltip { - margin: -4px; + margin: -4px 0; max-width: 300px; background: $purple; padding: 8px; border-radius: 4px; box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.16); font-size: 11px; + overflow: hidden; div, p { color: $white; } diff --git a/src/app/webapp-common/experiments/dumb/experiment-info-header/experiment-info-header.component.html b/src/app/webapp-common/experiments/dumb/experiment-info-header/experiment-info-header.component.html index f3a283ba..c1e10775 100644 --- a/src/app/webapp-common/experiments/dumb/experiment-info-header/experiment-info-header.component.html +++ b/src/app/webapp-common/experiments/dumb/experiment-info-header/experiment-info-header.component.html @@ -1,6 +1,6 @@
- +
-
+
- + {{model?.name}} - +
diff --git a/src/app/webapp-common/experiments/dumb/experiment-models-form-view/experiment-models-form-view.component.ts b/src/app/webapp-common/experiments/dumb/experiment-models-form-view/experiment-models-form-view.component.ts index 927c7f34..ac105bd9 100755 --- a/src/app/webapp-common/experiments/dumb/experiment-models-form-view/experiment-models-form-view.component.ts +++ b/src/app/webapp-common/experiments/dumb/experiment-models-form-view/experiment-models-form-view.component.ts @@ -1,6 +1,6 @@ import {Component, EventEmitter, Input, Output} from '@angular/core'; import {IModelInfo, IModelInfoSource} from '../../shared/common-experiment-model.model'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {filter} from 'rxjs/operators'; import {Model} from '~/business-logic/model/models/model'; import {SelectModelComponent} from '@common/select-model/select-model.component'; @@ -35,20 +35,28 @@ export class ExperimentModelsFormViewComponent extends BaseClickableArtifactComp return this._model; } - @Output() modelSelected = new EventEmitter(); + @Output() modelSelectedId = new EventEmitter(); constructor(private dialog: MatDialog, protected adminService: AdminService, protected store: Store) { super(adminService, store); } public chooseModel() { - const chooseModelDialog = this.dialog.open(SelectModelComponent, {maxWidth: '95vw'}); + const chooseModelDialog = this.dialog.open(SelectModelComponent, { + data: { + header: 'Select a published model', + hideShowArchived: true + }, + width: '98%', + height: '94vh', + maxWidth: '100%', + }); chooseModelDialog.afterClosed() .pipe(filter(model => !!model)) - .subscribe((selectedModel: Model) => this.modelSelected.emit(selectedModel)); + .subscribe((selectedModelId: string) => this.modelSelectedId.emit(selectedModelId)); } removeModel() { - this.modelSelected.emit({id: null}); + this.modelSelectedId.emit(null); } } diff --git a/src/app/webapp-common/experiments/dumb/experiment-output-model-view/experiment-output-model-view.component.html b/src/app/webapp-common/experiments/dumb/experiment-output-model-view/experiment-output-model-view.component.html index 5a3b846f..d6ee3985 100755 --- a/src/app/webapp-common/experiments/dumb/experiment-output-model-view/experiment-output-model-view.component.html +++ b/src/app/webapp-common/experiments/dumb/experiment-output-model-view/experiment-output-model-view.component.html @@ -4,12 +4,12 @@ {{model?.name}} diff --git a/src/app/webapp-common/experiments/dumb/experiments-table/experiments-table.component.html b/src/app/webapp-common/experiments/dumb/experiments-table/experiments-table.component.html index 7feaebc9..dc0837d6 100755 --- a/src/app/webapp-common/experiments/dumb/experiments-table/experiments-table.component.html +++ b/src/app/webapp-common/experiments/dumb/experiments-table/experiments-table.component.html @@ -78,7 +78,7 @@ [andFilter]="col.andFilter ? filtersMatch[col.id] === 'AND' : null" (sortOrderChanged)="onSortChanged($event, col.id)" (filterChanged)="tableFilterChanged(col, $event);" - (searchValueChanged)="searchValueChanged($event, col.id)" + (searchValueChanged)="searchValueChanged($event, col.id, col.asyncFilter)" (menuOpened)="columnFilterOpened(col)" (menuClosed)="columnFilterClosed(col)" > @@ -109,7 +109,7 @@ [smTooltip]="experiment.name"> {{experiment.name}}
- +
@@ -199,8 +199,8 @@ (click)="selected && onContextMenu({e: $event, rowData: experiment, backdrop: true})" >
-
+ class="al-icon al-ico-link sm-md ms-2">
+
v {{experiment?.runtime?.version || experiment?.hyperparams?.properties?.version?.value}}
diff --git a/src/app/webapp-common/experiments/dumb/experiments-table/experiments-table.component.ts b/src/app/webapp-common/experiments/dumb/experiments-table/experiments-table.component.ts index f995552c..285bebaa 100755 --- a/src/app/webapp-common/experiments/dumb/experiments-table/experiments-table.component.ts +++ b/src/app/webapp-common/experiments/dumb/experiments-table/experiments-table.component.ts @@ -36,7 +36,8 @@ import {hyperParamSelectedExperiments, selectAllExperiments} from '../../actions import {createFiltersFromStore, excludedKey, uniqueFilterValueAndExcluded} from '@common/shared/utils/tableParamEncode'; import {getRoundedNumber} from '../../shared/common-experiments.utils'; import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; -import {MAT_LEGACY_TOOLTIP_DEFAULT_OPTIONS as MAT_TOOLTIP_DEFAULT_OPTIONS, MatLegacyTooltipDefaultOptions as MatTooltipDefaultOptions} from '@angular/material/legacy-tooltip'; +import {MAT_TOOLTIP_DEFAULT_OPTIONS, MatTooltipDefaultOptions} from '@angular/material/tooltip'; +import {getTablesFilterProjectsOptions, resetTablesFilterProjectsOptions} from '@common/core/actions/projects.actions'; @Component({ selector: 'sm-experiments-table', @@ -57,8 +58,8 @@ export class ExperimentsTableComponent extends BaseTableView implements OnInit, [EXPERIMENTS_TABLE_COL_FIELDS.TYPE]: [], [EXPERIMENTS_TABLE_COL_FIELDS.USER]: [], [EXPERIMENTS_TABLE_COL_FIELDS.TAGS]: [], - [EXPERIMENTS_TABLE_COL_FIELDS.PARENT]: [], - [EXPERIMENTS_TABLE_COL_FIELDS.PROJECT]: [], + [EXPERIMENTS_TABLE_COL_FIELDS.PARENT]: null, + [EXPERIMENTS_TABLE_COL_FIELDS.PROJECT]: null, }; readonly getSystemTags = getSystemTags; public isDevelopment = isDevelopment; @@ -122,6 +123,10 @@ export class ExperimentsTableComponent extends BaseTableView implements OnInit, @Input() set parents(parents: ProjectsGetTaskParentsResponseParents[]) { + if (!parents) { + this.filtersOptions[EXPERIMENTS_TABLE_COL_FIELDS.PARENT] = null; + return; + } const parentsAndActiveFilter = Array.from(new Set(parents.concat(this.activeParentsFilter || []))); this.filtersOptions[EXPERIMENTS_TABLE_COL_FIELDS.PARENT] = parentsAndActiveFilter.map(parent => ({ label: parent.name ? parent.name : 'Unknown Experiment', @@ -175,14 +180,13 @@ export class ExperimentsTableComponent extends BaseTableView implements OnInit, @Input() set projects(projects) { if (!projects) { + this.filtersOptions[EXPERIMENTS_TABLE_COL_FIELDS.PROJECT] = null; return; } this.filtersOptions[EXPERIMENTS_TABLE_COL_FIELDS.PROJECT] = projects.map(project => ({ label: project.name, value: project.id, - tooltip: `${project.name}` })); - this.sortOptionsList(EXPERIMENTS_TABLE_COL_FIELDS.PROJECT); } @Input() systemTags = [] as string[]; @@ -330,6 +334,10 @@ export class ExperimentsTableComponent extends BaseTableView implements OnInit, } } else if (col.id.includes('hyperparams')) { this.store.dispatch(hyperParamSelectedExperiments({col})); + } else if (col.id === EXPERIMENTS_TABLE_COL_FIELDS.PROJECT) { + if (!this.filtersOptions[EXPERIMENTS_TABLE_COL_FIELDS.PROJECT]?.length) { + this.filterSearchChanged.emit({colId: col.id, value: {value: ''}}); + } } } diff --git a/src/app/webapp-common/experiments/dumb/model-auto-populate-dialog/model-auto-populate-dialog.component.ts b/src/app/webapp-common/experiments/dumb/model-auto-populate-dialog/model-auto-populate-dialog.component.ts index b1031f1e..1a558fd6 100644 --- a/src/app/webapp-common/experiments/dumb/model-auto-populate-dialog/model-auto-populate-dialog.component.ts +++ b/src/app/webapp-common/experiments/dumb/model-auto-populate-dialog/model-auto-populate-dialog.component.ts @@ -1,39 +1,39 @@ -import {Component, Inject} from '@angular/core'; -import {MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; - -@Component({ - selector : 'sm-model-auto-populate-dialog', - templateUrl: './model-auto-populate-dialog.component.html', - styleUrls : ['./model-auto-populate-dialog.component.scss'] -}) -export class ModelAutoPopulateDialogComponent { - - public showLabelEnumCheckbox: boolean; - public showDesignCheckbox: boolean; - public formData; - public subHeader: string; - - constructor( - private dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: { populateLabels: boolean; populateDesign: boolean; experimentName: string; modelName: string } - ) { - this.formData = { - labelEnum : this.data.populateLabels, - networkDesign: this.data.populateDesign, - }; - this.subHeader = `Overwrite the ${this.data.experimentName}’s current model configuration with ${this.data.modelName}'s configuration?`; - } - - closeDialog(isConfirmed) { - if (!isConfirmed) { - this.formData.networkDesign = false; - this.formData.labelEnum = false; - } - this.dialogRef.close(this.formData); - } - - updateFormData(event) { - this.formData[event.field] = event.value; - } - -} +// import {Component, Inject} from '@angular/core'; +// import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +// +// @Component({ +// selector : 'sm-model-auto-populate-dialog', +// templateUrl: './model-auto-populate-dialog.component.html', +// styleUrls : ['./model-auto-populate-dialog.component.scss'] +// }) +// export class ModelAutoPopulateDialogComponent { +// +// public showLabelEnumCheckbox: boolean; +// public showDesignCheckbox: boolean; +// public formData; +// public subHeader: string; +// +// constructor( +// private dialogRef: MatDialogRef, +// @Inject(MAT_DIALOG_DATA) public data: { populateLabels: boolean; populateDesign: boolean; experimentName: string; modelName: string } +// ) { +// this.formData = { +// labelEnum : this.data.populateLabels, +// networkDesign: this.data.populateDesign, +// }; +// this.subHeader = `Overwrite the ${this.data.experimentName}’s current model configuration with ${this.data.modelName}'s configuration?`; +// } +// +// closeDialog(isConfirmed) { +// if (!isConfirmed) { +// this.formData.networkDesign = false; +// this.formData.labelEnum = false; +// } +// this.dialogRef.close(this.formData); +// } +// +// updateFormData(event) { +// this.formData[event.field] = event.value; +// } +// +// } diff --git a/src/app/webapp-common/experiments/dumb/select-metric-for-custom-col/select-metric-for-custom-col.component.html b/src/app/webapp-common/experiments/dumb/select-metric-for-custom-col/select-metric-for-custom-col.component.html index db2f9efa..281e606c 100644 --- a/src/app/webapp-common/experiments/dumb/select-metric-for-custom-col/select-metric-for-custom-col.component.html +++ b/src/app/webapp-common/experiments/dumb/select-metric-for-custom-col/select-metric-for-custom-col.component.html @@ -1,4 +1,4 @@ -
+

SELECT METRIC TO DISPLAY

@@ -14,6 +14,12 @@ (valueChanged)="searchQ($event)" >
+
+ +
+
+
No data to show
+
- LAST + LAST MIN MAX diff --git a/src/app/webapp-common/experiments/dumb/select-metric-for-custom-col/select-metric-for-custom-col.component.scss b/src/app/webapp-common/experiments/dumb/select-metric-for-custom-col/select-metric-for-custom-col.component.scss index 076e21f4..f9cea61c 100644 --- a/src/app/webapp-common/experiments/dumb/select-metric-for-custom-col/select-metric-for-custom-col.component.scss +++ b/src/app/webapp-common/experiments/dumb/select-metric-for-custom-col/select-metric-for-custom-col.component.scss @@ -2,6 +2,14 @@ :host { + .metrics-container { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + min-height: 320px; + } + .head { margin-bottom: 12px; padding: 12px; @@ -113,4 +121,14 @@ padding: 12px; font-weight: 500; } + + .spinner { + margin: auto; + } + + .empty-state { + text-align: center; + margin: auto; + color: $blue-400; + } } diff --git a/src/app/webapp-common/experiments/dumb/select-metric-for-custom-col/select-metric-for-custom-col.component.ts b/src/app/webapp-common/experiments/dumb/select-metric-for-custom-col/select-metric-for-custom-col.component.ts index 839ada09..ea790144 100644 --- a/src/app/webapp-common/experiments/dumb/select-metric-for-custom-col/select-metric-for-custom-col.component.ts +++ b/src/app/webapp-common/experiments/dumb/select-metric-for-custom-col/select-metric-for-custom-col.component.ts @@ -23,12 +23,15 @@ export class SelectMetricForCustomColComponent { private debounceTimer: number; @Input() set metricVariants(metricVar: Array) { - this.metricTree = metricVar.reduce((result, metric) => { + if (metricVar === null) { + return; + } + this.metricTree = metricVar?.reduce((result, metric) => { result[metric.metric] ? result[metric.metric].push(metric) : result[metric.metric] = [metric]; return result; }, {} as {[metricName: string]: MetricVariantResult[]}); - this.filteredMetricTree = Object.entries(this.metricTree).slice(0, this.entriesLimit); - this.moreResults = Object.keys(this.metricTree).length - this.filteredMetricTree.length; + this.filteredMetricTree = Object.entries(this.metricTree || {}).slice(0, this.entriesLimit); + this.moreResults = Object.keys(this.metricTree || {}).length - this.filteredMetricTree.length; } @Input() set tableCols(tableCols) { diff --git a/src/app/webapp-common/experiments/effects/common-experiment-output.effects.ts b/src/app/webapp-common/experiments/effects/common-experiment-output.effects.ts index a5931975..a6e8d1c7 100644 --- a/src/app/webapp-common/experiments/effects/common-experiment-output.effects.ts +++ b/src/app/webapp-common/experiments/effects/common-experiment-output.effects.ts @@ -118,7 +118,10 @@ export class CommonExperimentOutputEffects { fetchExperimentScalar$ = createEffect(() => this.actions$.pipe( ofType(outputActions.experimentScalarRequested), - withLatestFrom(this.store.select(selectSelectedSettingsxAxisType), this.store.select(selectExperimentHistogramCacheAxisType)), + withLatestFrom( + this.store.select(selectSelectedSettingsxAxisType), + this.store.select(selectExperimentHistogramCacheAxisType) + ), switchMap(([action, axisType, prevAxisType]) => { if ([ScalarKeyEnum.IsoTime, ScalarKeyEnum.Timestamp].includes(prevAxisType) && [ScalarKeyEnum.IsoTime, ScalarKeyEnum.Timestamp].includes(axisType)) { diff --git a/src/app/webapp-common/experiments/effects/common-experiments-info.effects.ts b/src/app/webapp-common/experiments/effects/common-experiments-info.effects.ts index 3c1fccfc..35b2af55 100755 --- a/src/app/webapp-common/experiments/effects/common-experiments-info.effects.ts +++ b/src/app/webapp-common/experiments/effects/common-experiments-info.effects.ts @@ -183,7 +183,7 @@ export class CommonExperimentsInfoEffects { switchMap(([action, pipeline]) => this.apiTasks.tasksGetByIdEx({ id: [action.id], // eslint-disable-next-line @typescript-eslint/naming-convention - only_fields: pipeline ? PIPELINE_INFO_ONLY_FIELDS : ['name', 'comment', 'runtime', 'configuration', 'status'] + only_fields: pipeline ? PIPELINE_INFO_ONLY_FIELDS : ['name', 'comment', 'parent.name', 'parent.project.id', 'runtime', 'configuration', 'status'] }).pipe( mergeMap((res: any) => [commonInfoActions.setSelectedPipelineStep({step: res?.tasks[0]}), deactivateLoader(action.type)] diff --git a/src/app/webapp-common/experiments/effects/common-experiments-menu.effects.ts b/src/app/webapp-common/experiments/effects/common-experiments-menu.effects.ts index 1b5c4f69..7d940a54 100644 --- a/src/app/webapp-common/experiments/effects/common-experiments-menu.effects.ts +++ b/src/app/webapp-common/experiments/effects/common-experiments-menu.effects.ts @@ -37,7 +37,7 @@ import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; import {TasksEnqueueManyResponse} from '~/business-logic/model/tasks/tasksEnqueueManyResponse'; import {getNotificationAction, MenuItems, MoreMenuItems} from '../../shared/entity-page/items.utils'; import {getAllSystemProjects} from '../../core/actions/projects.actions'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {ApiPipelinesService} from '~/business-logic/api-services/pipelines.service'; import {PIPELINE_INFO_ONLY_FIELDS} from '../../pipelines-controller/controllers.consts'; import { @@ -212,7 +212,7 @@ export class CommonExperimentsMenuEffects { switchMap(([action, ]) => this.apiTasks.tasksClone({ task: action.originExperiment.id, /* eslint-disable @typescript-eslint/naming-convention */ - new_task_project: action.cloneData.project, + new_task_project: action.cloneData.project === ''? undefined : action.cloneData.project, new_task_comment: action.cloneData.comment, new_task_name: action.cloneData.name, new_project_name: action.cloneData.newProjectName diff --git a/src/app/webapp-common/experiments/effects/common-experiments-view.effects.ts b/src/app/webapp-common/experiments/effects/common-experiments-view.effects.ts index dae73473..d763d532 100755 --- a/src/app/webapp-common/experiments/effects/common-experiments-view.effects.ts +++ b/src/app/webapp-common/experiments/effects/common-experiments-view.effects.ts @@ -6,7 +6,7 @@ import {cloneDeep, flatten, isEqual} from 'lodash-es'; import {EMPTY, Observable, of} from 'rxjs'; import { auditTime, - catchError, + catchError, debounceTime, expand, filter, map, @@ -215,7 +215,7 @@ export class CommonExperimentsViewEffects { deactivateLoader(action.type) ]; } - if (res.scroll_id !== currentScrollId) { + if (res.scroll_id !== currentScrollId && currentScrollId) { actions.push( exActions.setCurrentScrollId({scrollId: res.scroll_id}), exActions.setNoMoreExperiments({hasMore: (res.tasks.length < EXPERIMENTS_PAGE_SIZE)})); @@ -280,7 +280,7 @@ export class CommonExperimentsViewEffects { ]; } res.tasks = convertStopToComplete(res.tasks); - const addTasksAction = scrollId === res.scroll_id + const addTasksAction = scrollId === res.scroll_id || !scrollId ? [exActions.addExperiments({experiments: res.tasks as ITableExperiment[]})] : [exActions.setTableRefreshPending({refresh: true}), addMessage(MESSAGES_SEVERITY.WARN, 'Session expired')]; @@ -378,15 +378,17 @@ export class CommonExperimentsViewEffects { getParentsEffect = createEffect(() => this.actions$.pipe( ofType(exActions.getParents), + debounceTime(300), withLatestFrom( this.store.select(selectRouterParams).pipe(map(params => params?.projectId)), this.store.select(selectIsArchivedMode) ), - switchMap(([, projectId, isArchive]) => this.projectsApi.projectsGetTaskParents({ + switchMap(([action, projectId, isArchive]) => this.projectsApi.projectsGetTaskParents({ projects: projectId !== '*' ? [projectId] : [], tasks_state: isArchive ? ProjectsGetTaskParentsRequest.TasksStateEnum.Archived : - ProjectsGetTaskParentsRequest.TasksStateEnum.Active + ProjectsGetTaskParentsRequest.TasksStateEnum.Active, + ...(action.searchValue && {task_name: `(?i)${action.searchValue}`}) // (?i) is case insensitive }).pipe( withLatestFrom(this.store.select(selectTableFilters).pipe(map(filters => filters?.['parent.name']?.value || []))), mergeMap(([res, filteredParentIds]: [ProjectsGetTaskParentsResponse, string[]]) => { diff --git a/src/app/webapp-common/experiments/experiment.consts.ts b/src/app/webapp-common/experiments/experiment.consts.ts index 6d272db6..0e3c9427 100644 --- a/src/app/webapp-common/experiments/experiment.consts.ts +++ b/src/app/webapp-common/experiments/experiment.consts.ts @@ -1,5 +1,6 @@ import {ColHeaderFilterTypeEnum, ColHeaderTypeEnum, ISmCol} from '../shared/ui-components/data/table/table.consts'; import {EXPERIMENTS_TABLE_COL_FIELDS} from '~/features/experiments/shared/experiments.const'; +import {rootProjectsPageSize} from '@common/constants'; export const EXPERIMENTS_STORE_KEY = 'experiments'; export const EXPERIMENTS_PREFIX = 'EXPERIMENTS_'; @@ -69,6 +70,8 @@ export const INITIAL_EXPERIMENT_TABLE_COLS: ISmCol[] = [ header : 'PROJECT', filterable : true, searchableFilter: true, + asyncFilter: true, + paginatedFilterPageSize: rootProjectsPageSize, sortable : false, style : {width: '150px'}, }, @@ -142,7 +145,8 @@ export const INITIAL_EXPERIMENT_TABLE_COLS: ISmCol[] = [ sortable : false, header : 'PARENT TASK', style : {width: '200px'}, - showInCardFilters: true + showInCardFilters: true, + asyncFilter: true } ]; diff --git a/src/app/webapp-common/experiments/experiments.component.html b/src/app/webapp-common/experiments/experiments.component.html index 2febadcf..3b4beff1 100644 --- a/src/app/webapp-common/experiments/experiments.component.html +++ b/src/app/webapp-common/experiments/experiments.component.html @@ -24,7 +24,7 @@ >
- + Project - (Create New) - + (Create New) + + Please provide a Project Please provide a name longer than 3 characters - Please provide a different name as this project name is taken as an Example project + Please provide a different name as this + project name is taken as an Example project + - {{isMulti? (type | titlecase)+'s are' : (type| titlecase) + ' is'}} already in the selected project + + {{isMulti? (type | titlecase)+'s are' : (type| titlecase) + ' is'}} already in the selected project + + *Project name can't contain only spaces. + "{{filterText}}" (Create New) -
+ *ngIf="!projectInput?.errors && projects !== null && projectInput.value && !(projectInput.value | stringIncludedInArray:projectsNames)" + [value]="projectInput.value" + >"{{projectInput.value}}" (Create New) + +
+
+
+ +
+
Loading more...
+
diff --git a/src/app/webapp-common/experiments/shared/components/change-project-dialog/change-project-dialog.component.scss b/src/app/webapp-common/experiments/shared/components/change-project-dialog/change-project-dialog.component.scss index 270a232e..4ebd0a29 100755 --- a/src/app/webapp-common/experiments/shared/components/change-project-dialog/change-project-dialog.component.scss +++ b/src/app/webapp-common/experiments/shared/components/change-project-dialog/change-project-dialog.component.scss @@ -34,4 +34,8 @@ margin-left: 16px; } } + + .search-icon { + transform: translateY(3px); + } } diff --git a/src/app/webapp-common/experiments/shared/components/change-project-dialog/change-project-dialog.component.ts b/src/app/webapp-common/experiments/shared/components/change-project-dialog/change-project-dialog.component.ts index e1973d90..1784bafa 100755 --- a/src/app/webapp-common/experiments/shared/components/change-project-dialog/change-project-dialog.component.ts +++ b/src/app/webapp-common/experiments/shared/components/change-project-dialog/change-project-dialog.component.ts @@ -1,20 +1,23 @@ -import {MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {Project} from '~/business-logic/model/projects/project'; -import {Component, Inject, OnDestroy, OnInit, ViewChild} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, OnDestroy, OnInit, ViewChild} from '@angular/core'; import {Store} from '@ngrx/store'; -import {asyncScheduler, Observable, Subscription} from 'rxjs'; -import {selectRootProjects} from '@common/core/reducers/projects.reducer'; -import {getAllSystemProjects} from '@common/core/actions/projects.actions'; -import {filter, map, startWith} from 'rxjs/operators'; +import {Observable, Subscription} from 'rxjs'; +import {selectTablesFilterProjectsOptions} from '@common/core/reducers/projects.reducer'; +import {getTablesFilterProjectsOptions, resetTablesFilterProjectsOptions} from '@common/core/actions/projects.actions'; +import {filter, map, tap} from 'rxjs/operators'; import {castArray, isEqual} from 'lodash-es'; import {NgForm} from '@angular/forms'; import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; import {isReadOnly} from '@common/shared/utils/is-read-only'; +import {rootProjectsPageSize} from '@common/constants'; +import {ProjectsGetAllResponseSingle} from '~/business-logic/model/projects/projectsGetAllResponseSingle'; @Component({ selector: 'sm-change-project-dialog', templateUrl: './change-project-dialog.component.html', - styleUrls: ['./change-project-dialog.component.scss'] + styleUrls: ['./change-project-dialog.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush }) export class ChangeProjectDialogComponent implements OnInit, OnDestroy { @@ -22,12 +25,11 @@ export class ChangeProjectDialogComponent implements OnInit, OnDestroy { public sourceProject: Project; public currentProjects: string[]; public projects: { label: string; value: string }[]; - public filteredProjects: Observable<{ label: string; value: string }[]>; public formData: { project: any } = { project: null }; public reference: string; - private projectsSub: Subscription; + private subs = new Subscription(); filterText: string = ''; isNewName: boolean = false; @@ -37,6 +39,13 @@ export class ChangeProjectDialogComponent implements OnInit, OnDestroy { public currentProjectInstance: Project; public isMulti: boolean; type: EntityTypeEnum; + private projectRoot = 'Projects root'; + private rootFiltered: boolean; + public projectsNames: string[]; + public loading: boolean; + public noMoreOptions: boolean; + private allProjectsBeforeFilter: Partial[]; + private previousLength: number | undefined; constructor( private store: Store, public dialogRef: MatDialogRef, @@ -52,43 +61,63 @@ export class ChangeProjectDialogComponent implements OnInit, OnDestroy { this.isMulti = !!Array.isArray(data.reference); this.type = data.type; this.reference = Array.isArray(data.reference) ? `${data.reference.length} ${data.type}s` : data.reference; - this.readOnlyProjects$ = this.store.select(selectRootProjects) - .pipe(map(projects => projects.filter(project => isReadOnly(project)).map(project=> project.name).concat(this.currentProjectInstance?.name))); - this.projects$ = this.store.select(selectRootProjects).pipe( + this.readOnlyProjects$ = this.store.select(selectTablesFilterProjectsOptions) + .pipe(map(projects => projects?.filter(project => isReadOnly(project)).map(project=> project.name).concat(this.currentProjectInstance?.name))); + + this.projects$ = this.store.select(selectTablesFilterProjectsOptions).pipe( + tap(projects => this.allProjectsBeforeFilter = projects), filter(projects => !!projects), map(projects => projects.filter((project) => !isReadOnly(project))) ); } ngOnInit(): void { - this.store.dispatch(getAllSystemProjects()); - this.projectsSub = this.projects$.subscribe(projects => { + this.searchChanged(''); + // this.store.dispatch(getAllSystemProjects()); + this.subs.add(this.projects$.subscribe(projects => { + this.loading = false; + this.noMoreOptions = this.allProjectsBeforeFilter?.length === this.previousLength || this.allProjectsBeforeFilter?.length < rootProjectsPageSize; + this.previousLength = this.allProjectsBeforeFilter?.length; if (this.currentProjects.length === 1) { this.currentProjectInstance = projects.find(proj => proj.id === this.currentProjects[0]); } - const projectNameToHide = (this.sourceProject && !this.sourceProject.name.match(/^\.\w+$/)) ? this.sourceProject.name?.replace(/\/\.\w+$/, '') : 'Projects root'; - const sourceProjectOrChild = new RegExp(`^${projectNameToHide}(\/\.[a-zA-Z]+)*$`); - const projectList = [{value: null, label: 'Projects root'}].concat(projects.map(project => ({value: project.id, label: project.name}))) - .filter( project => !project.label.match(sourceProjectOrChild) && project.value !== this.sourceProject?.id); + // const projectNameToHide = (this.sourceProject && !this.sourceProject.name.match(/^\.\w+$/)) ? this.sourceProject.name?.replace(/\/\.\w+$/, '') : 'Projects root'; + // const sourceProjectOrChild = new RegExp(`^${projectNameToHide}(\/\.[a-zA-Z]+)*$`); + const projectList = [ + ...(this.rootFiltered ? [] : [{value: null, label: this.projectRoot}]), + ...projects.map(project => ({value: project.id, label: project.name})) + ] + .filter( project => project.value !== this.sourceProject?.id); if (!isEqual(projectList, this.projects)) { this.projects = projectList; + this.projectsNames = projectList.map(p => p.label); } - }); + })); + setTimeout(() => { if (!this.moveToForm?.controls['projectName']) { return; } - this.filteredProjects = this.moveToForm.controls['projectName'].valueChanges - .pipe( - map(value => typeof value === 'string' ? value : value.label), - map(value => this._filter(value)), - startWith(this.projects, asyncScheduler) - ); + this.subs.add(this.moveToForm.controls['projectName'].valueChanges + .subscribe(searchString => { + if (typeof searchString === 'string') { + this.searchChanged(searchString || ''); + this.previousLength = 0; + } + } + )); }, 1000); } + searchChanged(searchString: string) { + this.projects = null; + this.rootFiltered = !this.projectRoot.includes(searchString); + this.store.dispatch(resetTablesFilterProjectsOptions()); + this.store.dispatch(getTablesFilterProjectsOptions({searchString, loadMore: false})); + } + ngOnDestroy(): void { - this.projectsSub.unsubscribe(); + this.subs.unsubscribe(); } closeDialog(isConfirmed) { @@ -102,25 +131,25 @@ export class ChangeProjectDialogComponent implements OnInit, OnDestroy { } } - private _filter(value: string) { - this.filterText = value; - const projectsNames = this.projects.map(project => project.label); - this.isNewName = !projectsNames.includes(value); - const filterValue = value.toLowerCase(); - return this.projects.filter((project: any) => project.label.toLowerCase().includes(filterValue.toLowerCase())); - } - displayFn(project: any ): string { return project && project.label ? project.label : project ; } clear() { - this.filterText = ''; this.formData.project = ''; } setIsAutoCompleteOpen(focus: boolean) { this.isAutoCompleteOpen = focus; } - trackByFn = (index, project) => project.value; + trackByFn = (index, project) => project.label; + + loadMore(searchString) { + this.loading = true; + this.store.dispatch(getTablesFilterProjectsOptions({searchString: searchString || '', loadMore: true})); + } + + isFocused(locationRef: HTMLInputElement) { + return document.activeElement === locationRef; + } } diff --git a/src/app/webapp-common/experiments/shared/components/clone-dialog/clone-dialog.component.html b/src/app/webapp-common/experiments/shared/components/clone-dialog/clone-dialog.component.html index 691c7429..54b47a2c 100755 --- a/src/app/webapp-common/experiments/shared/components/clone-dialog/clone-dialog.component.html +++ b/src/app/webapp-common/experiments/shared/components/clone-dialog/clone-dialog.component.html @@ -15,11 +15,10 @@ + (mousedown)="!isFocused(projectInputRef) && projectInput.value && clear(); projectInputRef.blur(); projectInputRef.focus()"> Project - + (Create New) - Please provide a Project Please provide a name longer than 3 characters Please provide a different name as this project name is - taken as an Example project + taken as an Example project + + *Project name can't contain only spaces. "{{filterText}}" (Create New) - {{project.label}} + *ngIf="!projectInput?.errors && projects !== null && projectInput.value && !(projectInput.value | stringIncludedInArray:projectsNames)" + [value]="projectInput.value" + >"{{projectInput.value.label || projectInput.value}}" (Create New) + + {{project.label}} + +
+ +
+
Loading more...
+
Name @@ -82,7 +89,7 @@ class="btn btn-neon yes-button" data-id="CloneButton" #cloneButton> {{extend ? 'EXTEND' : 'CLONE'}} - diff --git a/src/app/webapp-common/experiments/shared/components/clone-dialog/clone-dialog.component.scss b/src/app/webapp-common/experiments/shared/components/clone-dialog/clone-dialog.component.scss index beea0f34..ddc307eb 100755 --- a/src/app/webapp-common/experiments/shared/components/clone-dialog/clone-dialog.component.scss +++ b/src/app/webapp-common/experiments/shared/components/clone-dialog/clone-dialog.component.scss @@ -57,4 +57,8 @@ display: block; position: absolute; } + + .search-icon { + transform: translateY(3px); + } } diff --git a/src/app/webapp-common/experiments/shared/components/clone-dialog/clone-dialog.component.ts b/src/app/webapp-common/experiments/shared/components/clone-dialog/clone-dialog.component.ts index eb3bb05c..1cf15983 100755 --- a/src/app/webapp-common/experiments/shared/components/clone-dialog/clone-dialog.component.ts +++ b/src/app/webapp-common/experiments/shared/components/clone-dialog/clone-dialog.component.ts @@ -1,20 +1,23 @@ -import {MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {Project} from '~/business-logic/model/projects/project'; -import {Component, ElementRef, Inject, OnDestroy, OnInit, ViewChild} from '@angular/core'; +import {ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Inject, OnDestroy, OnInit, ViewChild} from '@angular/core'; import {Store} from '@ngrx/store'; import {NgForm} from '@angular/forms'; import {Observable, Subscription} from 'rxjs'; -import {selectRootProjects} from '@common/core/reducers/projects.reducer'; -import {getAllSystemProjects} from '@common/core/actions/projects.actions'; -import {map} from 'rxjs/operators'; +import {selectTablesFilterProjectsOptions} from '@common/core/reducers/projects.reducer'; +import {getTablesFilterProjectsOptions, resetTablesFilterProjectsOptions} from '@common/core/actions/projects.actions'; +import {filter, map, tap} from 'rxjs/operators'; import {CloneForm} from '../../common-experiment-model.model'; import {isEqual} from 'lodash-es'; import {isReadOnly} from '@common/shared/utils/is-read-only'; +import {rootProjectsPageSize} from '@common/constants'; +import {ProjectsGetAllResponseSingle} from '~/business-logic/model/projects/projectsGetAllResponseSingle'; @Component({ selector: 'sm-clone-dialog', templateUrl: './clone-dialog.component.html', - styleUrls: ['./clone-dialog.component.scss'] + styleUrls: ['./clone-dialog.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush }) export class CloneDialogComponent implements OnInit, OnDestroy { @@ -30,20 +33,25 @@ export class CloneDialogComponent implements OnInit, OnDestroy { public projects: { label: string; value: string }[]; private readonly defaultProjectId: string; - private projectsSub: Subscription; + private subs = new Subscription(); private readonly cloneNamePrefix: string; @ViewChild('cloneForm', {static: true}) cloneForm: NgForm; @ViewChild('cloneButton', {static: true}) cloneButton: ElementRef; public filteredProjects: Observable<{ label: string; value: string }[]>; - filterText: string = ''; - isNewName: boolean = false; isAutoCompleteOpen: boolean; public readOnlyProjects$: Observable; public extend: boolean; + public projectsNames: string[]; + public loading: boolean; + public noMoreOptions: boolean; + private previousLength: number | undefined; + private allProjectsBeforeFilter: Partial[]; constructor( private store: Store, + public dialogRef: MatDialogRef, + private cdr: ChangeDetectorRef, @Inject(MAT_DIALOG_DATA) data: { type: string; defaultProject: string; @@ -51,12 +59,7 @@ export class CloneDialogComponent implements OnInit, OnDestroy { defaultComment: string; extend: boolean; }, - public dialogRef: MatDialogRef ) { - this.readOnlyProjects$ = this.store.select(selectRootProjects) - .pipe(map(projects => projects?.filter(project => isReadOnly(project)).map(project => project.name))); - this.projects$ = this.store.select(selectRootProjects) - .pipe(map(projects => projects?.filter(project => !isReadOnly(project)))); this.defaultProjectId = data.defaultProject; this.header = `${data.extend ? 'Extend' : 'Clone'} ${data.type}`; this.cloneNamePrefix = data.extend ? '' : 'Clone Of '; @@ -71,35 +74,61 @@ export class CloneDialogComponent implements OnInit, OnDestroy { comment: data.defaultComment || '', }; }); + + this.readOnlyProjects$ = this.store.select(selectTablesFilterProjectsOptions) + .pipe(map(projects => projects?.filter(project => isReadOnly(project)).map(project => project.name))); + this.projects$ = this.store.select(selectTablesFilterProjectsOptions).pipe( + tap(projects => this.allProjectsBeforeFilter = projects), + filter(projects => !!projects), + map(projects => projects?.filter(project => !isReadOnly(project)))); } + searchChanged(searchString: {value: string; loadMore?: boolean}) { + this.projects = null; + // this.rootFiltered = !this.projectRoot.includes(searchString); + !searchString.loadMore && this.store.dispatch(resetTablesFilterProjectsOptions()); + this.store.dispatch(getTablesFilterProjectsOptions({searchString: searchString.value, loadMore: searchString.loadMore})); + } + ngOnDestroy(): void { - this.projectsSub.unsubscribe(); + this.subs.unsubscribe(); } ngOnInit(): void { - this.store.dispatch(getAllSystemProjects()); - this.projectsSub = this.projects$.subscribe(projects => { - const projectList = projects?.map(project => ({value: project.id, label: project.name})); + this.searchChanged({value: this.defaultProjectId ? this.defaultProjectId : ''}); + this.subs.add(this.projects$.subscribe(projects => { + this.loading = false; + this.noMoreOptions = this.allProjectsBeforeFilter?.length === this.previousLength || this.allProjectsBeforeFilter?.length < rootProjectsPageSize; + this.previousLength = this.allProjectsBeforeFilter?.length; + const projectList = [ + // ...(this.rootFiltered ? [] : [{value: null, label: this.projectRoot}]), + ...projects.map(project => ({value: project.id, label: project.name})) + ]; if (!isEqual(projectList, this.projects)) { this.projects = projectList; + this.projectsNames = projectList.map(p => p.label); const defaultProjectIndex = this.projects.findIndex(project => project.value === this.defaultProjectId); - setTimeout(() => { - this.formData.project = (defaultProjectIndex > -1 && projects[defaultProjectIndex].company?.id) ? this.projects[defaultProjectIndex] : projects[0] ? this.projects[0] : null; - this.filterText = this.formData.project?.label; - }, 0); + // setTimeout(() => { + if (this.formData.project === null) { + this.formData.project = (defaultProjectIndex > -1 && projects[defaultProjectIndex].company?.id) ? this.projects[defaultProjectIndex] : projects[0] ? this.projects[0] : null; + // this.cdr.detectChanges(); + } + // }, 0); } - }); + })); setTimeout(() => { if (!this.cloneForm?.controls['projectName']) { return; } - this.filteredProjects = this.cloneForm.controls['projectName'].valueChanges - .pipe( - map(value => typeof value === 'string' ? value : value?.label || ''), - map(value => this._filter(value)) - ); + this.subs.add(this.cloneForm.controls['projectName'].valueChanges + .subscribe(searchString => { + if (typeof searchString === 'string') { + this.searchChanged({value: searchString || ''}); + this.previousLength = 0; + } + } + )); }, 1000); } @@ -108,14 +137,6 @@ export class CloneDialogComponent implements OnInit, OnDestroy { return project && project.label ? project.label : project ; } - private _filter(value: string) { - this.filterText = value; - const projectsNames = this.projects.map(project => project.label); - this.isNewName = !projectsNames.includes(value); - const filterValue = value.toLowerCase(); - return this.projects.filter((project: any) => project.label.toLowerCase().includes(filterValue.toLowerCase())); - } - closeDialog(isConfirmed) { if (isConfirmed) { if (typeof this.formData.project === 'string') { @@ -128,17 +149,21 @@ export class CloneDialogComponent implements OnInit, OnDestroy { } clear() { - this.filterText = ''; this.formData.project = ''; } - clearOnFirstFocus($event: FocusEvent) { - if (this.cloneForm.controls['projectName'].untouched) { - this.clear(); - } - } - setIsAutoCompleteOpen(focus: boolean) { this.isAutoCompleteOpen = focus; } + + trackByFn = (index, project) => project.label; + + loadMore() { + this.loading = true; + this.store.dispatch(getTablesFilterProjectsOptions({searchString: this.formData.project || '', loadMore: true})); + } + + isFocused(locationRef: HTMLInputElement) { + return document.activeElement === locationRef; + } } diff --git a/src/app/webapp-common/experiments/shared/components/experiment-menu/experiment-menu.component.ts b/src/app/webapp-common/experiments/shared/components/experiment-menu/experiment-menu.component.ts index 05b6b40a..ea07e443 100755 --- a/src/app/webapp-common/experiments/shared/components/experiment-menu/experiment-menu.component.ts +++ b/src/app/webapp-common/experiments/shared/components/experiment-menu/experiment-menu.component.ts @@ -1,4 +1,4 @@ -import {MatLegacyDialog as MatDialog, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MatDialog, MatDialogRef} from '@angular/material/dialog'; import {ActivatedRoute, Router} from '@angular/router'; import {Store} from '@ngrx/store'; import {filter, take} from 'rxjs/operators'; @@ -11,7 +11,7 @@ import {ExperimentInfoState} from '~/features/experiments/reducers/experiment-in import {CloneForm} from '../../common-experiment-model.model'; import {SmSyncStateSelectorService} from '@common/core/services/sync-state-selector.service'; import {ConfirmDialogComponent} from '@common/shared/ui-components/overlay/confirm-dialog/confirm-dialog.component'; -import {htmlTextShorte} from '@common/shared/utils/shared-utils'; +import {htmlTextShort} from '@common/shared/utils/shared-utils'; import * as commonMenuActions from '../../../actions/common-experiments-menu.actions'; import {abortAllChildren, archiveSelectedExperiments} from '../../../actions/common-experiments-menu.actions'; import {ChangeProjectDialogComponent} from '../change-project-dialog/change-project-dialog.component'; @@ -166,7 +166,7 @@ export class ExperimentMenuComponent extends BaseContextMenuComponent implements dequeuePopup() { const selectedExperiments = this.selectedExperiments ? selectionDisabledDequeue(this.selectedExperiments).selectedFiltered : [this._experiment]; - const getBody = (queueName: string) => `${selectedExperiments.length === 1 ? htmlTextShorte(this._experiment.name) : selectedExperiments.length + 'experiments'} will be removed from the ${queueName ? '' + queueName + ' ' : ''}execution queue.`; + const getBody = (queueName: string) => `${selectedExperiments.length === 1 ? htmlTextShort(this._experiment.name) : selectedExperiments.length + 'experiments'} will be removed from the ${queueName ? '' + queueName + ' ' : ''}execution queue.`; this.store.dispatch(new GetQueuesForEnqueue()); const confirmDialogRef = this.dialog.open(ConfirmDialogComponent, { data: { @@ -240,7 +240,7 @@ export class ExperimentMenuComponent extends BaseContextMenuComponent implements const confirmDialogRef = this.dialog.open(ConfirmDialogComponent, { data: { title: 'ABORT', - body: `${selectedExperiments.length === 1 ? htmlTextShorte(selectedExperiments[0]?.name || '') : selectedExperiments.length + ' experiments'} + body: `${selectedExperiments.length === 1 ? htmlTextShort(selectedExperiments[0]?.name || '') : selectedExperiments.length + ' experiments'} will be stopped and additional model updates will not be allowed.
`, yes: 'Abort', @@ -262,7 +262,7 @@ export class ExperimentMenuComponent extends BaseContextMenuComponent implements public publishPopup() { const selectedExperiments = this.selectedExperiments ? selectionDisabledPublishExperiments(this.selectedExperiments).selectedFiltered : [this._experiment]; - const publishPopupBody = `${selectedExperiments.length === 1 ? htmlTextShorte(selectedExperiments[0]?.name || '') : selectedExperiments.length + ' experiments'} + const publishPopupBody = `${selectedExperiments.length === 1 ? htmlTextShort(selectedExperiments[0]?.name || '') : selectedExperiments.length + ' experiments'} status will be set to Published.

Published experiments are read-only and cannot be reset. The experiment's output, including models will also be published so that other experiments can use it.`; diff --git a/src/app/webapp-common/experiments/dumb/experiments-table/hyper-param-metric-column/get-param-metric-value.pipe.ts b/src/app/webapp-common/experiments/shared/components/hyper-param-metric-column/get-param-metric-value.pipe.ts similarity index 91% rename from src/app/webapp-common/experiments/dumb/experiments-table/hyper-param-metric-column/get-param-metric-value.pipe.ts rename to src/app/webapp-common/experiments/shared/components/hyper-param-metric-column/get-param-metric-value.pipe.ts index d354dddb..c97ea315 100644 --- a/src/app/webapp-common/experiments/dumb/experiments-table/hyper-param-metric-column/get-param-metric-value.pipe.ts +++ b/src/app/webapp-common/experiments/shared/components/hyper-param-metric-column/get-param-metric-value.pipe.ts @@ -2,11 +2,12 @@ import {Pipe, PipeTransform} from '@angular/core'; import {ISmCol} from '@common/shared/ui-components/data/table/table.consts'; import {ITask} from '~/business-logic/model/al-task'; import {GetVariantWithoutRoundPipe} from './get-variant-without-round.pipe'; -import {getRoundedNumber} from '../../../shared/common-experiments.utils'; +import {getRoundedNumber} from '../../common-experiments.utils'; import {decodeHyperParam} from '@common/shared/utils/tableParamEncode'; @Pipe({ - name: 'getParamMetricValue' + name: 'getParamMetricValue', + standalone: true }) export class GetParamMetricValuePipe implements PipeTransform { diff --git a/src/app/webapp-common/experiments/dumb/experiments-table/hyper-param-metric-column/get-variant-without-round.pipe.ts b/src/app/webapp-common/experiments/shared/components/hyper-param-metric-column/get-variant-without-round.pipe.ts similarity index 82% rename from src/app/webapp-common/experiments/dumb/experiments-table/hyper-param-metric-column/get-variant-without-round.pipe.ts rename to src/app/webapp-common/experiments/shared/components/hyper-param-metric-column/get-variant-without-round.pipe.ts index e644b779..d543543c 100644 --- a/src/app/webapp-common/experiments/dumb/experiments-table/hyper-param-metric-column/get-variant-without-round.pipe.ts +++ b/src/app/webapp-common/experiments/shared/components/hyper-param-metric-column/get-variant-without-round.pipe.ts @@ -1,7 +1,8 @@ import {Pipe, PipeTransform} from '@angular/core'; @Pipe({ - name: 'getVariantWithoutRound' + name: 'getVariantWithoutRound', + standalone: true }) export class GetVariantWithoutRoundPipe implements PipeTransform { diff --git a/src/app/webapp-common/experiments/dumb/experiments-table/hyper-param-metric-column/hyper-param-metric-column.component.html b/src/app/webapp-common/experiments/shared/components/hyper-param-metric-column/hyper-param-metric-column.component.html similarity index 90% rename from src/app/webapp-common/experiments/dumb/experiments-table/hyper-param-metric-column/hyper-param-metric-column.component.html rename to src/app/webapp-common/experiments/shared/components/hyper-param-metric-column/hyper-param-metric-column.component.html index d2b81802..a89385e6 100644 --- a/src/app/webapp-common/experiments/dumb/experiments-table/hyper-param-metric-column/hyper-param-metric-column.component.html +++ b/src/app/webapp-common/experiments/shared/components/hyper-param-metric-column/hyper-param-metric-column.component.html @@ -3,6 +3,6 @@ [smTooltip]="roundedMetricValue?.[experiment.id] && !roundedMetricValue?.noRound ? (col | getVariantWithoutRound:experiment?.last_metrics) : ''" >{{col | getParamMetricValue:experiment:roundedMetricValue}} diff --git a/src/app/webapp-common/experiments/dumb/experiments-table/hyper-param-metric-column/hyper-param-metric-column.component.scss b/src/app/webapp-common/experiments/shared/components/hyper-param-metric-column/hyper-param-metric-column.component.scss similarity index 100% rename from src/app/webapp-common/experiments/dumb/experiments-table/hyper-param-metric-column/hyper-param-metric-column.component.scss rename to src/app/webapp-common/experiments/shared/components/hyper-param-metric-column/hyper-param-metric-column.component.scss diff --git a/src/app/webapp-common/experiments/dumb/experiments-table/hyper-param-metric-column/hyper-param-metric-column.component.ts b/src/app/webapp-common/experiments/shared/components/hyper-param-metric-column/hyper-param-metric-column.component.ts similarity index 62% rename from src/app/webapp-common/experiments/dumb/experiments-table/hyper-param-metric-column/hyper-param-metric-column.component.ts rename to src/app/webapp-common/experiments/shared/components/hyper-param-metric-column/hyper-param-metric-column.component.ts index 6ee32309..2ff5d150 100644 --- a/src/app/webapp-common/experiments/dumb/experiments-table/hyper-param-metric-column/hyper-param-metric-column.component.ts +++ b/src/app/webapp-common/experiments/shared/components/hyper-param-metric-column/hyper-param-metric-column.component.ts @@ -1,11 +1,22 @@ import {ChangeDetectionStrategy, Component, EventEmitter, Input, Output} from '@angular/core'; import {ISmCol} from '@common/shared/ui-components/data/table/table.consts'; +import {GetParamMetricValuePipe} from '@common/experiments/shared/components/hyper-param-metric-column/get-param-metric-value.pipe'; +import {GetVariantWithoutRoundPipe} from '@common/experiments/shared/components/hyper-param-metric-column/get-variant-without-round.pipe'; +import {TooltipDirective} from '@common/shared/ui-components/indicators/tooltip/tooltip.directive'; +import {NgIf} from '@angular/common'; @Component({ selector: 'sm-hyper-param-metric-column', templateUrl: './hyper-param-metric-column.component.html', styleUrls: ['./hyper-param-metric-column.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + GetParamMetricValuePipe, + GetVariantWithoutRoundPipe, + TooltipDirective, + NgIf + ], + standalone: true }) export class HyperParamMetricColumnComponent { diff --git a/src/app/webapp-common/experiments/shared/components/select-queue/select-queue.component.ts b/src/app/webapp-common/experiments/shared/components/select-queue/select-queue.component.ts index 027fd098..5664be3d 100755 --- a/src/app/webapp-common/experiments/shared/components/select-queue/select-queue.component.ts +++ b/src/app/webapp-common/experiments/shared/components/select-queue/select-queue.component.ts @@ -1,5 +1,5 @@ import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnDestroy, OnInit} from '@angular/core'; -import {MatLegacyDialogRef as MatDialogRef, MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA} from '@angular/material/legacy-dialog'; +import {MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog'; import {Store} from '@ngrx/store'; import {GetQueuesForEnqueue, GetTaskForEnqueue, SetTaskForEnqueue} from './select-queue.actions'; import {selectQueuesList, selectTaskForEnqueue} from './select-queue.reducer'; diff --git a/src/app/webapp-common/experiments/shared/components/select-queue/select-queue.module.ts b/src/app/webapp-common/experiments/shared/components/select-queue/select-queue.module.ts index 4a1508e2..b367e82d 100755 --- a/src/app/webapp-common/experiments/shared/components/select-queue/select-queue.module.ts +++ b/src/app/webapp-common/experiments/shared/components/select-queue/select-queue.module.ts @@ -8,6 +8,7 @@ import {selectQueueReducer} from './select-queue.reducer'; import {SMSharedModule} from '@common/shared/shared.module'; import {FormsModule, ReactiveFormsModule} from '@angular/forms'; import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module'; +import {LabeledFormFieldDirective} from '@common/shared/directive/labeled-form-field.directive'; @NgModule({ imports: [ @@ -17,7 +18,8 @@ import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module'; StoreModule.forFeature('selectQueue', selectQueueReducer), FormsModule, ReactiveFormsModule, - SharedPipesModule + SharedPipesModule, + LabeledFormFieldDirective, ], providers : [], declarations : [SelectQueueComponent], diff --git a/src/app/webapp-common/experiments/shared/experiment-output-log/experiment-output-log.module.ts b/src/app/webapp-common/experiments/shared/experiment-output-log/experiment-output-log.module.ts index e1ec8251..22d8ceac 100644 --- a/src/app/webapp-common/experiments/shared/experiment-output-log/experiment-output-log.module.ts +++ b/src/app/webapp-common/experiments/shared/experiment-output-log/experiment-output-log.module.ts @@ -4,7 +4,7 @@ import {ExperimentOutputLogComponent} from '../../containers/experiment-output-l import {ExperimentLogInfoComponent} from '../../dumb/experiment-log-info/experiment-log-info.component'; import {SMSharedModule} from '@common/shared/shared.module'; import {UiComponentsModule} from '@common/shared/ui-components/ui-components.module'; -import { MatLegacyProgressSpinnerModule as MatProgressSpinnerModule } from '@angular/material/legacy-progress-spinner'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module'; import {ScrollingModule} from '@angular/cdk/scrolling'; import {ExperimentSharedModule} from '~/features/experiments/shared/experiment-shared.module'; diff --git a/src/app/webapp-common/layout/breadcrumbs/breadcrumbs-common.utils.ts b/src/app/webapp-common/layout/breadcrumbs/breadcrumbs-common.utils.ts deleted file mode 100644 index ef6c1cf5..00000000 --- a/src/app/webapp-common/layout/breadcrumbs/breadcrumbs-common.utils.ts +++ /dev/null @@ -1,138 +0,0 @@ -import {IBreadcrumbsLink} from './breadcrumbs.component'; -import {isExample} from '../../shared/utils/shared-utils'; -import {Project} from '~/business-logic/model/projects/project'; -import {IExperimentInfo} from '~/features/experiments/shared/experiment-info.model'; -import {TableModel} from '@common/models/shared/models.model'; -import {Task} from '~/business-logic/model/tasks/task'; -import {Report} from '~/business-logic/model/reports/report'; -import {NestedProjectTypeUrlEnum} from '~/layout/breadcrumbs/breadcrumbs.utils'; - -export interface IBreadcrumbs { - project: Project; - projects: Project[]; - experiment: IExperimentInfo; - model: TableModel; - task: Task; - report: Report; -} - -const addSuffixForExamples = crumb => { - if (!crumb?.name) { - return; - } - if (isExample(crumb) && crumb.id !== '*') { - return crumb.name + ' (Example)'; - } else { - return crumb.name; - } -}; - - -export const prepareLinkData = (crumb, supportsExamples = false): IBreadcrumbsLink => { - const crumbName = crumb ? crumb.name : ''; - const preparedName = (supportsExamples === true) ? addSuffixForExamples(crumb) : crumbName; - return crumb ? {name: preparedName, url: crumb.id} : {name: '', url: ''}; -}; - -export const formatStaticCrumb = (crumb: string, nested?: boolean, routeConfig?: Array): IBreadcrumbsLink | IBreadcrumbsLink[] => { - if (!crumb) { - return {url: null, name: null}; - } - let name: string; - switch (crumb) { - case 'workers-and-queues': - return {name: 'Workers & Queues', url: null}; - case 'output': - name = 'Results'; - break; - case 'compare-experiments': - return [{url: 'experiments', name: 'Experiments'}, {url: null, name: 'Compare Experiments'}]; - case 'hyper-params': - name = 'Configuration'; - break; - case 'general': - name = 'Info'; - break; - case 'account-administration': - name = 'Access Controls'; - break; - case ':projectId': - name = 'All Experiments'; - break; - case 'experiments': - return {name: 'All Experiments', url: null}; - case 'models': - return {name: 'All Models', url: null}; - case 'pipelines': - return {name: 'Pipelines', url: nested ? 'pipelines/*/projects' : 'pipelines'}; - case 'datasets': - return {name: 'Datasets', url: nested ? 'datasets/simple/*/projects' : 'datasets'}; - case 'reports': - return {name: 'Reports', url: nested ? 'reports/*/projects' : 'reports'}; - default: - name = crumb.charAt(0).toUpperCase() + crumb.slice(1); - break; - } - return {url: crumb, name}; -}; - -export const prepareNames = (data: IBreadcrumbs, projectType?: NestedProjectTypeUrlEnum, fullScreen = false, - showHidden = false, compare = false) => { - if(!data.project && data.report){ - data.project = data.report.project as Project; - } - const customProject = projectType !== 'projects'; - const project = prepareLinkData(data.project, true); - if (data.project) { - let subProjectsNames = [data.project?.name]; - subProjectsNames = data.project?.name?.split('/').filter(name => !['.datasets', '.pipelines', '.reports'].includes(name)); - const allProjects = [ - ...(data.projects || []), - {id: '*', name: 'All Experiments'}, - data.project - ]; - let currentName = ''; - const subProjects = subProjectsNames.map(name => { - currentName += currentName ? ('/' + name) : name; - return allProjects.find(proj => currentName === proj.name.replace(/\/\.datasets|\/\.pipelines|\/\.reports/, '')); - }) || []; - const subProjectsLinks = subProjects.map((subProject, index, arr) => ({ - name: subProjectsNames[index], - hidden: showHidden && subProject?.hidden, - url: customProject ? ((subProject?.id) ? - `${projectType}/${subProject?.id}/projects` : null) : - fullScreen && index === (arr.length - 1) ? `projects/${subProject?.id}/experiments/${data?.experiment?.id}` : - subProject?.name === data.project?.name && data.project?.sub_projects?.length === 0 ? - compare ? `projects/${subProject?.id}` : '' : - `projects/${subProject?.id}/projects` - })) as { name: string; url: string }[]; - project.name = project?.name.substring(project.name.lastIndexOf('/') + 1); - project.subCrumbs = subProjectsLinks; - } - const task = prepareLinkData(data.task); - const experiment = (data.experiment && !customProject) ? prepareLinkData(data.experiment, true) : {}; - const output = formatStaticCrumb(''); - const experiments = formatStaticCrumb('experiments'); - const models = formatStaticCrumb('models'); - const compareExperiment = customProject ? - data.project?.system_tags?.includes('pipeline') ? - {url: 'compare-experiments', name: 'Compare Runs'} : - {url: 'compare-experiments', name: 'Compare Versions'} - : formatStaticCrumb('compare-experiments'); - const accountAdministration = formatStaticCrumb('account-administration'); - return { - /* eslint-disable @typescript-eslint/naming-convention */ - ':projectId': project, - ':taskId': task, - ':controllerId': experiment, - 'compare-experiments': compareExperiment, - output, - experiments, - models, - accountAdministration, - profile: {url: 'profile', name: 'Profile'}, - 'webapp-configuration': {url: 'webapp-configuration', name: 'Configuration'}, - 'workspace-configuration': {url: 'workspace-configuration', name: 'Workspace'}, - /* eslint-enable @typescript-eslint/naming-convention */ - }; -}; diff --git a/src/app/webapp-common/layout/breadcrumbs/breadcrumbs.component.html b/src/app/webapp-common/layout/breadcrumbs/breadcrumbs.component.html index e8f663d8..bdaadb43 100644 --- a/src/app/webapp-common/layout/breadcrumbs/breadcrumbs.component.html +++ b/src/app/webapp-common/layout/breadcrumbs/breadcrumbs.component.html @@ -1,83 +1,52 @@ -
+
{{activeWorkspace.name}} - + - - - - - - - - - - {{subProjects[subProjects.length - 1].name}} - - - {{subProjects[subProjects.length - 1].name}} - - - - {{subProject.name}} - - - - + + + - - - - -
{{subProject.name}}
-
- - -
{{subProject.name}}
-
- -
-
-
-
+ + + {{breadcrumb.name}} + + + +
{{breadcrumb.name}} {{breadcrumb.example? ' (example)':''}}
+
+
+ + + + + + + + {{breadcrumb.name}} + + - - {{crumb.name}} - -
{{crumb.name}}
-
- -
+
-
Archive
+
Archive +
diff --git a/src/app/webapp-common/layout/breadcrumbs/breadcrumbs.component.scss b/src/app/webapp-common/layout/breadcrumbs/breadcrumbs.component.scss index d42f5185..6e849180 100644 --- a/src/app/webapp-common/layout/breadcrumbs/breadcrumbs.component.scss +++ b/src/app/webapp-common/layout/breadcrumbs/breadcrumbs.component.scss @@ -13,19 +13,26 @@ span { width: 100%; } - .sub-projects-breadcrumbs{ + .sub-projects-breadcrumbs { display: flex; overflow: hidden; flex-shrink: 0; } - .crumb{ + + .crumb { font-size: 15px; color: $blue-100; - &:hover{ + &:hover { color: #fff; + + &.url { + text-decoration: underline; + } } + } + .crumb.first { text-transform: uppercase; } @@ -37,11 +44,11 @@ span { overflow: hidden; } - .sub-project{ + .sub-project { color: $blue-100; white-space: nowrap; - &:hover{ + &:hover { color: #fff; } diff --git a/src/app/webapp-common/layout/breadcrumbs/breadcrumbs.component.ts b/src/app/webapp-common/layout/breadcrumbs/breadcrumbs.component.ts index 9491953e..12c74367 100644 --- a/src/app/webapp-common/layout/breadcrumbs/breadcrumbs.component.ts +++ b/src/app/webapp-common/layout/breadcrumbs/breadcrumbs.component.ts @@ -10,11 +10,9 @@ import { } from '@angular/core'; import {Store} from '@ngrx/store'; import {selectRouterConfig, selectRouterQueryParams} from '../../core/reducers/router-reducer'; -import {debounceTime, filter} from 'rxjs/operators'; -import {selectBreadcrumbsStrings} from '../layout.reducer'; -import {ActivatedRoute} from '@angular/router'; -import {combineLatest, fromEvent, Subscription} from 'rxjs'; -import {formatStaticCrumb, NestedProjectTypeUrlEnum, prepareNames} from '~/layout/breadcrumbs/breadcrumbs.utils'; +import {debounceTime, filter, withLatestFrom} from 'rxjs/operators'; +import {ActivatedRoute, NavigationStart, Router, RouterLink} from '@angular/router'; +import {combineLatest, fromEvent, Observable, Subscription} from 'rxjs'; import {addMessage} from '../../core/actions/layout.actions'; import {ConfigurationService} from '../../shared/services/configuration.service'; import { @@ -23,31 +21,63 @@ import { import { selectDefaultNestedModeForFeature, selectIsDeepMode, - selectRootProjects, + selectProjectAncestors, + selectSelectedProject, + selectSelectedProjectId, selectShowHiddenUserSelection } from '../../core/reducers/projects.reducer'; -import {getAllSystemProjects} from '@common/core/actions/projects.actions'; -import {castArray, isEqual} from 'lodash-es'; import {selectIsSearching} from '../../common-search/common-search.reducer'; import {MESSAGES_SEVERITY} from '@common/constants'; -import { routeConfToProjectType } from '~/features/projects/projects-page.utils'; +import {setBreadcrumbs} from '@common/core/actions/router.actions'; +import {selectBreadcrumbs} from '@common/core/reducers/view.reducer'; +import {routeConfToProjectType} from '~/features/projects/projects-page.utils'; +import {isExample} from '@common/shared/utils/shared-utils'; +import {MatMenuModule} from '@angular/material/menu'; +import {TooltipDirective} from '@common/shared/ui-components/indicators/tooltip/tooltip.directive'; +import {NgForOf, NgIf, TitleCasePipe} from '@angular/common'; +import { + ShowTooltipIfEllipsisDirective +} from '@common/shared/ui-components/indicators/tooltip/show-tooltip-if-ellipsis.directive'; +import {ClipboardModule} from 'ngx-clipboard'; +import {ClickStopPropagationDirective} from '@common/shared/ui-components/directives/click-stop-propagation.directive'; +export enum CrumbTypeEnum { + Workspace = 'Workspace', + Feature = 'Feature', + Project = 'Project', + SubFeature = 'SubFeature', +} export interface IBreadcrumbsLink { name?: string; url?: string; subCrumbs?: { name: string; url: string; hidden?: boolean }[]; isProject?: boolean; + type?: CrumbTypeEnum; + hidden?: boolean; + collapsable?: boolean; + example?: boolean; } @Component({ selector: 'sm-breadcrumbs', templateUrl: './breadcrumbs.component.html', styleUrls: ['./breadcrumbs.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + MatMenuModule, + TooltipDirective, + NgForOf, + ShowTooltipIfEllipsisDirective, + ClipboardModule, + RouterLink, + NgIf, + ClickStopPropagationDirective + ], + standalone: true }) export class BreadcrumbsComponent implements OnInit, OnDestroy { - public breadcrumbs: Array = []; + public breadcrumbs: IBreadcrumbsLink[][] = []; public currentUrl: string; public showShareButton: boolean = false; public isCommunity: boolean; @@ -57,24 +87,26 @@ export class BreadcrumbsComponent implements OnInit, OnDestroy { public subProjectsMenuIsOpen: boolean; public lastSegment: string; public shouldCollapse: boolean; - private previousProjectNames: any; - private tempBread: Array = []; - private routeConfig: Array = []; - public breadcrumbsStrings; private sub = new Subscription(); private isSearching$ = this.store.select(selectIsSearching); @Input() activeWorkspace: GetCurrentUserResponseUserObjectCompany; @ViewChild('container') private breadCrumbsContainer: ElementRef; private expandedSize: number; + public breadcrumbs$: Observable; + public showHidden: boolean; + public projectFeature: boolean; constructor( private store: Store, public route: ActivatedRoute, + private router: Router, private configService: ConfigurationService, private cd: ChangeDetectorRef, - private ref: ElementRef + private ref: ElementRef, + private titleCasePipe: TitleCasePipe ) { + this.breadcrumbs$ = this.store.select(selectBreadcrumbs); } ngOnInit() { @@ -86,8 +118,19 @@ export class BreadcrumbsComponent implements OnInit, OnDestroy { }) ); + this.sub.add(this.breadcrumbs$.subscribe(breadcrumbs => { + this.breadcrumbs = breadcrumbs.map(breadcrumbsGroup => breadcrumbsGroup.filter(breadcrumb => (!breadcrumb.hidden) || (this.showHidden && this.projectFeature))).filter(breadcrumbsGroup => breadcrumbsGroup.length > 0); + this.cd.detectChanges(); + })); + + this.sub.add(this.breadcrumbs$.pipe(debounceTime(300)).subscribe(() => { + this.calcOverflowing(); + this.cd.detectChanges(); + + })); + this.sub.add(this.isSearching$.pipe(debounceTime(300)).subscribe(() => { - if (this.checkIfBreadcrumbsInitiated() && !this.shouldCollapse) { + if (!this.shouldCollapse) { this.calcOverflowing(); this.cd.detectChanges(); } @@ -101,31 +144,88 @@ export class BreadcrumbsComponent implements OnInit, OnDestroy { this.cd.detectChanges(); }) ); + this.sub.add(this.store.select(selectRouterConfig).subscribe(config => { + let route = this.route.snapshot; + while (route.firstChild) { + route = route.firstChild; + } + !config?.includes(':projectId') && route?.data?.staticBreadcrumb && this.store.dispatch(setBreadcrumbs({ + breadcrumbs: route?.data?.staticBreadcrumb + })); + })); + + this.sub.add(this.router.events + .pipe( + filter(event => event instanceof NavigationStart), + withLatestFrom(this.store.select(selectSelectedProjectId)), + filter(([event, projectId]) => projectId && !(event as any)?.url?.includes(projectId)) + ) + .subscribe( + () => { + this.store.dispatch(setBreadcrumbs({breadcrumbs: [[]]})); + })); this.sub.add(combineLatest([ this.store.select(selectRouterConfig), - this.store.select(selectBreadcrumbsStrings), this.store.select(selectRouterQueryParams), - this.store.select(selectDefaultNestedModeForFeature), this.store.select(selectShowHiddenUserSelection), - this.store.select(selectRootProjects), + this.store.select(selectProjectAncestors), + this.store.select(selectSelectedProject), + this.store.select(selectDefaultNestedModeForFeature) ]).pipe( debounceTime(200), - filter(([, names]) => !!names) - ).subscribe(([config, names, params, nestedForFeature, showHidden]) => { + ).subscribe(([config, params, showHidden, projectAncestors, selectedProject, nestedModeForFeature]) => { + const compareNameMap = { + projects: 'Experiments', + datasets: 'Versions', + pipelines: 'Runs' + }; + this.showHidden = showHidden; + this.projectFeature = config?.[0] === 'projects'; + const nestedDatasets = ['simple', 'hyper'].includes(config?.[1]); + const isCompareExperiments = config?.includes('compare-experiments'); + const isCompareModels = config?.includes('compare-models'); + const isDeep = params?.deep === 'true'; + const isPipelinesControllers = config?.[0] === 'pipelines' && config?.[2]?.includes('experiments'); + const isSimpleDatasetsTasksView = config?.[0] === 'datasets' && config?.[3]?.includes('experiments'); + !!config && config.includes(':projectId') && (projectAncestors !== null || selectedProject?.id === '*') + && this.resetShouldCollapse() && this.store.dispatch(setBreadcrumbs({ + breadcrumbs: [[{ + name: config[0].toUpperCase(), + url: nestedModeForFeature[routeConfToProjectType(config)] ? `${config[0]}/${nestedDatasets ? config[1] + '/' : ''}/*/projects` : config[0], + type: CrumbTypeEnum.Feature + }], + ...(projectAncestors?.length > 0 ? [projectAncestors?.filter(ancestor => (this.projectFeature || !['.datasets', '.pipelines', '.reports'].includes(ancestor.basename))) + .map(ancestor => ({ + name: ancestor.basename, + example: isExample(ancestor), + url: `${config[0]}/${nestedDatasets ? config[1] + '/' : ''}${ancestor.id}/projects`, + type: CrumbTypeEnum.Project, + hidden: ancestor.hidden, + collapsable: true + }))] : []), + ...(!!selectedProject && (!['.datasets', '.pipelines', '.reports'].includes(selectedProject.basename) || config[0] === 'projects') && (selectedProject.id !== '*' || (selectedProject.id === '*' && config[0] === 'projects')) ? [[{ + name: selectedProject.id === '*' && config[0] === 'projects' ? `All ${isCompareExperiments ? 'Experiments' : isCompareModels ? 'Models' : this.titleCasePipe.transform(config[2])}` : selectedProject.basename, + example: isExample(selectedProject), + type: CrumbTypeEnum.Project, + hidden: selectedProject.hidden && !isSimpleDatasetsTasksView && !isPipelinesControllers, + url: `${config[0]}/${nestedDatasets ? config[1] + '/' : ''}${selectedProject.id}/${isCompareExperiments ? 'experiments' : isCompareModels ? 'models' : 'projects'}`, + }]] : []), + ...((isDeep && selectedProject.id !== '*') ? [[{ + name: `All ${this.titleCasePipe.transform(config[2])}`, + type: CrumbTypeEnum.SubFeature + }]] : []), + ...(isCompareExperiments ? [[{ + name: `Compare ${compareNameMap[config[0]]}`, + type: CrumbTypeEnum.SubFeature + }]] : []), + ...(isCompareModels ? [[{ + name: `Compare Models`, + type: CrumbTypeEnum.SubFeature + }]] : []), + ] + })); this.archive = !!params?.archive; - const compare = config?.includes('compare-experiments'); - this.routeConfig = (!compare && names.project?.id === '*') ? config?.filter(c => c !== ':projectId') : - this.isDeep ? config : config?.filter(c => !['experiments', 'models', 'dataviews'].includes(c)); - const experimentFullScreen = config?.[4] === ('output'); - const projectType = `${config?.[0]}${['simple', 'hyper'].includes(config?.[1]) ? '/' + config?.[1] : ''}`; - this.breadcrumbsStrings = prepareNames(names, projectType as NestedProjectTypeUrlEnum, experimentFullScreen, showHidden, compare); - if (!isEqual(this.previousProjectNames, this.breadcrumbsStrings[':projectId']?.subCrumbs) && - this.breadcrumbsStrings[':projectId']?.subCrumbs?.map(project => project.name).includes(undefined)) { - this.previousProjectNames = this.breadcrumbsStrings[':projectId']?.subCrumbs; - this.store.dispatch(getAllSystemProjects()); - } - this.refreshBreadcrumbs(nestedForFeature); let route = this.route.snapshot; let hide = false; while (route.firstChild) { @@ -152,57 +252,6 @@ export class BreadcrumbsComponent implements OnInit, OnDestroy { this.sub.unsubscribe(); } - private refreshBreadcrumbs(nestedForFeature?: { [feature: string]: boolean }): Array { - if (!this.routeConfig) { - return; - } - this.tempBread = this.routeConfig - .reduce((acc, config) => { - const parts = this.breadcrumbsStrings?.[config]; - if (Array.isArray(parts)) { - parts.forEach(part => { - const previous = acc.slice(-1)[0]; // get the last item in the array - const url = part.url ? `${previous ? previous?.url : ''}/${part.url}` : ''; - const isProject = config === ':projectId'; - acc.push({name: part?.name ?? '', url, isProject}); - }); - } else { - const part = parts; - const id = this.getRouteId(config); - const isProject = config === ':projectId'; - let url; - if (part?.url === null) { - url = ''; - } else { - const previous = acc.slice(-1)[0]; // get the last item in the array - url = `${previous ? previous?.url : ''}/${id}`; - } - if (!isProject || this.subProjects?.length > 0) { - acc.push({name: part?.name ?? '', url, isProject}); - } - } - return acc; - }, [{url: '', name: '', isProject: true}]) - .filter((i) => !!i.name); - const rootCrumb = formatStaticCrumb(this.routeConfig[0], nestedForFeature?.[routeConfToProjectType(this.routeConfig)], this.routeConfig); - this.tempBread = [...castArray(rootCrumb), ...this.tempBread]; - if (!isEqual(this.tempBread, this.breadcrumbs)) { - this.shouldCollapse = false; - this.breadcrumbs = this.tempBread; - } - setTimeout(() => { - if (this.checkIfBreadcrumbsInitiated()) { - this.calcOverflowing(); - this.cd.detectChanges(); - } - }, 0); - // this.showShareButton = !(this.routeConfig.includes('login') || this.routeConfig.includes('dashboard')); - } - - private getRouteId(config: string) { - return this.breadcrumbsStrings?.[config]?.url ?? config; - } - openShareModal() { this.currentUrl = window.location.href; } @@ -211,15 +260,13 @@ export class BreadcrumbsComponent implements OnInit, OnDestroy { this.store.dispatch(addMessage(MESSAGES_SEVERITY.SUCCESS, 'URL copied successfully')); } - checkIfBreadcrumbsInitiated() { - return this.breadcrumbs && this.routeConfig && this.breadcrumbs.length <= this.routeConfig.length; - } - - get subProjects() { - return this.breadcrumbsStrings?.[':projectId']?.subCrumbs; - } subProjectsMenuOpened(b: boolean) { this.subProjectsMenuIsOpen = b; } + + private resetShouldCollapse() { + this.shouldCollapse = false; + return true; + } } diff --git a/src/app/webapp-common/layout/header/header.component.html b/src/app/webapp-common/layout/header/header.component.html index 1fd8cccb..0bdb598d 100644 --- a/src/app/webapp-common/layout/header/header.component.html +++ b/src/app/webapp-common/layout/header/header.component.html @@ -6,7 +6,7 @@ [class.share-view]="isShareMode" [activeWorkspace]="activeWorkspace"> -
+
@@ -23,10 +23,10 @@
- + - - + + avatar
@@ -34,19 +34,16 @@
-
+ diff --git a/src/app/webapp-common/layout/header/header.component.scss b/src/app/webapp-common/layout/header/header.component.scss index c14c2e2a..adde5682 100644 --- a/src/app/webapp-common/layout/header/header.component.scss +++ b/src/app/webapp-common/layout/header/header.component.scss @@ -49,7 +49,7 @@ } } - sm-common-search, + sm-common-search, .resources-trigger { margin-right: 24px; } @@ -135,13 +135,3 @@ background-color: $neon-yellow; } } - -.mat-menu-item { - display: flex; - align-items: center; - background-color: white; - - .fab { - margin-right: 12px; - } -} diff --git a/src/app/webapp-common/layout/header/header.component.ts b/src/app/webapp-common/layout/header/header.component.ts index 1b97a5a9..c83f1c5b 100644 --- a/src/app/webapp-common/layout/header/header.component.ts +++ b/src/app/webapp-common/layout/header/header.component.ts @@ -4,7 +4,7 @@ import {selectActiveWorkspace, selectCurrentUser} from '../../core/reducers/user import {Observable, Subscription} from 'rxjs'; import {logout} from '../../core/actions/users.actions'; import {addMessage, openAppsAwarenessDialog} from '../../core/actions/layout.actions'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {GetCurrentUserResponseUserObject} from '~/business-logic/model/users/getCurrentUserResponseUserObject'; import {ConfigurationService} from '../../shared/services/configuration.service'; import {GetCurrentUserResponseUserObjectCompany} from '~/business-logic/model/users/getCurrentUserResponseUserObjectCompany'; diff --git a/src/app/webapp-common/layout/layout.module.ts b/src/app/webapp-common/layout/layout.module.ts index f04f8567..636bf7ea 100755 --- a/src/app/webapp-common/layout/layout.module.ts +++ b/src/app/webapp-common/layout/layout.module.ts @@ -1,5 +1,5 @@ import {NgModule} from '@angular/core'; -import {CommonModule, NgOptimizedImage} from '@angular/common'; +import {CommonModule, NgOptimizedImage, TitleCasePipe} from '@angular/common'; import {SMSharedModule} from '../shared/shared.module'; import {FormsModule, ReactiveFormsModule} from '@angular/forms'; import {RouterModule} from '@angular/router'; @@ -10,7 +10,6 @@ import {S3AccessResolverComponent} from './s3-access-resolver/s3-access-resolver import {StoreModule} from '@ngrx/store'; import {LayoutReducer} from './layout.reducer'; import {ServerNotificationDialogContainerComponent} from './server-notification-dialog-container/server-notification-dialog-container.component'; -import {BreadcrumbsComponent} from './breadcrumbs/breadcrumbs.component'; import {CommonSearchModule} from '../common-search/common-search.module'; import {HeaderComponent} from './header/header.component'; import { UiUpdateDialogComponent } from './ui-update-dialog/ui-update-dialog.component'; @@ -20,28 +19,31 @@ import {HeaderUserMenuActionsComponent} from '~/layout/header/header-user-menu-a import {WelcomeMessageComponent} from '@common/layout/welcome-message/welcome-message.component'; import {YouTubePlayerModule} from '@angular/youtube-player'; import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module'; +import {BreadcrumbsComponent} from '@common/layout/breadcrumbs/breadcrumbs.component'; @NgModule({ - imports: [ - CommonModule, - SMSharedModule, - FormsModule, - ReactiveFormsModule, - CommonSearchModule, - RouterModule, - StoreModule.forFeature('layout', LayoutReducer), - SharedModule, - YouTubePlayerModule, - SharedPipesModule, - NgOptimizedImage, - ], + imports: [ + CommonModule, + SMSharedModule, + FormsModule, + ReactiveFormsModule, + CommonSearchModule, + RouterModule, + StoreModule.forFeature('layout', LayoutReducer), + SharedModule, + YouTubePlayerModule, + SharedPipesModule, + NgOptimizedImage, + BreadcrumbsComponent, + ], declarations: [ - HeaderComponent, BreadcrumbsComponent, ProjectContextNavbarComponent, LoggedOutAlertComponent, + HeaderComponent, ProjectContextNavbarComponent, LoggedOutAlertComponent, S3AccessResolverComponent, S3AccessDialogComponent, ServerNotificationDialogContainerComponent, UiUpdateDialogComponent, TipOfTheDayModalComponent, HeaderUserMenuActionsComponent, WelcomeMessageComponent ], - exports: [HeaderComponent, BreadcrumbsComponent, ProjectContextNavbarComponent, LoggedOutAlertComponent, S3AccessResolverComponent, S3AccessDialogComponent, ServerNotificationDialogContainerComponent, UiUpdateDialogComponent, WelcomeMessageComponent] + providers:[TitleCasePipe], + exports: [HeaderComponent, ProjectContextNavbarComponent, LoggedOutAlertComponent, S3AccessResolverComponent, S3AccessDialogComponent, ServerNotificationDialogContainerComponent, UiUpdateDialogComponent, WelcomeMessageComponent] }) export class CommonLayoutModule { } diff --git a/src/app/webapp-common/layout/layout.reducer.ts b/src/app/webapp-common/layout/layout.reducer.ts index fa076c70..ea4e84f0 100755 --- a/src/app/webapp-common/layout/layout.reducer.ts +++ b/src/app/webapp-common/layout/layout.reducer.ts @@ -1,9 +1,3 @@ -import {selectBreadcrumbsStringsBase} from '../../layout/breadcrumbs/breadcrumbs.utils'; - - -export const selectBreadcrumbsStrings = selectBreadcrumbsStringsBase; export function LayoutReducer(state = {}, action) { } - - diff --git a/src/app/webapp-common/layout/logged-out-alert/logged-out-alert.component.ts b/src/app/webapp-common/layout/logged-out-alert/logged-out-alert.component.ts index d658103e..9d6f93f7 100755 --- a/src/app/webapp-common/layout/logged-out-alert/logged-out-alert.component.ts +++ b/src/app/webapp-common/layout/logged-out-alert/logged-out-alert.component.ts @@ -1,7 +1,7 @@ import {Component, Input} from '@angular/core'; import {Store} from '@ngrx/store'; import {AlertDialogComponent} from '../../shared/ui-components/overlay/alert-dialog/alert-dialog.component'; -import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog'; +import { MatDialog } from '@angular/material/dialog'; import {take} from 'rxjs/operators'; import {logout} from '@common/core/actions/users.actions'; diff --git a/src/app/webapp-common/layout/s3-access-resolver/s3-access-resolver.component.ts b/src/app/webapp-common/layout/s3-access-resolver/s3-access-resolver.component.ts index bf072850..31bc6bc0 100755 --- a/src/app/webapp-common/layout/s3-access-resolver/s3-access-resolver.component.ts +++ b/src/app/webapp-common/layout/s3-access-resolver/s3-access-resolver.component.ts @@ -1,7 +1,7 @@ import {Component, Inject} from '@angular/core'; import {Credentials} from '../../core/reducers/common-auth-reducer'; import {Observable} from 'rxjs'; -import {MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {ProjectDialogComponent} from '../../shared/project-dialog/project-dialog.component'; @Component({ diff --git a/src/app/webapp-common/layout/server-notification-dialog-container/server-notification-dialog-container.component.ts b/src/app/webapp-common/layout/server-notification-dialog-container/server-notification-dialog-container.component.ts index 86ca2287..2f3ccdfa 100644 --- a/src/app/webapp-common/layout/server-notification-dialog-container/server-notification-dialog-container.component.ts +++ b/src/app/webapp-common/layout/server-notification-dialog-container/server-notification-dialog-container.component.ts @@ -1,6 +1,6 @@ import {ChangeDetectionStrategy, Component, OnDestroy, OnInit} from '@angular/core'; import {select, Store} from '@ngrx/store'; -import { MatLegacyDialog as MatDialog, MatLegacyDialogRef as MatDialogRef } from '@angular/material/legacy-dialog'; +import { MatDialog, MatDialogRef } from '@angular/material/dialog'; import {selectNotification} from '../../core/reducers/view.reducer'; import {filter, take} from 'rxjs/operators'; import {setNotificationDialog} from '../../core/actions/layout.actions'; diff --git a/src/app/webapp-common/layout/tip-of-the-day-modal/tip-of-the-day-modal.component.ts b/src/app/webapp-common/layout/tip-of-the-day-modal/tip-of-the-day-modal.component.ts index eb579dd3..59b1a3e7 100644 --- a/src/app/webapp-common/layout/tip-of-the-day-modal/tip-of-the-day-modal.component.ts +++ b/src/app/webapp-common/layout/tip-of-the-day-modal/tip-of-the-day-modal.component.ts @@ -1,5 +1,5 @@ import {Component, Inject} from '@angular/core'; -import {MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {Store} from '@ngrx/store'; import {addMessage} from '../../core/actions/layout.actions'; import {Tip} from '../../shared/services/tips.service'; @@ -24,7 +24,7 @@ export class TipOfTheDayModalComponent { this.visitedIndex = data.visitedIndex % this.tips.length; this.tipIndex = this.visitedIndex; this.saveIndexInLocalstorage(); - this.matDialogRef.beforeClosed().subscribe(() => this.matDialogRef.close(this.neverShowAgain)); + this.matDialogRef.beforeClosed().subscribe(res => this.neverShowAgain && !res ? this.matDialogRef.close(this.neverShowAgain) : false); } copyToClipboardSuccess() { diff --git a/src/app/webapp-common/layout/ui-update-dialog/ui-update-dialog.component.ts b/src/app/webapp-common/layout/ui-update-dialog/ui-update-dialog.component.ts index 12c0097e..5fceed45 100644 --- a/src/app/webapp-common/layout/ui-update-dialog/ui-update-dialog.component.ts +++ b/src/app/webapp-common/layout/ui-update-dialog/ui-update-dialog.component.ts @@ -1,5 +1,5 @@ import {Component} from '@angular/core'; -import {MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MatDialogRef} from '@angular/material/dialog'; @Component({ selector: 'sm-ui-update-dialog', diff --git a/src/app/webapp-common/layout/welcome-message/welcome-message.component.html b/src/app/webapp-common/layout/welcome-message/welcome-message.component.html index 3cb2b805..222667a6 100644 --- a/src/app/webapp-common/layout/welcome-message/welcome-message.component.html +++ b/src/app/webapp-common/layout/welcome-message/welcome-message.component.html @@ -62,7 +62,7 @@ theme="text-area" [clipboardText]="stepCode.innerHTML">
-
+
Manage your app credentials in the workspace settings page @@ -103,7 +103,7 @@ theme="text-area" [clipboardText]="content.textContent">
-
Manage your app credentials in the workspace settings page
+
Manage your app credentials in the workspace settings page
diff --git a/src/app/webapp-common/layout/welcome-message/welcome-message.component.ts b/src/app/webapp-common/layout/welcome-message/welcome-message.component.ts index c7615fd3..67751902 100644 --- a/src/app/webapp-common/layout/welcome-message/welcome-message.component.ts +++ b/src/app/webapp-common/layout/welcome-message/welcome-message.component.ts @@ -1,5 +1,5 @@ import {Component, Inject, OnDestroy, OnInit} from '@angular/core'; -import {MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {setSelectedWorkspaceTab} from '@common/core/actions/users.actions'; import {Subscription} from 'rxjs'; import {selectActiveWorkspace, selectGettingStarted} from '@common/core/reducers/users-reducer'; diff --git a/src/app/webapp-common/login/login-page.component.html b/src/app/webapp-common/login/login-page.component.html index 72c9e6ae..ba0725c6 100644 --- a/src/app/webapp-common/login/login-page.component.html +++ b/src/app/webapp-common/login/login-page.component.html @@ -4,6 +4,6 @@ Notice! The Web-App is not yet optimized for mobile devices.
-
- +
+
diff --git a/src/app/webapp-common/login/login-page.component.scss b/src/app/webapp-common/login/login-page.component.scss index 7c96a233..47bed31f 100644 --- a/src/app/webapp-common/login/login-page.component.scss +++ b/src/app/webapp-common/login/login-page.component.scss @@ -1,9 +1,6 @@ @import "variables"; :host { - ::ng-deep .mat-spinner circle { - stroke: #FFFFFF !important; - } .light-theme { overflow: auto; } diff --git a/src/app/webapp-common/login/login-reducer.ts b/src/app/webapp-common/login/login-reducer.ts index f412899a..ff7c00a6 100755 --- a/src/app/webapp-common/login/login-reducer.ts +++ b/src/app/webapp-common/login/login-reducer.ts @@ -1,4 +1,4 @@ -import {createReducer, createSelector, on, ReducerTypes} from '@ngrx/store'; +import {createSelector, on, ReducerTypes} from '@ngrx/store'; import {setTOU} from './login.actions'; export interface LoginState { diff --git a/src/app/webapp-common/login/login/login.component.scss b/src/app/webapp-common/login/login/login.component.scss index 171abce6..e7be81d4 100644 --- a/src/app/webapp-common/login/login/login.component.scss +++ b/src/app/webapp-common/login/login/login.component.scss @@ -1,7 +1,6 @@ @import "variables"; :host { - .marketing-content-bottom { display: flex; flex-direction: column; @@ -16,15 +15,29 @@ text-decoration: none; color: #dce0ee; font-size: 12px; + + &:hover { + text-decoration: underline; + cursor: pointer; + color: #fff; + } } .community-links { .link { margin: 0 12px; + text-decoration: none; &:hover { cursor: pointer; - color: #fff; + + .text { + text-decoration: underline; + } + } + + i { + color: $blue-300 !important; } } } @@ -200,6 +213,10 @@ transform: rotate(360deg); } } + + mat-spinner { + --mdc-circular-progress-active-indicator-color: #FFFFFF; + } } .errors { diff --git a/src/app/webapp-common/login/login/login.component.ts b/src/app/webapp-common/login/login/login.component.ts index fbc7a84d..0cd375fb 100644 --- a/src/app/webapp-common/login/login/login.component.ts +++ b/src/app/webapp-common/login/login/login.component.ts @@ -10,10 +10,12 @@ import {LoginMode, loginModes} from '../../shared/services/login.service'; import {selectInviteId} from '../login-reducer'; import {ConfigurationService} from '../../shared/services/configuration.service'; import {ConfirmDialogComponent} from '../../shared/ui-components/overlay/confirm-dialog/confirm-dialog.component'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {LoginService} from '~/shared/services/login.service'; import {UserPreferences} from '../../user-preferences'; import {Environment} from '../../../../environments/base'; +import {setBreadcrumbs} from "@common/core/actions/router.actions"; +import {CrumbTypeEnum} from "@common/layout/breadcrumbs/breadcrumbs.component"; @Component({ @@ -74,6 +76,11 @@ export class LoginComponent implements OnInit, OnDestroy { } ngOnInit() { + this.store.dispatch(setBreadcrumbs({ + breadcrumbs: [[{ + name: 'Login', + type: CrumbTypeEnum.Feature + }]]})); this.store.select(selectCurrentUser) .pipe( filter(user => !!user), diff --git a/src/app/webapp-common/models/actions/models-info.actions.ts b/src/app/webapp-common/models/actions/models-info.actions.ts index 0e3d8fbe..2924567f 100755 --- a/src/app/webapp-common/models/actions/models-info.actions.ts +++ b/src/app/webapp-common/models/actions/models-info.actions.ts @@ -4,7 +4,6 @@ import {SelectedModel} from '../shared/models.model'; import {ModelsUpdateRequest} from '~/business-logic/model/models/modelsUpdateRequest'; import {IModelMetadataMap} from '../containers/model-info-metadata/model-info-metadata.component'; import {TableFilter} from '@common/shared/utils/tableParamEncode'; -import {ScalarKeyEnum} from '~/business-logic/model/events/scalarKeyEnum'; const MODELS_PREFIX = 'MODELS_INFO_'; @@ -81,12 +80,12 @@ export const setPlots = createAction( props<{plots: any[]}>() ); -export const getScalars = createAction( - MODELS_PREFIX + '[get scalars]', - props<{id: string}>() -); - -export const setScalars = createAction( - MODELS_PREFIX + '[set scalars]', - props<{scalars: any[]; axisType: ScalarKeyEnum}>() -); +// export const getScalars = createAction( +// MODELS_PREFIX + '[get scalars]', +// props<{id: string}>() +// ); +// +// export const setScalars = createAction( +// MODELS_PREFIX + '[set scalars]', +// props<{scalars: any[]; axisType: ScalarKeyEnum}>() +// ); diff --git a/src/app/webapp-common/models/actions/models-menu.actions.ts b/src/app/webapp-common/models/actions/models-menu.actions.ts index 1af92a36..080caea1 100644 --- a/src/app/webapp-common/models/actions/models-menu.actions.ts +++ b/src/app/webapp-common/models/actions/models-menu.actions.ts @@ -24,13 +24,13 @@ export const removeTag = createAction( props<{models: SelectedModel[]; tag: string}>() ); -export const archivedSelectedModels = createAction( +export const archiveSelectedModels = createAction( MODELS_PREFIX + '[archive selected models]', - props<{selectedEntities: SelectedModel[], skipUndo: boolean }>() + props<{selectedEntities: SelectedModel[]; skipUndo: boolean }>() ); export const restoreSelectedModels = createAction( MODELS_PREFIX + '[restore selected models]', - props<{selectedEntities: SelectedModel[], skipUndo: boolean }>() + props<{selectedEntities: SelectedModel[]; skipUndo: boolean }>() ); diff --git a/src/app/webapp-common/models/actions/models-view.actions.ts b/src/app/webapp-common/models/actions/models-view.actions.ts index 90e5b613..bfaf28af 100755 --- a/src/app/webapp-common/models/actions/models-view.actions.ts +++ b/src/app/webapp-common/models/actions/models-view.actions.ts @@ -4,6 +4,8 @@ import {SelectedModel} from '../shared/models.model'; import {TableFilter} from '../../shared/utils/tableParamEncode'; import {SortMeta} from 'primeng/api'; import {CountAvailableAndIsDisableSelectedFiltered} from '@common/shared/entity-page/items.utils'; +import {EXPERIMENTS_PREFIX} from '@common/experiments/experiment.consts'; +import {MetricVariantResult} from '~/business-logic/model/projects/metricVariantResult'; const MODELS_PREFIX = 'MODELS_'; @@ -77,12 +79,17 @@ export const getMetadataKeysForProject = createAction( MODELS_PREFIX + 'GET_METADATA_FOR_PROJECT' ); export const addColumn = createAction( - MODELS_PREFIX + ' [ add column]', + MODELS_PREFIX + ' [ add column ]', props<{col: ISmCol}>() ); export const removeCol = createAction( - MODELS_PREFIX + ' [ remove column]', + MODELS_PREFIX + ' [ remove column ]', + props<{ id: string; projectId: string }>() +); + +export const removeMetricCol = createAction( + MODELS_PREFIX + ' [ remove metric column ]', props<{ id: string; projectId: string }>() ); @@ -150,6 +157,10 @@ export const getModelsMetadataValuesForKey = createAction( props<{ col: ISmCol }>() ); +export const getCustomMetrics = createAction( + MODELS_PREFIX + '[get custom metrics]', +); + export const setTableFilters = createAction( MODELS_PREFIX + 'SET_TABLE_FILTERS', props<{ filters: TableFilter[]; projectId: string }>() @@ -201,4 +212,9 @@ export const setSelectedModelsDisableAvailable = createAction( export const setTableMode = createAction( MODELS_PREFIX + '[set table view mode]', props<{mode: 'info' | 'table'}>() -) +); + +export const setCustomMetrics = createAction( + EXPERIMENTS_PREFIX + ' [set custom metrics]', + props<{ metrics: MetricVariantResult[] }>() +); diff --git a/src/app/webapp-common/models/containers/model-experiments-table/model-experiments-table.component.html b/src/app/webapp-common/models/containers/model-experiments-table/model-experiments-table.component.html index cc000265..84be2bb8 100644 --- a/src/app/webapp-common/models/containers/model-experiments-table/model-experiments-table.component.html +++ b/src/app/webapp-common/models/containers/model-experiments-table/model-experiments-table.component.html @@ -1,7 +1,7 @@

USED BY

- +
diff --git a/src/app/webapp-common/models/containers/model-info-metadata/model-info-metadata.component.html b/src/app/webapp-common/models/containers/model-info-metadata/model-info-metadata.component.html index 9359e334..b41503b1 100644 --- a/src/app/webapp-common/models/containers/model-info-metadata/model-info-metadata.component.html +++ b/src/app/webapp-common/models/containers/model-info-metadata/model-info-metadata.component.html @@ -9,7 +9,7 @@
-
+
diff --git a/src/app/webapp-common/models/containers/model-info-plots/model-info-plots.component.ts b/src/app/webapp-common/models/containers/model-info-plots/model-info-plots.component.ts index 49388bec..a41dacf9 100644 --- a/src/app/webapp-common/models/containers/model-info-plots/model-info-plots.component.ts +++ b/src/app/webapp-common/models/containers/model-info-plots/model-info-plots.component.ts @@ -9,6 +9,7 @@ import {convertPlots, groupIterations, sortMetricsList} from '@common/tasks/task import { MetricsPlotEvent } from '~/business-logic/model/events/metricsPlotEvent'; import {selectRouterParams} from '@common/core/reducers/router-reducer'; import {getPlots, setPlots} from '@common/models/actions/models-info.actions'; +import {ReportCodeEmbedService} from '~/shared/services/report-code-embed.service'; @Component({ selector: 'sm-model-info-plot', @@ -32,7 +33,11 @@ export class ModelInfoPlotsComponent implements OnInit, OnDestroy { private refreshDisabled: boolean; private modelId: string; - constructor(private store: Store, private cdr: ChangeDetectorRef) { + constructor( + private store: Store, + private cdr: ChangeDetectorRef, + private reportEmbed: ReportCodeEmbedService + ) { // this.searchTerm$ = this.store.select(selectExperimentMetricsSearchTerm); this.splitSize$ = this.store.select(selectSplitSize); } @@ -109,6 +114,15 @@ export class ModelInfoPlotsComponent implements OnInit, OnDestroy { this.store.dispatch(setPlots({plots: null})); } + createEmbedCode(event: { metrics?: string[]; variants?: string[]; domRect: DOMRect }) { + this.reportEmbed.createCode({ + type: 'plot', + objects: [this.modelId], + objectType: 'model', + ...event + }); + } + ngOnDestroy(): void { this.sub.unsubscribe(); } diff --git a/src/app/webapp-common/models/containers/model-info-scalars/model-info-scalars.component.ts b/src/app/webapp-common/models/containers/model-info-scalars/model-info-scalars.component.ts index 0e3669dc..8ad96ede 100644 --- a/src/app/webapp-common/models/containers/model-info-scalars/model-info-scalars.component.ts +++ b/src/app/webapp-common/models/containers/model-info-scalars/model-info-scalars.component.ts @@ -3,11 +3,20 @@ import { ExperimentOutputScalarsComponent } from '@common/experiments/containers/experiment-output-scalars/experiment-output-scalars.component'; import {ExperimentInfoState} from '~/features/experiments/reducers/experiment-info.reducer'; -import {Store} from '@ngrx/store'; +import {select, Store} from '@ngrx/store'; import {ActivatedRoute, Router} from '@angular/router'; -import { selectSelectedModel } from '@common/models/reducers'; +import {selectSelectedModel} from '@common/models/reducers'; import {experimentScalarRequested} from '@common/experiments/actions/common-experiment-output.actions'; import {ReportCodeEmbedService} from '~/shared/services/report-code-embed.service'; +import {distinctUntilChanged, filter, map, tap} from 'rxjs/operators'; +import {selectSelectedModelSettings} from '~/features/experiments/reducers'; +import {selectRouterParams} from '@common/core/reducers/router-reducer'; +import { + selectModelInfoHistograms, + selectModelSettingsGroupBy, selectModelSettingsHiddenScalar, selectModelSettingsSmoothWeight, + selectModelSettingsXAxisType, +} from '@common/experiments/reducers'; +import {isEqual} from 'lodash-es'; @Component({ selector: 'sm-model-info-scalars', @@ -19,7 +28,7 @@ import {ReportCodeEmbedService} from '~/shared/services/report-code-embed.servic }) export class ModelInfoScalarsComponent extends ExperimentOutputScalarsComponent { protected entitySelector = this.store.select(selectSelectedModel); - protected exportForReport = false; + protected entityType: 'task' | 'model' = 'model'; constructor( protected store: Store, @@ -29,6 +38,32 @@ export class ModelInfoScalarsComponent extends ExperimentOutputScalarsComponent protected reportEmbed: ReportCodeEmbedService ) { super(store, router, activeRoute, changeDetection, reportEmbed); + + this.xAxisType$ = this.store.select(selectModelSettingsXAxisType); + this.groupBy$ = this.store.select(selectModelSettingsGroupBy); + this.smoothWeight$ = this.store.select(selectModelSettingsSmoothWeight); + this.listOfHidden$ = this.store.select(selectModelSettingsHiddenScalar) + .pipe(distinctUntilChanged(isEqual)); + + this.settings$ = this.store.pipe( + select(selectSelectedModelSettings), + filter(settings => !!settings), + map(settings => settings ? settings.selectedScalar : null), + distinctUntilChanged() + ); + + this.scalars$ = this.store.select(selectModelInfoHistograms) + .pipe( + filter((metrics) => !!metrics), + ); + + this.routerParams$ = this.store.select(selectRouterParams) + .pipe( + filter(params => !!params.modelId), + tap(params => this.experimentId = params.modelId), + distinctUntilChanged() + ); + } refresh() { diff --git a/src/app/webapp-common/models/containers/model-info/model-info.component.html b/src/app/webapp-common/models/containers/model-info/model-info.component.html index 3b3eb50f..a27588a3 100755 --- a/src/app/webapp-common/models/containers/model-info/model-info.component.html +++ b/src/app/webapp-common/models/containers/model-info/model-info.component.html @@ -12,30 +12,18 @@ (closeInfoClicked)="closePanel()" > - +
+ + + + +
diff --git a/src/app/webapp-common/models/containers/model-info/model-info.component.scss b/src/app/webapp-common/models/containers/model-info/model-info.component.scss index b311bffc..1c9a94f4 100755 --- a/src/app/webapp-common/models/containers/model-info/model-info.component.scss +++ b/src/app/webapp-common/models/containers/model-info/model-info.component.scss @@ -2,10 +2,19 @@ :host { + sm-model-info-header { + margin-bottom: 12px; + } + sm-model-info-header { display: block; } + sm-router-tab-nav-bar { + overflow: hidden; + flex-grow: 1; + } + .model-info-container { height: calc(100% - 32px); @@ -19,11 +28,46 @@ } .model-info-body { - height: calc(100% - 110px); + height: calc(100% - 119px); } - ::ng-deep nav { - border-bottom: 1px solid rgba(2, 2, 2, 0.07); + .tab-nav { + //display: grid; need to fix when we'll have full page + display: flex; + grid-template-columns: 200px 1fr 200px; + align-items: center; + border-bottom: 1px solid #efefef; + + &.minimized { + display: flex; + } + + @media(max-width: 1200px) { + grid-template-columns: 0 1fr 200px; + } + } + + sm-router-tab-nav-bar { + overflow: hidden; + flex-grow: 1; + } + + .setting-icon { + margin-right: 30px; + margin-left: auto; + } + + .refresh-position { + position: absolute; + right: 26px; + top: 2px; + display: flex; + align-items: center; + } + + sm-experiment-settings.maximized { + display: block; + padding-top: 6px; } } diff --git a/src/app/webapp-common/models/containers/model-info/model-info.component.ts b/src/app/webapp-common/models/containers/model-info/model-info.component.ts index aabee483..9218f13a 100755 --- a/src/app/webapp-common/models/containers/model-info/model-info.component.ts +++ b/src/app/webapp-common/models/containers/model-info/model-info.component.ts @@ -1,10 +1,10 @@ import {Component, OnDestroy, OnInit, ViewChild} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; -import {selectRouterParams} from '@common/core/reducers/router-reducer'; +import {selectRouterConfig, selectRouterParams} from '@common/core/reducers/router-reducer'; import {Store} from '@ngrx/store'; import {ModelInfoState} from '../../reducers/model-info.reducer'; import * as infoActions from '../../actions/models-info.actions'; -import {selectSelectedModel, selectSelectedTableModel} from '../../reducers'; +import {selectSelectedModel, selectSelectedTableModel, selectSplitSize} from '../../reducers'; import {SelectedModel} from '../../shared/models.model'; import {selectS3BucketCredentials} from '@common/core/reducers/common-auth-reducer'; import {Observable, Subscription} from 'rxjs'; @@ -14,6 +14,8 @@ import {selectBackdropActive} from '@common/core/reducers/view.reducer'; import {setTableMode} from '@common/models/actions/models-view.actions'; import {isReadOnly} from '@common/shared/utils/is-read-only'; import {MESSAGES_SEVERITY} from '@common/constants'; +import {toggleSettings} from '@common/experiments/actions/common-experiment-output.actions'; +import {Link} from '@common/shared/components/router-tab-nav-bar/router-tab-nav-bar.component'; @Component({ @@ -23,9 +25,8 @@ import {MESSAGES_SEVERITY} from '@common/constants'; }) export class ModelInfoComponent implements OnInit, OnDestroy { - private paramsSubscription: Subscription; public selectedModel: SelectedModel; - private selectedModelSubscription: Subscription; + private sub = new Subscription(); private s3BucketCredentials: Observable; @ViewChild('modelInfoHeader', { static: true }) modelInfoHeader; public selectedModel$: Observable; @@ -33,6 +34,17 @@ export class ModelInfoComponent implements OnInit, OnDestroy { public backdropActive$: Observable; private projectId: string; public selectedTableModel$: Observable; + public scalars$: Observable; + public splitSize$: Observable; + links = [ + {name: 'general', url: ['general']}, + {name: 'network', url: ['network']}, + {name: 'labels', url: ['labels']}, + {name: 'metadata', url: ['metadata']}, + {name: 'lineage', url: ['experiments']}, + {name: 'scalars', url: ['scalars']}, + {name: 'plots', url: ['plots']}, + ] as Link[]; constructor( private router: Router, @@ -42,15 +54,25 @@ export class ModelInfoComponent implements OnInit, OnDestroy { this.s3BucketCredentials = store.select(selectS3BucketCredentials); this.backdropActive$ = this.store.select(selectBackdropActive); this.selectedTableModel$ = this.store.select(selectSelectedTableModel); + this.splitSize$ = this.store.select(selectSplitSize); } ngOnInit() { - this.selectedModelSubscription = this.store.select(selectSelectedModel) + this.scalars$ = this.store.select(selectRouterConfig) + .pipe( + filter(c => !!c), + distinctUntilChanged(), + map((config: string[]) => config.includes('scalars')) + ); + + this.sub.add(this.store.select(selectSelectedModel) .subscribe(model => { this.selectedModel = model; this.isExample = isReadOnly(model); - }); - this.paramsSubscription = this.store.select(selectRouterParams) + }) + ); + + this.sub.add(this.store.select(selectRouterParams) .pipe( tap((params) => { this.projectId = params?.projectId; @@ -60,13 +82,15 @@ export class ModelInfoComponent implements OnInit, OnDestroy { filter(modelId => !!modelId), distinctUntilChanged() ) - .subscribe(id => this.store.dispatch(infoActions.getModelInfo({id}))); - this.selectedModel$ = this.store.select(selectSelectedModel).pipe(filter(model => !!model)); + .subscribe(id => this.store.dispatch(infoActions.getModelInfo({id}))) + ); + + this.selectedModel$ = this.store.select(selectSelectedModel) + .pipe(filter(model => !!model)); } ngOnDestroy(): void { - this.paramsSubscription.unsubscribe(); - this.selectedModelSubscription.unsubscribe(); + this.sub.unsubscribe(); this.store.dispatch(infoActions.setModelInfo({model: null})); } @@ -85,6 +109,10 @@ export class ModelInfoComponent implements OnInit, OnDestroy { return ready ? 'published' : 'created'; } + toggleSettingsBar() { + this.store.dispatch(toggleSettings()); + } + closePanel() { this.store.dispatch(setTableMode({mode: 'table'})); return this.router.navigate(['..'], {relativeTo: this.route, queryParamsHandling: 'merge'}); diff --git a/src/app/webapp-common/models/containers/model-menu/model-menu.component.ts b/src/app/webapp-common/models/containers/model-menu/model-menu.component.ts index e7065e56..4ad95213 100644 --- a/src/app/webapp-common/models/containers/model-menu/model-menu.component.ts +++ b/src/app/webapp-common/models/containers/model-menu/model-menu.component.ts @@ -1,13 +1,13 @@ import {Component, ElementRef, EventEmitter, Input, Output} from '@angular/core'; import { - archivedSelectedModels, + archiveSelectedModels, changeProjectRequested, publishModelClicked, restoreSelectedModels } from '../../actions/models-menu.actions'; -import {htmlTextShorte} from '@common/shared/utils/shared-utils'; +import {htmlTextShort} from '@common/shared/utils/shared-utils'; import {ICONS} from '@common/constants'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {Store} from '@ngrx/store'; import {AdminService} from '~/shared/services/admin.service'; import {selectS3BucketCredentials} from '@common/core/reducers/common-auth-reducer'; @@ -86,10 +86,10 @@ export class ModelMenuComponent extends BaseContextMenuComponent { archiveClicked() { // info header case const selectedModels = this.selectedModels ? selectionDisabledArchive(this.selectedModels).selectedFiltered : [this.model]; - if (this.isArchive) { + if (selectedModels[0].system_tags?.includes('archived')) { this.store.dispatch(restoreSelectedModels({selectedEntities: selectedModels, skipUndo: false})); } else { - this.store.dispatch(archivedSelectedModels({selectedEntities: selectedModels, skipUndo: false})); + this.store.dispatch(archiveSelectedModels({selectedEntities: selectedModels, skipUndo: false})); } } @@ -99,7 +99,7 @@ export class ModelMenuComponent extends BaseContextMenuComponent { const confirmDialogRef = this.dialog.open(ConfirmDialogComponent, { data: { title: 'PUBLISH', - body: `${selectedModels.length === 1 ? htmlTextShorte(selectedModels[0].name) : selectedModels.length + ' models'} status will be set to Published. + body: `${selectedModels.length === 1 ? htmlTextShort(selectedModels[0].name) : selectedModels.length + ' models'} status will be set to Published.

Published models are read-only and cannot be reset.`, yes: 'Publish', no: 'Cancel', diff --git a/src/app/webapp-common/models/dumbs/model-custom-cols-menu/model-custom-cols-menu.component.html b/src/app/webapp-common/models/dumbs/model-custom-cols-menu/model-custom-cols-menu.component.html index bc2d9d04..03d0d038 100644 --- a/src/app/webapp-common/models/dumbs/model-custom-cols-menu/model-custom-cols-menu.component.html +++ b/src/app/webapp-common/models/dumbs/model-custom-cols-menu/model-custom-cols-menu.component.html @@ -4,8 +4,9 @@ smMenuClass="light-theme custom-columns" [showButton]="false" [style.pointer-events]="disabled ? 'none' : 'initial'" + (menuClosed)="customColumnMode = customColumnModeEnum.Standard" > -
+
+
ADD CUSTOM COLUMN
ADD CUSTOM METADATA COLUMN + (click)="selectMetadataKeys(customColumnModeEnum.Metrics); $event.stopPropagation()" + >METRICS +
+
METADATA
- + + diff --git a/src/app/webapp-common/models/dumbs/model-custom-cols-menu/model-custom-cols-menu.component.scss b/src/app/webapp-common/models/dumbs/model-custom-cols-menu/model-custom-cols-menu.component.scss index 17da6674..7ed28859 100644 --- a/src/app/webapp-common/models/dumbs/model-custom-cols-menu/model-custom-cols-menu.component.scss +++ b/src/app/webapp-common/models/dumbs/model-custom-cols-menu/model-custom-cols-menu.component.scss @@ -6,16 +6,23 @@ color: $blue-400; background: $faint-gray; cursor: pointer; + font-size: 14px; + .add-button { display: flex; justify-content: center; align-items: center; - padding: 15px 15px; + padding: 15px; &.meta-button { width: 100%; .caption { - margin-top: 2px; + margin-top: 4px; + white-space: nowrap; + } + + &:first-child { + border-right: 1px solid $blue-200; } } } @@ -25,3 +32,10 @@ transition: color 0.3s; } } + +sm-select-metric-for-custom-col, +sm-select-metadata-keys-custom-cols { + display: block; + height: 640px; + max-height: calc(100vh - 120px); +} diff --git a/src/app/webapp-common/models/dumbs/model-custom-cols-menu/model-custom-cols-menu.component.ts b/src/app/webapp-common/models/dumbs/model-custom-cols-menu/model-custom-cols-menu.component.ts index 536bacf4..c4b8e087 100644 --- a/src/app/webapp-common/models/dumbs/model-custom-cols-menu/model-custom-cols-menu.component.ts +++ b/src/app/webapp-common/models/dumbs/model-custom-cols-menu/model-custom-cols-menu.component.ts @@ -1,31 +1,39 @@ import {Component, EventEmitter, Input, Output} from '@angular/core'; import {ISmCol} from '@common/shared/ui-components/data/table/table.consts'; +import {CustomColumnMode} from '@common/experiments/shared/common-experiments.const'; +import {MetricVariantResult} from '~/business-logic/model/projects/metricVariantResult'; +import {MetricValueType} from '@common/experiments-compare/experiments-compare.constants'; @Component({ selector: 'sm-model-custom-cols-menu', templateUrl: './model-custom-cols-menu.component.html', styleUrls: ['./model-custom-cols-menu.component.scss'] }) -export class ModelCustomColsMenuComponent{ +export class ModelCustomColsMenuComponent { + protected readonly customColumnModeEnum = CustomColumnMode; + public customColumnMode: CustomColumnMode = CustomColumnMode.Standard; + @Input() tableCols: ISmCol[]; @Input() isLoading: boolean; @Input() disabled: boolean; @Input() metadataKeys: string[]; + @Input() metricVariants; @Output() removeColFromList = new EventEmitter(); @Output() selectedTableColsChanged = new EventEmitter(); - @Output() selectMetadataKeysActiveChanged = new EventEmitter(); - @Output() addOrRemoveMetadataKeyFromColumns = new EventEmitter<{key: string; show: boolean }>(); + @Output() selectMetadataKeysActiveChanged = new EventEmitter<{ customMode: CustomColumnMode }>(); + @Output() addOrRemoveMetadataKeyFromColumns = new EventEmitter<{ key: string; show: boolean }>(); + @Output() selectedMetricToShow = new EventEmitter<{ + variant: MetricVariantResult; + addCol: boolean; + valueType: MetricValueType; + }>(); - customColumnMode: string; - - selectMetadataKeys(metadata: string) { - this.selectMetadataKeysActiveChanged.emit(); - this.customColumnMode = metadata; + selectMetadataKeys(mode: CustomColumnMode) { + this.selectMetadataKeysActiveChanged.emit({customMode: mode}); + this.customColumnMode = mode; } setCustomColumnMode(param) { this.customColumnMode = param; } - - } diff --git a/src/app/webapp-common/models/dumbs/model-general-info/model-general-info.component.html b/src/app/webapp-common/models/dumbs/model-general-info/model-general-info.component.html index 5110c666..4f320682 100755 --- a/src/app/webapp-common/models/dumbs/model-general-info/model-general-info.component.html +++ b/src/app/webapp-common/models/dumbs/model-general-info/model-general-info.component.html @@ -5,7 +5,7 @@ diff --git a/src/app/webapp-common/models/dumbs/model-header/model-header.component.html b/src/app/webapp-common/models/dumbs/model-header/model-header.component.html index 404b3dde..eed019d5 100644 --- a/src/app/webapp-common/models/dumbs/model-header/model-header.component.html +++ b/src/app/webapp-common/models/dumbs/model-header/model-header.component.html @@ -8,7 +8,7 @@ [minimize]="(isSmallScreen$ | async).matches" (toggleArchived)="onIsArchivedChanged($event)"> ; @Input() isLoadingMetadataKeys: any; @Input() tableMode: string; @Input() rippleEffect: boolean; @@ -34,6 +37,11 @@ export class ModelHeaderComponent extends BaseEntityHeaderComponent { @Output() refreshListClicked = new EventEmitter(); @Output() setAutoRefresh = new EventEmitter(); @Output() selectedTableColsChanged = new EventEmitter(); + @Output() selectedMetricToShow = new EventEmitter<{ + variant: MetricVariantResult; + addCol: boolean; + valueType: MetricValueType; + }>(); @Output() selectMetadataKeysActiveChanged = new EventEmitter(); @Output() clearTableFilters = new EventEmitter<{ [s: string]: FilterMetadata }>(); @Output() addOrRemoveMetadataKeyFromColumns = new EventEmitter<{key: string; show: boolean}>(); diff --git a/src/app/webapp-common/models/dumbs/model-info-header/model-info-header.component.html b/src/app/webapp-common/models/dumbs/model-info-header/model-info-header.component.html index 1fbe4c33..4a53a749 100755 --- a/src/app/webapp-common/models/dumbs/model-info-header/model-info-header.component.html +++ b/src/app/webapp-common/models/dumbs/model-info-header/model-info-header.component.html @@ -19,7 +19,7 @@
- + + + Required +
- diff --git a/src/app/webapp-common/models/dumbs/model-view-network/model-view-network.component.ts b/src/app/webapp-common/models/dumbs/model-view-network/model-view-network.component.ts index a2cbea61..d12fda9c 100755 --- a/src/app/webapp-common/models/dumbs/model-view-network/model-view-network.component.ts +++ b/src/app/webapp-common/models/dumbs/model-view-network/model-view-network.component.ts @@ -1,8 +1,8 @@ import {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core'; import {getModelDesign} from '@common/tasks/tasks.utils'; -import {EditJsonComponent} from '@common/shared/ui-components/overlay/edit-json/edit-json.component'; +import {EditJsonComponent, EditJsonData} from '@common/shared/ui-components/overlay/edit-json/edit-json.component'; import {take} from 'rxjs/operators'; -import {MatLegacyDialog as MatDialog, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MatDialog, MatDialogRef} from '@angular/material/dialog'; import {ConfirmDialogComponent} from '@common/shared/ui-components/overlay/confirm-dialog/confirm-dialog.component'; import {EditableSectionComponent} from '@common/shared/ui-components/panel/editable-section/editable-section.component'; @@ -61,7 +61,7 @@ export class ModelViewNetworkComponent { editPrototext() { const editPrototextDialog = this.dialog.open(EditJsonComponent, { - data: {textData: this.design, readOnly: false, title: 'EDIT MODEL CONFIGURATION', typeJson: false} + data: {textData: this.design, readOnly: false, title: 'EDIT MODEL CONFIGURATION'} as EditJsonData }); editPrototextDialog.afterClosed().pipe(take(1)).subscribe((data) => { diff --git a/src/app/webapp-common/models/effects/models-info.effects.ts b/src/app/webapp-common/models/effects/models-info.effects.ts index 6bd5b918..72012544 100755 --- a/src/app/webapp-common/models/effects/models-info.effects.ts +++ b/src/app/webapp-common/models/effects/models-info.effects.ts @@ -22,14 +22,13 @@ import {resetActiveSection} from '../actions/models-info.actions'; import * as viewActions from '../actions/models-view.actions'; import {ModelInfoState} from '../reducers/model-info.reducer'; import {MODELS_INFO_ONLY_FIELDS} from '../shared/models.const'; -import {selectCacheAxisType, selectSelectedModel, selectSelectedxAxisType} from '../reducers'; +import {selectSelectedModel} from '../reducers'; import {SelectedModel} from '../shared/models.model'; import {selectActiveWorkspace} from '../../core/reducers/users-reducer'; import {isExample} from '../../shared/utils/shared-utils'; import {isSharedAndNotOwner} from '@common/shared/utils/is-shared-and-not-owner'; import {ApiEventsService} from '~/business-logic/api-services/events.service'; import {EMPTY} from 'rxjs'; -import {ScalarKeyEnum} from '~/business-logic/model/events/scalarKeyEnum'; @Injectable() export class ModelsInfoEffects { @@ -173,40 +172,40 @@ export class ModelsInfoEffects { ]) )); - fetchScalars$ = createEffect(() => this.actions$.pipe( - ofType(infoActions.getScalars), - withLatestFrom( - this.store.select(selectSelectedxAxisType), - this.store.select(selectCacheAxisType) - ), - switchMap(([action, axisType, prevAxisType]) => { - if ([ScalarKeyEnum.IsoTime, ScalarKeyEnum.Timestamp].includes(prevAxisType) && - [ScalarKeyEnum.IsoTime, ScalarKeyEnum.Timestamp].includes(axisType)) { - return [ - deactivateLoader(infoActions.refreshModelInfo.type), - deactivateLoader(action.type) - ]; - } - - return this.eventsService.eventsScalarMetricsIterHistogram({ - task: action.id, - // eslint-disable-next-line @typescript-eslint/naming-convention - model_events: true, - key: axisType === ScalarKeyEnum.IsoTime ? ScalarKeyEnum.Timestamp : axisType - }) - .pipe( - mergeMap(res => [ - infoActions.setScalars({scalars: res, axisType}), - deactivateLoader(infoActions.refreshModelInfo.type), - deactivateLoader(action.type) - ]), - catchError(error => [ - requestFailed(error), - deactivateLoader(action.type), - deactivateLoader(infoActions.refreshModelInfo.type), - setServerError(error, null, 'Failed to get Scalar Charts') - ]) - ); - }) - )); + // fetchScalars$ = createEffect(() => this.actions$.pipe( + // ofType(infoActions.getScalars), + // withLatestFrom( + // this.store.select(selectSelectedSettingsxAxisType), + // this.store.select(selectExperimentHistogramCacheAxisType) + // ), + // switchMap(([action, axisType, prevAxisType]) => { + // if ([ScalarKeyEnum.IsoTime, ScalarKeyEnum.Timestamp].includes(prevAxisType) && + // [ScalarKeyEnum.IsoTime, ScalarKeyEnum.Timestamp].includes(axisType)) { + // return [ + // deactivateLoader(infoActions.refreshModelInfo.type), + // deactivateLoader(action.type) + // ]; + // } + // + // return this.eventsService.eventsScalarMetricsIterHistogram({ + // task: action.id, + // // eslint-disable-next-line @typescript-eslint/naming-convention + // model_events: true, + // key: axisType === ScalarKeyEnum.IsoTime ? ScalarKeyEnum.Timestamp : axisType + // }) + // .pipe( + // mergeMap(res => [ + // infoActions.setScalars({scalars: res, axisType}), + // deactivateLoader(infoActions.refreshModelInfo.type), + // deactivateLoader(action.type) + // ]), + // catchError(error => [ + // requestFailed(error), + // deactivateLoader(action.type), + // deactivateLoader(infoActions.refreshModelInfo.type), + // setServerError(error, null, 'Failed to get Scalar Charts') + // ]) + // ); + // }) + // )); } diff --git a/src/app/webapp-common/models/effects/models-menu.effects.ts b/src/app/webapp-common/models/effects/models-menu.effects.ts index b09288fa..329ea88f 100644 --- a/src/app/webapp-common/models/effects/models-menu.effects.ts +++ b/src/app/webapp-common/models/effects/models-menu.effects.ts @@ -36,7 +36,7 @@ export class ModelsMenuEffects { } activeLoader = createEffect( () => this.actions$.pipe( - ofType(menuActions.archivedSelectedModels, menuActions.publishModelClicked, + ofType(menuActions.archiveSelectedModels, menuActions.publishModelClicked, menuActions.restoreSelectedModels, menuActions.changeProjectRequested), map(action => activeLoader(action.type)))); @@ -152,7 +152,7 @@ export class ModelsMenuEffects { )); archiveModels = createEffect(() => this.actions$.pipe( - ofType(menuActions.archivedSelectedModels), + ofType(menuActions.archiveSelectedModels), withLatestFrom( this.store.select(selectSelectedTableModel) ), @@ -221,7 +221,7 @@ export class ModelsMenuEffects { { name: 'Undo', actions: [ viewActions.setSelectedModels({models}), - menuActions.archivedSelectedModels({selectedEntities: models, skipUndo: true}) + menuActions.archiveSelectedModels({selectedEntities: models, skipUndo: true}) ] } ]; diff --git a/src/app/webapp-common/models/effects/models-view.effects.ts b/src/app/webapp-common/models/effects/models-view.effects.ts index 2ad58770..fec9c8af 100755 --- a/src/app/webapp-common/models/effects/models-view.effects.ts +++ b/src/app/webapp-common/models/effects/models-view.effects.ts @@ -66,6 +66,7 @@ import {selectTableMode} from '../../experiments/reducers'; import {selectActiveWorkspaceReady} from '~/core/reducers/view.reducer'; import {escapeRegex} from '@common/shared/utils/escape-regex'; import {MESSAGES_SEVERITY} from '@common/constants'; +import {sortByField} from '@common/tasks/tasks.utils'; @Injectable() export class ModelsViewEffects { @@ -74,7 +75,8 @@ export class ModelsViewEffects { private actions$: Actions, private store: Store, private apiModels: ApiModelsService, private projectsApi: ApiProjectsService, private modelBl: BlModelsService, private router: Router, private route: ActivatedRoute - ) {} + ) { + } /* eslint-disable @typescript-eslint/naming-convention */ @@ -105,7 +107,7 @@ export class ModelsViewEffects { ...action.filters.reduce((acc, updatedFilter) => { acc[updatedFilter.col] = {value: updatedFilter.value, matchMode: updatedFilter.filterMatchMode}; return acc; - }, {} as {[col: string]: FilterMetadata}) + }, {} as { [col: string]: FilterMetadata }) }, update: true })] ) @@ -119,7 +121,7 @@ export class ModelsViewEffects { ), switchMap(([action, isDeep, selectedProject]) => { const projectId = action.col.projectId || selectedProject.id; - return this.projectsApi.projectsGetModelMetadataValues ({ + return this.projectsApi.projectsGetModelMetadataValues({ include_subprojects: isDeep, key: action.col.key, ...(projectId !== '*' && {projects: [projectId]}) @@ -162,7 +164,7 @@ export class ModelsViewEffects { withLatestFrom( this.store.select(selectRouterParams).pipe(map(params => params?.projectId)), ), - switchMap(([action, projectId]) => this.apiModels.modelsGetFrameworks({projects: projectId !== '*' && action.type !== actions.getAllProjectsFrameworks.type ? [projectId] : []}) + switchMap(([action, projectId]) => this.apiModels.modelsGetFrameworks({projects: projectId !== '*' && action.type !== actions.getAllProjectsFrameworks.type ? [projectId] : []}) .pipe( mergeMap(res => [ actions.setFrameworks({frameworks: res.frameworks.concat(null)}), @@ -190,7 +192,7 @@ export class ModelsViewEffects { ofType(actions.getTags, actions.getTagsForAllProjects), withLatestFrom(this.store.select(selectRouterParams).pipe(map(params => params?.projectId))), switchMap(([action, projectId]) => this.projectsApi.projectsGetModelTags({ - projects: (projectId === '*' || action.type=== actions.getTagsForAllProjects.type) ? [] : [projectId] + projects: (projectId === '*' || action.type === actions.getTagsForAllProjects.type) ? [] : [projectId] }).pipe( mergeMap(res => [ actions.setTags({tags: res.tags.concat(null)}), @@ -222,6 +224,34 @@ export class ModelsViewEffects { )) )); + getCustomMetrics = createEffect(() => this.actions$.pipe( + ofType(actions.getCustomMetrics), + withLatestFrom( + this.store.select(selectRouterParams).pipe(map(params => params?.projectId)), + this.store.select(selectIsDeepMode) + ), + switchMap(([action, projectId, isDeep]) => this.projectsApi.projectsGetUniqueMetricVariants({ + project: projectId === '*' ? null : projectId, + model_metrics: true, + include_subprojects: isDeep + }) + .pipe( + mergeMap(res => [ + actions.setCustomMetrics({metrics: sortByField(res.metrics, 'metric')}), + deactivateLoader(action.type) + ]), + catchError(error => [ + requestFailed(error), + deactivateLoader(action.type), + addMessage('warn', 'Fetch custom metrics failed', error?.meta && [{ + name: 'More info', + actions: [setServerError(error, null, 'Fetch custom metrics failed')] + }]), + ]) + ) + ) + )); + lockRefresh = false; refreshModels = createEffect(() => this.actions$.pipe( ofType(actions.refreshModels), @@ -233,8 +263,8 @@ export class ModelsViewEffects { this.store.select(selectAppVisible)), filter((values) => values[4]), switchMap(([action, scrollId, selectedModel, models]) => { - this.lockRefresh = !action.autoRefresh; - return this.fetchModels$(scrollId, true) + this.lockRefresh = !action.autoRefresh; + return this.fetchModels$(scrollId, true) .pipe( mergeMap(res => { this.lockRefresh = false; @@ -276,7 +306,7 @@ export class ModelsViewEffects { .pipe( mergeMap(res => { - const addModelsAction = scrollId === res.scroll_id ? + const addModelsAction = scrollId === res.scroll_id || !scrollId ? [actions.addModels({models: res.models})] : [actions.getNextModelsWithPageSize({pageSize: modelsList.length}), addMessage(MESSAGES_SEVERITY.WARN, 'Session expired')]; @@ -364,7 +394,7 @@ export class ModelsViewEffects { this.store.select(selectRouterParams).pipe(map(params => params?.projectId)), this.store.select(selectTableMode) ), - filter(([, , , tableMode])=>tableMode==='info'), + filter(([, , , tableMode]) => tableMode === 'info'), tap(([, models, projectId]) => this.navigateAfterModelSelectionChanged(models[0] as SelectedModel, projectId)), mergeMap(() => [actions.setTableMode({mode: 'info'})]) )); @@ -460,7 +490,7 @@ export class ModelsViewEffects { this.store.select(modelsSelectors.selectModelTableColumns), this.store.select(selectIsDeepMode), ), - switchMap(([scrollId, projectId, isArchived, metadataCols, gb, orderFields, filters, selectedModels, showAllSelectedIsActive, colsOrder, hiddenCols,cols ,deep]) => { + switchMap(([scrollId, projectId, isArchived, metadataCols, gb, orderFields, filters, selectedModels, showAllSelectedIsActive, colsOrder, hiddenCols, cols, deep]) => { const selectedIds = showAllSelectedIsActive ? selectedModels.map(exp => exp.id) : []; const columns = encodeColumns(MODELS_TABLE_COLS, hiddenCols, metadataCols, colsOrder); this.setModelsUrlParams(filters, orderFields, isArchived, columns, deep); diff --git a/src/app/webapp-common/models/models.component.html b/src/app/webapp-common/models/models.component.html index c1f1086f..88c68cdb 100755 --- a/src/app/webapp-common/models/models.component.html +++ b/src/app/webapp-common/models/models.component.html @@ -7,14 +7,16 @@ [sharedView]="isSharedAndNotOwner$|async" [tableFilters]="tableFilters$ | async" [metadataKeys]="metadataKeys$ | async" + [metricVariants]="metricVariants$ | async" [tableMode]="firstModel && (tableMode$ | async)" [rippleEffect]="tableModeAwareness$ | async" (isArchivedChanged)="archivedChanged($event)" (setAutoRefresh)="setAutoRefresh($event)" (selectedTableColsChanged)="selectedTableColsChanged($event)" + (selectedMetricToShow)="selectedMetricToShow($event)" (addOrRemoveMetadataKeyFromColumns)="addOrRemoveMetadataKeyFromColumns($event)" (removeColFromList)="removeColFromList($event)" - (selectMetadataKeysActiveChanged)="selectMetadataKeysActiveChanged()" + (selectMetadataKeysActiveChanged)="selectMetadataKeysActiveChanged($event)" (clearTableFilters)="clearTableFiltersHandler($event)" (tableModeChanged)="modeChanged($event); tableModeUserAware()" > @@ -61,6 +63,7 @@ (sortedChanged)="sortedChanged($event)" (columnResized)="columnResized($event)" (filterChanged)="filterChanged($event)" + (filterSearchChanged)="filterSearchChanged($event)" (loadMoreModels)="getNextModels()" (clearAllFilters)="clearTableFiltersHandler($event)" > diff --git a/src/app/webapp-common/models/models.component.ts b/src/app/webapp-common/models/models.component.ts index baf5a0c7..03f75169 100755 --- a/src/app/webapp-common/models/models.component.ts +++ b/src/app/webapp-common/models/models.component.ts @@ -1,10 +1,10 @@ import {Component, OnDestroy, OnInit, ViewChild} from '@angular/core'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {ActivatedRoute, Params, Router} from '@angular/router'; import {select, Store} from '@ngrx/store'; import {isEqual} from 'lodash-es'; -import {combineLatest, Observable} from 'rxjs'; -import {debounceTime, distinctUntilChanged, filter, map, skip, withLatestFrom} from 'rxjs/operators'; +import {combineLatest, Observable, of} from 'rxjs'; +import {debounceTime, distinctUntilChanged, filter, map, skip, switchMap, withLatestFrom} from 'rxjs/operators'; import {getTags, setArchive as setProjectArchive, setDeep} from '../core/actions/projects.actions'; import {initSearch, resetSearch} from '../common-search/common-search.actions'; import {SearchState, selectSearchQuery} from '../common-search/common-search.reducer'; @@ -13,7 +13,7 @@ import { selectCompanyTags, selectIsArchivedMode, selectProjectSystemTags, - selectProjectTags, + selectProjectTags, selectSelectedProjectId, selectTagsFilterByProject } from '../core/reducers/projects.reducer'; import {selectRouterParams} from '../core/reducers/router-reducer'; @@ -21,14 +21,14 @@ import {selectAppVisible} from '../core/reducers/view.reducer'; import {BaseEntityPageComponent} from '../shared/entity-page/base-entity-page'; import {FilterMetadata} from 'primeng/api/filtermetadata'; import {ISmCol, TableSortOrderEnum} from '../shared/ui-components/data/table/table.consts'; -import {createMetadataCol, decodeColumns, decodeFilter, decodeOrder} from '../shared/utils/tableParamEncode'; +import {createMetadataCol, createMetricColumn, decodeColumns, decodeFilter, decodeOrder} from '../shared/utils/tableParamEncode'; import * as modelsActions from './actions/models-view.actions'; import {MODELS_TABLE_COLS} from './models.consts'; import * as modelsSelectors from './reducers'; import { selectMetadataColsForProject, selectMetadataColsOptions, - selectMetadataKeys, + selectMetadataKeys, selectMetricVariants, selectModelsFrameworks, selectModelsTags, selectModelTableColumns, @@ -52,6 +52,10 @@ import {HasReadOnlyFooterItem} from '../shared/entity-page/footer-items/has-read import {SelectedTagsFooterItem} from '../shared/entity-page/footer-items/selected-tags-footer-item'; import {RefreshService} from '@common/core/services/refresh.service'; import {SmSyncStateSelectorService} from '../core/services/sync-state-selector.service'; +import {CompareFooterItem} from '@common/shared/entity-page/footer-items/compare-footer-item'; +import {MetricVariantResult} from '~/business-logic/model/projects/metricVariantResult'; +import {MetricValueType} from '@common/experiments-compare/experiments-compare.constants'; +import {CustomColumnMode} from '@common/experiments/shared/common-experiments.const'; @Component({ @@ -87,6 +91,7 @@ export class ModelsComponent extends BaseEntityPageComponent implements OnInit, public filteredTableCols$: Observable; public firstModel: TableModel; public metadataColsOptions$: Observable>; + public metricVariants$: Observable; protected inEditMode$: Observable; protected addTag = addTag; protected setSplitSizeAction = modelsActions.setSplitSize; @@ -120,6 +125,7 @@ export class ModelsComponent extends BaseEntityPageComponent implements OnInit, this.noMoreModels$ = this.store.select(modelsSelectors.selectNoMoreModels); this.isSharedAndNotOwner$ = this.store.select(selectIsSharedAndNotOwner); this.metadataColsOptions$ = this.store.select(selectMetadataColsOptions); + this.metricVariants$ = this.store.select(selectMetricVariants); this.showAllSelectedIsActive$ = this.store.select(modelsSelectors.selectShowAllSelectedIsActive); this.searchQuery$ = this.store.select(selectSearchQuery); @@ -203,7 +209,7 @@ export class ModelsComponent extends BaseEntityPageComponent implements OnInit, } if (params.columns) { - const [, , , metadataCols, allIds] = decodeColumns(params.columns, this.originalTableColumns); + const [,metrics , , metadataCols, allIds] = decodeColumns(params.columns, this.originalTableColumns); const hiddenCols = {}; this.originalTableColumns.forEach((tableCol) => { if (tableCol.id !== 'selected') { @@ -212,8 +218,9 @@ export class ModelsComponent extends BaseEntityPageComponent implements OnInit, }); this.store.dispatch(modelsActions.setHiddenCols({hiddenCols})); this.store.dispatch(modelsActions.setExtraColumns({ - projectId: this.projectId, + projectId: projectId ?? this.projectId, columns: metadataCols.map(metadataCol => createMetadataCol(metadataCol, projectId)) + .concat(metrics.map(metricCol => createMetricColumn(metricCol, projectId))) })); this.columnsReordered(allIds, false); } @@ -230,8 +237,10 @@ export class ModelsComponent extends BaseEntityPageComponent implements OnInit, tags$: this.tags$, data$: this.selectedModelsDisableAvailable$, tagsFilterByProject$: this.tagsFilterByProject$, - companyTags$: this.companyTags$, - projectTags$: this.projectTags$ + companyTags$: this.selectedProjectId === '*' ? of(null) : this.companyTags$, + projectTags$: this.store.select(selectSelectedProjectId).pipe(switchMap(id => + id === '*' ? this.companyTags$ : this.projectTags$ + )), }); this.sub.add(this.selectedModels$.subscribe(selectedModels => this.selectedModels = selectedModels)); @@ -289,7 +298,7 @@ export class ModelsComponent extends BaseEntityPageComponent implements OnInit, project: this.projectId })); } else { - this.store.dispatch(modelsActions.setTableMode({mode: !!id ? 'info' : 'table'})); + this.store.dispatch(modelsActions.setTableMode({mode: !!id ? 'info' : 'table'})); } return models?.find(model => model.id === id); }), @@ -310,7 +319,7 @@ export class ModelsComponent extends BaseEntityPageComponent implements OnInit, } } - modelSelectionChanged(event: {model: SelectedModel; openInfo?: boolean}) { + modelSelectionChanged(event: { model: SelectedModel; openInfo?: boolean }) { (this.minimizedView || event.openInfo) && event.model && this.store.dispatch(modelsActions.modelSelectionChanged({ model: event.model, project: this.projectId @@ -400,6 +409,7 @@ export class ModelsComponent extends BaseEntityPageComponent implements OnInit, super.createFooterItems(config); this.footerItems = [ new ShowItemsFooterSelected(config.entitiesType), + new CompareFooterItem(config.entitiesType), new DividerFooterItem(), new ArchiveFooterItem(config.entitiesType), @@ -418,6 +428,9 @@ export class ModelsComponent extends BaseEntityPageComponent implements OnInit, case MenuItems.showAllItems: this.showAllSelected(!emitValue); break; + case MenuItems.compare: + this.compareExperiments(); + break; case MenuItems.archive: this.table.contextMenuExtended.contextMenu.archiveClicked(); break; @@ -433,13 +446,27 @@ export class ModelsComponent extends BaseEntityPageComponent implements OnInit, } } + compareExperiments() { + this.router.navigate( + [ + `compare-models`, + {ids: this.selectedModels.map(experiment => experiment.id).join(',')}, + 'models-details' + ], + {relativeTo: this.route.parent.parent}); + } + clearTableFiltersHandler(tableFilters: any) { const filters = Object.keys(tableFilters).map(col => ({col, value: []})); this.store.dispatch(modelsActions.tableFilterChanged({filters, projectId: this.projectId})); } - selectMetadataKeysActiveChanged() { - this.store.dispatch(modelsActions.getMetadataKeysForProject()); + selectMetadataKeysActiveChanged(mode: {customMode: CustomColumnMode}) { + if (mode.customMode === CustomColumnMode.Metadata) { + this.store.dispatch(modelsActions.getMetadataKeysForProject()); + } else if (mode.customMode === CustomColumnMode.Metrics) { + this.store.dispatch(modelsActions.getCustomMetrics()); + } } @@ -452,7 +479,11 @@ export class ModelsComponent extends BaseEntityPageComponent implements OnInit, } removeColFromList(id: string) { - this.store.dispatch(modelsActions.removeCol({id: id.split('.')[1], projectId: this.projectId})); + if (id.startsWith('last_metrics')) { + this.store.dispatch(modelsActions.removeMetricCol({id, projectId: this.projectId})); + } else { + this.store.dispatch(modelsActions.removeCol({id: id.split('.')[1], projectId: this.projectId})); + } } modeChanged(mode: 'info' | 'table') { @@ -466,4 +497,22 @@ export class ModelsComponent extends BaseEntityPageComponent implements OnInit, return this.closePanel(); } } + + selectedMetricToShow(event: { variant: MetricVariantResult; addCol: boolean; valueType: MetricValueType }) { + if (!event.valueType) { + return; + } + const variantCol = createMetricColumn({ + metricHash: event.variant.metric_hash, + variantHash: event.variant.variant_hash, + valueType: event.valueType, + metric: event.variant.metric, + variant: event.variant.variant + }, this.projectId); + if (event.addCol) { + this.store.dispatch(modelsActions.addColumn({col: variantCol})); + } else { + this.store.dispatch(modelsActions.removeMetricCol({id: variantCol.id, projectId: variantCol.projectId})); + } + } } diff --git a/src/app/webapp-common/models/models.consts.ts b/src/app/webapp-common/models/models.consts.ts index 68b727e5..40589616 100755 --- a/src/app/webapp-common/models/models.consts.ts +++ b/src/app/webapp-common/models/models.consts.ts @@ -1,5 +1,6 @@ import {ColHeaderTypeEnum, ISmCol} from '../shared/ui-components/data/table/table.consts'; import {MODELS_TABLE_COL_FIELDS} from './shared/models.const'; +import {rootProjectsPageSize} from '@common/constants'; export type ModelWizardMethodsEnum = 'create' | 'edit' | 'clone' | 'extend'; export const WIZARD_METHODS = { @@ -52,7 +53,7 @@ export const MODELS_TABLE_COLS: ISmCol[] = [ id : MODELS_TABLE_COL_FIELDS.ID, headerType : ColHeaderTypeEnum.title, header : 'ID', - style : {width: '200px'}, + style : {width: '100px'}, }, { id : MODELS_TABLE_COL_FIELDS.FRAMEWORK, @@ -68,7 +69,7 @@ export const MODELS_TABLE_COLS: ISmCol[] = [ headerType : ColHeaderTypeEnum.sortFilter, sortable : true, header : 'NAME', - style : {width: '160px'}, + style : {width: '300px'}, }, { id : MODELS_TABLE_COL_FIELDS.TAGS, @@ -98,6 +99,8 @@ export const MODELS_TABLE_COLS: ISmCol[] = [ filterable : true, searchableFilter: true, sortable : false, + asyncFilter : true, + paginatedFilterPageSize : rootProjectsPageSize, header : 'PROJECT', style : {width: '135px'} }, diff --git a/src/app/webapp-common/models/models.module.ts b/src/app/webapp-common/models/models.module.ts index 8b9620f9..8f4bce69 100755 --- a/src/app/webapp-common/models/models.module.ts +++ b/src/app/webapp-common/models/models.module.ts @@ -41,6 +41,8 @@ import {ExperimentGraphsModule} from '@common/shared/experiment-graphs/experimen import {createUserPrefFeatureReducer} from '@common/core/meta-reducers/user-pref-reducer'; import {UserPreferences} from '@common/user-preferences'; import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module'; +import {ExperimentCompareSharedModule} from '@common/experiments-compare/shared/experiment-compare-shared.module'; +import {RouterTabNavBarComponent} from '@common/shared/components/router-tab-nav-bar/router-tab-nav-bar.component'; export const modelSyncedKeys = [ 'view.projectColumnsSortOrder', @@ -83,26 +85,28 @@ const getInitState = (userPreferences: UserPreferences) => ({ @NgModule({ - imports: [ - ExperimentSharedModule, - FormsModule, - ReactiveFormsModule, - CommonModule, - CommonLayoutModule, - ModelRouterModule, - ModelSharedModule, - ExperimentSharedModule, - CommonDeleteDialogModule, - SMSharedModule, - FeatureModelsModule, - AngularSplitModule, - StoreModule.forFeature(MODELS_STORE_KEY, reducers, MODELS_CONFIG_TOKEN), - EffectsModule.forFeature([ModelsViewEffects, ModelsInfoEffects, ModelsMenuEffects]), - FeatureModelsModule, - SharedModule, - SharedPipesModule, - ExperimentGraphsModule, - ], + imports: [ + ExperimentSharedModule, + FormsModule, + ReactiveFormsModule, + CommonModule, + CommonLayoutModule, + ModelRouterModule, + ModelSharedModule, + ExperimentSharedModule, + CommonDeleteDialogModule, + SMSharedModule, + FeatureModelsModule, + AngularSplitModule, + StoreModule.forFeature(MODELS_STORE_KEY, reducers, MODELS_CONFIG_TOKEN), + EffectsModule.forFeature([ModelsViewEffects, ModelsInfoEffects, ModelsMenuEffects]), + FeatureModelsModule, + SharedModule, + SharedPipesModule, + ExperimentGraphsModule, + ExperimentCompareSharedModule, + RouterTabNavBarComponent, + ], providers : [ SmFormBuilderService, DatePipe, {provide: MODELS_CONFIG_TOKEN, useFactory: getInitState, deps: [UserPreferences]}, diff --git a/src/app/webapp-common/models/reducers/index.ts b/src/app/webapp-common/models/reducers/index.ts index ff65082b..911ca269 100755 --- a/src/app/webapp-common/models/reducers/index.ts +++ b/src/app/webapp-common/models/reducers/index.ts @@ -7,7 +7,7 @@ import {MODELS_TABLE_COLS} from '@common/models/models.consts'; import {ISmCol} from '@common/shared/ui-components/data/table/table.consts'; import {selectRouterParams} from '@common/core/reducers/router-reducer'; import {FilterMetadata} from 'primeng/api/filtermetadata'; -import {ScalarKeyEnum} from '~/business-logic/model/events/scalarKeyEnum'; +import {MetricVariantResult} from '~/business-logic/model/projects/metricVariantResult'; export interface ModelsState { view: IModelsViewState; @@ -42,6 +42,7 @@ export const selectModelsTags = createSelector(modelsView, (state): Array => state.projectMetadataKeys); export const selectMetadataColsOptions = createSelector(modelsView, (state): Record => state.metadataColsOptions); export const selectMetadataCols = createSelector(modelsView, (state): ISmCol[] => state.metadataCols); +export const selectMetricVariants = createSelector(modelsView, (state): MetricVariantResult[] => state.metricVariants); export const selectModelsTableColsWidth = createSelector(modelsView, selectRouterParams, @@ -78,6 +79,3 @@ export const selectIsModelInEditMode = createSelector(modelInfo, (state): boolea export const selectModelExperimentsTableFilters = createSelector(modelInfo, (state): { [columnId: string]: FilterMetadata } => state.modelExperimentsTableFilter); export const selectModelPlots = createSelector(modelInfo, state => state.plots); -export const selectSelectedxAxisType = createSelector(modelInfo, - state => state?.xAxisType ?? ScalarKeyEnum.Iter as ScalarKeyEnum); -export const selectCacheAxisType = createSelector(modelInfo, (state) => state.cachedAxisType); diff --git a/src/app/webapp-common/models/reducers/models-view.reducer.ts b/src/app/webapp-common/models/reducers/models-view.reducer.ts index ee588390..de44a347 100755 --- a/src/app/webapp-common/models/reducers/models-view.reducer.ts +++ b/src/app/webapp-common/models/reducers/models-view.reducer.ts @@ -8,6 +8,7 @@ import {SearchState} from '../../common-search/common-search.reducer'; import {SortMeta} from 'primeng/api'; import {CountAvailableAndIsDisableSelectedFiltered} from '@common/shared/entity-page/items.utils'; import {setSelectedProject} from '@common/core/actions/projects.actions'; +import {MetricVariantResult} from '~/business-logic/model/projects/metricVariantResult'; export interface IModelsViewState { splitSize: number; @@ -34,6 +35,8 @@ export interface IModelsViewState { projectMetadataKeys: string[]; metadataCols: ISmCol[]; metadataColsOptions: Record; + metricsCols: ISmCol[]; + metricVariants: Array; selectedModelsDisableAvailable: Record; tableMode: 'info' | 'table'; } @@ -50,8 +53,10 @@ export const modelsInitialState: IModelsViewState = { tableSortFields: [{field: MODELS_TABLE_COL_FIELDS.CREATED, order: TABLE_SORT_ORDER.DESC}], projectColumnsSortOrder: {}, projectColumnsWidth: {}, - projectMetadataKeys: [], + projectMetadataKeys: null, metadataCols: [], + metricsCols: [], + metricVariants: null, colsOrder: {}, selectedModels: [], selectedModelsDisableAvailable: {}, @@ -67,30 +72,35 @@ export const modelsInitialState: IModelsViewState = { tableMode: 'table', }; -export const modelsViewReducer = createReducer( +export const modelsViewReducer = createReducer( modelsInitialState, - on(actions.resetState, (state) => ({ + on(actions.resetState, (state): IModelsViewState => ({ ...state, models: modelsInitialState.models, selectedModel: modelsInitialState.selectedModel, })), - on(setSelectedProject, (state) => ({...state, selectedModels: modelsInitialState.selectedModels})), - on(actions.addModels, (state, action) => ({...state, models: state.models?.concat(action.models) || null})), - on(actions.removeModels, (state, action) => ({ - ...state, - models: state.models?.filter(exp => !action.modelIds.includes(exp.id)) || null - })), - on(actions.showSelectedOnly, (state, action) => ({ - ...state, - showAllSelectedIsActive: action.active, - globalFilter: modelsInitialState.globalFilter, - tempFilters: state.projectColumnFilters[action.projectId] || {}, - projectColumnFilters: { - ...state.projectColumnFilters, - [action.projectId]: action.active ? modelsInitialState.tableFilters : state.tempFilters - } - })), - on(actions.updateModel, (state, action) => { + on(setSelectedProject, (state): IModelsViewState => ({...state, selectedModels: modelsInitialState.selectedModels})), + on(actions.addModels, (state, action): IModelsViewState => + ({...state, models: state.models?.concat(action.models) || null})), + on(actions.removeModels, (state, action): IModelsViewState => + ({ + ...state, + models: state.models?.filter(exp => !action.modelIds.includes(exp.id)) || null + })), + on(actions.showSelectedOnly, (state, action): IModelsViewState => + ({ + ...state, + showAllSelectedIsActive: action.active, + globalFilter: modelsInitialState.globalFilter, + tempFilters: state.projectColumnFilters[action.projectId] || {}, + ...(state.showAllSelectedIsActive && { + projectColumnFilters: { + ...state.projectColumnFilters, + [action.projectId]: action.active ? modelsInitialState.tableFilters : state.tempFilters + } + }) + })), + on(actions.updateModel, (state, action): IModelsViewState => { const newState = { ...state, models: state.models?.map(ex => ex.id === action.id ? {...ex, ...action.changes} : ex) @@ -103,35 +113,41 @@ export const modelsViewReducer = createReducer( } return newState; }), - on(actions.setModels, (state, action) => ({...state, models: action.models})), - on(actions.setModelsInPlace, (state, action) => + on(actions.setModels, (state, action): IModelsViewState => + ({...state, models: action.models})), + on(actions.setModelsInPlace, (state, action): IModelsViewState => ({...state, models: state.models?.map(currModel => action.models?.find(newModel => newModel.id === currModel.id)) || null })), - on(actions.setNoMoreModels, (state, action) => ({...state, noMoreModels: action.payload})), - on(actions.setCurrentScrollId, (state, action) => ({...state, scrollId: action.scrollId})), - on(actions.setSelectedModels, (state, action) => ({ - ...state, - selectedModels: action.models as unknown as TableModel[] - })), - on(actions.setSelectedModelsDisableAvailable, (state, action) => + on(actions.setNoMoreModels, (state, action): IModelsViewState => + ({...state, noMoreModels: action.payload})), + on(actions.setCurrentScrollId, (state, action): IModelsViewState => + ({...state, scrollId: action.scrollId})), + on(actions.setSelectedModels, (state, action): IModelsViewState => + ({...state, selectedModels: action.models as unknown as TableModel[]})), + on(actions.setSelectedModelsDisableAvailable, (state, action): IModelsViewState => ({...state, selectedModelsDisableAvailable: action.selectedModelsDisableAvailable})), - on(actions.setSelectedModel, (state, action) => ({...state, selectedModel: action.model})), - on(actions.globalFilterChanged, (state, action) => + on(actions.setSelectedModel, (state, action): IModelsViewState => + ({...state, selectedModel: action.model})), + on(actions.globalFilterChanged, (state, action): IModelsViewState => ({...state, globalFilter: action as ReturnType})), - on(actions.resetGlobalFilter, (state) => ({...state, globalFilter: modelsInitialState.globalFilter})), - on(actions.toggleColHidden, (state, action) => ({ - ...state, - hiddenProjectTableCols: { - ...state.hiddenProjectTableCols, - [action.projectId]: { - ...(state.hiddenProjectTableCols[action.projectId] || modelsInitialState.hiddenTableCols), - [action.columnId]: state.hiddenProjectTableCols?.[action.projectId]?.[action.columnId] ? undefined : true + on(actions.resetGlobalFilter, (state): IModelsViewState => + ({...state, globalFilter: modelsInitialState.globalFilter})), + on(actions.toggleColHidden, (state, action): IModelsViewState => + ({ + ...state, + hiddenProjectTableCols: { + ...state.hiddenProjectTableCols, + [action.projectId]: { + ...(state.hiddenProjectTableCols[action.projectId] || modelsInitialState.hiddenTableCols), + [action.columnId]: state.hiddenProjectTableCols?.[action.projectId]?.[action.columnId] ? undefined : true + } } - } - })), - on(actions.setHiddenCols, (state, action) => ({...state, hiddenTableCols: action.hiddenCols})), - on(actions.addColumn, (state, action) => ({...state, metadataCols: [...state.metadataCols, action.col]})), - on(actions.removeCol, (state, action) => ({ + })), + on(actions.setHiddenCols, (state, action): IModelsViewState => + ({...state, hiddenTableCols: action.hiddenCols})), + on(actions.addColumn, (state, action): IModelsViewState => + ({...state, metadataCols: [...state.metadataCols, action.col]})), + on(actions.removeCol, (state, action): IModelsViewState => ({ ...state, metadataCols: [...state.metadataCols.filter(tableCol => !(tableCol.key === action.id && tableCol.projectId === action.projectId))], colsOrder: { @@ -139,17 +155,18 @@ export const modelsViewReducer = createReducer( [action.projectId]: state.colsOrder[action.projectId] ? state.colsOrder[action.projectId].filter(colId => colId !== action.id) : null } })), - on(actions.setExtraColumns, (state, action) => + on(actions.setExtraColumns, (state, action): IModelsViewState => ({ ...state, metadataCols: [...state.metadataCols.filter(tableCol => !(tableCol.projectId === action['projectId'])), ...action['columns']] })), - on(actions.setFrameworks, (state, action) => ({...state, frameworks: action.frameworks})), - on(actions.setTags, (state, action) => ({...state, projectTags: action.tags})), - on(actions.setMetadataKeys, (state, action) => ({...state, projectMetadataKeys: action.keys})), - on(actions.setMetadataColValuesOptions, (state, action) => + on(actions.setFrameworks, (state, action): IModelsViewState => + ({...state, frameworks: action.frameworks})), + on(actions.setTags, (state, action): IModelsViewState => ({...state, projectTags: action.tags})), + on(actions.setMetadataKeys, (state, action): IModelsViewState => ({...state, projectMetadataKeys: action.keys})), + on(actions.setMetadataColValuesOptions, (state, action): IModelsViewState => ({...state, metadataColsOptions: {...state.metadataColsOptions, [action.col.id]: action.values}})), - on(actions.setTableSort, (state, action) => { + on(actions.setTableSort, (state, action): IModelsViewState => { const colIds = (Object.values(MODELS_TABLE_COL_FIELDS) as string[]).concat(state.metadataCols.map(col => col.id)); let orders = action.orders.filter(order => colIds.includes(order.field)); orders = orders.length > 0 ? orders : null; @@ -161,7 +178,7 @@ export const modelsViewReducer = createReducer( } }; }), - on(actions.setColumnWidth, (state, action) => ({ + on(actions.setColumnWidth, (state, action): IModelsViewState => ({ ...state, projectColumnsWidth: { ...state.projectColumnsWidth, @@ -171,9 +188,9 @@ export const modelsViewReducer = createReducer( } } })), - on(actions.setColsOrderForProject, (state, action) => + on(actions.setColsOrderForProject, (state, action): IModelsViewState => ({...state, colsOrder: {...state.colsOrder, [action.project]: action.cols}})), - on(actions.setTableFilters, (state, action) => ({ + on(actions.setTableFilters, (state, action): IModelsViewState => ({ ...state, projectColumnFilters: { ...state.projectColumnFilters, @@ -185,6 +202,25 @@ export const modelsViewReducer = createReducer( } } })), - on(actions.setSplitSize, (state, action) => ({...state, splitSize: action.splitSize})), - on(actions.setTableMode, (state, action) => ({...state, tableMode: action.mode})), + on(actions.removeMetricCol, (state, action): IModelsViewState => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const {[action.id]: removedCol, ...remainingColsWidth} = state.projectColumnsWidth[action.projectId] || {}; + return { + ...state, + metadataCols: [...state.metadataCols.filter(tableCol => !(tableCol.id === action.id && tableCol.projectId === action.projectId))], + projectColumnsSortOrder: { + ...state.projectColumnsSortOrder, + [action.projectId]: state.projectColumnsSortOrder[action.projectId]?.filter(order => order.field !== action.id) || null + }, + projectColumnsWidth: {...state.projectColumnsWidth, [action.projectId]: remainingColsWidth}, + colsOrder: { + ...state.colsOrder, + [action.projectId]: state.colsOrder[action.projectId] ? state.colsOrder[action.projectId].filter(colId => colId !== action.id) : null + } + }; + }), + on(actions.setSplitSize, (state, action): IModelsViewState => + ({...state, splitSize: action.splitSize})), + on(actions.setTableMode, (state, action): IModelsViewState => ({...state, tableMode: action.mode})), + on(actions.setCustomMetrics, (state, action): IModelsViewState => ({...state, metricVariants: action.metrics})), ); diff --git a/src/app/webapp-common/models/shared/model-shared.module.ts b/src/app/webapp-common/models/shared/model-shared.module.ts index 661a571f..3304d959 100755 --- a/src/app/webapp-common/models/shared/model-shared.module.ts +++ b/src/app/webapp-common/models/shared/model-shared.module.ts @@ -11,20 +11,22 @@ import {CommonLayoutModule} from '../../layout/layout.module'; import {FeatureModelsModule} from '~/features/models/feature-models.module'; import {SharedModule} from '~/shared/shared.module'; import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module'; +import {HyperParamMetricColumnComponent} from '@common/experiments/shared/components/hyper-param-metric-column/hyper-param-metric-column.component'; const DECLERATIONS = [ModelTypeIconLabelComponent, ModelStatusIconLabelComponent, SelectModelHeaderComponent, ModelsTableComponent, ModelTagsComponent]; @NgModule({ - imports: [ - LayoutModule, - SMSharedModule, - CommonModule, - CommonLayoutModule, - FeatureModelsModule, - SharedModule, - SharedPipesModule, - ], + imports: [ + LayoutModule, + SMSharedModule, + CommonModule, + CommonLayoutModule, + FeatureModelsModule, + SharedModule, + SharedPipesModule, + HyperParamMetricColumnComponent, + ], declarations: DECLERATIONS, exports : DECLERATIONS }) diff --git a/src/app/webapp-common/models/shared/models-table/models-table.component.html b/src/app/webapp-common/models/shared/models-table/models-table.component.html index c2431762..b1e0d3d9 100755 --- a/src/app/webapp-common/models/shared/models-table/models-table.component.html +++ b/src/app/webapp-common/models/shared/models-table/models-table.component.html @@ -25,7 +25,8 @@ [noMoreData]="noMoreModels" [resizableColumns]="enableMultiSelect" [columns]="tableCols" - [reorderableColumns]="enableMultiSelect" + [reorderableColumns]="reorderableColumns && enableMultiSelect" + [scrollable]="true" [columnsOrder]="colsOrder" [lazyLoading]="true" [selection]="selectedModel" @@ -61,7 +62,7 @@ -
+
@@ -110,7 +111,7 @@
{{model.name}}
- +
@@ -146,7 +147,13 @@ {{model | colGetter: col}} - {{model[col.id]}} + + + + @@ -164,7 +171,7 @@ [entityType]="entityType" (click)="selected && openContextMenu({e: $event, rowData: model, backdrop: true})" > -
+
Updated {{model.last_update | timeAgo}} by {{model.user?.name || 'Unknown User'}}{{model.task.name}} diff --git a/src/app/webapp-common/models/shared/models-table/models-table.component.ts b/src/app/webapp-common/models/shared/models-table/models-table.component.ts index 9bfe8c5b..875fac85 100755 --- a/src/app/webapp-common/models/shared/models-table/models-table.component.ts +++ b/src/app/webapp-common/models/shared/models-table/models-table.component.ts @@ -34,11 +34,13 @@ import { selectionDisabledMoveTo, selectionDisabledPublishModels } from '@common/shared/entity-page/items.utils'; -import {getModelsMetadataValuesForKey, selectAllModels} from '../../actions/models-view.actions'; +import {getCustomMetrics, getModelsMetadataValuesForKey, selectAllModels} from '../../actions/models-view.actions'; import { ModelMenuExtendedComponent } from '~/features/models/containers/model-menu-extended/model-menu-extended.component'; import {createFiltersFromStore} from '@common/shared/utils/tableParamEncode'; +import {EXPERIMENTS_TABLE_COL_FIELDS} from '~/features/experiments/shared/experiments.const'; +import {getRoundedNumber} from '@common/experiments/shared/common-experiments.utils'; @Component({ selector: 'sm-models-table', @@ -75,9 +77,18 @@ export class ModelsTableComponent extends BaseTableView { public filtersSubValues: { [colId: string]: any } = {}; public singleRowContext: boolean; private _tableFilters: { [p: string]: FilterMetadata }; + public roundedMetricValues: { [colId: string]: { [expId: string]: boolean } } = {}; + @Input() set models(models: SelectedModel[]) { this._models = models; + + this.tableCols?.filter(tableCol => tableCol.id.startsWith('last_metrics')).forEach(col => models?.forEach(exp => { + const value = get(exp, col.id); + this.roundedMetricValues[col.id] = this.roundedMetricValues[col.id] || {}; + this.roundedMetricValues[col.id][exp.id] = value && getRoundedNumber(value) !== value; + })); + if (this.contextModel) { this.contextModel = this.models.find(model => model.id === this.contextModel.id); } @@ -88,10 +99,16 @@ export class ModelsTableComponent extends BaseTableView { } @Input() noMoreModels: boolean; + @Input() reorderableColumns: boolean = true; @Input() set tableCols(tableCols: ISmCol[]) { if (tableCols?.length > 0) { tableCols[0].hidden = this.enableMultiSelect === false; + const statusColumn = tableCols.find(col => col.id === 'ready'); + if (statusColumn) { + statusColumn.filterable = this.enableMultiSelect; + statusColumn.sortable = this.enableMultiSelect; + } this._tableCols = tableCols; } } @@ -107,6 +124,7 @@ export class ModelsTableComponent extends BaseTableView { @Input() set projects(projects) { if (!projects) { + this.filtersOptions[MODELS_TABLE_COL_FIELDS.PROJECT] = null; return; } this.filtersOptions[MODELS_TABLE_COL_FIELDS.PROJECT] = projects.map(project => ({ @@ -114,7 +132,6 @@ export class ModelsTableComponent extends BaseTableView { value: project.id, tooltip: `${project.name}` })); - this.sortOptionsList(MODELS_TABLE_COL_FIELDS.PROJECT); } @Input() set enableMultiSelect(enable: boolean) { @@ -337,14 +354,25 @@ export class ModelsTableComponent extends BaseTableView { this.tagsMenuOpened.emit(); } else if (col.type === 'metadata') { this.store.dispatch(getModelsMetadataValuesForKey({col})); + } else if (col.type === 'hyperparams') { + this.store.dispatch(getCustomMetrics()); + } else if (col.id === EXPERIMENTS_TABLE_COL_FIELDS.PROJECT) { + if (!this.filtersOptions[EXPERIMENTS_TABLE_COL_FIELDS.PROJECT]?.length) { + this.filterSearchChanged.emit({colId: col.id, value: {value: ''}}); + } } } - getSingleSelectedModelsDisableAvailable = (model): Record => ({ [MenuItems.publish]: selectionDisabledPublishModels([model]), [MenuItems.moveTo]: selectionDisabledMoveTo([model]), [MenuItems.delete]: selectionDisabledDelete([model]), [MenuItems.archive]: selectionDisabledArchive([model]) }); + + columnsWidthChanged({columnId, width}) { + const colIndex = this.tableCols.findIndex(col => col.id === columnId); + const delta = width - parseInt(this.tableCols[colIndex].style.width, 10); + this.table?.updateColumnsWidth(columnId, width, delta); + } } diff --git a/src/app/webapp-common/models/shared/select-model-header/select-model-header.component.html b/src/app/webapp-common/models/shared/select-model-header/select-model-header.component.html index 5e8d0a18..24fee5f6 100755 --- a/src/app/webapp-common/models/shared/select-model-header/select-model-header.component.html +++ b/src/app/webapp-common/models/shared/select-model-header/select-model-header.component.html @@ -1,26 +1,32 @@
-
+
+ + +
+
+ (valueChanged)="onAllProjectsChanged($event)">
- -
-
- - -
+
+ Include Archived +
-
diff --git a/src/app/webapp-common/models/shared/select-model-header/select-model-header.component.scss b/src/app/webapp-common/models/shared/select-model-header/select-model-header.component.scss index eddfc9ff..a1d91447 100755 --- a/src/app/webapp-common/models/shared/select-model-header/select-model-header.component.scss +++ b/src/app/webapp-common/models/shared/select-model-header/select-model-header.component.scss @@ -1,17 +1,9 @@ :host { - .center-buttons-container { - position: relative; - left: 50%; - transform: translateX(-50%); - } - .search-container { - width: 0; - overflow: hidden; - transition: 0.3s; - &.open { - width: 250px; - } + + ::ng-deep .search-input-container.active { + width: 500px !important; } + sm-search { display: contents; } diff --git a/src/app/webapp-common/models/shared/select-model-header/select-model-header.component.ts b/src/app/webapp-common/models/shared/select-model-header/select-model-header.component.ts index ddd7ed49..b32d9d1e 100755 --- a/src/app/webapp-common/models/shared/select-model-header/select-model-header.component.ts +++ b/src/app/webapp-common/models/shared/select-model-header/select-model-header.component.ts @@ -1,5 +1,6 @@ import {ChangeDetectionStrategy, Component, EventEmitter, Input, Output, ViewChild} from '@angular/core'; import {ModelsViewModesEnum} from '../../models.consts'; +import {FilterMetadata} from 'primeng/api/filtermetadata'; @Component({ selector : 'sm-select-model-header', @@ -28,12 +29,15 @@ export class SelectModelHeaderComponent { @Input() hideCreateNewButton: boolean; @Input() viewMode: ModelsViewModesEnum; @Input() searchActive: boolean; + @Input() tableFilters: { [s: string]: FilterMetadata }; + @Input() isShowArchived: boolean; @Output() searchValueChanged = new EventEmitter(); @Output() isArchivedChanged = new EventEmitter(); @Output() isAllProjectsChanged = new EventEmitter(); @Output() viewModeChanged = new EventEmitter(); @Output() addModelClicked = new EventEmitter(); + @Output() clearFilters = new EventEmitter(); @ViewChild('search') searchElem; diff --git a/src/app/webapp-common/nested-project-view/nested-card/nested-card.component.html b/src/app/webapp-common/nested-project-view/nested-card/nested-card.component.html index ca537077..980d34a5 100644 --- a/src/app/webapp-common/nested-project-view/nested-card/nested-card.component.html +++ b/src/app/webapp-common/nested-project-view/nested-card/nested-card.component.html @@ -6,14 +6,14 @@ [subFolderTitle]="project?.sub_projects?.length + ' sub projects'" >
- -
- -
+ +
diff --git a/src/app/webapp-common/nested-project-view/nested-card/nested-card.component.scss b/src/app/webapp-common/nested-project-view/nested-card/nested-card.component.scss index 389c3694..ed979343 100644 --- a/src/app/webapp-common/nested-project-view/nested-card/nested-card.component.scss +++ b/src/app/webapp-common/nested-project-view/nested-card/nested-card.component.scss @@ -69,7 +69,7 @@ hr { } :host { - ::ng-deep .mat-menu-content { + ::ng-deep .mat-mdc-menu-content { background-color: $blue-600; } } diff --git a/src/app/webapp-common/nested-project-view/nested-project-view-page/nested-project-view-page.component.html b/src/app/webapp-common/nested-project-view/nested-project-view-page/nested-project-view-page.component.html index 6bd277ae..e4b133f3 100644 --- a/src/app/webapp-common/nested-project-view/nested-project-view-page/nested-project-view-page.component.html +++ b/src/app/webapp-common/nested-project-view/nested-project-view-page/nested-project-view-page.component.html @@ -9,7 +9,7 @@ > - NEW PIPELINE + NEW PIPELINE
- - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/app/webapp-common/nested-project-view/nested-project-view-page/nested-project-view-page.component.spec.ts b/src/app/webapp-common/nested-project-view/nested-project-view-page/nested-project-view-page.component.spec.ts index fd8323b2..cc687263 100644 --- a/src/app/webapp-common/nested-project-view/nested-project-view-page/nested-project-view-page.component.spec.ts +++ b/src/app/webapp-common/nested-project-view/nested-project-view-page/nested-project-view-page.component.spec.ts @@ -3,7 +3,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { NestedProjectViewPageComponent } from './nested-project-view-page.component'; import {StoreModule} from '@ngrx/store'; import {RouterTestingModule} from '@angular/router/testing'; -import {MatLegacyDialogModule as MatDialogModule} from '@angular/material/legacy-dialog'; +import {MatDialogModule} from '@angular/material/dialog'; describe('PipelinesPageComponent', () => { let component: NestedProjectViewPageComponent; diff --git a/src/app/webapp-common/nested-project-view/nested-project-view-page/nested-project-view-page.component.ts b/src/app/webapp-common/nested-project-view/nested-project-view-page/nested-project-view-page.component.ts index 0a6900df..89be60e1 100644 --- a/src/app/webapp-common/nested-project-view/nested-project-view-page/nested-project-view-page.component.ts +++ b/src/app/webapp-common/nested-project-view/nested-project-view-page/nested-project-view-page.component.ts @@ -8,7 +8,15 @@ import {Subscription} from 'rxjs'; import {showExampleDatasets, showExamplePipelines} from '@common/projects/common-projects.actions'; import {ReportDialogComponent} from '@common/reports/report-dialog/report-dialog.component'; import {createReport} from '@common/reports/reports.actions'; -import {datasetLabel, EntityTypePluralEnum, getDatasetUrlPrefix, getEntityTypeFromUrlConf, getNestedEntityBaseUrl, getNestedEntityName, isDatasetType} from '~/features/nested-project-view/nested-project-view-utils'; +import { + datasetLabel, + EntityTypePluralEnum, + getDatasetUrlPrefix, + getEntityTypeFromUrlConf, + getNestedEntityBaseUrl, + getNestedEntityName, + isDatasetType +} from '~/features/nested-project-view/nested-project-view-utils'; @Component({ @@ -18,20 +26,25 @@ import {datasetLabel, EntityTypePluralEnum, getDatasetUrlPrefix, getEntityTypeFr }) export class NestedProjectViewPageComponent extends SimpleDatasetsComponent implements OnInit, OnDestroy { hideMenu = false; - entityType: string = 'pipelines'; + entityType = 'pipelines' as EntityTypePluralEnum; entityTypeEnum = EntityTypePluralEnum; circleTypeEnum = CircleTypeEnum; - private routeConfigSub: Subscription; isDatasetType = isDatasetType; datasetLabel= datasetLabel; + private routeConfigSub: Subscription; + totalVirtualCards = 0; ngOnInit() { super.ngOnInit(); - this.routeConfigSub = this.store.select(selectRouterConfig).subscribe(conf => { - this.entityType = getEntityTypeFromUrlConf(conf); - this.syncAppSearch(); - this.store.dispatch(setDefaultNestedModeForFeature({feature: this.entityType, isNested: true})); - }); + this.routeConfigSub = this.store.select(selectRouterConfig) + .subscribe(conf => { + this.entityType = getEntityTypeFromUrlConf(conf); + if (this.entityType === EntityTypePluralEnum.reports) { + this.totalVirtualCards = 1; + } + this.syncAppSearch(); + this.store.dispatch(setDefaultNestedModeForFeature({feature: this.entityType, isNested: true})); + }); } getName() { @@ -43,15 +56,24 @@ export class NestedProjectViewPageComponent extends SimpleDatasetsComponent impl this.routeConfigSub.unsubscribe(); } - nestedProjectCardClicked(project: Project, cardProject) { + const simpleUrl = [this.entityTypeEnum.pipelines, this.entityTypeEnum.reports].includes(this.entityType); const relevantSubProjects = cardProject?.id === project?.id ? project.sub_projects : cardProject?.sub_projects.filter(pr => pr.name.startsWith(project.name + '/')); + const parent = (this.entityType === this.entityTypeEnum.pipelines) ? this.route.parent?.parent?.parent : this.route.parent?.parent; + if ((project as any).isRoot && project.id === '*') { + return this.router.navigate(['*', 'reports'], {relativeTo: parent}); + } if ((relevantSubProjects ?? []).filter((subProject) => (!subProject.name.slice(project.name.length).startsWith(`/.${this.entityType}`))).length === 0) { - this.router.navigate([(this.entityType === this.entityTypeEnum.pipelines || this.entityType === this.entityTypeEnum.reports) ? - project.id : `${getDatasetUrlPrefix(this.entityType)}/${project.id}` , this.entityType], - {relativeTo: (this.entityType === this.entityTypeEnum.pipelines) ? this.route.parent?.parent?.parent : this.route.parent?.parent}); + return this.router.navigate([ + ...(simpleUrl ? [project.id] : [getDatasetUrlPrefix(this.entityType), project.id]), + this.entityType + ], + {relativeTo: parent} + ); } else { - this.router.navigate([(this.entityType === this.entityTypeEnum.pipelines || this.entityType === this.entityTypeEnum.reports) ? project.id : `${getDatasetUrlPrefix(this.entityType)}/${project.id}`, 'projects'], {relativeTo: (this.entityType === this.entityTypeEnum.pipelines) ? this.route.parent?.parent?.parent : this.route.parent?.parent}); + return this.router.navigate(simpleUrl ? [project.id, 'projects'] : [getDatasetUrlPrefix(this.entityType), project.id, 'projects'], + {relativeTo: parent} + ); } } @@ -73,10 +95,12 @@ export class NestedProjectViewPageComponent extends SimpleDatasetsComponent impl public openCreateReportDialog() { - this.dialog.open(ReportDialogComponent).afterClosed().subscribe(report => { - if (report) { - this.store.dispatch(createReport({reportsCreateRequest: report})); - } + this.dialog.open(ReportDialogComponent, {panelClass: 'light-theme', data: {defaultProjectId: this.projectId}}) + .afterClosed() + .subscribe(report => { + if (report) { + this.store.dispatch(createReport({reportsCreateRequest: report})); + } }); } diff --git a/src/app/webapp-common/pipelines-controller/controllers.component.html b/src/app/webapp-common/pipelines-controller/controllers.component.html index c16f01e6..ef732cd2 100644 --- a/src/app/webapp-common/pipelines-controller/controllers.component.html +++ b/src/app/webapp-common/pipelines-controller/controllers.component.html @@ -55,7 +55,7 @@ [users]="users$ | async" [hyperParamsOptions]="hyperParamsOptions$ | async" [activeParentsFilter]="activeParentsFilter$ | async" - [parents]="parent$ | async" + [parents]="parents$ | async" [experimentTypes]="types$ | async" [tags]="tags$ | async" [systemTags]="systemTags$ | async" @@ -115,7 +115,7 @@ [selectedDisableAvailable]="singleRowContext ? getSingleSelectedDisableAvailable(contextExperiment) : (selectedExperimentsDisableAvailable$ | async)" [numSelected]="singleRowContext ? 1 : selectedExperiments.length" [tagsFilterByProject]="tagsFilterByProject$ | async" - [projectTags]="projectTags$ | async" + [projectTags]="tags$ | async" [companyTags]="companyTags$ | async" [activateFromMenuButton]="false" [useCurrentEntity]="singleRowContext" diff --git a/src/app/webapp-common/pipelines-controller/controllers.component.ts b/src/app/webapp-common/pipelines-controller/controllers.component.ts index 5ae2504e..1f62bc34 100644 --- a/src/app/webapp-common/pipelines-controller/controllers.component.ts +++ b/src/app/webapp-common/pipelines-controller/controllers.component.ts @@ -4,7 +4,7 @@ import {Store} from '@ngrx/store'; import {ExperimentsViewState} from '@common/experiments/reducers/experiments-view.reducer'; import {SmSyncStateSelectorService} from '@common/core/services/sync-state-selector.service'; import {ActivatedRoute, Router} from '@angular/router'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {INITIAL_CONTROLLER_TABLE_COLS} from '@common/pipelines-controller/controllers.consts'; import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; import {Observable} from 'rxjs'; diff --git a/src/app/webapp-common/pipelines-controller/controllers.consts.ts b/src/app/webapp-common/pipelines-controller/controllers.consts.ts index 0bd7badd..1acec467 100644 --- a/src/app/webapp-common/pipelines-controller/controllers.consts.ts +++ b/src/app/webapp-common/pipelines-controller/controllers.consts.ts @@ -1,5 +1,6 @@ import {ColHeaderFilterTypeEnum, ColHeaderTypeEnum, ISmCol} from '../shared/ui-components/data/table/table.consts'; import {EXPERIMENTS_TABLE_COL_FIELDS} from '~/features/experiments/shared/experiments.const'; +import {rootProjectsPageSize} from '@common/constants'; export const INITIAL_CONTROLLER_TABLE_COLS: ISmCol[] = [ { @@ -64,6 +65,10 @@ export const INITIAL_CONTROLLER_TABLE_COLS: ISmCol[] = [ headerType: ColHeaderTypeEnum.title, header: 'PROJECT', style: {width: '150px'}, + filterable : true, + searchableFilter: true, + asyncFilter: true, + paginatedFilterPageSize: rootProjectsPageSize }, { id: EXPERIMENTS_TABLE_COL_FIELDS.USER, diff --git a/src/app/webapp-common/pipelines-controller/pipeline-controller-info/pipeline-controller-info.component.html b/src/app/webapp-common/pipelines-controller/pipeline-controller-info/pipeline-controller-info.component.html index 195592cc..5fd1031f 100644 --- a/src/app/webapp-common/pipelines-controller/pipeline-controller-info/pipeline-controller-info.component.html +++ b/src/app/webapp-common/pipelines-controller/pipeline-controller-info/pipeline-controller-info.component.html @@ -1,7 +1,7 @@
-
+
-
+
- + {{(selected$ | async)?.name}}
- + +
-
+
+ - +
- -

NO CODE

+ +

NO CODE

-
+
diff --git a/src/app/webapp-common/pipelines-controller/pipeline-controller-info/pipeline-controller-info.component.scss b/src/app/webapp-common/pipelines-controller/pipeline-controller-info/pipeline-controller-info.component.scss index 9117f4bc..b3fa5a39 100644 --- a/src/app/webapp-common/pipelines-controller/pipeline-controller-info/pipeline-controller-info.component.scss +++ b/src/app/webapp-common/pipelines-controller/pipeline-controller-info/pipeline-controller-info.component.scss @@ -8,6 +8,15 @@ $log-header-height: 48px; position: relative; height: 100%; background-color: $blue-950; + .results-panel { + &.maximized { + height: 100%; + + .content { + flex: 1; + } + } + } sm-pipeline-info { display: block; diff --git a/src/app/webapp-common/pipelines-controller/pipeline-controller-info/pipeline-controller-info.component.ts b/src/app/webapp-common/pipelines-controller/pipeline-controller-info/pipeline-controller-info.component.ts index bef1217e..4f5218ee 100644 --- a/src/app/webapp-common/pipelines-controller/pipeline-controller-info/pipeline-controller-info.component.ts +++ b/src/app/webapp-common/pipelines-controller/pipeline-controller-info/pipeline-controller-info.component.ts @@ -88,6 +88,7 @@ export class PipelineControllerInfoComponent implements OnInit, AfterViewInit, O trackArrows = (index: number, arrow: Arrow) => arrow.path; trackByStepId = (index: number, step) => step.stepId; + public maximizeResults: boolean; @HostListener('document:keydown', ['$event']) onKeyDown(e: KeyboardEvent) { @@ -376,6 +377,16 @@ export class PipelineControllerInfoComponent implements OnInit, AfterViewInit, O this.aceEditor = aceEditor; }); } + toggleResultSize() { + this.maximizeResults = ! this.maximizeResults; + if (this.detailsPanelMode === StatusOption.content) { + this.detailsPanelMode = null; + window.setTimeout(() => { + this.detailsPanelMode = StatusOption.content; + this.cdr.detectChanges(); + }, 450); + } + } protected highlightArrows() { this.arrows = this.arrows diff --git a/src/app/webapp-common/pipelines-controller/pipeline-controller-menu/abort-controller-dialog/abort-controller-dialog.component.ts b/src/app/webapp-common/pipelines-controller/pipeline-controller-menu/abort-controller-dialog/abort-controller-dialog.component.ts index 313b5e09..66a4251b 100644 --- a/src/app/webapp-common/pipelines-controller/pipeline-controller-menu/abort-controller-dialog/abort-controller-dialog.component.ts +++ b/src/app/webapp-common/pipelines-controller/pipeline-controller-menu/abort-controller-dialog/abort-controller-dialog.component.ts @@ -1,4 +1,4 @@ -import {MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {ChangeDetectionStrategy, Component, Inject} from '@angular/core'; import {Store} from '@ngrx/store'; import {ISelectedExperiment} from '~/features/experiments/shared/experiment-info.model'; diff --git a/src/app/webapp-common/pipelines-controller/pipeline-controller-menu/pipeline-controller-menu.component.ts b/src/app/webapp-common/pipelines-controller/pipeline-controller-menu/pipeline-controller-menu.component.ts index 787e20d2..fd5ce3a6 100755 --- a/src/app/webapp-common/pipelines-controller/pipeline-controller-menu/pipeline-controller-menu.component.ts +++ b/src/app/webapp-common/pipelines-controller/pipeline-controller-menu/pipeline-controller-menu.component.ts @@ -1,7 +1,7 @@ import {Component, ElementRef} from '@angular/core'; import {ExperimentMenuComponent} from '@common/experiments/shared/components/experiment-menu/experiment-menu.component'; import {BlTasksService} from '~/business-logic/services/tasks.service'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {ActivatedRoute, Router} from '@angular/router'; import {Store} from '@ngrx/store'; import {ExperimentInfoState} from '~/features/experiments/reducers/experiment-info.reducer'; diff --git a/src/app/webapp-common/pipelines-controller/pipeline-details/pipeline-info.component.html b/src/app/webapp-common/pipelines-controller/pipeline-details/pipeline-info.component.html index 44625fe6..03ba160f 100644 --- a/src/app/webapp-common/pipelines-controller/pipeline-details/pipeline-info.component.html +++ b/src/app/webapp-common/pipelines-controller/pipeline-details/pipeline-info.component.html @@ -11,7 +11,7 @@
{{step.name}}
{{step.data.status}}
- +
diff --git a/src/app/webapp-common/pipelines-controller/pipelines-controller.module.ts b/src/app/webapp-common/pipelines-controller/pipelines-controller.module.ts index 778eeef3..28cc993d 100644 --- a/src/app/webapp-common/pipelines-controller/pipelines-controller.module.ts +++ b/src/app/webapp-common/pipelines-controller/pipelines-controller.module.ts @@ -13,16 +13,20 @@ import {ExperimentSharedModule} from '~/features/experiments/shared/experiment-s import {SMSharedModule} from '@common/shared/shared.module'; import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module'; import {RouterModule, Routes} from '@angular/router'; -import {MatLegacyProgressSpinnerModule as MatProgressSpinnerModule} from '@angular/material/legacy-progress-spinner'; +import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; import {SharedModule} from '~/shared/shared.module'; import {ExperimentOutputLogModule} from '@common/experiments/shared/experiment-output-log/experiment-output-log.module'; -import {MatLegacyRadioModule as MatRadioModule} from '@angular/material/legacy-radio'; +import {MatRadioModule} from '@angular/material/radio'; import {PipelineControllerInfoComponent} from './pipeline-controller-info/pipeline-controller-info.component'; import {PipelineControllerStepComponent} from './pipeline-controller-step/pipeline-controller-step.component'; import { PipelineInfoComponent } from './pipeline-details/pipeline-info.component'; import {PipelineControllerMenuComponent} from '@common/pipelines-controller/pipeline-controller-menu/pipeline-controller-menu.component'; import {RunPipelineControllerDialogComponent} from './run-pipeline-controller-dialog/run-pipeline-controller-dialog.component'; import {AbortControllerDialogComponent} from '@common/pipelines-controller/pipeline-controller-menu/abort-controller-dialog/abort-controller-dialog.component'; +import { + SimpleDatasetVersionPreviewComponent +} from '@common/dataset-version/simple-dataset-version-preview/simple-dataset-version-preview.component'; +import {LabeledFormFieldDirective} from '@common/shared/directive/labeled-form-field.directive'; export const routes: Routes = [ { @@ -70,6 +74,8 @@ export const routes: Routes = [ SharedModule, ExperimentOutputLogModule, MatRadioModule, + SimpleDatasetVersionPreviewComponent, + LabeledFormFieldDirective, ], providers: [ ControllersComponent, diff --git a/src/app/webapp-common/pipelines-controller/run-pipeline-controller-dialog/run-pipeline-controller-dialog.component.html b/src/app/webapp-common/pipelines-controller/run-pipeline-controller-dialog/run-pipeline-controller-dialog.component.html index 5cd3c0d7..d599208a 100644 --- a/src/app/webapp-common/pipelines-controller/run-pipeline-controller-dialog/run-pipeline-controller-dialog.component.html +++ b/src/app/webapp-common/pipelines-controller/run-pipeline-controller-dialog/run-pipeline-controller-dialog.component.html @@ -4,23 +4,23 @@
Parameters
-
{{param.name}}
+
{{param.name}}
- + Please provide an float - + Please provide an integer - + @@ -31,7 +31,7 @@
Pipeline controller queue
- + {{queue.name}} diff --git a/src/app/webapp-common/pipelines-controller/run-pipeline-controller-dialog/run-pipeline-controller-dialog.component.scss b/src/app/webapp-common/pipelines-controller/run-pipeline-controller-dialog/run-pipeline-controller-dialog.component.scss index 6273dcd9..ad6ff476 100644 --- a/src/app/webapp-common/pipelines-controller/run-pipeline-controller-dialog/run-pipeline-controller-dialog.component.scss +++ b/src/app/webapp-common/pipelines-controller/run-pipeline-controller-dialog/run-pipeline-controller-dialog.component.scss @@ -27,7 +27,7 @@ width: 180px; font-size: 12px; } - .mat-form-field{ + .mat-mdc-form-field{ width: 340px; &.hidden{ display: none; diff --git a/src/app/webapp-common/pipelines-controller/run-pipeline-controller-dialog/run-pipeline-controller-dialog.component.ts b/src/app/webapp-common/pipelines-controller/run-pipeline-controller-dialog/run-pipeline-controller-dialog.component.ts index c7d8f46d..7da5d23d 100644 --- a/src/app/webapp-common/pipelines-controller/run-pipeline-controller-dialog/run-pipeline-controller-dialog.component.ts +++ b/src/app/webapp-common/pipelines-controller/run-pipeline-controller-dialog/run-pipeline-controller-dialog.component.ts @@ -1,5 +1,5 @@ import {Component, Inject, OnDestroy, OnInit} from '@angular/core'; -import {MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {Store} from '@ngrx/store'; import {combineLatest, filter, Subscription} from 'rxjs'; import {Queue} from '~/business-logic/model/queues/queue'; diff --git a/src/app/webapp-common/pipelines/pipeline-card-menu/pipeline-card-menu.component.spec.ts b/src/app/webapp-common/pipelines/pipeline-card-menu/pipeline-card-menu.component.spec.ts index 401e5e9d..a4f08957 100644 --- a/src/app/webapp-common/pipelines/pipeline-card-menu/pipeline-card-menu.component.spec.ts +++ b/src/app/webapp-common/pipelines/pipeline-card-menu/pipeline-card-menu.component.spec.ts @@ -1,7 +1,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { PipelineCardMenuComponent } from './pipeline-card-menu.component'; -import {MatLegacyMenuModule as MatMenuModule} from '@angular/material/legacy-menu'; +import {MatMenuModule} from '@angular/material/menu'; describe('PipelineCardMenuComponent', () => { let component: PipelineCardMenuComponent; diff --git a/src/app/webapp-common/pipelines/pipeline-card/pipeline-card.component.html b/src/app/webapp-common/pipelines/pipeline-card/pipeline-card.component.html index 482390b3..69a24864 100644 --- a/src/app/webapp-common/pipelines/pipeline-card/pipeline-card.component.html +++ b/src/app/webapp-common/pipelines/pipeline-card/pipeline-card.component.html @@ -5,16 +5,17 @@ [oneTabMode]="true" [subFolderTitle]="project?.sub_projects?.length + ' sub projects'" > -
-
-
    -
  • -
  • -
-
+
+ + +
@@ -35,7 +36,7 @@ >{{project.name | shortProjectName}} + class="al-icon al-ico-project-path sm ms-2"> - NEW PIPELINE + NEW PIPELINE
diff --git a/src/app/webapp-common/pipelines/pipelines-page/pipelines-page.component.ts b/src/app/webapp-common/pipelines/pipelines-page/pipelines-page.component.ts index 9eedbaef..9d98400a 100644 --- a/src/app/webapp-common/pipelines/pipelines-page/pipelines-page.component.ts +++ b/src/app/webapp-common/pipelines/pipelines-page/pipelines-page.component.ts @@ -27,6 +27,7 @@ import {ProjectsGetAllResponseSingle} from '~/business-logic/model/projects/proj import {selectShowPipelineExamples} from '@common/projects/common-projects.reducer'; import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; import {PipelinesEmptyStateComponent} from '@common/pipelines/pipelines-page/pipelines-empty-state/pipelines-empty-state.component'; +import {debounceTime} from 'rxjs/operators'; @Component({ selector: 'sm-pipelines-page', @@ -73,12 +74,15 @@ if __name__ == '__main__': this.showExamples$ = this.store.select(selectShowPipelineExamples); // Todo: delayed because of nested views, remove timeout after implementing nested view template window.setTimeout(() => this.store.dispatch(getProjectsTags({entity: this.getName()}))); - // this.isNested$ = this.store.select(selectRouterConfig).pipe(map(config.last => config.includes('projects'))); this.projectsTags$ = this.store.select(selectProjectTags); - this.mainPageFilterSub = combineLatest([this.store.select(selectMainPageTagsFilter), this.store.select(selectMainPageTagsFilterMatchMode)]).subscribe(() => { - this.store.dispatch(resetProjects()); - this.store.dispatch(getAllProjectsPageProjects()); - }); + this.mainPageFilterSub = combineLatest([ + this.store.select(selectMainPageTagsFilter), + this.store.select(selectMainPageTagsFilterMatchMode) + ]).pipe(debounceTime(0)) + .subscribe(() => { + this.store.dispatch(resetProjects()); + this.store.dispatch(getAllProjectsPageProjects()); + }); } diff --git a/src/app/webapp-common/pipelines/pipelines.route.ts b/src/app/webapp-common/pipelines/pipelines.route.ts index abf83f65..65bc8c99 100644 --- a/src/app/webapp-common/pipelines/pipelines.route.ts +++ b/src/app/webapp-common/pipelines/pipelines.route.ts @@ -2,26 +2,16 @@ import {FeaturesEnum} from '~/business-logic/model/users/featuresEnum'; import {NgModule} from '@angular/core'; import {RouterModule, Routes} from '@angular/router'; import {PipelinesPageComponent} from "@common/pipelines/pipelines-page/pipelines-page.component"; +import {CrumbTypeEnum} from "@common/layout/breadcrumbs/breadcrumbs.component"; const routes = [{ path: '', component: PipelinesPageComponent, // canActivate: [RolePermissionsGuard], - data: {search: true, features: FeaturesEnum.Pipelines}, - // children: [ - // { - // path: ':projectId', - // children: [ - // { - // path: 'experiments', loadChildren: () => import('@common/pipelines-controller/pipelines-controller.module').then(m => m.PipelinesControllerModule) - // }, - // { - // path: 'compare-experiments', - // loadChildren: () => import('../experiments-compare/experiments-compare.module').then(m => m.ExperimentsCompareModule) - // }, - // ] - // }, - // ] + data: {search: true, features: FeaturesEnum.Pipelines, staticBreadcrumb:[[{ + name: 'PIPELINES', + type: CrumbTypeEnum.Feature + }]]}, }] as Routes; @NgModule({ diff --git a/src/app/webapp-common/project-info/conteiners/metric-for-stats-dialog/metric-for-stats-dialog.component.html b/src/app/webapp-common/project-info/conteiners/metric-for-stats-dialog/metric-for-stats-dialog.component.html index e9ace7c5..0a47e6c2 100644 --- a/src/app/webapp-common/project-info/conteiners/metric-for-stats-dialog/metric-for-stats-dialog.component.html +++ b/src/app/webapp-common/project-info/conteiners/metric-for-stats-dialog/metric-for-stats-dialog.component.html @@ -10,7 +10,7 @@ (selectedMetricToShow)="close($event)">
-
diff --git a/src/app/webapp-common/project-info/conteiners/metric-for-stats-dialog/metric-for-stats-dialog.component.ts b/src/app/webapp-common/project-info/conteiners/metric-for-stats-dialog/metric-for-stats-dialog.component.ts index ba8b070d..6d2f3c5f 100644 --- a/src/app/webapp-common/project-info/conteiners/metric-for-stats-dialog/metric-for-stats-dialog.component.ts +++ b/src/app/webapp-common/project-info/conteiners/metric-for-stats-dialog/metric-for-stats-dialog.component.ts @@ -1,5 +1,5 @@ import {Component, Inject} from '@angular/core'; -import {MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {MetricVariantResult} from '~/business-logic/model/projects/metricVariantResult'; import {ISmCol} from '@common/shared/ui-components/data/table/table.consts'; diff --git a/src/app/webapp-common/project-info/conteiners/project-stats/project-stats.component.html b/src/app/webapp-common/project-info/conteiners/project-stats/project-stats.component.html index 44f02656..7964e1c8 100644 --- a/src/app/webapp-common/project-info/conteiners/project-stats/project-stats.component.html +++ b/src/app/webapp-common/project-info/conteiners/project-stats/project-stats.component.html @@ -4,7 +4,7 @@ [hidden]="!selectedVariant" (click)="selectVariant()" [smTooltip]="variantDisplay?.length > 30 ? variantDisplay : null" - + >{{variantDisplay}}
@@ -15,7 +15,8 @@ (clicked)="experimentClicked($event)" >
- {{state.label}} + {{state.label}}
diff --git a/src/app/webapp-common/project-info/conteiners/project-stats/project-stats.component.ts b/src/app/webapp-common/project-info/conteiners/project-stats/project-stats.component.ts index fa195bba..681b6722 100644 --- a/src/app/webapp-common/project-info/conteiners/project-stats/project-stats.component.ts +++ b/src/app/webapp-common/project-info/conteiners/project-stats/project-stats.component.ts @@ -1,27 +1,36 @@ -import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit} from '@angular/core'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + Input, + OnDestroy, + OnInit, + ViewChild +} from '@angular/core'; import {Observable} from 'rxjs/internal/Observable'; import {selectMetricVariants} from '~/features/experiments/reducers'; import {Store} from '@ngrx/store'; import {MetricVariantResult} from '~/business-logic/model/projects/metricVariantResult'; import {getCustomMetrics} from '@common/experiments/actions/common-experiments-view.actions'; -import {fetchGraphData, setMetricVariant} from '@common/core/actions/projects.actions'; +import {fetchGraphData, setMetricVariant, toggleState} from '@common/core/actions/projects.actions'; import { ProjectStatsGraphData, - selectGraphData, + selectGraphData, selectGraphHiddenStates, selectSelectedMetricVariantForCurrProject } from '@common/core/reducers/projects.reducer'; import {Project} from '~/business-logic/model/projects/project'; -import {filter, skip, take, tap} from 'rxjs/operators'; +import {debounceTime, filter, skip, take, tap} from 'rxjs/operators'; import {TaskStatusEnum} from '~/business-logic/model/tasks/taskStatusEnum'; -import {Subscription} from 'rxjs'; -import {TaskTypeEnum} from '~/business-logic/model/tasks/taskTypeEnum'; +import {combineLatest, Subscription} from 'rxjs'; import {createMetricColumn, MetricColumn} from '@common/shared/utils/tableParamEncode'; import {Router} from '@angular/router'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import { MetricForStatsDialogComponent } from '@common/project-info/conteiners/metric-for-stats-dialog/metric-for-stats-dialog.component'; import {MetricValueType} from '@common/experiments-compare/experiments-compare.constants'; +import {ScatterPlotComponent} from '@common/shared/components/charts/scatter-plot/scatter-plot.component'; +import tinycolor from 'tinycolor2'; @Component({ selector: 'sm-project-stats', @@ -36,7 +45,7 @@ export class ProjectStatsComponent implements OnInit, OnDestroy { public selectedVariant: MetricColumn; public colors: string[]; public metricVariantSelection = []; - public graphData: ProjectStatsGraphData[]; + public graphData = null as ProjectStatsGraphData[]; public loading = true; public gotOptions; public variantDisplay: string = 'Select Metric & Variant'; @@ -46,7 +55,7 @@ export class ProjectStatsComponent implements OnInit, OnDestroy { {label: 'Published', type: TaskStatusEnum.Published}, {label: 'Failed', type: TaskStatusEnum.Failed}, {label: 'Running', type: TaskStatusEnum.InProgress} - ]; + ] as {label: string; type: TaskStatusEnum; color?: string}[]; @Input() set project(proj: Project) { if (proj) { @@ -61,6 +70,8 @@ export class ProjectStatsComponent implements OnInit, OnDestroy { constructor(private store: Store, private router: Router, private dialog: MatDialog, private cdr: ChangeDetectorRef) { } + @ViewChild(ScatterPlotComponent) plot: ScatterPlotComponent; + ngOnInit(): void { this.sub.add(this.store.select(selectSelectedMetricVariantForCurrProject) .subscribe(data => { @@ -74,19 +85,29 @@ export class ProjectStatsComponent implements OnInit, OnDestroy { }) ); - this.sub.add(this.store.select(selectGraphData) - .pipe(filter(values => !!values)) - .subscribe(values => { - this.colors = values.map(val => this.statusToColor(val.status)); - this.loading = false; - this.graphData = values.map(val => ({ - ...val, - title: val.name, - nameExt: `Created By ${val.user}, Finished ${new Date(val.x).toLocaleString()}`, - name: val.id - })); - this.cdr.detectChanges(); - }) + this.sub.add(combineLatest([ + this.store.select(selectGraphData), + this.store.select(selectGraphHiddenStates) + ]) + .pipe( + debounceTime(0), + filter(([values]) => !!values) + ) + .subscribe(([values, hidden]) => { + const filteredValues = values.filter(val => !hidden?.[val.status]); + this.colors = filteredValues.map(val => this.statusToColor(val.status, hidden?.[val.status])); + this.states = this.states.map(state => ({...state, color: this.statusToColor(state.type, hidden?.[state.type])})); + this.loading = false; + this.graphData = filteredValues + .map(val => ({ + ...val, + title: val.name, + nameExt: `Created By ${val.user}, Finished ${new Date(val.x).toLocaleString()}`, + name: val.id + })); + this.cdr.detectChanges(); + this.plot?.onResize(); + }) ); } @@ -129,52 +150,63 @@ export class ProjectStatsComponent implements OnInit, OnDestroy { ); } - public statusToColor(status: string) { + public statusToColor(status: string, hidden: boolean) { + let color: string; switch (status) { case TaskStatusEnum.Completed: case TaskStatusEnum.Stopped: - return '#009aff'; + color = '#009aff'; + break; case TaskStatusEnum.Failed: - return '#ff001f'; + color = '#ff001f'; + break; case TaskStatusEnum.Published: - return '#d3ff00'; + color = '#d3ff00'; + break; case TaskStatusEnum.InProgress: - return '#14aa8c'; + color = '#14aa8c'; + break; default: - return '#50e3c2'; + color = '#50e3c2'; + break; } + if (hidden) { + return tinycolor(color).darken(30).toHexString(); + } + return color; } ngOnDestroy(): void { this.sub.unsubscribe(); } - private typeToIcon(type: string) { - switch (type) { - case TaskTypeEnum.Training: - return '\uea33'; - case TaskTypeEnum.Testing: - return '\ueA32'; - case TaskTypeEnum.DataProcessing: - return '\ueA2c'; - case TaskTypeEnum.Qc: - return '\ueA30'; - case TaskTypeEnum.Service: - return '\ueA31'; - case TaskTypeEnum.Optimizer: - return '\ueA2F'; - case TaskTypeEnum.Monitor: - return '\ueA2E'; - case TaskTypeEnum.Inference: - return '\ueA2D'; - case TaskTypeEnum.Application: - return '\ueA29'; - case TaskTypeEnum.Controller: - return '\ueA2A'; - default: - return '\ueA2B'; - } - } + // private typeToIcon(type: string) { + // switch (type) { + // case TaskTypeEnum.Training: + // return '\uea33'; + // case TaskTypeEnum.Testing: + // return '\ueA32'; + // case TaskTypeEnum.DataProcessing: + // return '\ueA2c'; + // case TaskTypeEnum.Qc: + // return '\ueA30'; + // case TaskTypeEnum.Service: + // return '\ueA31'; + // case TaskTypeEnum.Optimizer: + // return '\ueA2F'; + // case TaskTypeEnum.Monitor: + // return '\ueA2E'; + // case TaskTypeEnum.Inference: + // return '\ueA2D'; + // case TaskTypeEnum.Application: + // return '\ueA29'; + // case TaskTypeEnum.Controller: + // return '\ueA2A'; + // default: + // return '\ueA2B'; + // } + // } + trackByType = (index: number, state) => state.type; experimentClicked(event: ProjectStatsGraphData) { this.router.navigateByUrl(`/projects/${this.project.id}/experiments/${event.id}`); @@ -190,4 +222,14 @@ export class ProjectStatsComponent implements OnInit, OnDestroy { return 'Last'; } } + + toggleState(state: TaskStatusEnum) { + this.loading = true; + this.graphData = null; + this.cdr.detectChanges(); + this.store.dispatch(toggleState({state})); + if(state === TaskStatusEnum.Completed) { + this.store.dispatch(toggleState({state: TaskStatusEnum.Stopped})); + } + } } diff --git a/src/app/webapp-common/projects/common-projects.effects.ts b/src/app/webapp-common/projects/common-projects.effects.ts index 66c792ed..cca0faed 100755 --- a/src/app/webapp-common/projects/common-projects.effects.ts +++ b/src/app/webapp-common/projects/common-projects.effects.ts @@ -25,7 +25,7 @@ import {Store} from '@ngrx/store'; import {TABLE_SORT_ORDER} from '../shared/ui-components/data/table/table.consts'; import {ProjectsGetAllExRequest} from '~/business-logic/model/projects/projectsGetAllExRequest'; import {isExample} from '../shared/utils/shared-utils'; -import {catchError, filter, map, mergeMap, switchMap, withLatestFrom} from 'rxjs/operators'; +import {catchError, debounceTime, filter, map, mergeMap, switchMap, withLatestFrom} from 'rxjs/operators'; import {pageSize} from './common-projects.consts'; import {selectRouterParams} from '../core/reducers/router-reducer'; import {selectCurrentUser, selectShowOnlyUserWork} from '../core/reducers/users-reducer'; @@ -34,7 +34,6 @@ import { selectHideExamples, selectMainPageTagsFilter, selectMainPageTagsFilterMatchMode, - selectRootProjects, selectSelectedProject, selectSelectedProjectId, selectShowHidden @@ -42,7 +41,6 @@ import { import {forkJoin, of} from 'rxjs'; import {Project} from '~/business-logic/model/projects/project'; import { - setAllProjects, setMainPageTagsFilter, setMainPageTagsFilterMatchMode, setSelectedProjectStats @@ -60,7 +58,8 @@ import {TaskTypeEnum} from '~/business-logic/model/tasks/taskTypeEnum'; export class CommonProjectsEffects { constructor( - private actions: Actions, public projectsApi: ApiProjectsService, + private actions: Actions, + public projectsApi: ApiProjectsService, private store: Store, private route: ActivatedRoute, ) { } @@ -72,25 +71,12 @@ export class CommonProjectsEffects { updateProject = createEffect(() => this.actions.pipe( ofType(updateProject), - withLatestFrom(this.store.select(selectRootProjects)), - mergeMap(([action, rootProjects]) => this.projectsApi.projectsUpdate({project: action.id, ...action.changes}) + mergeMap(action => this.projectsApi.projectsUpdate({project: action.id, ...action.changes}) .pipe( - mergeMap((res: ProjectsUpdateResponse) => { - const actions = [ - deactivateLoader(action.type), - updateProjectSuccess({id: action.id, changes: res.fields}) - ]; - if (action.changes.name) { - const parentProject = rootProjects.find(project => project.id === action.id); - if (parentProject) { - const affectedRootProjects = rootProjects - .filter(project => project.name.startsWith(`${parentProject.name}/`)) - .map(project => ({...project, name: project.name.replace(parentProject?.name, action.changes.name)})); - actions.push(setAllProjects({projects: affectedRootProjects, updating: true}) as any); - } - } - return actions; - }), + mergeMap((res: ProjectsUpdateResponse) => [ + deactivateLoader(action.type), + updateProjectSuccess({id: action.id, changes: res.fields}) + ]), catchError(error => [deactivateLoader(action.type), requestFailed(error), setServerError(error, undefined, error?.error?.meta?.result_subcode === 800 ? 'Name should be 3 characters long' : error?.error?.meta?.result_subcode === 801 ? 'Name' + @@ -103,124 +89,146 @@ export class CommonProjectsEffects { getAllProjects = createEffect(() => this.actions.pipe( ofType(getAllProjectsPageProjects), withLatestFrom( - this.store.select(selectProjectsOrderBy), - this.store.select(selectProjectsSortOrder), - this.store.select(selectProjectsSearchQuery), - this.store.select(selectProjectsScrollId), - this.store.select(selectCurrentUser), - this.store.select(selectShowOnlyUserWork), - this.store.select(selectShowHidden), - this.store.select(selectHideExamples), this.store.select(selectRouterParams).pipe(map(params => params?.projectId)), this.store.select(selectSelectedProjectId), - this.store.select(selectMainPageTagsFilter), - this.store.select(selectMainPageTagsFilterMatchMode), - this.store.select(selectRootProjects), + this.store.select(selectSelectedProject), ), - filter(([ - action, orderBy, sortOrder, searchQuery, scrollId, user, showOnlyUserWork, showHidden, hideExamples, - routerProjectId, projectId, mainPageTagsFilter, mainPageTagsFilterMatchMode, rootProjects]) => rootProjects?.length > 0), - switchMap(([ - action, orderBy, sortOrder, searchQuery, scrollId, user, showOnlyUserWork, showHidden, hideExamples, - routerProjectId, projectId, mainPageTagsFilter, mainPageTagsFilterMatchMode, rootProjects] - ) => { - const selectedProjectId = routerProjectId || projectId; // In rare cases where router not updated yet with - const selectedProjectName = rootProjects?.find(project => selectedProjectId == project.id)?.name; - // current project id - const projects = this.route.snapshot.firstChild.routeConfig.path === 'projects'; - const nested = this.route.snapshot.firstChild?.firstChild?.firstChild?.routeConfig?.path === 'projects'; - const datasets = isDatasets(this.route.snapshot); - const pipelines = isPipelines(this.route.snapshot); - const reports = isReports(this.route.snapshot); - let statsFilter; - /* eslint-disable @typescript-eslint/naming-convention */ - if (!nested) { - if (pipelines) { - statsFilter = {system_tags: ['pipeline'], type: [TaskTypeEnum.Controller]}; - } else if (datasets) { - statsFilter = {system_tags: ['dataset'], type: [TaskTypeEnum.DataProcessing]}; - } - } - if (projects && !showHidden) { - statsFilter = {system_tags: ['-pipeline', '-dataset', '-Annotation','-report']}; - } - return forkJoin([ - this.projectsApi.projectsGetAllEx({ - ...(mainPageTagsFilter?.length > 0 && {tags: [(mainPageTagsFilterMatchMode ? '__$and' : '__$or'), ...addExcludeFilters(mainPageTagsFilter)]}), - stats_for_state: ProjectsGetAllExRequest.StatsForStateEnum.Active, - include_stats: true, - shallow_search: true, - ...((projects && !searchQuery?.query) && {permission_roots_only: true}), - ...((projects && selectedProjectId && selectedProjectId !== '*') && {parent: [selectedProjectId]}), - scroll_id: scrollId || null, // null to create new scroll (undefined doesn't generate scroll) - size: pageSize, - ...(showOnlyUserWork && {active_users: [user?.id]}), - ...((showHidden) && {search_hidden: true}), - ...(hideExamples && {allow_public: false}), - order_by: ['featured', sortOrder === TABLE_SORT_ORDER.DESC ? '-' + orderBy : orderBy], - only_fields: ['name', 'company', 'user', 'created', 'default_output_destination', 'basename', 'system_tags'] - .concat(pipelines || datasets ? ['tags', 'last_update'] : []), - ...(searchQuery?.query && { - _any_: { - pattern: searchQuery.regExp ? searchQuery.query : escapeRegex(searchQuery.query), - fields: ['id', 'basename', 'description'] + switchMap(([action, routerProjectId, projectId, selectedProject]) => + (selectedProject || !projectId && !routerProjectId ? of(selectedProject) : this.projectsApi.projectsGetAllEx({ + id: routerProjectId || projectId, + // eslint-disable-next-line @typescript-eslint/naming-convention + only_fields: ['name'] + }).pipe(map(res => res.projects[0]))) + .pipe( + withLatestFrom( + this.store.select(selectProjectsOrderBy), + this.store.select(selectProjectsSortOrder), + this.store.select(selectProjectsSearchQuery), + this.store.select(selectProjectsScrollId), + this.store.select(selectCurrentUser), + this.store.select(selectShowOnlyUserWork), + this.store.select(selectShowHidden), + this.store.select(selectHideExamples), + this.store.select(selectMainPageTagsFilter), + this.store.select(selectMainPageTagsFilterMatchMode), + ), + + switchMap(( [currentProject, + orderBy, sortOrder, searchQuery, scrollId, user, showOnlyUserWork, showHidden, hideExamples, + mainPageTagsFilter, mainPageTagsFilterMatchMode] + ) => { + const selectedProjectId = routerProjectId || projectId; // In rare cases where router not updated yet with + const selectedProjectName = selectSelectedProjectId && selectedProjectId !== '*' ? currentProject?.name : null; + // current project id + const projectsView = this.route.snapshot.firstChild.routeConfig.path === 'projects'; + const nested = this.route.snapshot.firstChild?.firstChild?.firstChild?.routeConfig?.path === 'projects'; + const datasets = isDatasets(this.route.snapshot); + const pipelines = isPipelines(this.route.snapshot); + const reports = isReports(this.route.snapshot); + let statsFilter; + /* eslint-disable @typescript-eslint/naming-convention */ + if (!nested) { + if (pipelines) { + statsFilter = {system_tags: ['pipeline'], type: [TaskTypeEnum.Controller]}; + } else if (datasets) { + statsFilter = {system_tags: ['dataset'], type: [TaskTypeEnum.DataProcessing]}; + } } - }), - ...(!projects && getFeatureProjectRequest(this.route.snapshot, nested, searchQuery, selectedProjectName, selectedProjectId)), - }), - // Getting [current project] stats from server - ((nested || projects) && selectedProjectId && selectedProjectId !== '*' && !scrollId && !searchQuery?.query) ? this.projectsApi.projectsGetAllEx({ - ...(!datasets && !pipelines && !reports && {id: selectedProjectId}), - ...(datasets && {name: `^${selectedProjectName}/.datasets$`, search_hidden: true, children_type:'dataset'}), - ...(pipelines && {name: `^${selectedProjectName}/.pipelines$`, search_hidden: true, children_type: 'pipeline'}), - ...(reports && {name: `^${selectedProjectName}/.reports$`, search_hidden: true, children_type: 'report'}), - ...((!showHidden && projects) && {include_stats_filter: statsFilter}), - ...((pipelines && !nested) && {include_stats_filter: {system_tags: ['pipeline'], type: ['controller']}}), - ...(datasets && !nested ? {include_dataset_stats: true} : {include_stats: true}), - stats_with_children: false, - stats_for_state: ProjectsGetAllExRequest.StatsForStateEnum.Active, - ...(showHidden && {search_hidden: true}), - check_own_contents: true, // in order to check if project is empty - ...(showOnlyUserWork && {active_users: [user.id]}), - only_fields: ['name', 'company', 'user', 'created', 'default_output_destination'], - ...(!projects && getSelfFeatureProjectRequest(this.route.snapshot)), - /* eslint-enable @typescript-eslint/naming-convention */ - }) : of(null), - ]).pipe( - withLatestFrom(this.store.select(selectRootProjects).pipe(map(currentRootProjects => currentRootProjects?.find(project => project.id === selectedProjectId) ?? []))), - map(([[projectsRes, currentProjectRes], selectedProject]: [[ProjectsGetAllExResponse, ProjectsGetAllExResponse], Project]) => ({ - newScrollId: projectsRes.scroll_id, - projects: currentProjectRes !== null && currentProjectRes.projects.length !== 0 && - this.isNotEmptyExampleProject(currentProjectRes.projects[0]) ? - /* eslint-disable @typescript-eslint/naming-convention */ - [(currentProjectRes?.projects?.length === 0 ? - {...selectedProject, isRoot: true, sub_projects: null, name: `[${selectedProject.name}]`} : - { - ...currentProjectRes.projects[0], - id: selectedProjectId, - isRoot: true, - // eslint-disable-next-line @typescript-eslint/naming-convention - sub_projects: null, - name: `[${selectedProjectName}]` - }), - ...projectsRes.projects - /* eslint-enable @typescript-eslint/naming-convention */ - ] : - projectsRes.projects + if (projectsView && !showHidden) { + statsFilter = {system_tags: ['-pipeline', '-dataset', '-Annotation','-report']}; + } + return forkJoin([ + this.projectsApi.projectsGetAllEx({ + ...(mainPageTagsFilter?.length > 0 && {tags: [(mainPageTagsFilterMatchMode ? '__$and' : '__$or'), ...addExcludeFilters(mainPageTagsFilter)]}), + stats_for_state: ProjectsGetAllExRequest.StatsForStateEnum.Active, + include_stats: true, + shallow_search: true, + ...((projectsView && !searchQuery?.query) && {permission_roots_only: true}), + ...((projectsView && selectedProjectId && selectedProjectId !== '*') && {parent: [selectedProjectId]}), + scroll_id: scrollId || null, // null to create new scroll (undefined doesn't generate scroll) + size: pageSize, + ...(showOnlyUserWork && {active_users: [user?.id]}), + ...((showHidden) && {search_hidden: true}), + ...(hideExamples && {allow_public: false}), + order_by: ['featured', sortOrder === TABLE_SORT_ORDER.DESC ? '-' + orderBy : orderBy], + only_fields: ['name', 'company', 'user', 'created', 'default_output_destination', 'basename', 'system_tags'] + .concat(pipelines || datasets ? ['tags', 'last_update'] : []), + ...(searchQuery?.query && { + _any_: { + pattern: searchQuery.regExp ? searchQuery.query : escapeRegex(searchQuery.query), + fields: ['id', 'basename', 'description'] + } + }), + ...(!projectsView && getFeatureProjectRequest(this.route.snapshot, nested, searchQuery, selectedProjectName, selectedProjectId)), + }), + // Getting [current project] stats from server + ((nested || projectsView) && selectedProjectId && selectedProjectId !== '*' && !scrollId && !searchQuery?.query) ? + this.projectsApi.projectsGetAllEx({ + ...(!datasets && !pipelines && !reports && {id: selectedProjectId}), + ...(datasets && {name: `^${selectedProjectName}/\\.datasets$`, search_hidden: true, children_type:'dataset'}), + ...(pipelines && {name: `^${selectedProjectName}/\\.pipelines$`, search_hidden: true, children_type: 'pipeline'}), + ...(reports && {name: `^${selectedProjectName}/\\.reports$`, search_hidden: true, children_type: 'report'}), + ...((!showHidden && projectsView) && {include_stats_filter: statsFilter}), + ...((pipelines && !nested) && {include_stats_filter: {system_tags: ['pipeline'], type: ['controller']}}), + ...(datasets && !nested ? {include_dataset_stats: true} : {include_stats: true}), + stats_with_children: false, + stats_for_state: ProjectsGetAllExRequest.StatsForStateEnum.Active, + ...(showHidden && {search_hidden: true}), + check_own_contents: true, // in order to check if project is empty + ...(showOnlyUserWork && {active_users: [user.id]}), + only_fields: ['name', 'company', 'user', 'created', 'default_output_destination'], + ...(!projectsView && getSelfFeatureProjectRequest(this.route.snapshot)), + }) : nested && reports && selectedProjectId === '*' && !scrollId && !searchQuery ? + this.projectsApi.projectsGetAllEx({ + name: '^\\.reports$', + search_hidden: true, + children_type: 'report', + stats_with_children: false, + stats_for_state: ProjectsGetAllExRequest.StatsForStateEnum.Active, + include_stats: true, + check_own_contents: true, // in order to check if project is empty + ...(showOnlyUserWork && {active_users: [user.id]}), + only_fields: ['id', 'company'] + /* eslint-enable @typescript-eslint/naming-convention */ + }) : + of(null), + ]).pipe( + debounceTime(0), + map(([projectsRes, currentProjectRes]: [ProjectsGetAllExResponse, ProjectsGetAllExResponse]) => ({ + newScrollId: projectsRes.scroll_id, + projects: currentProjectRes !== null && currentProjectRes.projects.length !== 0 && + this.isNotEmptyExampleProject(currentProjectRes.projects[0]) ? + /* eslint-disable @typescript-eslint/naming-convention */ + [(currentProjectRes?.projects?.length === 0 ? + {isRoot: true, sub_projects: null, name: `[${selectedProjectName}]`} : + { + ...currentProjectRes.projects[0], + id: selectedProjectId, + isRoot: true, + // eslint-disable-next-line @typescript-eslint/naming-convention + sub_projects: null, + name: !selectedProjectName && currentProjectRes.projects[0].stats ? '[Root]' : `[${selectedProjectName}]` + }), + ...projectsRes.projects + /* eslint-enable @typescript-eslint/naming-convention */ + ] : + projectsRes.projects + } + )), + mergeMap(({newScrollId, projects}) => [ + addToProjectsList({ + projects, reset: + [setMainPageTagsFilter.type, setMainPageTagsFilterMatchMode.type].includes(action.type) + }), + deactivateLoader(action.type), + setCurrentScrollId({scrollId: newScrollId}), + setNoMoreProjects({payload: projects.length < pageSize})]), + catchError(error => [deactivateLoader(action.type), requestFailed(error)]) + ); } - )), - mergeMap(({newScrollId, projects}) => [ - addToProjectsList({ - projects, reset: - [setMainPageTagsFilter.type, setMainPageTagsFilterMatchMode.type].includes(action.type) - }), - deactivateLoader(action.type), - setCurrentScrollId({scrollId: newScrollId}), - setNoMoreProjects({payload: projects.length < pageSize})]), - catchError(error => [deactivateLoader(action.type), requestFailed(error)]) - ); - } - ) + ) + ) + ), )); updateProjectStats = createEffect(() => this.actions.pipe( diff --git a/src/app/webapp-common/projects/common-projects.module.ts b/src/app/webapp-common/projects/common-projects.module.ts index 97109d64..5e4115f3 100755 --- a/src/app/webapp-common/projects/common-projects.module.ts +++ b/src/app/webapp-common/projects/common-projects.module.ts @@ -7,11 +7,12 @@ import {FormsModule, ReactiveFormsModule} from '@angular/forms'; import {ProjectsListComponent} from './dumb/projects-list/projects-list.component'; import {ProjectsHeaderComponent} from './dumb/projects-header/projects-header.component'; import {ProjectDialogModule} from '../shared/project-dialog/project-dialog.module'; -import {ProjectsSharedModule} from '../../features/projects/shared/projects-shared.module'; +import {ProjectsSharedModule} from '~/features/projects/shared/projects-shared.module'; import {CommonLayoutModule} from '../layout/layout.module'; -import {SharedModule} from '../../shared/shared.module'; -import {ProjectsEffects} from '../../features/projects/projects.effect'; +import {SharedModule} from '~/shared/shared.module'; +import {ProjectsEffects} from '~/features/projects/projects.effect'; import {CommonProjectsEffects} from './common-projects.effects'; +import {LabeledFormFieldDirective} from '@common/shared/directive/labeled-form-field.directive'; @NgModule({ imports: [ @@ -23,7 +24,8 @@ import {CommonProjectsEffects} from './common-projects.effects'; ProjectsSharedModule, EffectsModule.forFeature([ProjectsEffects, CommonProjectsEffects]), SharedModule, - CommonLayoutModule + CommonLayoutModule, + LabeledFormFieldDirective, ], declarations: [CommonProjectsPageComponent, ProjectsListComponent, ProjectsHeaderComponent], exports: [CommonProjectsPageComponent, ProjectsListComponent, ProjectsHeaderComponent] diff --git a/src/app/webapp-common/projects/common-projects.utils.ts b/src/app/webapp-common/projects/common-projects.utils.ts index c732f0c9..071b8b1d 100644 --- a/src/app/webapp-common/projects/common-projects.utils.ts +++ b/src/app/webapp-common/projects/common-projects.utils.ts @@ -1,5 +1,5 @@ -import {ProjectsGetAllExRequest} from "~/business-logic/model/projects/projectsGetAllExRequest"; -import {ActivatedRouteSnapshot} from "@angular/router"; +import {ProjectsGetAllExRequest} from '~/business-logic/model/projects/projectsGetAllExRequest'; +import {ActivatedRouteSnapshot} from '@angular/router'; export const getPipelineRequest = (nested, searchQuery, selectedProjectName, selectedProjectId): ProjectsGetAllExRequest => ({ /* eslint-disable @typescript-eslint/naming-convention */ diff --git a/src/app/webapp-common/projects/containers/projects-page/common-projects-page.component.html b/src/app/webapp-common/projects/containers/projects-page/common-projects-page.component.html index b225499f..03520264 100755 --- a/src/app/webapp-common/projects/containers/projects-page/common-projects-page.component.html +++ b/src/app/webapp-common/projects/containers/projects-page/common-projects-page.component.html @@ -16,7 +16,7 @@ > diff --git a/src/app/webapp-common/projects/containers/projects-page/common-projects-page.component.ts b/src/app/webapp-common/projects/containers/projects-page/common-projects-page.component.ts index e6a36b3d..69552ddc 100755 --- a/src/app/webapp-common/projects/containers/projects-page/common-projects-page.component.ts +++ b/src/app/webapp-common/projects/containers/projects-page/common-projects-page.component.ts @@ -19,7 +19,7 @@ import { updateProject } from '../../common-projects.actions'; import {ActivatedRoute, Router} from '@angular/router'; -import {MatLegacyDialog as MatDialog, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MatDialog, MatDialogRef} from '@angular/material/dialog'; import {ProjectsGetAllResponseSingle} from '~/business-logic/model/projects/projectsGetAllResponseSingle'; import {ProjectDialogComponent} from '@common/shared/project-dialog/project-dialog.component'; import {combineLatest, Observable, Subscription} from 'rxjs'; @@ -51,10 +51,10 @@ import {Project} from '~/business-logic/model/projects/project'; import {CommonDeleteDialogComponent} from '@common/shared/entity-page/entity-delete/common-delete-dialog.component'; import {resetDeleteState} from '@common/shared/entity-page/entity-delete/common-delete-dialog.actions'; import {isExample} from '@common/shared/utils/shared-utils'; -import {selectRootProjects, selectSelectedProject} from '@common/core/reducers/projects.reducer'; +import {selectSelectedProject} from '@common/core/reducers/projects.reducer'; import {selectActiveWorkspaceReady} from '~/core/reducers/view.reducer'; import {EntityTypeEnum} from '~/shared/constants/non-common-consts'; -import {selectIsDatasets} from "@common/experiments-compare/reducers"; +import {selectIsDatasets} from '@common/experiments-compare/reducers'; @Component({ selector: 'sm-common-projects-page', @@ -98,6 +98,7 @@ export class CommonProjectsPageComponent implements OnInit, OnDestroy { private selectedProject$: Observable; public projectId: string; private subs = new Subscription(); + private selectedProject: Project; constructor( protected store: Store, @@ -110,7 +111,7 @@ export class CommonProjectsPageComponent implements OnInit, OnDestroy { this.projectsSortOrder$ = this.store.select(selectProjectsSortOrder); this.noMoreProjects$ = this.store.select(selectNoMoreProjects); this.selectedProjectId$ = this.store.select(selectRouterParams).pipe(map(params => params?.projectId)); - this.selectedProject$ = this.store.select(selectSelectedProject); + this.selectedProject$ = this.store.select(selectSelectedProject).pipe(tap(selectedProject => this.selectedProject = selectedProject)); this.projectReadyForDeletion$ = this.store.select(selectProjectReadyForDeletion).pipe( distinctUntilChanged(), filter(readyForDeletion => readyForDeletionFilter(readyForDeletion))); @@ -154,9 +155,8 @@ export class CommonProjectsPageComponent implements OnInit, OnDestroy { ngOnInit() { // this.store.dispatch(new ResetSelectedProject()); this.store.dispatch(setDeep({deep: false})); - - this.subs.add(combineLatest([this.store.select(selectActiveWorkspaceReady), this.store.select(selectRootProjects)]) - .pipe(filter(([ready, rootProjects]) => ready && rootProjects?.length > 0)).pipe(take(1)) + this.subs.add(this.store.select(selectActiveWorkspaceReady) + .pipe(filter(ready => ready), take(1)) .subscribe(() => { this.store.dispatch(getAllProjectsPageProjects()); })); @@ -262,9 +262,8 @@ export class CommonProjectsPageComponent implements OnInit, OnDestroy { if (allExperiments) { this.store.dispatch(setDeep({deep: true})); } - this.router.navigate(project?.sub_projects?.length > 0 ? [project.id, 'projects'] : - (!(project.id === '*' || allExperiments || (project as any).isRoot) ? [project.id] : [project.id, 'experiments']) - , {relativeTo: this.projectId ? this.route.parent.parent.parent : this.route}); + this.router.navigate(project?.sub_projects?.length > 0 ? [project.id, 'projects'] : [project.id], + {relativeTo: this.projectId ? this.route.parent.parent.parent : this.route}); this.store.dispatch(setSelectedProjectId({projectId: project.id, example: isExample(project)})); } @@ -289,11 +288,11 @@ export class CommonProjectsPageComponent implements OnInit, OnDestroy { } - openProjectDialog(mode?: string, projectId?: string) { + openProjectDialog(mode?: string, project?: Project) { this.projectDialog = this.dialog.open(ProjectDialogComponent, { data: { mode, - projectId + project: project ?? this.selectedProject } }); this.projectDialog.afterClosed().subscribe(projectHasBeenUpdated => { diff --git a/src/app/webapp-common/projects/dumb/projects-list/projects-list.component.ts b/src/app/webapp-common/projects/dumb/projects-list/projects-list.component.ts index 704ee5ae..da3b3ccb 100755 --- a/src/app/webapp-common/projects/dumb/projects-list/projects-list.component.ts +++ b/src/app/webapp-common/projects/dumb/projects-list/projects-list.component.ts @@ -34,7 +34,7 @@ export class ProjectsListComponent { @Output() projectNameChanged = new EventEmitter<{ id: string; name: string }>(); @Output() deleteProjectClicked = new EventEmitter(); @Output() loadMore = new EventEmitter(); - @Output() moveToClicked = new EventEmitter(); - @Output() createNewProjectClicked = new EventEmitter(); + @Output() moveToClicked = new EventEmitter(); + @Output() createNewProjectClicked = new EventEmitter(); } diff --git a/src/app/webapp-common/reports/report-card/report-card.component.html b/src/app/webapp-common/reports/report-card/report-card.component.html index 26dcc8e6..8769e2b3 100644 --- a/src/app/webapp-common/reports/report-card/report-card.component.html +++ b/src/app/webapp-common/reports/report-card/report-card.component.html @@ -17,7 +17,7 @@ > {{report.name}} - +
- +
{{report?.comment}}
diff --git a/src/app/webapp-common/reports/report-dialog/create-new-report-form/create-new-report-form.component.html b/src/app/webapp-common/reports/report-dialog/create-new-report-form/create-new-report-form.component.html index 27ddf079..5516c46e 100644 --- a/src/app/webapp-common/reports/report-dialog/create-new-report-form/create-new-report-form.component.html +++ b/src/app/webapp-common/reports/report-dialog/create-new-report-form/create-new-report-form.component.html @@ -13,12 +13,13 @@ [existingNames]="reportsNames" required minlength="3"> - + Project - Please provide a project - Please provide a different name as this project name is taken as an Example project + Please provide a different name as this project name is taken as an Example project + + - - - + + + +
+
+ +
+
Loading more...
+
diff --git a/src/app/webapp-common/reports/report-dialog/create-new-report-form/create-new-report-form.component.scss b/src/app/webapp-common/reports/report-dialog/create-new-report-form/create-new-report-form.component.scss index 9ffbed10..89f9e8ab 100644 --- a/src/app/webapp-common/reports/report-dialog/create-new-report-form/create-new-report-form.component.scss +++ b/src/app/webapp-common/reports/report-dialog/create-new-report-form/create-new-report-form.component.scss @@ -18,4 +18,8 @@ min-height: 68px; } } + + .search-icon { + transform: translateY(3px); + } } diff --git a/src/app/webapp-common/reports/report-dialog/create-new-report-form/create-new-report-form.component.ts b/src/app/webapp-common/reports/report-dialog/create-new-report-form/create-new-report-form.component.ts index db489954..267a94a1 100644 --- a/src/app/webapp-common/reports/report-dialog/create-new-report-form/create-new-report-form.component.ts +++ b/src/app/webapp-common/reports/report-dialog/create-new-report-form/create-new-report-form.component.ts @@ -1,18 +1,18 @@ import { - AfterViewInit, ChangeDetectionStrategy, - ChangeDetectorRef, + ChangeDetectionStrategy, Component, EventEmitter, Input, - OnChanges, + OnChanges, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; import {NgModel} from '@angular/forms'; -import {debounceTime, distinctUntilChanged, map, startWith, tap} from 'rxjs/operators'; -import {Observable} from 'rxjs'; -import { Project } from '~/business-logic/model/projects/project'; +import {Observable, Subscription} from 'rxjs'; +import {Project} from '~/business-logic/model/projects/project'; import {trackByValue} from '@common/shared/utils/forms-track-by'; +import {MatOptionSelectionChange} from '@angular/material/core'; +import {rootProjectsPageSize} from '@common/constants'; @Component({ @@ -21,90 +21,112 @@ import {trackByValue} from '@common/shared/utils/forms-track-by'; styleUrls: ['./create-new-report-form.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush }) -export class CreateNewReportFormComponent implements OnChanges, AfterViewInit{ +export class CreateNewReportFormComponent implements OnChanges, OnInit, OnDestroy { public filteredProjects$: Observable<{ label: string; value: string }[]>; private _projects: Project[]; public projectsOptions: { label: string; value: string }[]; public trackByValue = trackByValue; public panelHeight: number; - constructor(private changeDetection: ChangeDetectorRef) { - } + private subs = new Subscription(); + private rootFiltered: boolean; public readonly projectsRoot = {label: 'Projects root', value: null}; @ViewChild('projectInput') projectInput: NgModel; public reportsNames: Array; public projectsNames: Array; - public report: {name: string; description: string; project: {label: string; value: string}} = { - name: '', + public report: { name: string; description: string; project: { label: string; value: string } } = { + name: null, description: '', - project: undefined + project: null }; filterText: string = ''; - // isNewName: boolean = false; - + isAutoCompleteOpen: boolean; + @Input() readOnlyProjectsNames: string[]; + @Input() defaultProjectId: string; + public loading: boolean; + public noMoreOptions: boolean; + private previousLength: number | undefined; @Input() set projects(projects: Project[]) { + this.loading = false; + this.noMoreOptions = projects?.length === this.previousLength || projects?.length < rootProjectsPageSize; + this.previousLength = projects?.length; this._projects = projects; - this.projectsOptions = [this.projectsRoot].concat(projects?.map(project=> ({label:project.name, value: project.id})) ?? []); - this.projectsNames = [this.projectsRoot.label].concat(projects?.map(project => project.name)); + this.projectsOptions = [ + ...(this.rootFiltered || !projects ? [] : [this.projectsRoot]), + ...(projects ? projects.map(project => ({label: project.name, value: project.id})) : []) + ]; + this.projectsNames = this.projectsOptions.map(project => project.label); } get projects() { return this._projects; } - @Input() readOnlyProjectsNames: string[]; - + @Output() filterSearchChanged = new EventEmitter<{value: string; loadMore?: boolean}>(); @Output() reportCreated = new EventEmitter(); - isAutoCompleteOpen: boolean; + + ngOnInit(): void { + this.searchChanged(['*', null].includes(this.defaultProjectId) ? '' : this.defaultProjectId); + setTimeout(() => { + this.subs.add(this.projectInput.valueChanges.subscribe(searchString => { + if (searchString !== this.report.project) { + this.searchChanged(searchString?.label || searchString || ''); + } + }) + ); + }); + } + + ngOnDestroy(): void { + this.subs.unsubscribe(); + } + + ngOnChanges(): void { + if (this.projects?.length > 0 && this.report.project === null) { + this.report.project = this.projectsOptions.find(p => p.value === this.defaultProjectId) || {label: this.projectsRoot.label, value: null}; + this.projectInput.control.updateValueAndValidity(); + } + } + + createNewSelected($event: MatOptionSelectionChange) { + this.report.project = {label: $event.source.value, value: null}; + } + + projectSelected($event: MatOptionSelectionChange) { + this.report.project = {label: $event.source.value.label, value: $event.source.value.value}; + } + setIsAutoCompleteOpen(focus: boolean) { + this.isAutoCompleteOpen = focus; + } + + displayFn(project: any): string { + return project && project.label ? project.label : project; + } + + clear() { + this.projectInput.control.setValue(''); + } send() { this.reportCreated.emit(this.report); } - - ngOnChanges(): void { - if (this.projects?.length > 0) { - this.report.project = {label:this.projectsRoot.label, value: null}; - } + searchChanged(searchString: string) { + this.projectsOptions = null; + this.projectsNames = null; + this.rootFiltered = !this.projectsRoot.label.includes(searchString); + searchString !== null && this.filterSearchChanged.emit({value: searchString, loadMore: false}); } - detectChanges() { - this.changeDetection.detectChanges(); + loadMore(searchString) { + this.loading = true; + this.filterSearchChanged.emit({value: searchString || '', loadMore: true}); } - setIsAutoCompleteOpen(focus: boolean) { - this.isAutoCompleteOpen = focus; - } - - displayFn(project: any ): string { - return project && project.label ? project.label : project ; - } - - clear() { - this.filterText = ''; - this.report.project = undefined; - this.projectInput.control.setValue(''); - } - private _filter(value: string) { - this.filterText = value; - // const projectsNames = this.projectsOptions.map(project => project.label); - // this.isNewName = !projectsNames.includes(value); - const filterValue = value.toLowerCase(); - return this.projectsOptions.filter((project: any) => project.label.toLowerCase().includes(filterValue)); - } - - ngAfterViewInit() { - this.filteredProjects$ = this.projectInput.control.valueChanges - .pipe( - debounceTime(200), - map(value => typeof value === 'string' ? value : value?.label as string), - distinctUntilChanged(), - map(value => !!value ? this._filter(value) : this.projectsOptions), - tap(projects => this.panelHeight = Math.min(projects?.length || 0, 6) * 38), - startWith(this.projectsOptions) - ); + isFocused(locationRef: HTMLInputElement) { + return document.activeElement === locationRef; } } diff --git a/src/app/webapp-common/reports/report-dialog/report-dialog.component.html b/src/app/webapp-common/reports/report-dialog/report-dialog.component.html index aa668c3e..c2fe1d89 100644 --- a/src/app/webapp-common/reports/report-dialog/report-dialog.component.html +++ b/src/app/webapp-common/reports/report-dialog/report-dialog.component.html @@ -2,6 +2,8 @@ diff --git a/src/app/webapp-common/reports/report-dialog/report-dialog.component.ts b/src/app/webapp-common/reports/report-dialog/report-dialog.component.ts index f171a253..d8a7fa3e 100644 --- a/src/app/webapp-common/reports/report-dialog/report-dialog.component.ts +++ b/src/app/webapp-common/reports/report-dialog/report-dialog.component.ts @@ -1,9 +1,9 @@ -import {Component, OnDestroy, OnInit} from '@angular/core'; -import {MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {Component, Inject} from '@angular/core'; +import {MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog'; import {Store} from '@ngrx/store'; import {Observable} from 'rxjs'; -import {selectRootProjects} from '@common/core/reducers/projects.reducer'; -import {getAllSystemProjects} from '@common/core/actions/projects.actions'; +import {selectTablesFilterProjectsOptions} from '@common/core/reducers/projects.reducer'; +import {getTablesFilterProjectsOptions, resetTablesFilterProjectsOptions} from '@common/core/actions/projects.actions'; import { ReportsCreateRequest } from '~/business-logic/model/reports/models'; import {map} from 'rxjs/operators'; import { Project } from '~/business-logic/model/projects/project'; @@ -14,30 +14,16 @@ import {isReadOnly} from '@common/shared/utils/is-read-only'; templateUrl: './report-dialog.component.html', styleUrls: ['./report-dialog.component.scss'] }) -export class ReportDialogComponent implements OnInit, OnDestroy { +export class ReportDialogComponent { public projects$: Observable; - // private creationStatusSubscription: Subscription; public readOnlyProjectsNames$: Observable; - constructor(private store: Store, private matDialogRef: MatDialogRef) { - this.projects$ = this.store.select(selectRootProjects); - this.readOnlyProjectsNames$ = this.store.select(selectRootProjects) + constructor(private store: Store, private matDialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: { defaultProjectId: string}) { + this.projects$ = this.store.select(selectTablesFilterProjectsOptions); + this.readOnlyProjectsNames$ = this.store.select(selectTablesFilterProjectsOptions) .pipe(map(projects => projects?.filter(project => isReadOnly(project)).map(project=> project.name))); - } - - ngOnInit(): void { - this.store.dispatch(getAllSystemProjects()); - // this.creationStatusSubscription = this.store.select(createReportSelectors.selectCreationStatus).subscribe(status => { - // if (status === CREATION_STATUS.SUCCESS) { - // return this.matDialogRef.close(true); - // } - // }); - } - - ngOnDestroy(): void { - // this.store.dispatch(new ResetState()); - // this.creationStatusSubscription.unsubscribe(); + this.store.dispatch(resetTablesFilterProjectsOptions()); } public createReport(reportForm) { @@ -54,4 +40,9 @@ export class ReportDialogComponent implements OnInit, OnDestroy { project:reportForm.project.value }; } + + filterSearchChanged($event: {value: string; loadMore?: boolean}) { + !$event.loadMore && this.store.dispatch(resetTablesFilterProjectsOptions()); + this.store.dispatch(getTablesFilterProjectsOptions({searchString: $event.value || '', loadMore: $event.loadMore})); + } } diff --git a/src/app/webapp-common/reports/report/report.component.html b/src/app/webapp-common/reports/report/report.component.html index 2e50e25e..057e2ed6 100644 --- a/src/app/webapp-common/reports/report/report.component.html +++ b/src/app/webapp-common/reports/report/report.component.html @@ -50,7 +50,7 @@ [disabled]="!this.report.report?.trim()" [smTooltip]="!this.report.report?.trim() ? 'Can\'t publish an empty report' : ''" (click)="publish()" - >PUBLISH + >PUBLISH
diff --git a/src/app/webapp-common/reports/report/report.component.ts b/src/app/webapp-common/reports/report/report.component.ts index 797c2282..7ccc122b 100644 --- a/src/app/webapp-common/reports/report/report.component.ts +++ b/src/app/webapp-common/reports/report/report.component.ts @@ -29,11 +29,11 @@ import { map, switchMap, } from 'rxjs/operators'; -import {fromEvent, lastValueFrom, Observable, Subscription, take, combineLatest} from 'rxjs'; +import {fromEvent, lastValueFrom, Observable, Subscription, take, combineLatest, merge} from 'rxjs'; import {selectReport, selectReportsTags} from '@common/reports/reports.reducer'; import {ReportStatusEnum} from '~/business-logic/model/reports/reportStatusEnum'; import {getBaseName, isExample} from '@common/shared/utils/shared-utils'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {ConfirmDialogComponent} from '@common/shared/ui-components/overlay/confirm-dialog/confirm-dialog.component'; import {activeLoader, addMessage, deactivateLoader} from '@common/core/actions/layout.actions'; import {ICONS, MESSAGES_SEVERITY} from '@common/constants'; @@ -129,7 +129,10 @@ export class ReportComponent implements OnInit, OnDestroy { switchMap(() => { const img = new Image(); img.src = reader.result as string; - return fromEvent(img, 'load') + return merge( + fromEvent(img, 'load'), + fromEvent(img, 'error'), + ) .pipe( map(() => { if (img.width > 0 && img.height > 0) { @@ -148,6 +151,11 @@ export class ReportComponent implements OnInit, OnDestroy { reader.readAsDataURL(file); return obs; }); + if (valid.length === 0) { + this.store.dispatch(addMessage(MESSAGES_SEVERITY.ERROR, 'invalid file type')); + this.store.dispatch(deactivateLoader('upload')); + return Promise.reject('Invalid file type'); + } const uploads$ = combineLatest(valid).pipe( debounceTime(0), take(1), @@ -156,7 +164,7 @@ export class ReportComponent implements OnInit, OnDestroy { const results = [] as UploadResult[]; validFiles .forEach(file => { - const url = `reports/${replaceSlash(this.report.name)}.${this.report.id}/${replaceSlash(file.name)}`; + const url = `reports/${this.report.id}/${replaceSlash(file.name)}`; formData.append(url, file); results.push({name: file.name, url: `${filesServerUrl}/${url}`, isImg: true}); }); diff --git a/src/app/webapp-common/reports/reports-filters/reports-header.component.html b/src/app/webapp-common/reports/reports-filters/reports-header.component.html index 79f98178..126a1497 100644 --- a/src/app/webapp-common/reports/reports-filters/reports-header.component.html +++ b/src/app/webapp-common/reports/reports-filters/reports-header.component.html @@ -9,7 +9,7 @@ NEW REPORT + (click)="createReportClicked.emit(projectId)" + >NEW REPORT
diff --git a/src/app/webapp-common/reports/reports-list/reports-list.component.html b/src/app/webapp-common/reports/reports-list/reports-list.component.html index 325c35ac..dc8621a8 100644 --- a/src/app/webapp-common/reports/reports-list/reports-list.component.html +++ b/src/app/webapp-common/reports/reports-list/reports-list.component.html @@ -30,7 +30,7 @@

NO REPORTS TO SHOW

-
diff --git a/src/app/webapp-common/reports/reports-list/reports-list.component.ts b/src/app/webapp-common/reports/reports-list/reports-list.component.ts index fc302e0d..223ae958 100644 --- a/src/app/webapp-common/reports/reports-list/reports-list.component.ts +++ b/src/app/webapp-common/reports/reports-list/reports-list.component.ts @@ -15,11 +15,12 @@ export class ReportsListComponent { @Input() noMoreReports = false; @Input() allTags: string[] = []; @Input() archive = false; + @Input() projectId; @Output() reportSelected = new EventEmitter(); @Output() loadMore = new EventEmitter(); @Output() reportCardUpdateMetadata = new EventEmitter<{report: IReport; readOnly: boolean}>(); @Output() reportCardUpdateName = new EventEmitter<{name: string; report: IReport}>(); - @Output() newReport = new EventEmitter(); + @Output() newReport = new EventEmitter(); @Output() addTag = new EventEmitter<{report: IReport; tag: string}>(); @Output() moveToArchive = new EventEmitter<{report: IReport; archive: boolean}>(); @Output() removeTag = new EventEmitter<{report: IReport; tag: string}>(); diff --git a/src/app/webapp-common/reports/reports-page/reports-page.component.html b/src/app/webapp-common/reports/reports-page/reports-page.component.html index 909a5166..0cd86efb 100644 --- a/src/app/webapp-common/reports/reports-page/reports-page.component.html +++ b/src/app/webapp-common/reports/reports-page/reports-page.component.html @@ -3,12 +3,13 @@ [archive]="archive$ | async" [noMoreReports]="noMoreReports$ | async" [allTags]="reportsTags$ | async" + [projectId]="selectedProjectId$ | async" (reportSelected)="reportSelected($event)" (reportCardUpdateName)="reportCardUpdateName($event)" (moveTo)="moveTo($event)" (delete)="delete($event)" (share)="share($event)" - (newReport)="openCreateReportDialog()" + (newReport)="openCreateReportDialog($event)" (loadMore)="loadMore()" (addTag)="addTag($event)" (removeTag)="removeTag($event)" @@ -21,7 +22,7 @@ [sortByField]="reportsOrderBy$ | async" [projectId]="selectedProjectId$ | async" (toggleNestedView)="toggleNestedView($event)" - (createReportClicked)="openCreateReportDialog()" + (createReportClicked)="openCreateReportDialog($event)" (archiveToggled)="toggleArchive($event)" (orderByChanged)="orderByChanged($event)" > diff --git a/src/app/webapp-common/reports/reports-page/reports-page.component.ts b/src/app/webapp-common/reports/reports-page/reports-page.component.ts index f3028e71..4e9e1b2e 100644 --- a/src/app/webapp-common/reports/reports-page/reports-page.component.ts +++ b/src/app/webapp-common/reports/reports-page/reports-page.component.ts @@ -1,26 +1,29 @@ import {Component, OnDestroy, OnInit} from '@angular/core'; import {Store} from '@ngrx/store'; import {ActivatedRoute, Params, Router} from '@angular/router'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {ReportDialogComponent} from '../report-dialog/report-dialog.component'; import { addReportsTags, archiveReport, - createReport, deleteReport, + createReport, + deleteReport, getReports, getReportsTags, moveReport, resetReports, restoreReport, setArchive, - setReportsOrderBy, setReportsSearchQuery, + setReportsOrderBy, + setReportsSearchQuery, updateReport } from '../reports.actions'; import { selectArchiveView, selectNoMoreReports, selectReports, - selectReportsOrderBy, selectReportsQueryString, + selectReportsOrderBy, + selectReportsQueryString, selectReportsSortOrder, selectReportsTags } from '../reports.reducer'; @@ -74,12 +77,17 @@ export class ReportsPageComponent implements OnInit, OnDestroy { this.store.dispatch(getReportsTags()); } - public openCreateReportDialog() { - this.matDialog.open(ReportDialogComponent).afterClosed().subscribe(report => { - if (report) { - this.store.dispatch(createReport({reportsCreateRequest: report})); - } - }); + public openCreateReportDialog(projectId) { + this.matDialog.open(ReportDialogComponent, { + data: {defaultProjectId: projectId}, + panelClass: 'light-theme', + }) + .afterClosed() + .subscribe(report => { + if (report) { + this.store.dispatch(createReport({reportsCreateRequest: report})); + } + }); } ngOnDestroy(): void { @@ -89,7 +97,6 @@ export class ReportsPageComponent implements OnInit, OnDestroy { ngOnInit(): void { this.store.dispatch(initSearch({payload: 'Search for reports'})); - let prevQueryParams: Params; this.sub.add(combineLatest([ this.store.select(selectMainPageTagsFilter), diff --git a/src/app/webapp-common/reports/reports-routing.module.ts b/src/app/webapp-common/reports/reports-routing.module.ts index b342a969..f3d15648 100644 --- a/src/app/webapp-common/reports/reports-routing.module.ts +++ b/src/app/webapp-common/reports/reports-routing.module.ts @@ -4,11 +4,15 @@ import {ReportsPageComponent} from './reports-page/reports-page.component'; import {ReportComponent} from '@common/reports/report/report.component'; import { NestedProjectViewPageComponent -} from "@common/nested-project-view/nested-project-view-page/nested-project-view-page.component"; +} from '@common/nested-project-view/nested-project-view-page/nested-project-view-page.component'; +import {CrumbTypeEnum} from '@common/layout/breadcrumbs/breadcrumbs.component'; export const routes: Routes = [ { - path: '', component: ReportsPageComponent, data: {search: true} + path: '', component: ReportsPageComponent, data: {search: true, staticBreadcrumb:[[{ + name: 'REPORTS', + type: CrumbTypeEnum.Feature + }]]} }, // Adding project param to url, for automatic workspace switching. { @@ -16,7 +20,7 @@ export const routes: Routes = [ children: [ {path: 'reports', component: ReportsPageComponent, data: {search: true}}, {path: 'projects', component: NestedProjectViewPageComponent, data: {search: true}}, - {path: ':reportId', component: ReportComponent, data: {search: true}} + {path: ':reportId', component: ReportComponent} ] }, ]; diff --git a/src/app/webapp-common/reports/reports-shared.module.ts b/src/app/webapp-common/reports/reports-shared.module.ts index 00b1060d..8ec628b2 100644 --- a/src/app/webapp-common/reports/reports-shared.module.ts +++ b/src/app/webapp-common/reports/reports-shared.module.ts @@ -7,6 +7,7 @@ import {ReportCardComponent} from '@common/reports/report-card/report-card.compo import {ReportCardMenuComponent} from '@common/reports/report-card-menu/report-card-menu.component'; import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module'; import {ExperimentSharedModule} from '~/features/experiments/shared/experiment-shared.module'; +import {LabeledFormFieldDirective} from '@common/shared/directive/labeled-form-field.directive'; const declarations = [ ReportCardComponent, ReportCardMenuComponent,]; @@ -20,6 +21,7 @@ const declarations = [ ReportCardComponent, SharedModule, SharedPipesModule, ExperimentSharedModule, + LabeledFormFieldDirective ], declarations: [...declarations], exports: [...declarations], diff --git a/src/app/webapp-common/reports/reports.actions.ts b/src/app/webapp-common/reports/reports.actions.ts index 3bfee525..96fae802 100644 --- a/src/app/webapp-common/reports/reports.actions.ts +++ b/src/app/webapp-common/reports/reports.actions.ts @@ -78,7 +78,7 @@ export const removeReport = createAction( export const setReportChanges = createAction( REPORTS_PREFIX + '[set report changes]', - props<{ id: string; changes: Partial }>() + props<{ id: string; changes: Partial; filterOut?: boolean}>() ); export const setArchive = createAction( diff --git a/src/app/webapp-common/reports/reports.effects.ts b/src/app/webapp-common/reports/reports.effects.ts index 9ac3cc9b..8569cdea 100644 --- a/src/app/webapp-common/reports/reports.effects.ts +++ b/src/app/webapp-common/reports/reports.effects.ts @@ -38,14 +38,19 @@ import {ReportsGetAllExResponse} from '~/business-logic/model/reports/reportsGet import {Report} from '~/business-logic/model/reports/report'; import {ReportsUpdateResponse} from '~/business-logic/model/reports/reportsUpdateResponse'; import {ReportsMoveResponse} from '~/business-logic/model/reports/reportsMoveResponse'; -import {selectHideExamples, selectMainPageTagsFilter, selectMainPageTagsFilterMatchMode} from '../core/reducers/projects.reducer'; +import { + selectHideExamples, + selectMainPageTagsFilter, + selectMainPageTagsFilterMatchMode, + selectSelectedProjectId +} from '../core/reducers/projects.reducer'; import {ReportsGetTagsResponse} from '~/business-logic/model/reports/reportsGetTagsResponse'; import {TABLE_SORT_ORDER} from '../shared/ui-components/data/table/table.consts'; import {selectCurrentUser, selectShowOnlyUserWork} from '../core/reducers/users-reducer'; import {addExcludeFilters} from '../shared/utils/tableParamEncode'; import {escapeRegex} from '../shared/utils/escape-regex'; import {MESSAGES_SEVERITY} from '../constants'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import { ChangeProjectDialogComponent } from '@common/experiments/shared/components/change-project-dialog/change-project-dialog.component'; @@ -54,7 +59,7 @@ import {selectActiveWorkspaceReady} from '~/core/reducers/view.reducer'; import {ReportsCreateResponse} from '~/business-logic/model/reports/reportsCreateResponse'; import {ConfirmDialogComponent} from '@common/shared/ui-components/overlay/confirm-dialog/confirm-dialog.component'; import {HttpClient} from '@angular/common/http'; -import {selectRouterParams} from "@common/core/reducers/router-reducer"; +import {selectRouterParams} from '@common/core/reducers/router-reducer'; @Injectable() export class ReportsEffects { @@ -110,7 +115,7 @@ export class ReportsEffects { /* eslint-disable @typescript-eslint/naming-convention */ only_fields: ['name', 'comment', 'company', 'tags', 'report', 'project.name', 'user.name', 'status', 'last_update', 'system_tags'] as (keyof Report)[], size: PAGE_SIZE, - ...(projectId && {project: projectId}), + project: projectId === '*' ? null : projectId, scroll_id: action['loadMore'] ? scroll : null, ...(hideExamples && {allow_public: false}), system_tags: [archive ? '__$and' : '__$not', 'archived'], @@ -224,10 +229,13 @@ export class ReportsEffects { map(project => ({task: action.report.id, project: project.id, project_name: project.name})) ) ), - switchMap((moveRequest: ReportsMoveRequest) => this.reportsApiService.reportsMove(moveRequest).pipe( - mergeMap((res: ReportsMoveResponse) => [ + switchMap((moveRequest: ReportsMoveRequest) => this.reportsApiService.reportsMove(moveRequest) + .pipe( + withLatestFrom(this.store.select(selectSelectedProjectId)), + mergeMap(([res, projectId]: [ReportsMoveResponse, string]) => [ setReportChanges({ id: moveRequest.task, + filterOut: projectId && projectId !== '*' && projectId !== moveRequest.project, changes: { project: (moveRequest.project ? {id: moveRequest.project, name: moveRequest.project_name} : diff --git a/src/app/webapp-common/reports/reports.module.ts b/src/app/webapp-common/reports/reports.module.ts index 174bc635..62766254 100644 --- a/src/app/webapp-common/reports/reports.module.ts +++ b/src/app/webapp-common/reports/reports.module.ts @@ -22,6 +22,8 @@ import {ScrollingModule} from '@angular/cdk/scrolling'; import {ReportsSharedModule} from '@common/reports/reports-shared.module'; import {ExistNameValidatorDirective} from '@common/shared/ui-components/template-forms-ui/exist-name-validator.directive'; import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module'; +import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; +import {LabeledFormFieldDirective} from '@common/shared/directive/labeled-form-field.directive'; @NgModule({ imports: [ @@ -40,7 +42,9 @@ import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module'; ScrollingModule, ReportsSharedModule, ExistNameValidatorDirective, - SharedPipesModule + SharedPipesModule, + MatProgressSpinnerModule, + LabeledFormFieldDirective, ], declarations: [ReportsPageComponent, ReportsListComponent, ReportsHeaderComponent, ReportDialogComponent, CreateNewReportFormComponent, ReportComponent], diff --git a/src/app/webapp-common/reports/reports.reducer.ts b/src/app/webapp-common/reports/reports.reducer.ts index a909d6c0..7460a278 100644 --- a/src/app/webapp-common/reports/reports.reducer.ts +++ b/src/app/webapp-common/reports/reports.reducer.ts @@ -77,7 +77,10 @@ export const reportsReducer = createReducer( on(setReportChanges, (state, action) => ({ ...state, report: {...state.report, ...action.changes}, - reports: state.reports?.map(report => report.id !== action.id ? report : {...report, ...action.changes}) + reports: (action.filterOut ? + state.reports?.filter(report => report.id != action.id) : + state.reports + )?.map(report => report.id !== action.id ? report : {...report, ...action.changes}) })), on(setArchive, (state, action) => ({...state, archive: action.archive, scroll: null, reports: null})), on(resetReports, (state) => ({ diff --git a/src/app/webapp-common/select-model/select-model.actions.ts b/src/app/webapp-common/select-model/select-model.actions.ts index 477c7f1b..d4114875 100755 --- a/src/app/webapp-common/select-model/select-model.actions.ts +++ b/src/app/webapp-common/select-model/select-model.actions.ts @@ -1,129 +1,41 @@ import {Action, createAction, props} from '@ngrx/store'; -import {TableModel} from '../models/shared/models.model'; +import {SelectedModel, TableModel} from '../models/shared/models.model'; import {ISmCol} from '../shared/ui-components/data/table/table.consts'; import {ModelsViewModesEnum} from '../models/models.consts'; import {SortMeta} from 'primeng/api'; -const SELECT_MODEL_PREFIX = 'SELECT_MODEL_'; +const SELECT_MODEL_PREFIX = '[select model]'; -//COMMANDS: -export const ARCHIVE_SELECTED_MODELS = SELECT_MODEL_PREFIX + 'ARCHIVE_SELECTED_MODELS'; -export const ADD_MANY_MODELS = SELECT_MODEL_PREFIX + 'ADD_MANY_MODELS'; -export const GET_NEXT_MODELS = SELECT_MODEL_PREFIX + 'GET_NEXT_MODELS'; -export const SET_MODELS = SELECT_MODEL_PREFIX + 'SET_MODELS'; -export const SET_NO_MORE_MODELS = SELECT_MODEL_PREFIX + 'SET_NO_MORE_MODELS'; -export const SET_SELECTED_MODELS = SELECT_MODEL_PREFIX + 'SET_SELECTED_MODELS'; -export const SET_VIEW_MODE = SELECT_MODEL_PREFIX + 'SET_VIEW_MODE'; -export const REMOVE_MANY_MODELS = SELECT_MODEL_PREFIX + 'REMOVE_MANY_MODELS'; -export const UPDATE_ONE_MODELS = SELECT_MODEL_PREFIX + 'UPDATE_ONE_MODELS'; -export const RESET_STATE = SELECT_MODEL_PREFIX + 'RESET_STATE'; +export const getNextModels = createAction(`${SELECT_MODEL_PREFIX} get next models`); +export const getSelectedModels = createAction(`${SELECT_MODEL_PREFIX} get selected models`, props<{selectedIds: string[]}>()); -//EVENTS: -export const ALL_PROJECTS_MODE_CHANGED = SELECT_MODEL_PREFIX + 'ALL_PROJECTS_MODE_CHANGED'; +export const setModels = createAction(`${SELECT_MODEL_PREFIX} set models`, props<{ models: Array }>()); +export const setSelectedModelsList = createAction(`${SELECT_MODEL_PREFIX} set selected models list`, props<{ models: Array }>()); -export const GLOBAL_FILTER_CHANGED = SELECT_MODEL_PREFIX + 'GLOBAL_FILTER_CHANGED'; -export const TABLE_SORT_CHANGED = SELECT_MODEL_PREFIX + 'TABLE_SORT_CHANGED'; -export const SET_TABLE_SORT = SELECT_MODEL_PREFIX + 'SET_TABLE_SORT'; -export const TABLE_FILTER_CHANGED = SELECT_MODEL_PREFIX + 'TABLE_FILTER_CHANGED'; +export const setNoMoreModels = createAction(`${SELECT_MODEL_PREFIX} set no more models`, props<{ noMore: boolean }>()); -export class GetNextModels implements Action { - readonly type = GET_NEXT_MODELS; -} +export const addModels = createAction(`${SELECT_MODEL_PREFIX} add many models`, props<{ models: Array }>()); -export class SetModels implements Action { - readonly type = SET_MODELS; +export const removeModels = createAction(`${SELECT_MODEL_PREFIX} remove many models`, props<{ models: string[] }>()); - constructor(public payload: Array) { - } -} +export const updateModel = createAction(`${SELECT_MODEL_PREFIX} update one models`, props<{ id: string; changes: Partial }>()); -export class SetNoMoreModels implements Action { - readonly type = SET_NO_MORE_MODELS; +export const setSelectedModels = createAction(`${SELECT_MODEL_PREFIX} set selected models`, props<{ models: any}>()); - constructor(public payload: boolean) { - } -} +export const tableSortChanged = createAction(`${SELECT_MODEL_PREFIX} table sort changed`, props<{ isShift: boolean; colId: ISmCol['id'] }>()); -export class AddModels implements Action { - readonly type = ADD_MANY_MODELS; +export const setTableSort = createAction(`${SELECT_MODEL_PREFIX} 'set table sort`, props<{ orders: SortMeta[] }>()); - constructor(public payload: Array) { - } -} +export const showArchive = createAction(`${SELECT_MODEL_PREFIX} show archive`, props<{showArchive: boolean}>()); +export const clearTableFilter = createAction(`${SELECT_MODEL_PREFIX} table filter clear`); +export const tableFilterChanged = createAction(`${SELECT_MODEL_PREFIX} table filter changed`, props<{ col: ISmCol; value: any }>()); -export class RemoveModels implements Action { - readonly type = REMOVE_MANY_MODELS; +export const globalFilterChanged = createAction(`${SELECT_MODEL_PREFIX} global filter changed`, props<{ filter: string }>()); - constructor(public payload: Array) { - } -} +export const setCurrentScrollId = createAction(SELECT_MODEL_PREFIX + 'set current scrollId', props<{ scrollId: string }>()); -export class UpdateModel implements Action { - readonly type = UPDATE_ONE_MODELS; +export const allProjectsModeChanged = createAction(`${SELECT_MODEL_PREFIX} all projects mode changed`, props<{ isAllProjects: boolean }>()); - constructor(public payload: { id: TableModel['id']; changes: Partial }) { - } -} +export const setViewMode = createAction(`${SELECT_MODEL_PREFIX} set view mode`, props<{ viewMode: ModelsViewModesEnum }>()); -export class SetSelectedModels implements Action { - public type = SET_SELECTED_MODELS; - - constructor(public payload: Array) { - } -} - -export const tableSortChanged = createAction( - TABLE_SORT_CHANGED, - props<{ isShift: boolean; colId: ISmCol['id'] }>() -); - -export const setTableSort = createAction( - SET_TABLE_SORT, - props<{ orders: SortMeta[] }>() -); - -export class TableFilterChanged implements Action { - public type = TABLE_FILTER_CHANGED; - - constructor(public payload: { col: ISmCol; value: any }) { - } -} - -export class GlobalFilterChanged implements Action { - public type = GLOBAL_FILTER_CHANGED; - - constructor(public payload: string) { - } -} - -export const setCurrentScrollId = createAction( - SELECT_MODEL_PREFIX + ' [set current scrollId]', - props<{scrollId: string}>() -); - -export class AllProjectsModeChanged implements Action { - public type = ALL_PROJECTS_MODE_CHANGED; - - constructor(public payload: boolean) { - } -} - -export class ArchivedSelectedModels implements Action { - public type = ARCHIVE_SELECTED_MODELS; -} - -export class SetViewMode implements Action { - public type = SET_VIEW_MODE; - public payload: { viewMode: ModelsViewModesEnum }; - - constructor(viewMode: ModelsViewModesEnum) { - this.payload = {viewMode}; - } -} - -export class ResetState implements Action { - readonly type = RESET_STATE; - - constructor() { - } -} +export const resetState = createAction(`${SELECT_MODEL_PREFIX} reset state`); diff --git a/src/app/webapp-common/select-model/select-model.component.html b/src/app/webapp-common/select-model/select-model.component.html index 396522e1..314b080a 100755 --- a/src/app/webapp-common/select-model/select-model.component.html +++ b/src/app/webapp-common/select-model/select-model.component.html @@ -1,4 +1,4 @@ - +
-
+
+ + +
diff --git a/src/app/webapp-common/select-model/select-model.component.scss b/src/app/webapp-common/select-model/select-model.component.scss index 004fa7b6..bcf41775 100755 --- a/src/app/webapp-common/select-model/select-model.component.scss +++ b/src/app/webapp-common/select-model/select-model.component.scss @@ -9,10 +9,18 @@ } .model-table-container { - height: 53vh; - width: 85vw; + display: flex; + flex-direction: column; + gap: 18px; + height: calc(100% - 164px); + width: 92vw; } + .buttons { + display: flex; + justify-content: center; + gap: 16px; + } } ::ng-deep p-table table { diff --git a/src/app/webapp-common/select-model/select-model.component.ts b/src/app/webapp-common/select-model/select-model.component.ts index 71a731ac..6e0cd9d5 100755 --- a/src/app/webapp-common/select-model/select-model.component.ts +++ b/src/app/webapp-common/select-model/select-model.component.ts @@ -1,42 +1,36 @@ -import {Component, EventEmitter, OnDestroy, OnInit, ViewChild} from '@angular/core'; +import {ChangeDetectionStrategy, Component, EventEmitter, Inject, OnDestroy, OnInit, ViewChild} from '@angular/core'; import {Store} from '@ngrx/store'; import * as actions from './select-model.actions'; import { - selectGlobalFilter, - selectIsAllProjectsMode, - selectModelsList, - selectNoMoreModels, - selectSelectedModels, - selectTableFilters, - selectTableSortFields, - selectViewMode + selectGlobalFilter, selectIsAllProjectsMode, selectModels, selectNoMoreModels, selectSelectedModels, selectSelectedModelsList, selectTableFilters, selectTableSortFields, selectViewMode } from './select-model.reducer'; -import {combineLatest, Observable} from 'rxjs'; -import {MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {combineLatest, Observable, Subscription} from 'rxjs'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {ConfirmDialogComponent} from '../shared/ui-components/overlay/confirm-dialog/confirm-dialog.component'; import {ISmCol, TableSortOrderEnum} from '../shared/ui-components/data/table/table.consts'; import {SelectedModel} from '../models/shared/models.model'; import {MODELS_TABLE_COLS, ModelsViewModesEnum} from '../models/models.consts'; import {FilterMetadata} from 'primeng/api/filtermetadata'; -import { - selectAllProjectsUsers, - selectProjectSystemTags, - selectProjectUsers, - selectRootProjects, - selectSelectedProject -} from '../core/reducers/projects.reducer'; +import {selectAllProjectsUsers, selectProjectSystemTags, selectProjectUsers, selectSelectedProject, selectTablesFilterProjectsOptions} from '../core/reducers/projects.reducer'; import {selectModelsFrameworks, selectModelsTags} from '../models/reducers'; import {User} from '~/business-logic/model/users/user'; import * as modelsActions from '../models/actions/models-view.actions'; import {SortMeta} from 'primeng/api'; import {ModelsTableComponent} from '@common/models/shared/models-table/models-table.component'; -import {map} from 'rxjs/operators'; +import {map, tap} from 'rxjs/operators'; import {Project} from '~/business-logic/model/projects/models'; +import {getTablesFilterProjectsOptions, resetTablesFilterProjectsOptions, setTablesFilterProjectsOptions} from '@common/core/actions/projects.actions'; +import {clearTableFilter, setSelectedModels, showArchive} from './select-model.actions'; +import {unionBy} from 'lodash-es'; +import {compareLimitations} from '@common/shared/entity-page/footer-items/compare-footer-item'; +import {addMessage} from '@common/core/actions/layout.actions'; +import {MESSAGES_SEVERITY} from '@common/constants'; @Component({ - selector : 'sm-select-model', + selector: 'sm-select-model', templateUrl: './select-model.component.html', - styleUrls : ['./select-model.component.scss'] + styleUrls: ['./select-model.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush }) export class SelectModelComponent implements OnInit, OnDestroy { @@ -45,7 +39,7 @@ export class SelectModelComponent implements OnInit, OnDestroy { public tableSortOrder$: Observable; public noMoreModels$: Observable; public isAllProjects$: Observable; - public tableFilters$: Observable<{[s: string]: FilterMetadata}>; + public tableFilters$: Observable<{ [s: string]: FilterMetadata }>; public searchValue$: Observable; public selectedModels$: Observable>; public viewMode$: Observable; @@ -56,83 +50,136 @@ export class SelectModelComponent implements OnInit, OnDestroy { public selectedProject$: Observable; public projectsOptions$: Observable; public frameworks$: Observable; + private subs = new Subscription(); - constructor(private store: Store, public dialogRef: MatDialogRef) { - this.models$ = this.store.select(selectModelsList); + private isAllProjects: any; + public selectedProject: Project; + private selectedModels: Array; + + constructor(private store: Store, + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: { + selectionMode: 'multiple' | 'single' | null; + selectedModels: string[]; + header: string; + hideShowArchived: boolean; + }) { + // this.models$ = this.store.select(selectModelsList); + this.models$ = combineLatest([ + this.store.select(selectModels), + this.store.select(selectSelectedModelsList), + ]).pipe(map(([models, selectedModels]) => unionBy(selectedModels, models, 'id'))); this.tableSortFields$ = this.store.select(selectTableSortFields); - this.tableFilters$ = this.store.select(selectTableFilters); - this.selectedModels$ = this.store.select(selectSelectedModels); - this.viewMode$ = this.store.select(selectViewMode); - this.searchValue$ = this.store.select(selectGlobalFilter); - this.noMoreModels$ = this.store.select(selectNoMoreModels); - this.isAllProjects$ = this.store.select(selectIsAllProjectsMode); + this.tableFilters$ = this.store.select(selectTableFilters); + this.selectedModels$ = this.store.select(selectSelectedModels).pipe(tap(models => this.selectedModels = models)); + this.viewMode$ = this.store.select(selectViewMode); + this.searchValue$ = this.store.select(selectGlobalFilter); + this.noMoreModels$ = this.store.select(selectNoMoreModels); + this.isAllProjects$ = this.store.select(selectIsAllProjectsMode); this.users$ = combineLatest([ this.isAllProjects$, this.store.select(selectProjectUsers), this.store.select(selectAllProjectsUsers), - ]).pipe(map(([all, projUsers, allUsers]) => all ? allUsers : projUsers)); + ]).pipe( + tap(([all]) => this.isAllProjects = all), + map(([all, projUsers, allUsers]) => all ? allUsers : projUsers)); this.tags$ = this.store.select(selectModelsTags); this.systemTags$ = this.store.select(selectProjectSystemTags); - this.selectedProject$ = this.store.select(selectSelectedProject); + this.subs.add(this.store.select(selectSelectedProject).subscribe(selectedProject => this.selectedProject = selectedProject)); this.frameworks$ = this.store.select(selectModelsFrameworks); - this.projectsOptions$ = combineLatest([this.isAllProjects$, this.selectedProject$, this.store.select(selectRootProjects)]).pipe(map(([isAllProjectsMode,selectedProject, rootProjects]) => { - if (selectedProject) { - if (isAllProjectsMode) { - return rootProjects; - } else { - return [selectedProject].concat(selectedProject?.sub_projects ?? []); - } - } else { - return []; - } - })); + this.projectsOptions$ = this.store.select(selectTablesFilterProjectsOptions); + + // if (data.selectedModels) { + // this.store.dispatch(setSelectedModels({models: data.selectedModels.map(modelId => ({id: modelId}))})); + // } } @ViewChild(ModelsTableComponent) table: ModelsTableComponent; ngOnInit() { - this.store.dispatch(new actions.GetNextModels()); + this.store.dispatch(resetTablesFilterProjectsOptions()); + this.store.dispatch(actions.getNextModels()); + this.data.selectedModels && this.store.dispatch(actions.getSelectedModels({selectedIds: this.data.selectedModels})); this.store.dispatch(modelsActions.getAllProjectsFrameworks()); this.store.dispatch(modelsActions.getTagsForAllProjects()); window.setTimeout(() => this.table.table.rowRightClick = new EventEmitter()); } ngOnDestroy(): void { - this.store.dispatch(new actions.ResetState()); + this.store.dispatch(resetTablesFilterProjectsOptions()); + this.store.dispatch(actions.resetState()); + this.subs.unsubscribe(); } - closeDialog(model: SelectedModel) { - if (model) { - return this.dialogRef.close(model); + closeDialog(modelId: string) { + if (modelId) { + return this.dialogRef.close(modelId); } return this.dialogRef.close(null); } + closeDialogMultiple() { + return this.dialogRef.close(this.selectedModels.map( model => model.id)); + } getNextModels() { - this.store.dispatch(new actions.GetNextModels()); + this.store.dispatch(actions.getNextModels()); } sortedChanged(sort: { isShift: boolean; colId: ISmCol['id'] }) { this.store.dispatch(actions.tableSortChanged({colId: sort.colId, isShift: sort.isShift})); } - filterChanged(filter: {col: ISmCol; value: any}) { - this.store.dispatch(new actions.TableFilterChanged({col: filter.col, value: filter.value})); + filterChanged(filter: { col: ISmCol; value: any }) { + this.store.dispatch(actions.tableFilterChanged({col: filter.col, value: filter.value})); } onSearchValueChanged(value: string) { - this.store.dispatch(new actions.GlobalFilterChanged(value)); + this.store.dispatch(actions.globalFilterChanged({filter: value})); } - modelSelectionChanged(event: {model: SelectedModel}) { - this.closeDialog(event.model); + modelSelectionChanged(event: { model: SelectedModel }) { + if (this.data.selectionMode !== 'multiple') { + this.closeDialog(event.model?.id); + } + } + + modelsSelectionChanged(models: SelectedModel[]) { + if (this.data.selectionMode !== 'multiple') { + return; + } + if (models.length === 0) { + this.store.dispatch(addMessage(MESSAGES_SEVERITY.WARN, 'Compare module should include at least one model')); + return; + } + if (models.length <= compareLimitations) { + this.store.dispatch(setSelectedModels({models})); + } else { + this.store.dispatch(addMessage(MESSAGES_SEVERITY.WARN, compareLimitations + ' or fewer models can be compared')); + } } onIsAllProjectsChanged(isAllProjects: boolean) { - this.store.dispatch(new actions.AllProjectsModeChanged(isAllProjects)); - isAllProjects? this.store.dispatch(modelsActions.getTagsForAllProjects()): this.store.dispatch(modelsActions.getTags()); - isAllProjects? this.store.dispatch(modelsActions.getAllProjectsFrameworks()): this.store.dispatch(modelsActions.getFrameworks()); + this.store.dispatch(resetTablesFilterProjectsOptions()); + this.store.dispatch(actions.allProjectsModeChanged({isAllProjects})); + isAllProjects ? this.store.dispatch(modelsActions.getTagsForAllProjects()) : this.store.dispatch(modelsActions.getTags()); + isAllProjects ? this.store.dispatch(modelsActions.getAllProjectsFrameworks()) : this.store.dispatch(modelsActions.getFrameworks()); } + filterSearchChanged({value}: { colId: string; value: {value: string; loadMore?: boolean} }) { + if (this.isAllProjects) { + ! value.loadMore && this.store.dispatch(resetTablesFilterProjectsOptions()); + this.store.dispatch(getTablesFilterProjectsOptions({searchString: value.value || '', loadMore: value.loadMore})); + } else { + this.store.dispatch(setTablesFilterProjectsOptions({projects: this.selectedProject ? [this.selectedProject, ...this.selectedProject?.sub_projects] : [], scrollId: null})); + } + } + + clearFilters() { + this.store.dispatch(clearTableFilter()); + } + + showArchives($event: boolean) { + this.store.dispatch(showArchive({showArchive: $event})); + } } diff --git a/src/app/webapp-common/select-model/select-model.effects.ts b/src/app/webapp-common/select-model/select-model.effects.ts index 46c8bc20..0e7dc493 100755 --- a/src/app/webapp-common/select-model/select-model.effects.ts +++ b/src/app/webapp-common/select-model/select-model.effects.ts @@ -4,7 +4,7 @@ import {Actions, createEffect, ofType} from '@ngrx/effects'; import * as actions from './select-model.actions'; import * as exSelectors from './select-model.reducer'; import {MODELS_PAGE_SIZE} from '../models/models.consts'; -import {catchError, mergeMap, map, switchMap, withLatestFrom} from 'rxjs/operators'; +import {catchError, mergeMap, map, switchMap, withLatestFrom, debounceTime} from 'rxjs/operators'; import {get} from 'lodash-es'; import {MODEL_TAGS, MODELS_TABLE_COL_FIELDS} from '../models/shared/models.const'; import {IModelsViewState} from '../models/reducers/models-view.reducer'; @@ -20,16 +20,18 @@ import {SortMeta} from 'primeng/api'; import {encodeOrder} from '../shared/utils/tableParamEncode'; import {selectTableSortFields} from './select-model.reducer'; import {escapeRegex} from '@common/shared/utils/escape-regex'; +import {getNextModels, getSelectedModels, setSelectedModels, setSelectedModelsList, tableFilterChanged, tableSortChanged} from './select-model.actions'; @Injectable() export class SelectModelEffects { + private selectModelsOnlyFields = ['created', 'framework', 'id', 'labels', 'name', 'ready', 'tags', 'system_tags', 'task.name', 'uri', 'user.name', 'parent', 'design', 'company', 'project.name', 'comment', 'last_update']; constructor(private actions$: Actions, private store: Store, private apiModels: ApiModelsService) { } activeLoader = createEffect(() => this.actions$.pipe( - ofType(actions.GET_NEXT_MODELS, actions.GLOBAL_FILTER_CHANGED, - actions.ALL_PROJECTS_MODE_CHANGED, actions.TABLE_SORT_CHANGED, actions.TABLE_FILTER_CHANGED), + ofType(actions.getNextModels, actions.globalFilterChanged, + actions.allProjectsModeChanged, actions.tableSortChanged, actions.tableFilterChanged), map(action => activeLoader(action.type)) )); @@ -43,12 +45,13 @@ export class SelectModelEffects { )); modelsFilterChanged = createEffect(() => this.actions$.pipe( - ofType(actions.GLOBAL_FILTER_CHANGED, actions.ALL_PROJECTS_MODE_CHANGED, actions.TABLE_SORT_CHANGED, actions.TABLE_FILTER_CHANGED), + ofType(actions.globalFilterChanged, actions.allProjectsModeChanged, actions.tableSortChanged, actions.tableFilterChanged, actions.showArchive, actions.clearTableFilter), + debounceTime(0), // Let other effects finish first switchMap((action) => this.fetchModels$(null) .pipe( mergeMap(res => [ - new actions.SetNoMoreModels((res.models.length < MODELS_PAGE_SIZE)), - new actions.SetModels(res.models), + actions.setNoMoreModels({noMore: res.models.length < MODELS_PAGE_SIZE}), + actions.setModels({models: res.models}), actions.setCurrentScrollId({scrollId: res.scroll_id}), deactivateLoader(action.type) ]), @@ -58,14 +61,14 @@ export class SelectModelEffects { )); getModels = createEffect(() => this.actions$.pipe( - ofType(actions.GET_NEXT_MODELS), + ofType(getNextModels), withLatestFrom(this.store.select(exSelectors.selectCurrentScrollId)), switchMap(([action, scrollId]) => this.fetchModels$(scrollId) .pipe( mergeMap(res => [ - new actions.SetNoMoreModels((res.models.length < MODELS_PAGE_SIZE)), - new actions.AddModels(res.models), + actions.setNoMoreModels({noMore: res.models.length < MODELS_PAGE_SIZE}), + actions.addModels({models: res.models}), actions.setCurrentScrollId({scrollId: res.scroll_id}), deactivateLoader(action.type) ]), @@ -74,29 +77,44 @@ export class SelectModelEffects { ) )); + getSelectedModels = createEffect(() => this.actions$.pipe( + ofType(getSelectedModels), + switchMap(action => this.apiModels.modelsGetAllEx({ + id: action.selectedIds, + // eslint-disable-next-line @typescript-eslint/naming-convention + only_fields: this.selectModelsOnlyFields + })), + mergeMap(res => [ + setSelectedModelsList({models: res.models}), + setSelectedModels({models: res.models}) + ]) + )); + getGetAllQuery( scrollId: string, projectId: string, searchQuery: string, isAllProjects: boolean, - orderFields: SortMeta[], tableFilters: { [s: string]: FilterMetadata } + orderFields: SortMeta[], tableFilters: { [s: string]: FilterMetadata }, showArchived: boolean ): ModelsGetAllExRequest { - const userFilter = get(tableFilters,[MODELS_TABLE_COL_FIELDS.USER, 'value']); + const userFilter = get(tableFilters, [MODELS_TABLE_COL_FIELDS.USER, 'value']); const tagsFilter = tableFilters?.[MODELS_TABLE_COL_FIELDS.TAGS]?.value; - const projectFilter = get(tableFilters,[MODELS_TABLE_COL_FIELDS.PROJECT, 'value']); + const projectFilter = get(tableFilters, [MODELS_TABLE_COL_FIELDS.PROJECT, 'value']); const systemTags = tableFilters?.system_tags?.value; - const systemTagsFilter = ['-' + MODEL_TAGS.HIDDEN].concat(systemTags ? systemTags : []); + const systemTagsFilter = (showArchived ? [] : + false ? ['__$and', MODEL_TAGS.HIDDEN] : ['__$and', '__$not', MODEL_TAGS.HIDDEN]).concat(systemTags ? systemTags : []); return { _any_: searchQuery ? { pattern: escapeRegex(searchQuery), fields: ['id', 'name', 'framework', 'system_tags', 'uri'] } : undefined, /* eslint-disable @typescript-eslint/naming-convention */ - project: projectFilter ? projectFilter : ((isAllProjects || !projectId || projectId === '*') ? undefined : [projectId]), + project: projectFilter ? projectFilter : ((isAllProjects || !projectId || projectId === '*') ? undefined : [projectId]), scroll_id: scrollId || null, // null to create new scroll (undefined doesn't generate scroll) size: MODELS_PAGE_SIZE, order_by: encodeOrder(orderFields), tags: (tagsFilter && tagsFilter.length > 0) ? tagsFilter : [], system_tags: (systemTagsFilter && systemTagsFilter.length > 0) ? systemTagsFilter : [], - only_fields: ['created', 'framework', 'id', 'labels', 'name', 'ready', 'tags', 'system_tags', 'task.name', 'uri', 'user.name', 'parent', 'design', 'company', 'project.name', 'comment', 'last_update'], - ready: true, + only_fields: this.selectModelsOnlyFields, + ...(![0, 2].includes(tableFilters?.[MODELS_TABLE_COL_FIELDS.READY]?.value.length) && !!tableFilters && {ready: tableFilters?.[MODELS_TABLE_COL_FIELDS.READY]?.value[0] === 'true'}), + ...(!window.location.href.includes('compare') && {ready: true}), framework: tableFilters?.[MODELS_TABLE_COL_FIELDS.FRAMEWORK]?.value ?? undefined, user: (userFilter && userFilter.length > 0) ? userFilter : undefined /* eslint-enable @typescript-eslint/naming-convention */ @@ -113,9 +131,10 @@ export class SelectModelEffects { this.store.select(exSelectors.selectGlobalFilter), this.store.select(exSelectors.selectTableSortFields), this.store.select(exSelectors.selectTableFilters), + this.store.select(exSelectors.selectShowArchive), ), - switchMap(([scrollId, projectId, isAllProjects, gb, sortFields, filters]) => - this.apiModels.modelsGetAllEx(this.getGetAllQuery(scrollId, projectId, gb, isAllProjects, sortFields, filters)) + switchMap(([scrollId, projectId, isAllProjects, gb, sortFields, filters, showArchive]) => + this.apiModels.modelsGetAllEx(this.getGetAllQuery(scrollId, projectId, gb, isAllProjects, sortFields, filters, showArchive)) ) ); } diff --git a/src/app/webapp-common/select-model/select-model.reducer.ts b/src/app/webapp-common/select-model/select-model.reducer.ts index 8374b2bf..c0a4947e 100755 --- a/src/app/webapp-common/select-model/select-model.reducer.ts +++ b/src/app/webapp-common/select-model/select-model.reducer.ts @@ -10,6 +10,7 @@ import {SortMeta} from 'primeng/api'; export interface SelectModelState { models: SelectedModel[]; + selectedModelsList: SelectedModel[]; selectedModels: SelectedModel[]; noMoreModels: boolean; selectedModelSource: string; @@ -20,10 +21,12 @@ export interface SelectModelState { tableSortFields: SortMeta[]; scrollId: string; globalFilter: string; + showArchive: boolean; } const selectModelInitState: SelectModelState = { models: [], + selectedModelsList: [], selectedModels: [], noMoreModels: false, selectedModelSource: null, @@ -34,54 +37,62 @@ const selectModelInitState: SelectModelState = { tableSortFields: [{field: MODELS_TABLE_COL_FIELDS.CREATED, order: TABLE_SORT_ORDER.DESC}], scrollId: null, globalFilter: null, + showArchive: null }; export function selectModelReducer(state: SelectModelState = selectModelInitState, action): SelectModelState { switch (action.type) { - case actions.RESET_STATE: + case actions.resetState.type: return {...selectModelInitState}; - case actions.ADD_MANY_MODELS: - return {...state, models: state.models.concat(action.payload)}; - case actions.REMOVE_MANY_MODELS: - return {...state, models: state.models.filter(exp => !action.payload.includes(exp.id))}; - case actions.UPDATE_ONE_MODELS: + case actions.addModels.type: + return {...state, models: state.models.concat(action.models)}; + case actions.removeModels.type: + return {...state, models: state.models.filter(exp => !action.models.includes(exp.id))}; + case actions.updateModel.type: return { ...state, models: - state.models.map(ex => ex.id === action.payload.id ? {...ex, ...action.payload.changes} : ex) + state.models.map(ex => ex.id === action.id ? {...ex, ...action.changes} : ex) }; - case actions.SET_MODELS: - return {...state, models: action.payload}; - case actions.SET_NO_MORE_MODELS: - return {...state, noMoreModels: action.payload}; + case actions.setModels.type: + return {...state, models: action.models}; + case actions.setSelectedModelsList.type: + return {...state, selectedModelsList: action.models}; + case actions.setNoMoreModels.type: + return {...state, noMoreModels: action.noMore}; case actions.setCurrentScrollId.type: return {...state, scrollId: action.scrollId}; - case actions.SET_SELECTED_MODELS: - return {...state, selectedModels: action.payload}; - case actions.ALL_PROJECTS_MODE_CHANGED: - return {...state, allProjectsMode: action.payload}; - case actions.SET_VIEW_MODE: - return {...state, viewMode: action.payload}; - case actions.GLOBAL_FILTER_CHANGED: - return {...state, globalFilter: action.payload}; + case actions.setSelectedModels.type: + return {...state, selectedModels: action.models}; + case actions.allProjectsModeChanged.type: + return {...state, allProjectsMode: action.isAllProjects}; + case actions.setViewMode.type: + return {...state, viewMode: action.viewMode}; + case actions.globalFilterChanged.type: + return {...state, globalFilter: action.filter}; case actions.setTableSort.type: return {...state, tableSortFields: action.orders}; - case actions.TABLE_FILTER_CHANGED: + case actions.clearTableFilter.type: + return {...state, tableFilters: null}; + case actions.tableFilterChanged.type: return { ...state, tableFilters: { ...state.tableFilters, - [action.payload.col.id]: {value: action.payload.value, matchMode: action.payload.col.filterMatchMode} + [action.col.id]: {value: action.value, matchMode: action.col.filterMatchMode} } }; default: return state; + case actions.showArchive.type: + return {...state, showArchive: action.showArchive}; } } export const models = createFeatureSelector('selectModel'); -export const selectModelsList = createSelector(models, (state) => state ? state.models : []); +export const selectModels = createSelector(models, (state) => state ? state.models : []); +export const selectSelectedModelsList = createSelector(models, (state) => state ? state.selectedModelsList : []); export const selectCurrentScrollId = createSelector(models, (state): string => state.scrollId); export const selectGlobalFilter = createSelector(models, (state): string => state.globalFilter); export const selectTableSortFields = createSelector(models, (state): SortMeta[] => state.tableSortFields); @@ -90,3 +101,4 @@ export const selectIsAllProjectsMode = createSelector(models, (state): boolean = export const selectViewMode = createSelector(models, (state): ModelsViewModesEnum => state.viewMode); export const selectSelectedModels = createSelector(models, (state): Array => state.selectedModels); export const selectNoMoreModels = createSelector(models, (state): boolean => state.noMoreModels); +export const selectShowArchive = createSelector(models, (state): boolean => state.showArchive); diff --git a/src/app/webapp-common/settings/admin/admin-credential-table.base.ts b/src/app/webapp-common/settings/admin/admin-credential-table.base.ts index 630fc8d5..0779a1b3 100755 --- a/src/app/webapp-common/settings/admin/admin-credential-table.base.ts +++ b/src/app/webapp-common/settings/admin/admin-credential-table.base.ts @@ -1,5 +1,5 @@ import {EventEmitter, Input, Output, Directive} from '@angular/core'; -import {MatLegacyDialog as MatDialog, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MatDialog, MatDialogRef} from '@angular/material/dialog'; import {ConfirmDialogComponent} from '../../shared/ui-components/overlay/confirm-dialog/confirm-dialog.component'; import {ICONS} from '../../constants'; import {CredentialKey} from '~/business-logic/model/auth/credentialKey'; diff --git a/src/app/webapp-common/settings/admin/admin-credential-table/admin-credential-table.component.html b/src/app/webapp-common/settings/admin/admin-credential-table/admin-credential-table.component.html index 25bc86d6..61c5236d 100755 --- a/src/app/webapp-common/settings/admin/admin-credential-table/admin-credential-table.component.html +++ b/src/app/webapp-common/settings/admin/admin-credential-table/admin-credential-table.component.html @@ -12,10 +12,10 @@ {{credential.label}} {{credential.access_key}} - {{credential?.last_used ? (credential.last_used | date : timeFormatString): 'Never'}} + {{credential?.last_used ? (credential.last_used | date : timeFormatString): 'Never'}} {{credential?.last_used_from ? credential?.last_used_from : 'Not available'}} -
+
diff --git a/src/app/webapp-common/settings/admin/admin-credential-table/admin-credential-table.component.ts b/src/app/webapp-common/settings/admin/admin-credential-table/admin-credential-table.component.ts index d72acc83..7f72df35 100755 --- a/src/app/webapp-common/settings/admin/admin-credential-table/admin-credential-table.component.ts +++ b/src/app/webapp-common/settings/admin/admin-credential-table/admin-credential-table.component.ts @@ -1,5 +1,5 @@ import {Component} from '@angular/core'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {AdminCredentialTableBaseDirective} from '../admin-credential-table.base'; import {TIME_FORMAT_STRING} from '@common/constants'; diff --git a/src/app/webapp-common/settings/admin/admin-dialog-template/admin-dialog-template.component.html b/src/app/webapp-common/settings/admin/admin-dialog-template/admin-dialog-template.component.html index 9e026ef5..c560fbda 100755 --- a/src/app/webapp-common/settings/admin/admin-dialog-template/admin-dialog-template.component.html +++ b/src/app/webapp-common/settings/admin/admin-dialog-template/admin-dialog-template.component.html @@ -1,12 +1,12 @@
- Access key - {{newCredential?.access_key}} +
Access key
+
{{newCredential?.access_key}}
- Secret key - {{newCredential?.secret_key}} +
Secret key
+
{{newCredential?.secret_key}}
@@ -53,7 +53,7 @@
- + diff --git a/src/app/webapp-common/settings/admin/admin-dialog-template/admin-dialog-template.component.scss b/src/app/webapp-common/settings/admin/admin-dialog-template/admin-dialog-template.component.scss index 8a180285..accea478 100755 --- a/src/app/webapp-common/settings/admin/admin-dialog-template/admin-dialog-template.component.scss +++ b/src/app/webapp-common/settings/admin/admin-dialog-template/admin-dialog-template.component.scss @@ -11,6 +11,9 @@ $credentialBaseHeight: 252px; } .cred-row { + display: flex; + flex-direction: row; + align-items: center; border-bottom: 1px solid $blue-100; .label { @@ -122,7 +125,6 @@ form { } .label-button { - height: 38px; + height: 36px; flex: 1 0 152px; - margin-top: 3px; } diff --git a/src/app/webapp-common/settings/admin/admin-footer/admin-footer.component.scss b/src/app/webapp-common/settings/admin/admin-footer/admin-footer.component.scss index b675de9c..89bd6241 100644 --- a/src/app/webapp-common/settings/admin/admin-footer/admin-footer.component.scss +++ b/src/app/webapp-common/settings/admin/admin-footer/admin-footer.component.scss @@ -2,6 +2,8 @@ :host { footer { + display: flex; + justify-content: space-between; padding: 18px 24px; height: 64px; border-top: $blue-500 solid 1px; diff --git a/src/app/webapp-common/settings/admin/admin.component.scss b/src/app/webapp-common/settings/admin/admin.component.scss index 79d22c09..23fef23c 100644 --- a/src/app/webapp-common/settings/admin/admin.component.scss +++ b/src/app/webapp-common/settings/admin/admin.component.scss @@ -31,20 +31,46 @@ $tab-width: 15vw; } - + .toggle-title { + --mdc-theme-text-primary-on-background: #{$blue-200}; + margin-bottom: 8px; + } .body { flex: 1; padding: 0 24px; } + .read-only-section { + border-radius: 4px; + border: solid 1px $blue-500; + background-color: $blue-650; + padding: 16px; + + .read-only-title { + color: $blue-200; + font-weight: 500; + margin-bottom: 12px; + } + } + + .vault-group { + display: block; + color: $blue-280; + margin-bottom: 6px; + + &:hover { + color: white; + text-decoration: underline; + } + } + .title { display: flex; align-items: center; color: $white; font-size: 16px; text-transform: uppercase; - margin: 0 0 6px 0; i { color: $blue-300; &:hover { diff --git a/src/app/webapp-common/settings/admin/profile-key-storage/profile-key-storage.component.html b/src/app/webapp-common/settings/admin/profile-key-storage/profile-key-storage.component.html index 666dcbd0..5d9b44c0 100644 --- a/src/app/webapp-common/settings/admin/profile-key-storage/profile-key-storage.component.html +++ b/src/app/webapp-common/settings/admin/profile-key-storage/profile-key-storage.component.html @@ -1,8 +1,8 @@
WEB APP CLOUD ACCESS
diff --git a/src/app/webapp-common/settings/admin/profile-preferences/profile-preferences.component.html b/src/app/webapp-common/settings/admin/profile-preferences/profile-preferences.component.html index 2f4e3767..28f977e1 100644 --- a/src/app/webapp-common/settings/admin/profile-preferences/profile-preferences.component.html +++ b/src/app/webapp-common/settings/admin/profile-preferences/profile-preferences.component.html @@ -4,34 +4,39 @@ *ngIf="admin || usage.shown" (change)="statsChange($event)" [checked]="show$ | async" - >Show Hidden Projects + color="accent" + >Show Hidden Projects Don’t show ClearML examples - Disable HiDPI browser scale override - Disable HiDPI browser scale override + Reload to apply - Don’t show pro tips periodically + [checked]="(neverShowTipsAgain$ | async)?.includes(popupId)" + color="accent" + >Don’t show pro tips periodically
- Hide specific container arguments - Hide specific container arguments + diff --git a/src/app/webapp-common/settings/admin/profile-preferences/profile-preferences.component.scss b/src/app/webapp-common/settings/admin/profile-preferences/profile-preferences.component.scss index 901190c2..24471e31 100644 --- a/src/app/webapp-common/settings/admin/profile-preferences/profile-preferences.component.scss +++ b/src/app/webapp-common/settings/admin/profile-preferences/profile-preferences.component.scss @@ -26,7 +26,6 @@ position: relative; flex-direction: column; margin-top: 0; - mat-slide-toggle, sm-usage-stats { margin-bottom: 12px; diff --git a/src/app/webapp-common/settings/admin/profile-preferences/profile-preferences.component.ts b/src/app/webapp-common/settings/admin/profile-preferences/profile-preferences.component.ts index cdba6d69..9e23b2d1 100644 --- a/src/app/webapp-common/settings/admin/profile-preferences/profile-preferences.component.ts +++ b/src/app/webapp-common/settings/admin/profile-preferences/profile-preferences.component.ts @@ -1,5 +1,5 @@ import {Component, OnDestroy} from '@angular/core'; -import {MatLegacySlideToggleChange as MatSlideToggleChange} from '@angular/material/legacy-slide-toggle'; +import {MatSlideToggleChange} from '@angular/material/slide-toggle'; import {neverShowPopupAgain, setHideRedactedArguments} from '@common/core/actions/layout.actions'; import {Store} from '@ngrx/store'; import {popupId} from '@common/shared/services/tips.service'; @@ -10,7 +10,7 @@ import {filter} from 'rxjs/operators'; import {Observable, Subscription} from 'rxjs'; import {AuthEditUserRequest} from '~/business-logic/model/auth/authEditUserRequest'; import RoleEnum = AuthEditUserRequest.RoleEnum; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {RedactedArgumentsDialogComponent} from '../redacted-arguments-dialog/redacted-arguments-dialog.component'; import { selectHideExamples, diff --git a/src/app/webapp-common/settings/admin/redacted-arguments-dialog/redacted-arguments-dialog.component.ts b/src/app/webapp-common/settings/admin/redacted-arguments-dialog/redacted-arguments-dialog.component.ts index e6ceb042..605b1ffd 100644 --- a/src/app/webapp-common/settings/admin/redacted-arguments-dialog/redacted-arguments-dialog.component.ts +++ b/src/app/webapp-common/settings/admin/redacted-arguments-dialog/redacted-arguments-dialog.component.ts @@ -1,5 +1,5 @@ import {Component, OnDestroy, OnInit} from '@angular/core'; -import {MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MatDialogRef} from '@angular/material/dialog'; import {Store} from '@ngrx/store'; import {setRedactedArguments} from '@common/core/actions/layout.actions'; import {selectRedactedArguments} from '@common/core/reducers/view.reducer'; diff --git a/src/app/webapp-common/settings/admin/s3-access/s3-access.component.html b/src/app/webapp-common/settings/admin/s3-access/s3-access.component.html index d4fd7f19..94f3ef66 100755 --- a/src/app/webapp-common/settings/admin/s3-access/s3-access.component.html +++ b/src/app/webapp-common/settings/admin/s3-access/s3-access.component.html @@ -25,7 +25,7 @@
- + @@ -36,7 +36,7 @@
diff --git a/src/app/webapp-common/settings/settings.component.scss b/src/app/webapp-common/settings/settings.component.scss index e863d13b..4adbe1ca 100644 --- a/src/app/webapp-common/settings/settings.component.scss +++ b/src/app/webapp-common/settings/settings.component.scss @@ -8,14 +8,14 @@ border-right: 1px solid $blue-500; width: 220px; } - .mat-list-item { - color: $blue-200; - font-size: 14px; - padding-left: 8px; // mat-list-item has padding 0 16px - height: 40px; + .mat-mdc-list-item { + --mdc-list-list-item-label-text-color: #{$blue-200}; + --mdc-theme-text-primary-on-background: #{$blue-200}; + + padding-left: 24px; &.active { - background-color: $blue-500; - color: white; + --mdc-list-list-item-container-color: #{$blue-500}; + --mdc-theme-text-primary-on-background: white; } &:hover { background-color: $blue-650; @@ -34,7 +34,6 @@ .content { height: 100%; width: 100%; - max-width: 1660px; } } } diff --git a/src/app/webapp-common/shared/components/base-context-menu/base-context-menu.component.ts b/src/app/webapp-common/shared/components/base-context-menu/base-context-menu.component.ts index 174f19bd..0534d178 100644 --- a/src/app/webapp-common/shared/components/base-context-menu/base-context-menu.component.ts +++ b/src/app/webapp-common/shared/components/base-context-menu/base-context-menu.component.ts @@ -1,5 +1,5 @@ import {Component, ElementRef, EventEmitter, HostListener, Input, OnDestroy, Output, ViewChild} from '@angular/core'; -import {MatLegacyMenuTrigger as MatMenuTrigger} from '@angular/material/legacy-menu'; +import {MatMenuTrigger} from '@angular/material/menu'; import {TagsMenuComponent} from '../../ui-components/tags/tags-menu/tags-menu.component'; import {Store} from '@ngrx/store'; import {deactivateEdit, activateEdit} from 'app/webapp-common/experiments/actions/common-experiments-info.actions'; diff --git a/src/app/webapp-common/shared/components/charts/donut/donut.component.html b/src/app/webapp-common/shared/components/charts/donut/donut.component.html index 9953be02..3daef803 100644 --- a/src/app/webapp-common/shared/components/charts/donut/donut.component.html +++ b/src/app/webapp-common/shared/components/charts/donut/donut.component.html @@ -1,4 +1,4 @@ -
+
Loading
-
No data to show
diff --git a/src/app/webapp-common/shared/components/charts/scatter-plot/scatter-plot.component.scss b/src/app/webapp-common/shared/components/charts/scatter-plot/scatter-plot.component.scss index 9f3e8dc3..15bef8b5 100644 --- a/src/app/webapp-common/shared/components/charts/scatter-plot/scatter-plot.component.scss +++ b/src/app/webapp-common/shared/components/charts/scatter-plot/scatter-plot.component.scss @@ -14,8 +14,9 @@ } .overlay { + display: none; position: absolute; - top: $chart-bar-height; + top: $chart-bar-height; bottom: 0; left: 0; right: 0; diff --git a/src/app/webapp-common/shared/components/charts/scatter-plot/scatter-plot.component.ts b/src/app/webapp-common/shared/components/charts/scatter-plot/scatter-plot.component.ts index 39735184..7c1293d2 100644 --- a/src/app/webapp-common/shared/components/charts/scatter-plot/scatter-plot.component.ts +++ b/src/app/webapp-common/shared/components/charts/scatter-plot/scatter-plot.component.ts @@ -42,7 +42,7 @@ export class ScatterPlotComponent implements AfterViewInit, OnDestroy { @Input() colors: string[]; @Input() set data(data: ProjectStatsGraphData[]) { - if(data?.length > 0) { + if (data) { this.loading = false; this.chartData = cloneDeep(data); if (this.chartContainer) { @@ -97,6 +97,7 @@ export class ScatterPlotComponent implements AfterViewInit, OnDestroy { .xAxisFormatType('time') .xAxisFormat('%x') .maxCircleArea(3) + .isAnimated(false) .on('customMouseOver', this.tooltip.show) .on('customMouseMove', (dataPoint, mousePos, chartSize) => { this.tooltip.title(dataPoint.title); diff --git a/src/app/webapp-common/shared/components/clear-filters-button/clear-filters-button.component.ts b/src/app/webapp-common/shared/components/clear-filters-button/clear-filters-button.component.ts index 56b1c571..086b8fe6 100644 --- a/src/app/webapp-common/shared/components/clear-filters-button/clear-filters-button.component.ts +++ b/src/app/webapp-common/shared/components/clear-filters-button/clear-filters-button.component.ts @@ -10,7 +10,7 @@ import {FilterMetadata} from 'primeng/api/filtermetadata'; export class ClearFiltersButtonComponent implements OnInit { @Input() set tableFilters(tableFilters: { [s: string]: FilterMetadata }) { - this.isTableFiltered = Object.values(tableFilters).some(({value}) => value?.length > 0); + this.isTableFiltered = Object.values(tableFilters ?? {}).some(({value}) => value?.length > 0); }; @Output() clearTableFilters = new EventEmitter(); diff --git a/src/app/webapp-common/shared/components/custom-columns-list/custom-columns-list.component.html b/src/app/webapp-common/shared/components/custom-columns-list/custom-columns-list.component.html index 8a3504dd..b5277073 100644 --- a/src/app/webapp-common/shared/components/custom-columns-list/custom-columns-list.component.html +++ b/src/app/webapp-common/shared/components/custom-columns-list/custom-columns-list.component.html @@ -6,6 +6,7 @@ [selectable]="true" [removable]="!!col.metric_hash || col.isParam || col.type==='metadata' || col.type==='hdmd'" [itemValue]="col.id" + [enableIcon]="false" (removeItemClicked)="removeColFromList.emit($event)" (itemClicked)="selectedTableColsChanged.emit(col)"> diff --git a/src/app/webapp-common/shared/components/id-badge/id-badge.component.ts b/src/app/webapp-common/shared/components/id-badge/id-badge.component.ts index 64fc77a9..6cf51dba 100644 --- a/src/app/webapp-common/shared/components/id-badge/id-badge.component.ts +++ b/src/app/webapp-common/shared/components/id-badge/id-badge.component.ts @@ -1,5 +1,5 @@ import {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core'; -import {MatLegacyMenuTrigger as MatMenuTrigger} from '@angular/material/legacy-menu'; +import {MatMenuTrigger} from '@angular/material/menu'; @Component({ selector: 'sm-id-badge', diff --git a/src/app/webapp-common/shared/components/main-pages-header-filter/main-pages-header-filter.component.html b/src/app/webapp-common/shared/components/main-pages-header-filter/main-pages-header-filter.component.html index 872fa460..009274ac 100644 --- a/src/app/webapp-common/shared/components/main-pages-header-filter/main-pages-header-filter.component.html +++ b/src/app/webapp-common/shared/components/main-pages-header-filter/main-pages-header-filter.component.html @@ -1,29 +1,29 @@
- +
- + - +
- Any - All
@@ -41,6 +41,6 @@ smClickStopPropagation class="user-filter-button" (click)="clearAll()"> -
Clear all
+
Clear all
diff --git a/src/app/webapp-common/shared/components/main-pages-header-filter/main-pages-header-filter.component.scss b/src/app/webapp-common/shared/components/main-pages-header-filter/main-pages-header-filter.component.scss index 78164303..4a1aef26 100644 --- a/src/app/webapp-common/shared/components/main-pages-header-filter/main-pages-header-filter.component.scss +++ b/src/app/webapp-common/shared/components/main-pages-header-filter/main-pages-header-filter.component.scss @@ -14,7 +14,7 @@ overflow: auto; } .column-explanation { - padding: 5px 16px; + margin: 5px; font-size: 10px; } .filter-type { @@ -46,4 +46,4 @@ } .lbl { margin-left: 32px; -} \ No newline at end of file +} diff --git a/src/app/webapp-common/shared/components/main-pages-header-filter/main-pages-header-filter.component.ts b/src/app/webapp-common/shared/components/main-pages-header-filter/main-pages-header-filter.component.ts index e1b81c32..2959ec95 100644 --- a/src/app/webapp-common/shared/components/main-pages-header-filter/main-pages-header-filter.component.ts +++ b/src/app/webapp-common/shared/components/main-pages-header-filter/main-pages-header-filter.component.ts @@ -6,6 +6,8 @@ import {Observable, Subscription} from 'rxjs'; import {setMainPageTagsFilter, setMainPageTagsFilterMatchMode} from '../../../core/actions/projects.actions'; import {selectMainPageTagsFilter, selectMainPageTagsFilterMatchMode} from '../../../core/reducers/projects.reducer'; import {sortByArr} from '../../pipes/show-selected-first.pipe'; +import {selectRouterConfig} from "@common/core/reducers/router-reducer"; +import {map} from "rxjs/operators"; @Component({ selector: 'sm-main-pages-header-filter', @@ -22,6 +24,9 @@ export class MainPagesHeaderFilterComponent implements OnInit, OnDestroy { private tagsFiltersSubscription: Subscription; private showOnlyUserWork: boolean; private showOnlyUserWorkSub: Subscription; + private currentFeature$: Observable; + private currentFeatureSub: Subscription; + private currentFeature: string; @Input() set allTags(allTags: string[]) { if (allTags) { @@ -39,6 +44,7 @@ export class MainPagesHeaderFilterComponent implements OnInit, OnDestroy { this.showOnlyUserWork$ = this.store.select(selectShowOnlyUserWork); this.tagsFilterMatchMode$ = this.store.select(selectMainPageTagsFilterMatchMode); this.tagsFilters$ = this.store.select(selectMainPageTagsFilter); + this.currentFeature$ = this.store.select(selectRouterConfig).pipe(map((conf) => conf?.[0])); } @@ -65,7 +71,7 @@ export class MainPagesHeaderFilterComponent implements OnInit, OnDestroy { } emitFilterChangedCheckBox(tags: string[]) { - this.store.dispatch(setMainPageTagsFilter({tags})); + this.store.dispatch(setMainPageTagsFilter({tags, feature: this.currentFeature})); } @@ -80,14 +86,18 @@ export class MainPagesHeaderFilterComponent implements OnInit, OnDestroy { this.showOnlyUserWork = showOnlyUserWork; }); + this.currentFeatureSub = this.currentFeature$.subscribe((feature) => { + this.currentFeature = feature; + }); + } ngOnDestroy(): void { this.matchModeSubscription.unsubscribe(); this.tagsFiltersSubscription.unsubscribe(); this.showOnlyUserWorkSub.unsubscribe(); + this.currentFeatureSub.unsubscribe(); this.store.dispatch(setMainPageTagsFilterMatchMode({matchMode: undefined})); - this.store.dispatch(setMainPageTagsFilter({tags: []})); } private sortTags() { @@ -98,7 +108,7 @@ export class MainPagesHeaderFilterComponent implements OnInit, OnDestroy { clearAll() { this.store.dispatch(setMainPageTagsFilterMatchMode({matchMode: undefined})); - this.store.dispatch(setMainPageTagsFilter({tags: []})); + this.store.dispatch(setMainPageTagsFilter({tags: [], feature: this.currentFeature})); this.store.dispatch(setFilterByUser({showOnlyUserWork: false})); } } diff --git a/src/app/webapp-common/shared/components/markdown-editor/markdown-editor.component.html b/src/app/webapp-common/shared/components/markdown-editor/markdown-editor.component.html index 5911c347..52bfe05d 100644 --- a/src/app/webapp-common/shared/components/markdown-editor/markdown-editor.component.html +++ b/src/app/webapp-common/shared/components/markdown-editor/markdown-editor.component.html @@ -3,7 +3,7 @@
No uploads yet
@@ -53,7 +53,7 @@ - - - - - - - - + + + + + diff --git a/src/app/webapp-common/shared/experiment-graphs/experiment-graphs.component.html b/src/app/webapp-common/shared/experiment-graphs/experiment-graphs.component.html index 2bc9056a..aa52faf2 100644 --- a/src/app/webapp-common/shared/experiment-graphs/experiment-graphs.component.html +++ b/src/app/webapp-common/shared/experiment-graphs/experiment-graphs.component.html @@ -5,7 +5,11 @@
- +
{{metric}}
-
+
group.length === 1); + const groups = Object.values(this.graphsData || {}); + return (this.isGroupGraphs || this.disableResize || groups.length === 1) && groups.every(group => group.length === 1); } public calculateGraphsLayout(delay = 200) { @@ -383,7 +384,7 @@ export class ExperimentGraphsComponent implements OnDestroy { this.activeResizeElement = singleGraph; this.changeDetection.detectChanges(); this.graphsNumberLimit = this.isGroupGraphs ? metricGroup.querySelectorAll(':not(.resize-ghost-element) > sm-single-graph').length : this.graphList.length; - this.resizeTextElement = singleGraph?.parentElement.querySelectorAll('.resize-overlay-text')[1]; + this.resizeTextElement = singleGraph?.parentElement.querySelectorAll('.resize-ghost-element .resize-overlay-text')[0]; } onResizing($event: ResizeEvent) { @@ -402,6 +403,8 @@ export class ExperimentGraphsComponent implements OnDestroy { const element = this.allMetrics.nativeElement.getElementsByClassName('graph-id')[EXPERIMENT_GRAPH_ID_PREFIX + id] as HTMLDivElement; if (element) { this.allMetrics.nativeElement.scrollTo({top: element.offsetTop, behavior: 'smooth'}); + } else if (this.allMetrics.nativeElement.getElementsByTagName('sm-single-value-summary-table')[0]){ + this.allMetrics.nativeElement.scrollTo({top: 0, behavior: 'smooth'}); } } @@ -421,6 +424,11 @@ export class ExperimentGraphsComponent implements OnDestroy { public generateIdentifier = (chartItem: any) => `${this.singleGraphidPrefix} ${this.experimentGraphidPrefix} ${chartItem.metric} ${chartItem.layout.title} ${chartItem.iter} ${chartItem.variant} ${(chartItem.layout.images && chartItem.layout.images[0]?.source)}`; creatingEmbedCode(chartItem: any, domRect: DOMRect) { + if (!chartItem) { + this.createEmbedCode.emit({domRect}); + return; + } + if (this.groupBy === groupByCharts.none) { // split scalars by variants this.createEmbedCode.emit({ diff --git a/src/app/webapp-common/shared/experiment-graphs/experiment-graphs.module.ts b/src/app/webapp-common/shared/experiment-graphs/experiment-graphs.module.ts index dcb95312..dc142d91 100644 --- a/src/app/webapp-common/shared/experiment-graphs/experiment-graphs.module.ts +++ b/src/app/webapp-common/shared/experiment-graphs/experiment-graphs.module.ts @@ -1,7 +1,7 @@ import {NgModule} from '@angular/core'; import { CommonModule } from '@angular/common'; -import {MatLegacySliderModule as MatSliderModule} from '@angular/material/legacy-slider'; -import {MatLegacySelectModule as MatSelectModule} from '@angular/material/legacy-select'; +import {MatSliderModule} from '@angular/material/slider'; +import {MatSelectModule} from '@angular/material/select'; import {FormsModule} from '@angular/forms'; import {ResizableModule} from 'angular-resizable-element'; import {ExperimentGraphsComponent} from './experiment-graphs.component'; @@ -9,16 +9,15 @@ import {GraphSettingsBarComponent} from './graph-settings-bar/graph-settings-bar import {GraphScalarDataToMetric} from './graph-scalar-data-to-metric.pipe'; import {GraphPlotDataToMetric} from './graph-plot-data-to-metric.pipe'; import {SharedPipesModule} from '../pipes/shared-pipes.module'; -import {SingleValueSummaryTableComponent} from './single-value-summary-table/single-value-summary-table.component'; +import {SingleValueSummaryTableComponent} from '../single-value-summary-table/single-value-summary-table.component'; import {SingleGraphModule} from '@common/shared/single-graph/single-graph.module'; -import {MatLegacyInputModule as MatInputModule} from '@angular/material/legacy-input'; +import {MatInputModule} from '@angular/material/input'; const declarations= [ ExperimentGraphsComponent, GraphSettingsBarComponent, GraphScalarDataToMetric, GraphPlotDataToMetric, - SingleValueSummaryTableComponent ]; @NgModule({ declarations, @@ -31,7 +30,8 @@ const declarations= [ ResizableModule, SharedPipesModule, SingleGraphModule, - MatInputModule + MatInputModule, + SingleValueSummaryTableComponent ] }) export class ExperimentGraphsModule { } diff --git a/src/app/webapp-common/shared/experiment-graphs/graph-settings-bar/graph-settings-bar.component.html b/src/app/webapp-common/shared/experiment-graphs/graph-settings-bar/graph-settings-bar.component.html index 7d428b4e..6f50257a 100644 --- a/src/app/webapp-common/shared/experiment-graphs/graph-settings-bar/graph-settings-bar.component.html +++ b/src/app/webapp-common/shared/experiment-graphs/graph-settings-bar/graph-settings-bar.component.html @@ -1,15 +1,15 @@
-
+
Group by - + {{type.name}}
-
+
Horizontal Axis - + {{type.name}} @@ -19,20 +19,23 @@
Smoothing + - + -
Summary - -
- -
-
-
{{item.variant}}
-
{{item.value}}
-
-
-
diff --git a/src/app/webapp-common/shared/experiment-graphs/single-value-summary-table/single-value-summary-table.component.scss b/src/app/webapp-common/shared/experiment-graphs/single-value-summary-table/single-value-summary-table.component.scss deleted file mode 100644 index f379553d..00000000 --- a/src/app/webapp-common/shared/experiment-graphs/single-value-summary-table/single-value-summary-table.component.scss +++ /dev/null @@ -1,49 +0,0 @@ -@import "variables"; - - -.single-table-container { - border-radius: 4px; - border: solid 1px $blue-100; - - - .summary-header { - padding: 12px; - font-size: 16px; - color: $blue-600; - text-align: center; - .al-ico-csv { - position: absolute; - top: 12px; - right: 12px; - opacity: 0; - transition: opacity 300ms ease; - &.show{ - opacity: 1; - } - } - } - - - .items-container { - border-top: solid 1px $blue-100; - overflow: auto; - - .item { - padding: 12px 24px; - text-align: center; - - &:not(:last-child) { - border-right: solid 1px $blue-100; - } - - .variant { - color: #71758a; - margin-bottom: 6px; - } - - .value { - color: $blue-500; - } - } - } -} diff --git a/src/app/webapp-common/shared/experiment-type-icon-label/experiment-type-icon-label.component.html b/src/app/webapp-common/shared/experiment-type-icon-label/experiment-type-icon-label.component.html index 1719f93a..89ed9937 100644 --- a/src/app/webapp-common/shared/experiment-type-icon-label/experiment-type-icon-label.component.html +++ b/src/app/webapp-common/shared/experiment-type-icon-label/experiment-type-icon-label.component.html @@ -1,5 +1,5 @@ - + {{type?.length < 4 ? type?.toUpperCase() : (type | noUnderscore | titlecase)}} diff --git a/src/app/webapp-common/shared/guards/general-leaving-before-save-alert.guard.ts b/src/app/webapp-common/shared/guards/general-leaving-before-save-alert.guard.ts index ecbc4dd9..66840aba 100644 --- a/src/app/webapp-common/shared/guards/general-leaving-before-save-alert.guard.ts +++ b/src/app/webapp-common/shared/guards/general-leaving-before-save-alert.guard.ts @@ -1,7 +1,7 @@ import {Injectable} from '@angular/core'; import {CanDeactivate} from '@angular/router'; import {Observable} from 'rxjs'; -import {MatLegacyDialog as MatDialog, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MatDialog, MatDialogRef} from '@angular/material/dialog'; import {ConfirmDialogComponent} from '../ui-components/overlay/confirm-dialog/confirm-dialog.component'; @Injectable() diff --git a/src/app/webapp-common/shared/guards/leaving-before-save-alert.guard.ts b/src/app/webapp-common/shared/guards/leaving-before-save-alert.guard.ts index 6abd4dc3..0b50ac9f 100755 --- a/src/app/webapp-common/shared/guards/leaving-before-save-alert.guard.ts +++ b/src/app/webapp-common/shared/guards/leaving-before-save-alert.guard.ts @@ -1,7 +1,7 @@ import {Injectable} from '@angular/core'; import {ActivatedRouteSnapshot, CanDeactivate, RouterStateSnapshot} from '@angular/router'; import {Observable} from 'rxjs'; -import {MatLegacyDialog as MatDialog, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MatDialog, MatDialogRef} from '@angular/material/dialog'; import {ConfirmDialogComponent} from '../ui-components/overlay/confirm-dialog/confirm-dialog.component'; import {Store} from '@ngrx/store'; import {GuardBase} from '~/shared/guards/guard-base'; diff --git a/src/app/webapp-common/shared/material/material.module.ts b/src/app/webapp-common/shared/material/material.module.ts index 7895912e..71f0c24a 100755 --- a/src/app/webapp-common/shared/material/material.module.ts +++ b/src/app/webapp-common/shared/material/material.module.ts @@ -1,18 +1,18 @@ import {NgModule} from '@angular/core'; -import {MatLegacyDialogModule as MatDialogModule} from '@angular/material/legacy-dialog'; -import {MatLegacyAutocompleteModule as MatAutocompleteModule} from '@angular/material/legacy-autocomplete'; -import {MatLegacyCheckboxModule as MatCheckboxModule} from '@angular/material/legacy-checkbox'; +import {MatDialogModule} from '@angular/material/dialog'; +import {MatAutocompleteModule} from '@angular/material/autocomplete'; +import {MatCheckboxModule} from '@angular/material/checkbox'; import {MatDividerModule} from '@angular/material/divider'; import {MatExpansionModule} from '@angular/material/expansion'; -import {MatLegacyFormFieldModule as MatFormFieldModule} from '@angular/material/legacy-form-field'; -import {MatLegacyInputModule as MatInputModule} from '@angular/material/legacy-input'; -import {MatLegacySelectModule as MatSelectModule} from '@angular/material/legacy-select'; -import {MatLegacySlideToggleModule as MatSlideToggleModule} from '@angular/material/legacy-slide-toggle'; -import {MatLegacyTooltipModule as MatTooltipModule} from '@angular/material/legacy-tooltip'; -import {MatLegacyMenuModule as MatMenuModule} from '@angular/material/legacy-menu'; -import {MatLegacyChipsModule as MatChipsModule} from '@angular/material/legacy-chips'; +import {MatFormFieldModule} from '@angular/material/form-field'; +import {MatInputModule} from '@angular/material/input'; +import {MatSelectModule} from '@angular/material/select'; +import {MatSlideToggleModule} from '@angular/material/slide-toggle'; +import {MatTooltipModule} from '@angular/material/tooltip'; +import {MatMenuModule} from '@angular/material/menu'; +import {MatChipsModule} from '@angular/material/chips'; import {MatSidenavModule} from '@angular/material/sidenav'; -import {MatLegacyListModule as MatListModule} from '@angular/material/legacy-list'; +import {MatListModule} from '@angular/material/list'; @NgModule({ diff --git a/src/app/webapp-common/shared/pipes/count-lines.pipe.ts b/src/app/webapp-common/shared/pipes/count-lines.pipe.ts new file mode 100644 index 00000000..451c6843 --- /dev/null +++ b/src/app/webapp-common/shared/pipes/count-lines.pipe.ts @@ -0,0 +1,11 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'countLines' +}) +export class CountLinesPipe implements PipeTransform { + + transform(text: string) { + return text.split(/\n|\r|\r\n/).length; + } +} diff --git a/src/app/webapp-common/shared/pipes/shared-pipes.module.ts b/src/app/webapp-common/shared/pipes/shared-pipes.module.ts index 5725e01f..cd4f4290 100644 --- a/src/app/webapp-common/shared/pipes/shared-pipes.module.ts +++ b/src/app/webapp-common/shared/pipes/shared-pipes.module.ts @@ -64,6 +64,7 @@ import {HasCompletedPipe} from './has-completed.pipe'; import {IsStringPipe} from './is-string.pipe'; import {CleanProjectPathPipe} from './clean-project-path.pipe'; import {BaseNamePipe} from '@common/shared/pipes/base-name.pipe'; +import {CountLinesPipe} from '@common/shared/pipes/count-lines.pipe'; const pipes = [ CamelToTitlePipe, FilenameFromPath, FilterPipe, FloorPipe, KeyValuePipe, NAPipe, SortPipe, IsVideoPipe, IsAudioPipe, FilterInternalPipe, UuidPipe, @@ -80,9 +81,9 @@ const pipes = [ CommonModule, FileSizePipe ], - declarations: [pipes, ShowSelectedFirstPipe, CountPipe, ColGetterPipe, FilterMonitorMetricPipe, ReversePipe, ], + declarations: [pipes, ShowSelectedFirstPipe, CountPipe, ColGetterPipe, FilterMonitorMetricPipe, ReversePipe, CountLinesPipe], providers: [pipes], - exports: [pipes, ShowSelectedFirstPipe, CountPipe, ColGetterPipe, FilterMonitorMetricPipe, ReversePipe, FileSizePipe] + exports: [pipes, ShowSelectedFirstPipe, CountPipe, ColGetterPipe, FilterMonitorMetricPipe, ReversePipe, FileSizePipe, CountLinesPipe] }) export class SharedPipesModule { } diff --git a/src/app/webapp-common/shared/pipes/simple-filter.pipe.ts b/src/app/webapp-common/shared/pipes/simple-filter.pipe.ts index f0971406..4509659f 100644 --- a/src/app/webapp-common/shared/pipes/simple-filter.pipe.ts +++ b/src/app/webapp-common/shared/pipes/simple-filter.pipe.ts @@ -8,7 +8,7 @@ export class SimpleFilterPipe implements PipeTransform { if (!term) { return items; } - return items.filter(item => item.toLowerCase().includes(term.toLowerCase())); + return items?.filter(item => item.toLowerCase().includes(term.toLowerCase())) ?? []; } } diff --git a/src/app/webapp-common/shared/pipes/string-included-in-array.pipe.ts b/src/app/webapp-common/shared/pipes/string-included-in-array.pipe.ts index 8bd7f0f4..ecd168bc 100644 --- a/src/app/webapp-common/shared/pipes/string-included-in-array.pipe.ts +++ b/src/app/webapp-common/shared/pipes/string-included-in-array.pipe.ts @@ -9,7 +9,7 @@ export class StringIncludedInArrayPipe implements PipeTransform { if (!value) { return false; } - return stingsArr.includes(value); + return stingsArr?.includes(value); } } diff --git a/src/app/webapp-common/shared/project-dialog/create-new-project-form/create-new-project-form.component.html b/src/app/webapp-common/shared/project-dialog/create-new-project-form/create-new-project-form.component.html index dc6e01d2..50645d8d 100755 --- a/src/app/webapp-common/shared/project-dialog/create-new-project-form/create-new-project-form.component.html +++ b/src/app/webapp-common/shared/project-dialog/create-new-project-form/create-new-project-form.component.html @@ -2,58 +2,66 @@ Project name *Please add name. - *Project name in this path already exists. - *Project name should contain more than 2 characters. + *Project name in this path already exists. + *Project name should contain more than 3 characters. *Project name can't contain only spaces. + [existingNames]="[]" + [parent]="targetFolder.value" + required minlength="3" > - *Please add location. - Please provide a name longer than 3 characters + (mousedown)="!isFocused(locationRef) && targetFolder.value && targetFolder.reset(); locationRef.blur(); locationRef.focus()"> + *Please add location. + Please provide a name longer than 3 characters Create in - (Create New) - + (Create New) + - + "{{location.value}}" (Create New) + *ngIf="projectsNames !== null && targetFolder.value && !(targetFolder.value | stringIncludedInArray:projectsNames)" + [value]="targetFolder.value" + >"{{targetFolder.value}}" (Create New) -
+
+
+ +
+
Loading more...
+
diff --git a/src/app/webapp-common/shared/project-dialog/create-new-project-form/create-new-project-form.component.scss b/src/app/webapp-common/shared/project-dialog/create-new-project-form/create-new-project-form.component.scss index cbd369ed..2bd0d35a 100755 --- a/src/app/webapp-common/shared/project-dialog/create-new-project-form/create-new-project-form.component.scss +++ b/src/app/webapp-common/shared/project-dialog/create-new-project-form/create-new-project-form.component.scss @@ -1,4 +1,7 @@ :host { + form { + gap: 12px; + } .create-project-button { padding-top: 32px; } @@ -7,15 +10,22 @@ //position: absolute !important; //top: -15px; } - #project-description{ - max-height:250px; + + #project-description { + max-height: 250px; padding-top: 12px; height: 65px; } - mat-form-field{ + + mat-form-field { width: 100%; - .project-description{ + + .project-description { min-height: 68px; } } + + .search-icon { + transform: translateY(3px); + } } diff --git a/src/app/webapp-common/shared/project-dialog/create-new-project-form/create-new-project-form.component.ts b/src/app/webapp-common/shared/project-dialog/create-new-project-form/create-new-project-form.component.ts index b7a32def..f37ec7f2 100755 --- a/src/app/webapp-common/shared/project-dialog/create-new-project-form/create-new-project-form.component.ts +++ b/src/app/webapp-common/shared/project-dialog/create-new-project-form/create-new-project-form.component.ts @@ -1,42 +1,63 @@ -import {ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild} from '@angular/core'; +import {ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, ViewChild} from '@angular/core'; import {URI_REGEX} from '~/app.constants'; import {Project} from '~/business-logic/model/projects/project'; import {NgForm} from '@angular/forms'; -import {MatLegacyAutocompleteSelectedEvent as MatAutocompleteSelectedEvent} from '@angular/material/legacy-autocomplete'; +import {MatAutocompleteSelectedEvent} from '@angular/material/autocomplete'; +import {Subscription} from 'rxjs'; +import {rootProjectsPageSize} from '@common/constants'; @Component({ selector: 'sm-create-new-project-form', templateUrl: './create-new-project-form.component.html', - styleUrls: ['./create-new-project-form.component.scss'] + styleUrls: ['./create-new-project-form.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush }) -export class CreateNewProjectFormComponent implements OnChanges { - constructor(private changeDetection: ChangeDetectorRef) { - } +export class CreateNewProjectFormComponent implements OnChanges, OnInit, OnDestroy { + public rootFiltered: boolean; public readonly projectsRoot = 'Projects root'; - public projectsNames: Array; + public projectsNames: Array = null; public outputDestPattern = `${URI_REGEX.S3_WITH_BUCKET}$|${URI_REGEX.S3_WITH_BUCKET_AND_HOST}$|${URI_REGEX.FILE}$|${URI_REGEX.NON_AWS_S3}$|${URI_REGEX.GS_WITH_BUCKET}$|${URI_REGEX.GS_WITH_BUCKET_AND_HOST}$`; public project = { name: '', description: '', + // eslint-disable-next-line @typescript-eslint/naming-convention default_output_destination: null, + // eslint-disable-next-line @typescript-eslint/naming-convention system_tags: [], - parent: '' + parent: null }; private _projects: Project[]; + private subs = new Subscription(); + public loading: boolean; + public noMoreOptions: boolean; + private inititated: boolean; + private previousLength: number | undefined; @Input() set projects(projects) { + this.loading = false; + this.noMoreOptions = projects?.length === this.previousLength || projects?.length < rootProjectsPageSize; + this.previousLength = projects?.length; this._projects = projects; - this.projectsNames = [this.projectsRoot].concat(projects.map(project => project.name)); + if (!projects) { + return; + } + // this.projectsNames = this.rootFiltered ? projects.map(project => project.name) : [this.projectsRoot].concat(projects.map(project => project.name)); + this.projectsNames = [ + ...(this.rootFiltered ? []: [this.projectsRoot]), + ...(this.baseProject && !this.project.parent ? [this.baseProject.name] : []), + ...projects.map(project => project.name) + ]; } get projects(): Project[] { return this._projects; } - @Input() baseProjectId; + @Input() baseProject: Project; + @Output() filterSearchChanged = new EventEmitter<{value: string; loadMore?: boolean}>(); @Output() projectCreated = new EventEmitter(); @ViewChild('projectForm') public form: NgForm; isAutoCompleteOpen: boolean; @@ -49,17 +70,14 @@ export class CreateNewProjectFormComponent implements OnChanges { } - ngOnChanges(changes: SimpleChanges): void { - if (this.projects.length > 0) { - this.project.parent = this.baseProjectId? this.projects.find(project => project.id === this.baseProjectId)?.name: this.projectsRoot; + ngOnChanges(): void { + if (this.projects?.length > 0 && this.project.parent === null && !this.inititated) { + this.project.parent = this.baseProject?.name ?? this.projectsRoot; + this.inititated = true; } } - detectChanges() { - this.changeDetection.detectChanges(); - } - - clearLocation() { + clearLocation() { this.project.parent = ''; } @@ -71,5 +89,35 @@ export class CreateNewProjectFormComponent implements OnChanges { locationSelected($event: MatAutocompleteSelectedEvent) { this.project.parent = $event.option.value; } + + searchChanged(searchString: any) { + this.projectsNames = null; + this.rootFiltered = !this.projectsRoot.includes(searchString) && this.projectsRoot === this.baseProject?.name; + searchString !== null && this.filterSearchChanged.emit({value: searchString}); + } + + ngOnInit(): void { + setTimeout(() => { + this.subs.add(this.form.controls['location'].valueChanges.subscribe(searchString => { + if (searchString !== this.project.parent) { + this.searchChanged(searchString || ''); + } + }) + ); + }); + } + + ngOnDestroy(): void { + this.subs.unsubscribe(); + } + + loadMore(searchString) { + this.loading = true; + this.filterSearchChanged.emit({value: searchString || '', loadMore: true}); + } + + isFocused(locationRef: HTMLInputElement) { + return document.activeElement === locationRef; + } } diff --git a/src/app/webapp-common/shared/project-dialog/project-dialog.component.html b/src/app/webapp-common/shared/project-dialog/project-dialog.component.html index 80893e63..c1827007 100755 --- a/src/app/webapp-common/shared/project-dialog/project-dialog.component.html +++ b/src/app/webapp-common/shared/project-dialog/project-dialog.component.html @@ -1,7 +1,16 @@ - + - + diff --git a/src/app/webapp-common/shared/project-dialog/project-dialog.component.ts b/src/app/webapp-common/shared/project-dialog/project-dialog.component.ts index 4c08cd20..f459b687 100755 --- a/src/app/webapp-common/shared/project-dialog/project-dialog.component.ts +++ b/src/app/webapp-common/shared/project-dialog/project-dialog.component.ts @@ -4,12 +4,13 @@ import * as createProjectSelectors from './project-dialog.reducer'; import {CREATION_STATUS} from './project-dialog.reducer'; import {Component, Inject, OnDestroy, OnInit} from '@angular/core'; -import {MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {Store} from '@ngrx/store'; import {Observable, Subscription} from 'rxjs'; import {ProjectsCreateRequest} from '~/business-logic/model/projects/projectsCreateRequest'; -import {selectRootProjects} from '@common/core/reducers/projects.reducer'; -import {getAllSystemProjects} from '@common/core/actions/projects.actions'; +import {selectTablesFilterProjectsOptions} from '@common/core/reducers/projects.reducer'; +import {getTablesFilterProjectsOptions, resetTablesFilterProjectsOptions} from '@common/core/actions/projects.actions'; +import {Project} from '~/business-logic/model/projects/project'; @Component({ selector: 'sm-project-create-dialog', @@ -19,7 +20,7 @@ import {getAllSystemProjects} from '@common/core/actions/projects.actions'; export class ProjectDialogComponent implements OnInit, OnDestroy { public projects$: Observable; private creationStatusSubscription: Subscription; - public baseProjectId: string; + public baseProject: Project; public mode: string; public header: string; public modeParameters: { [mode: string]: { header: string; icon: string } } = { @@ -34,14 +35,15 @@ export class ProjectDialogComponent implements OnInit, OnDestroy { }; - constructor(private store: Store, private matDialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) data: { projectId: string; mode: string }) { - this.baseProjectId = data.projectId; + constructor(private store: Store, private matDialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) data: { project: Project; mode: string }) { + this.baseProject = data.project; this.mode = data.mode; - this.projects$ = this.store.select(selectRootProjects); + this.projects$ = this.store.select(selectTablesFilterProjectsOptions); } ngOnInit(): void { - this.store.dispatch(getAllSystemProjects()); + this.store.dispatch(getTablesFilterProjectsOptions({searchString: '', loadMore: false})); this.creationStatusSubscription = this.store.select(createProjectSelectors.selectCreationStatus).subscribe(status => { if (status === CREATION_STATUS.SUCCESS) { return this.matDialogRef.close(true); @@ -61,8 +63,9 @@ export class ProjectDialogComponent implements OnInit, OnDestroy { moveProject(event: {location: string; name: string; fromName: string; toName: string; projectName: string}) { this.store.dispatch(moveProject({ - project: this.baseProjectId, + project: this.baseProject.id, ...event, + // eslint-disable-next-line @typescript-eslint/naming-convention new_location: event.location === 'Projects root' ? '' : event.location, })); } @@ -71,11 +74,17 @@ export class ProjectDialogComponent implements OnInit, OnDestroy { return { name: `${projectForm.parent === 'Projects root' ? '' : projectForm.parent + '/'}${projectForm.name}`, description: projectForm.description, + // eslint-disable-next-line @typescript-eslint/naming-convention system_tags: projectForm.system_tags, + // eslint-disable-next-line @typescript-eslint/naming-convention default_output_destination: projectForm.default_output_destination }; } + filterSearchChanged($event: {value: string; loadMore?: boolean}) { + !$event.loadMore && this.store.dispatch(resetTablesFilterProjectsOptions()); + this.store.dispatch(getTablesFilterProjectsOptions({searchString: $event.value || '', loadMore: $event.loadMore})); + } closeDialog() { this.matDialogRef.close(); diff --git a/src/app/webapp-common/shared/project-dialog/project-dialog.module.ts b/src/app/webapp-common/shared/project-dialog/project-dialog.module.ts index 3837e6dd..01ed563f 100755 --- a/src/app/webapp-common/shared/project-dialog/project-dialog.module.ts +++ b/src/app/webapp-common/shared/project-dialog/project-dialog.module.ts @@ -10,7 +10,10 @@ import {UiComponentsModule} from '../ui-components/ui-components.module'; import {ProjectDialogComponent} from './project-dialog.component'; import {CreateNewProjectFormComponent} from './create-new-project-form/create-new-project-form.component'; import {SharedPipesModule} from '../pipes/shared-pipes.module'; -import {ProjectMoveToFormComponent} from "./project-move-to-form/project-move-to-form.component"; +import {ProjectMoveToFormComponent} from './project-move-to-form/project-move-to-form.component'; +import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; +import {UniqueProjectValidator} from '@common/shared/project-dialog/unique-project.validator'; +import {LabeledFormFieldDirective} from '@common/shared/directive/labeled-form-field.directive'; @NgModule({ imports: [ @@ -21,8 +24,10 @@ import {ProjectMoveToFormComponent} from "./project-move-to-form/project-move-to SMMaterialModule, StoreModule.forFeature('projectCreateDialog', projectDialogReducer), EffectsModule.forFeature([ProjectDialogEffects]), - SharedPipesModule + SharedPipesModule, + MatProgressSpinnerModule, + LabeledFormFieldDirective ], - declarations: [ProjectDialogComponent, CreateNewProjectFormComponent, ProjectMoveToFormComponent] + declarations: [ProjectDialogComponent, CreateNewProjectFormComponent, ProjectMoveToFormComponent, UniqueProjectValidator] }) export class ProjectDialogModule { } diff --git a/src/app/webapp-common/shared/project-dialog/project-move-to-form/project-move-to-form.component.html b/src/app/webapp-common/shared/project-dialog/project-move-to-form/project-move-to-form.component.html index c99ec93d..4d028be2 100755 --- a/src/app/webapp-common/shared/project-dialog/project-move-to-form/project-move-to-form.component.html +++ b/src/app/webapp-common/shared/project-dialog/project-move-to-form/project-move-to-form.component.html @@ -1,5 +1,5 @@
-
Move {{projectName | shortProjectName}} from Move {{projectName | shortProjectName}} from {{projectName | projectLocation}}
To {{project.parent}} Project… @@ -9,11 +9,11 @@ + (mousedown)="!isFocused(projectInputRef) && projectInput.value && projectInput.reset(); projectInputRef.blur(); projectInputRef.focus()"> Destination - (Create New) - (Create New) + Please provide a Project Please provide a project name longer than 3 characters - Can't move a project to its current location + Can't move a project to its current location Can't move a project to its nested projects {{projectInput.value}} already contains a project named {{projectName | shortProjectName}} + *Project name can't contain only spaces. "{{projectInput.value}}" (Create New) - +
+
+ +
+
Loading more...
+
diff --git a/src/app/webapp-common/shared/project-dialog/project-move-to-form/project-move-to-form.component.scss b/src/app/webapp-common/shared/project-dialog/project-move-to-form/project-move-to-form.component.scss index 154eef4a..7404435e 100755 --- a/src/app/webapp-common/shared/project-dialog/project-move-to-form/project-move-to-form.component.scss +++ b/src/app/webapp-common/shared/project-dialog/project-move-to-form/project-move-to-form.component.scss @@ -1,9 +1,10 @@ @import "variables"; :host { - .creat-new-suffix{ + .creat-new-suffix { margin-right: 18px; } + .buttons { margin-top: 48px; display: flex; @@ -18,10 +19,12 @@ width: 130px; text-transform: uppercase; } + .yes-button { margin-left: 16px; } } + .line { line-height: 2; } @@ -37,6 +40,9 @@ .p-name { font-weight: bold; + max-width: calc(100% - 38px); + display: inline-block; + vertical-align: middle; } .p-holder { @@ -67,4 +73,8 @@ min-height: 68px; } } + + .search-icon { + transform: translateY(3px); + } } diff --git a/src/app/webapp-common/shared/project-dialog/project-move-to-form/project-move-to-form.component.ts b/src/app/webapp-common/shared/project-dialog/project-move-to-form/project-move-to-form.component.ts index 4a3b295e..8773ad94 100755 --- a/src/app/webapp-common/shared/project-dialog/project-move-to-form/project-move-to-form.component.ts +++ b/src/app/webapp-common/shared/project-dialog/project-move-to-form/project-move-to-form.component.ts @@ -1,62 +1,88 @@ import { - ChangeDetectorRef, + AfterViewInit, + ChangeDetectionStrategy, Component, EventEmitter, Input, - OnChanges, - OnInit, + OnChanges, OnDestroy, Output, - SimpleChanges, ViewChild } from '@angular/core'; import {Project} from '~/business-logic/model/projects/project'; import {NgForm} from '@angular/forms'; -import {MatLegacyAutocompleteSelectedEvent as MatAutocompleteSelectedEvent} from '@angular/material/legacy-autocomplete'; -import {MatLegacyOptionSelectionChange as MatOptionSelectionChange} from '@angular/material/legacy-core'; +import {MatAutocompleteSelectedEvent} from '@angular/material/autocomplete'; +import {MatOptionSelectionChange} from '@angular/material/core'; import {ShortProjectNamePipe} from '@common/shared/pipes/short-project-name.pipe'; import {ProjectLocationPipe} from '@common/shared/pipes/project-location.pipe'; +import {Subscription} from 'rxjs'; +import {rootProjectsPageSize} from '@common/constants'; @Component({ selector: 'sm-project-move-to-form', templateUrl: './project-move-to-form.component.html', - styleUrls: ['./project-move-to-form.component.scss'] + styleUrls: ['./project-move-to-form.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush }) -export class ProjectMoveToFormComponent implements OnChanges, OnInit { +export class ProjectMoveToFormComponent implements OnChanges, AfterViewInit, OnDestroy { + public readonly projectsRoot = 'Projects root'; + public rootFiltered: boolean; public projectName: string; public isAutoCompleteOpen: boolean; public filterText: string = ''; public projectsNames: Array; public project = { - parent: '' + parent: null }; private _projects: Project[]; - - @ViewChild('moveToForm', {static: true}) moveToForm: NgForm; private newProjectName: string; + private subs = new Subscription(); + @ViewChild('moveToForm', {static: true}) moveToForm: NgForm; + public loading: boolean; + public noMoreOptions: boolean; + private previousLength: number | undefined; constructor( - private changeDetection: ChangeDetectorRef, private shortProjectName: ShortProjectNamePipe, private projectLocation: ProjectLocationPipe -) {} + ) { + } - ngOnInit(): void { + ngAfterViewInit(): void { + setTimeout(() => { + this.subs.add(this.moveToForm.controls['projectName'].valueChanges.subscribe(searchString => { + if (searchString !== this.project.parent) { + this.searchChanged(searchString || ''); + } + }) + ); + }); } @Input() set projects(projects) { + this.loading = false; + this.noMoreOptions = projects?.length === this.previousLength || projects?.length < rootProjectsPageSize; + this.previousLength = projects?.length; + this._projects = projects; - this.projectsNames = ['Projects root'].concat(projects.map(project => project.name)); + if (!projects) { + return; + } + this.projectsNames = [ + ...(this.rootFiltered ? [] : [this.projectsRoot]), + ...projects.map(project => project.name) + ]; } get projects(): Project[] { return this._projects; } - @Input() baseProjectId; + @Input() baseProject; - @Output() moveProject = new EventEmitter<{location: string; name: string; fromName: string; toName: string; projectName: string}>(); + @Output() filterSearchChanged = new EventEmitter<{ value: string; loadMore?: boolean }>(); + @Output() moveProject = new EventEmitter<{ location: string; name: string; fromName: string; toName: string; projectName: string }>(); @Output() dismissDialog = new EventEmitter(); @ViewChild('projectForm') public form: NgForm; @@ -70,17 +96,15 @@ export class ProjectMoveToFormComponent implements OnChanges, OnInit { }); } - ngOnChanges(changes: SimpleChanges) { - if (this.projects.length > 0 && this.baseProjectId) { - this.projectName = this.projects.find(project => project.id === this.baseProjectId)?.name; + ngOnChanges() { + if (this.projects?.length > 0 && this.baseProject) { + this.projectName = this.baseProject?.name ?? this.projectsRoot; + // if (this.baseProject && this.project.parent === null) { + // this.project.parent = this.baseProject.name; + // } } } - detectChanges() { - // this.form.controls.projectName.updateValueAndValidity(); - this.changeDetection.detectChanges(); - } - clear() { this.project.parent = ''; } @@ -102,8 +126,27 @@ export class ProjectMoveToFormComponent implements OnChanges, OnInit { this.newProjectName = $event.source.value; } - optionSelected($event: MatOptionSelectionChange) { + optionSelected() { this.newProjectName = null; } + + searchChanged(searchString: any) { + this.projectsNames = null; + this.rootFiltered = !this.projectsRoot.includes(searchString); + searchString !== null && this.filterSearchChanged.emit({value: searchString}); + } + + loadMore(searchString) { + this.loading = true; + this.filterSearchChanged.emit({value: searchString || '', loadMore: true}); + } + + isFocused(locationRef: HTMLInputElement) { + return document.activeElement === locationRef; + } + + ngOnDestroy(): void { + this.subs.unsubscribe(); + } } diff --git a/src/app/webapp-common/shared/project-dialog/unique-project.validator.ts b/src/app/webapp-common/shared/project-dialog/unique-project.validator.ts new file mode 100644 index 00000000..2e82e351 --- /dev/null +++ b/src/app/webapp-common/shared/project-dialog/unique-project.validator.ts @@ -0,0 +1,38 @@ +import {Directive, Input} from '@angular/core'; +import {AbstractControl, AsyncValidator, NG_ASYNC_VALIDATORS, ValidationErrors} from '@angular/forms'; +import {Observable, of, switchMap} from 'rxjs'; +import {ApiProjectsService} from '~/business-logic/api-services/projects.service'; +import {catchError, delay, map} from 'rxjs/operators'; +import {ProjectsGetAllExResponse} from '~/business-logic/model/projects/projectsGetAllExResponse'; + +@Directive({ + selector: '[smUniqueProjectValidator]', + providers: [{provide: NG_ASYNC_VALIDATORS, useExisting: UniqueProjectValidator, multi: true}] +}) +export class UniqueProjectValidator implements AsyncValidator { + @Input() parent: string; + + constructor(private projectsApi: ApiProjectsService) { + } + + validate(control: AbstractControl): Promise | Observable { + if (!(control.value?.length > 2)) { + return null; + } + + return of(control.value).pipe( + delay(300), + switchMap((name: string) => this.projectsApi.projectsGetAllEx({ + name: this.parent ? `${this.parent}/${name}` : name, + // eslint-disable-next-line @typescript-eslint/naming-convention + only_fields: ['id'] + }).pipe( + map((res: ProjectsGetAllExResponse) => res.projects.length === 0 ? null : {uniqueProject: {value: control.value}}), + catchError(() => of({uniqueProject: {value: control.value}})) + ), + ) + ); + } +} + + diff --git a/src/app/webapp-common/shared/queue-create-dialog/queue-create-dialog.component.ts b/src/app/webapp-common/shared/queue-create-dialog/queue-create-dialog.component.ts index 8fc1d0c1..edb5841e 100755 --- a/src/app/webapp-common/shared/queue-create-dialog/queue-create-dialog.component.ts +++ b/src/app/webapp-common/shared/queue-create-dialog/queue-create-dialog.component.ts @@ -2,7 +2,7 @@ import * as createNewQueueActions from './queue-create-dialog.actions'; import * as createQueueSelectors from './queue-create-dialog.reducer'; import {Component, Inject, OnDestroy, OnInit} from '@angular/core'; -import { MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialogRef as MatDialogRef } from '@angular/material/legacy-dialog'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import {Store} from '@ngrx/store'; import {CREATION_STATUS} from './queue-create-dialog.reducer'; import {Observable, Subscription} from 'rxjs'; diff --git a/src/app/webapp-common/shared/queue-create-dialog/queue-create-dialog.module.ts b/src/app/webapp-common/shared/queue-create-dialog/queue-create-dialog.module.ts index de5e883e..36950974 100755 --- a/src/app/webapp-common/shared/queue-create-dialog/queue-create-dialog.module.ts +++ b/src/app/webapp-common/shared/queue-create-dialog/queue-create-dialog.module.ts @@ -9,6 +9,7 @@ import {QueueCreateDialogComponent} from './queue-create-dialog.component'; import {CreateNewQueueFormComponent} from './create-new-queue-form/create-new-queue-form.component'; import {UiComponentsModule} from '../ui-components/ui-components.module'; import {SMMaterialModule} from '../material/material.module'; +import {LabeledFormFieldDirective} from '@common/shared/directive/labeled-form-field.directive'; @NgModule({ imports : [ @@ -18,7 +19,8 @@ import {SMMaterialModule} from '../material/material.module'; ReactiveFormsModule, SMMaterialModule, StoreModule.forFeature('queueCreateDialog', queueCreateDialogReducer), - EffectsModule.forFeature([QueueCreateDialogEffects]) + EffectsModule.forFeature([QueueCreateDialogEffects]), + LabeledFormFieldDirective, ], declarations : [QueueCreateDialogComponent, CreateNewQueueFormComponent] }) diff --git a/src/app/webapp-common/shared/services/login.service.ts b/src/app/webapp-common/shared/services/login.service.ts index bf5e7a9b..559c22bf 100644 --- a/src/app/webapp-common/shared/services/login.service.ts +++ b/src/app/webapp-common/shared/services/login.service.ts @@ -6,7 +6,7 @@ import {UsersGetAllResponse} from '~/business-logic/model/users/usersGetAllRespo import {AuthCreateUserResponse} from '~/business-logic/model/auth/authCreateUserResponse'; import {v1 as uuidV1} from 'uuid'; import {EMPTY, Observable, of, throwError, timer} from 'rxjs'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {ConfirmDialogComponent} from '../ui-components/overlay/confirm-dialog/confirm-dialog.component'; import {LoginModeResponse} from '~/business-logic/model/LoginModeResponse'; import {clone} from 'lodash-es'; diff --git a/src/app/webapp-common/shared/services/report-code-embed-base.service.ts b/src/app/webapp-common/shared/services/report-code-embed-base.service.ts index e45b1603..a7e2ad3e 100644 --- a/src/app/webapp-common/shared/services/report-code-embed-base.service.ts +++ b/src/app/webapp-common/shared/services/report-code-embed-base.service.ts @@ -11,8 +11,9 @@ import {ClipboardService} from 'ngx-clipboard'; import { take } from 'rxjs'; export interface ReportCodeEmbedConfiguration { - type: 'plot' | 'multiplot' | 'scalar' | 'multiscalar' | 'sample' | 'parcoords'; - tasks: string[]; + type: 'plot' | 'multiplot' | 'scalar' | 'multiscalar' | 'sample' | 'parcoords' | 'single'; + objects?: string[]; + objectType: 'model' | 'task'; domRect: DOMRect; name?: string; metrics?: string[]; @@ -50,9 +51,10 @@ export class ReportCodeEmbedBaseService { const url = new URL(window.location.origin + this.locationStrategy.getBaseHref()); url.pathname = url.pathname + 'widgets/'; url.searchParams.set('type', conf.type); + url.searchParams.set('objectType', conf.objectType); conf.valueType && url.searchParams.set('value_type', conf.valueType); let urlStr = url.toString(); - ['tasks', 'metrics', 'variants'].forEach(key => { + ['objects', 'metrics', 'variants'].forEach(key => { if (conf[key]?.filter(v => !!v).length > 0) { urlStr += '&' + conf[key].map(val => `${key}=${encodeURIComponent(val)}`).join('&'); } diff --git a/src/app/webapp-common/shared/services/tips.service.ts b/src/app/webapp-common/shared/services/tips.service.ts index 74aabc3b..20a08ec2 100644 --- a/src/app/webapp-common/shared/services/tips.service.ts +++ b/src/app/webapp-common/shared/services/tips.service.ts @@ -1,7 +1,7 @@ import {Injectable} from '@angular/core'; import {HttpClient} from '@angular/common/http'; import {Store} from '@ngrx/store'; -import {MatLegacyDialog as MatDialog, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MatDialog, MatDialogRef} from '@angular/material/dialog'; import {selectRouterConfig} from '../../core/reducers/router-reducer'; import {combineLatest, Subscription} from 'rxjs'; import {debounceTime, distinctUntilChanged, filter, map, withLatestFrom} from 'rxjs/operators'; @@ -53,9 +53,10 @@ export class TipsService { initTipsService(showAllTips = true) { this.nextTimeToShowTips = new Date(window.localStorage.getItem('nextTimeToShowTips') || new Date().getTime()); - this.httpClient.get('onboarding.json').pipe(withLatestFrom(this.store.select(selectFeatures))) + this.httpClient.get('onboarding.json') + .pipe(withLatestFrom(this.store.select(selectFeatures))) .subscribe(([tipsConfig, features]: [{ onboarding: Tip[] }, FeaturesEnum[]]) => { - const tipsFiltered = tipsConfig.onboarding.filter(tip => !tip.feature || features.includes(tip.feature) || showAllTips); + const tipsFiltered = tipsConfig.onboarding.filter(tip => !tip.feature || !features || features.includes(tip.feature) || showAllTips); this.tipsConfig = { global: [], ...tipsFiltered.reduce((acc, curr) => { const context = curr.context || 'global'; diff --git a/src/app/webapp-common/shared/services/ui-updates.service.ts b/src/app/webapp-common/shared/services/ui-updates.service.ts index 93bf4342..aadde73c 100644 --- a/src/app/webapp-common/shared/services/ui-updates.service.ts +++ b/src/app/webapp-common/shared/services/ui-updates.service.ts @@ -3,7 +3,7 @@ import {HttpClient} from '@angular/common/http'; import versionConf from '../../../../version.json'; import {Store} from '@ngrx/store'; import {UiUpdateDialogComponent} from '../../layout/ui-update-dialog/ui-update-dialog.component'; -import {MatLegacyDialog as MatDialog, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MatDialog, MatDialogRef} from '@angular/material/dialog'; @Injectable({ providedIn: 'root' diff --git a/src/app/webapp-common/shared/shared.module.ts b/src/app/webapp-common/shared/shared.module.ts index 7888c623..10e02b7a 100755 --- a/src/app/webapp-common/shared/shared.module.ts +++ b/src/app/webapp-common/shared/shared.module.ts @@ -10,9 +10,8 @@ import {UiComponentsModule} from './ui-components/ui-components.module'; import {ChipsModule} from './ui-components/buttons/chips/chips.module'; import {ExperimentCardComponent} from './ui-components/panel/experiment-card/experiment-card.component'; import {ModelCardComponent} from './ui-components/panel/model-card/model-card.component'; -import {MatLegacyProgressSpinnerModule as MatProgressSpinnerModule} from '@angular/material/legacy-progress-spinner'; +import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; import {MatButtonToggleModule} from '@angular/material/button-toggle'; -import {MatLegacySnackBarModule as MatSnackBarModule} from '@angular/material/legacy-snack-bar'; import { ExperimentInfoHeaderStatusProgressBarComponent } from './experiment-info-header-status-progress-bar/experiment-info-header-status-progress-bar.component'; @@ -59,6 +58,7 @@ import { import { ExperimentTypeIconLabelComponent } from '@common/shared/experiment-type-icon-label/experiment-type-icon-label.component'; +import {LabeledFormFieldDirective} from '@common/shared/directive/labeled-form-field.directive'; const _declarations = [ ExperimentInfoHeaderStatusProgressBarComponent, @@ -100,14 +100,14 @@ const _declarations = [ UiComponentsModule, MatProgressSpinnerModule, MatButtonToggleModule, - MatSnackBarModule, ChipsModule, ScrollingModule, LMarkdownEditorModule, SharedPipesModule, + LabeledFormFieldDirective, ], declarations: [ - _declarations, + ..._declarations, BaseContextMenuComponent, ScatterPlotComponent, ClearFiltersButtonComponent, @@ -115,7 +115,7 @@ const _declarations = [ IdBadgeComponent, MarkdownCheatSheetDialogComponent, ], - exports: [..._declarations, UiComponentsModule, TableModule, ClipboardModule, MatSnackBarModule, + exports: [..._declarations, UiComponentsModule, TableModule, ClipboardModule, ScatterPlotComponent, ClearFiltersButtonComponent, IdBadgeComponent ], providers: [LeavingBeforeSaveAlertGuard, GeneralLeavingBeforeSaveAlertGuard] diff --git a/src/app/webapp-common/shared/single-graph/graph-viewer/graph-viewer.component.html b/src/app/webapp-common/shared/single-graph/graph-viewer/graph-viewer.component.html index 9e12977e..6bea5be7 100644 --- a/src/app/webapp-common/shared/single-graph/graph-viewer/graph-viewer.component.html +++ b/src/app/webapp-common/shared/single-graph/graph-viewer/graph-viewer.component.html @@ -6,54 +6,56 @@
Iteration {{iteration}} +
-
-
+
+
-
+
Horizontal Axis - - + + {{type.name}}
-
+
Smoothing + > - + null; + public yAxisType: AxisType; + public showSmooth: boolean; @HostListener('document:keydown', ['$event']) onKeyDown(e: KeyboardEvent) { @@ -127,7 +131,7 @@ export class GraphViewerComponent implements AfterViewInit, OnInit, OnDestroy { constructor( @Inject(MAT_DIALOG_DATA) public data: GraphViewerData, public dialogRef: MatDialogRef, - private store: Store, + private store: Store, private cdr: ChangeDetectorRef, ) { this.chart$ = this.store.select(selectFullScreenChart); @@ -142,11 +146,13 @@ export class GraphViewerComponent implements AfterViewInit, OnInit, OnDestroy { } this.store.dispatch(setGraphDisplayFullDetailsScalarsIsOpen({isOpen: true})); this.isCompare = data.isCompare; - this.isFullDetailsMode = ['multiScalar', 'scalar'].includes(data.chart.layout.type) && !this.isCompare; + this.yAxisType = data.yAxisType ?? 'linear'; + this.showSmooth = ['multiScalar', 'scalar'].includes(data.chart.layout.type); + this.isFullDetailsMode = this.showSmooth && !this.isCompare; this.id = data.id; this.embedFunction = data.embedFunction; this.darkTheme = data.darkTheme; - this.smoothWeight = data.smoothWeight; + this.smoothWeight = data.smoothWeight ?? 0; const reqData = { task: this.data.chart.task, metric: this.data.chart.metric, @@ -206,7 +212,8 @@ export class GraphViewerComponent implements AfterViewInit, OnInit, OnDestroy { if (this.index === null) { this.index = Math.max(this.charts.findIndex(c => c.variant === this.data.chart.variant), 0); } else { - this.index = this.isForward ? 0 : this.charts.length - 1; + this.index = this.charts.findIndex(chrt => chrt.metric === this.chart?.metric && chrt.variant === this.chart?.variant); + this.index = this.index === -1 ? (this.isForward ? 0 : this.charts.length - 1) : this.index; } this.chart = this.charts[this.index]; this.iteration = currentPlotEvents[0].iter; diff --git a/src/app/webapp-common/shared/single-graph/single-graph.component.scss b/src/app/webapp-common/shared/single-graph/single-graph.component.scss index 62ba71a4..36d8afe7 100644 --- a/src/app/webapp-common/shared/single-graph/single-graph.component.scss +++ b/src/app/webapp-common/shared/single-graph/single-graph.component.scss @@ -66,19 +66,9 @@ z-index: 2; } - // fix table content overflow 1px above header - ::ng-deep svg #header .column-cell { - transform: translate(0px, -1px); - - .cell-rect { - height: 30px; - } - } - ::ng-deep sm-color-picker-wrapper { display: block; top: 0px; - } ::ng-deep .legendlines path, ::ng-deep .legendpoints path { diff --git a/src/app/webapp-common/shared/single-graph/single-graph.component.ts b/src/app/webapp-common/shared/single-graph/single-graph.component.ts index da066153..22c9345f 100644 --- a/src/app/webapp-common/shared/single-graph/single-graph.component.ts +++ b/src/app/webapp-common/shared/single-graph/single-graph.component.ts @@ -35,11 +35,11 @@ import {ColorHashService} from '@common/shared/services/color-hash/color-hash.se import {wordWrap} from '@common/tasks/tasks.utils'; import {attachColorChooser} from '@common/shared/ui-components/directives/choose-color/choose-color.directive'; import {DARK_THEME_GRAPH_LINES_COLOR, DARK_THEME_GRAPH_TICK_COLOR, ExtData, ExtFrame, ExtLayout, ExtLegend, PlotlyGraphBaseComponent} from './plotly-graph-base'; -import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog'; +import {MatDialog} from '@angular/material/dialog'; import {PALLET} from '@common/constants'; import {download} from '@common/shared/utils/download'; import {chooseTimeUnit} from '@common/shared/utils/choose-time-unit'; -import {GraphViewerComponent} from './graph-viewer/graph-viewer.component'; +import {GraphViewerComponent, GraphViewerData} from './graph-viewer/graph-viewer.component'; // eslint-disable-next-line @typescript-eslint/naming-convention declare const Plotly; @@ -60,7 +60,6 @@ export class SingleGraphComponent extends PlotlyGraphBaseComponent { public type: PlotData['type'] | 'table'; public ratio: number; public title: string; - private yaxisType: AxisType = 'linear'; private originalChart: ExtFrame; private _chart: ExtFrame; private smoothnessTimeout: number; @@ -82,6 +81,7 @@ export class SingleGraphComponent extends PlotlyGraphBaseComponent { @Input() showLoaderOnDraw = true; @Input() hideMaximize: 'show' | 'hide' | 'disabled' = 'show'; @Input() legendConfiguration: Partial = {}; + @Input() yAxisType: AxisType = 'linear'; @Input() set height(height: number) { this._height = height; @@ -104,7 +104,7 @@ export class SingleGraphComponent extends PlotlyGraphBaseComponent { if (chart) { this.ratioEnable = !!chart.layout.width && !!chart.layout.height; this.ratio = this.ratioEnable ? chart.layout.width / chart.layout.height : null; - this.height = chart.layout.height || this.height || 450; + this._height = chart.layout.height || this.height || 450; this.originalChart = chart; this._chart = cloneDeep(chart); this.drawGraph$.next({forceRedraw: true, forceSkipReact: false}); @@ -176,7 +176,10 @@ export class SingleGraphComponent extends PlotlyGraphBaseComponent { ); this.sub.add(this.drawGraph$ - .pipe(debounceTime(100)) + .pipe( + debounceTime(100), + filter(() => !!this.chart) + ) .subscribe(({forceRedraw, forceSkipReact}) => { if (this.showLoaderOnDraw) { this.loading = true; @@ -197,7 +200,7 @@ export class SingleGraphComponent extends PlotlyGraphBaseComponent { // root.height > 0 to avoid rare plotly exception if ((this.plotlyContainer.nativeElement.offsetWidth !== this.previousOffsetWidth || forceSkipReact) && (root as HTMLElement).offsetHeight > 0) { - skipReact = true; + skipReact = this.plotlyContainer.nativeElement.offsetWidth === this.previousOffsetWidth; this.zone.runOutsideAngular(() => Plotly.relayout(root, { width: this.ratio ? this.height * this.ratio + RATIO_OFFSET_FIX : Math.max((data?.['data']?.[0]?.cells?.values?.length ?? 0) * 100, this.plotlyContainer.nativeElement.offsetWidth - 3), height: this.height, @@ -205,6 +208,9 @@ export class SingleGraphComponent extends PlotlyGraphBaseComponent { this.loading = false; this.changeDetector.detectChanges(); this.updateLegend(); + if ((data[0] as any)?.mode === 'gauge+number') { + this.fixGaugeValuePositionAfterResize(); + } })); } this.previousOffsetWidth = this.plotlyContainer.nativeElement.offsetWidth; @@ -396,7 +402,6 @@ export class SingleGraphComponent extends PlotlyGraphBaseComponent { r: 24, b: 0 }; - layout.height = Math.min((graph?.data?.[0]?.cells?.values?.[0]?.length ?? 15 ) * 30 + 150, this.height); } const barLayoutConfig = { hovermode: 'closest', @@ -442,7 +447,7 @@ export class SingleGraphComponent extends PlotlyGraphBaseComponent { spikedash: 'dash', rangeslider: {visible: false}, fixedrange: false, - type: this.yaxisType, + type: this.yAxisType, ...this.addParametersIfDarkTheme({ color: DARK_THEME_GRAPH_LINES_COLOR, gridcolor: DARK_THEME_GRAPH_LINES_COLOR, @@ -468,11 +473,11 @@ export class SingleGraphComponent extends PlotlyGraphBaseComponent { if (['multiScalar', 'scalar'].includes(graph.layout.type)) { modeBarButtonsToAdd.push({ name: 'Log view', - title: this.getLogButtonTitle(this.yaxisType === 'log'), - icon: this.getLogIcon(this.yaxisType === 'log'), + title: this.getLogButtonTitle(this.yAxisType === 'log'), + icon: this.getLogIcon(this.yAxisType === 'log'), click: (gd: PlotlyHTMLElement, ev: MouseEvent) => { - this.yaxisType = this.yaxisType === 'log' ? 'linear' : 'log'; - const icon = this.getLogIcon(this.yaxisType === 'log'); + this.yAxisType = this.yAxisType === 'log' ? 'linear' : 'log'; + const icon = this.getLogIcon(this.yAxisType === 'log'); let path: SVGPathElement; let svg: HTMLElement; if ((ev.target as SVGElement).tagName === 'svg') { @@ -482,7 +487,7 @@ export class SingleGraphComponent extends PlotlyGraphBaseComponent { path = ev.target as SVGPathElement; svg = path.parentElement as HTMLElement; } - svg.parentElement.attributes['data-title'].value = this.getLogButtonTitle(this.yaxisType === 'log'); + svg.parentElement.attributes['data-title'].value = this.getLogButtonTitle(this.yAxisType === 'log'); path.attributes[0].value = icon.path; this.smoothnessTimeout = window.setTimeout(() => { this._chart = cloneDeep(this.originalChart); @@ -578,8 +583,9 @@ export class SingleGraphComponent extends PlotlyGraphBaseComponent { const config = { modeBarButtonsToRemove: (this.hideDownloadButtons ? ['sendDataToCloud', 'toImage']: ['sendDataToCloud']) as ModeBarDefaultButtons[], displaylogo: false, - modeBarButtonsToAdd - }; + modeBarButtonsToAdd, + toImageButtonOptions : {scale: 3} + } as Config; return [this.chartElm, graph.data, layout, config, this.chartData]; } @@ -715,7 +721,7 @@ export class SingleGraphComponent extends PlotlyGraphBaseComponent { .subscribe(colorObj => { const graph = this.chart; let changed: boolean = false; - graph.data.forEach(trace => { + graph?.data.forEach(trace => { const name = trace.name; const [colorKey, ] = this.extractColorKey(name); if (!name || !this.colorHash.hasColor(colorKey)) { @@ -918,10 +924,11 @@ export class SingleGraphComponent extends PlotlyGraphBaseComponent { }), id: this.identifier, xAxisType: this.xAxisType, + yAxisType: this.yAxisType, smoothWeight: this.smoothWeight, darkTheme: this.isDarkTheme, isCompare: this.isCompare, - }, + } as GraphViewerData, panelClass: ['image-viewer-dialog', this.isDarkTheme ? 'dark-theme' : 'light-theme'], height: '100%', maxHeight: 'auto', @@ -966,4 +973,10 @@ export class SingleGraphComponent extends PlotlyGraphBaseComponent { public redrawPlot() { this.drawGraph$.next({forceRedraw: true, forceSkipReact: false}); }; + + private fixGaugeValuePositionAfterResize() { + const graph = select(this.plotlyContainer.nativeElement).selectAll('.main-svg .indicatorlayer .trace'); + const graphPosition = graph.selectAll('.angular').attr('transform'); + graph.selectAll('.numbers').attr('transform', graphPosition); + } } diff --git a/src/app/webapp-common/shared/single-graph/single-graph.effects.ts b/src/app/webapp-common/shared/single-graph/single-graph.effects.ts index fb3d3d6e..13c142e4 100644 --- a/src/app/webapp-common/shared/single-graph/single-graph.effects.ts +++ b/src/app/webapp-common/shared/single-graph/single-graph.effects.ts @@ -55,17 +55,13 @@ export class SingleGraphEffects { getNextPlotsForIter$ = createEffect(() => this.actions$.pipe( ofType(getNextPlotSample), - withLatestFrom( - this.store.select(selectPlotViewerScrollId), - this.store.select(selectRouterConfig).pipe(map(config => !!config?.includes('models'))) - ), - switchMap(([action, scrollId, model]) => + withLatestFrom(this.store.select(selectPlotViewerScrollId)), + switchMap(([action, scrollId]) => this.eventsApi.eventsNextPlotSample({ /* eslint-disable @typescript-eslint/naming-convention */ task: action.task, scroll_id: scrollId, navigate_earlier: action.navigateEarlier, - ...(model && {model_events: true}), ...(action.iteration && {next_iteration: true}) /* eslint-enable @typescript-eslint/naming-convention */ }) diff --git a/src/app/webapp-common/shared/single-graph/single-graph.module.ts b/src/app/webapp-common/shared/single-graph/single-graph.module.ts index 7fd8be35..4d8823e2 100644 --- a/src/app/webapp-common/shared/single-graph/single-graph.module.ts +++ b/src/app/webapp-common/shared/single-graph/single-graph.module.ts @@ -6,10 +6,10 @@ import {SingleGraphComponent} from '@common/shared/single-graph/single-graph.com import {GraphViewerComponent} from '@common/shared/single-graph/graph-viewer/graph-viewer.component'; import {singleGraphReducer} from '@common/shared/single-graph/single-graph.reducer'; import { SingleGraphEffects } from './single-graph.effects'; -import {MatLegacySliderModule as MatSliderModule} from '@angular/material/legacy-slider'; -import {MatLegacySelectModule as MatSelectModule} from '@angular/material/legacy-select'; +import {MatSliderModule} from '@angular/material/slider'; +import {MatSelectModule} from '@angular/material/select'; import {FormsModule} from '@angular/forms'; -import {MatLegacyInputModule as MatInputModule} from '@angular/material/legacy-input'; +import {MatInputModule} from '@angular/material/input'; import {TooltipDirective} from '@common/shared/ui-components/indicators/tooltip/tooltip.directive'; diff --git a/src/app/webapp-common/shared/single-value-summary-table/single-value-summary-table.component.html b/src/app/webapp-common/shared/single-value-summary-table/single-value-summary-table.component.html new file mode 100644 index 00000000..d9025d70 --- /dev/null +++ b/src/app/webapp-common/shared/single-value-summary-table/single-value-summary-table.component.html @@ -0,0 +1,14 @@ +
+
Summary
+ +
+
+
{{item.variant}}
+
{{item.value}}
+
+
+
+ + +
+
diff --git a/src/app/webapp-common/shared/single-value-summary-table/single-value-summary-table.component.scss b/src/app/webapp-common/shared/single-value-summary-table/single-value-summary-table.component.scss new file mode 100644 index 00000000..52a8a4c6 --- /dev/null +++ b/src/app/webapp-common/shared/single-value-summary-table/single-value-summary-table.component.scss @@ -0,0 +1,100 @@ +@import "src/app/webapp-common/shared/ui-components/styles/variables"; + + +.single-table-container { + border-radius: 4px; + border: solid 1px $blue-100; + + + .summary-header { + padding: 12px; + font-size: 16px; + color: $blue-600; + text-align: center; + } + + + .items-container { + border-top: solid 1px $blue-100; + overflow: auto; + + .item { + padding: 12px 24px; + text-align: center; + + &:not(:last-child) { + border-right: solid 1px $blue-100; + } + + .variant { + color: #71758a; + margin-bottom: 6px; + } + + .value { + color: $blue-500; + } + } + } +} + +:host { + position: relative; + display: flex; + align-items: center; + justify-content: center; + height: 100%; + + .actions { + position: absolute; + display: flex; + align-items: center; + top: 12px; + right: 12px; + gap: 6px; + opacity: 0; + transition: opacity 300ms ease; + + .clickable-icon { + background-color: $blue-300; + color: $blue-50; + border-radius: 4px; + cursor: pointer; + } + } + + &:hover { + .actions { + opacity: 1; + } + } + + /////// DARK THEME ////////// + .dark-theme { + &.single-table-container { + border: solid 1px $dark-border; + } + + .summary-header { + color: $blue-300; + } + + .items-container { + border-top: solid 1px $dark-border; + + .item { + &:not(:last-child) { + border-right: solid 1px $dark-border; + } + + .variant { + color: $blue-300; + } + + .value { + color: $blue-100; + } + } + } + } +} diff --git a/src/app/webapp-common/shared/experiment-graphs/single-value-summary-table/single-value-summary-table.component.ts b/src/app/webapp-common/shared/single-value-summary-table/single-value-summary-table.component.ts similarity index 52% rename from src/app/webapp-common/shared/experiment-graphs/single-value-summary-table/single-value-summary-table.component.ts rename to src/app/webapp-common/shared/single-value-summary-table/single-value-summary-table.component.ts index 6e80f113..2169d144 100644 --- a/src/app/webapp-common/shared/experiment-graphs/single-value-summary-table/single-value-summary-table.component.ts +++ b/src/app/webapp-common/shared/single-value-summary-table/single-value-summary-table.component.ts @@ -1,15 +1,24 @@ -import {Component, Input, OnInit} from '@angular/core'; -import { EventsGetTaskSingleValueMetricsResponseValues } from '~/business-logic/model/events/eventsGetTaskSingleValueMetricsResponseValues'; -import {download} from '../../utils/download'; +import {ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {EventsGetTaskSingleValueMetricsResponseValues} from '~/business-logic/model/events/eventsGetTaskSingleValueMetricsResponseValues'; +import {download} from '../utils/download'; +import {NgForOf, NgIf} from '@angular/common'; @Component({ selector: 'sm-single-value-summary-table', templateUrl: './single-value-summary-table.component.html', - styleUrls: ['./single-value-summary-table.component.scss'] + styleUrls: ['./single-value-summary-table.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + NgForOf, + NgIf + ], + standalone: true }) export class SingleValueSummaryTableComponent implements OnInit { @Input() data: Array; @Input() experimentName; + @Input() darkTheme: boolean; + @Output() createEmbedCode = new EventEmitter(); public hover: boolean; constructor() { } @@ -26,7 +35,7 @@ export class SingleValueSummaryTableComponent implements OnInit { } } - setHover(hover: boolean) { - this.hover = hover; + createEmbedCodeClicked($event: MouseEvent) { + this.createEmbedCode.emit({x: $event.clientX, y: $event.clientY}); } } diff --git a/src/app/webapp-common/shared/ui-components/buttons/chips/chips.component.html b/src/app/webapp-common/shared/ui-components/buttons/chips/chips.component.html index dbfdc2df..c9949524 100755 --- a/src/app/webapp-common/shared/ui-components/buttons/chips/chips.component.html +++ b/src/app/webapp-common/shared/ui-components/buttons/chips/chips.component.html @@ -6,19 +6,21 @@ (mousedown)="$event.stopPropagation()" > - {{label}} + {{label}} - +
diff --git a/src/app/webapp-common/shared/ui-components/data/selectable-list/selectable-list.component.html b/src/app/webapp-common/shared/ui-components/data/selectable-list/selectable-list.component.html index 33e4bce4..6644c19c 100644 --- a/src/app/webapp-common/shared/ui-components/data/selectable-list/selectable-list.component.html +++ b/src/app/webapp-common/shared/ui-components/data/selectable-list/selectable-list.component.html @@ -5,7 +5,7 @@ [class.unchecked]="!item.visible" (click)="onItemSelect.emit(item.value)" > -
{{item.value}}
+
{{item.value}}
diff --git a/src/app/webapp-common/shared/ui-components/data/simple-table/simple-table.component.scss b/src/app/webapp-common/shared/ui-components/data/simple-table/simple-table.component.scss index 6b4aec92..74988675 100755 --- a/src/app/webapp-common/shared/ui-components/data/simple-table/simple-table.component.scss +++ b/src/app/webapp-common/shared/ui-components/data/simple-table/simple-table.component.scss @@ -97,7 +97,7 @@ $table-row-padding: 10px; .empty-state { text-align: center; padding-top: 12px; - color: $blue-300; + color: $blue-400; } } diff --git a/src/app/webapp-common/shared/ui-components/data/table-card/table-card.component.html b/src/app/webapp-common/shared/ui-components/data/table-card/table-card.component.html index e6cc6f83..d0d64b6c 100644 --- a/src/app/webapp-common/shared/ui-components/data/table-card/table-card.component.html +++ b/src/app/webapp-common/shared/ui-components/data/table-card/table-card.component.html @@ -1,4 +1,4 @@ -
@@ -14,7 +14,7 @@
-
+
diff --git a/src/app/webapp-common/shared/ui-components/data/table/base-table-view.ts b/src/app/webapp-common/shared/ui-components/data/table/base-table-view.ts index 7fd95ec9..3e7d45d4 100644 --- a/src/app/webapp-common/shared/ui-components/data/table/base-table-view.ts +++ b/src/app/webapp-common/shared/ui-components/data/table/base-table-view.ts @@ -64,11 +64,13 @@ export abstract class BaseTableView implements AfterViewInit, OnDestroy { @Input() tableSortOrder: TableSortOrderEnum; @Input() minimizedView: boolean; + @Input() hideSelectAll: boolean; @Input() set split(size: number) { this.table?.resize(); } + @Output() filterSearchChanged = new EventEmitter() as EventEmitter<{ colId: string; value: {value: string; loadMore?: boolean} }>; @Output() filterChanged = new EventEmitter() as EventEmitter<{ col: ISmCol; value: any; andFilter?: boolean }>; @Output() columnsReordered = new EventEmitter(); @ViewChildren(TableComponent) tables: QueryList; @@ -161,9 +163,13 @@ export abstract class BaseTableView implements AfterViewInit, OnDestroy { this.filtersOptions = {...this.filtersOptions, [columnId]: [...this.filtersOptions[columnId]]}; } - searchValueChanged($event: string, colId: string) { - this.searchValues[colId] = $event; - this.sortOptionsList(colId); + searchValueChanged($event: {value: string; loadMore?: boolean}, colId: string, asyncFilter?: boolean) { + this.searchValues[colId] = $event.value; + if (asyncFilter) { + this.filterSearchChanged.emit({colId, value: $event}); + } else { + this.sortOptionsList(colId); + } } columnFilterClosed(col: ISmCol) { diff --git a/src/app/webapp-common/shared/ui-components/data/table/table-card-filter-template/table-card-filter-template.component.html b/src/app/webapp-common/shared/ui-components/data/table/table-card-filter-template/table-card-filter-template.component.html index 3df8d8a6..d6e9b1ea 100755 --- a/src/app/webapp-common/shared/ui-components/data/table/table-card-filter-template/table-card-filter-template.component.html +++ b/src/app/webapp-common/shared/ui-components/data/table/table-card-filter-template/table-card-filter-template.component.html @@ -14,13 +14,13 @@
- + - +
- Any All @@ -45,10 +45,11 @@ (itemClicked)="onSubFilterChanged({id :'system_tags'}, $event)" >
+
{{col.columnExplain}}
-
+
Clear all
diff --git a/src/app/webapp-common/shared/ui-components/data/table/table-card-filter-template/table-card-filter-template.component.scss b/src/app/webapp-common/shared/ui-components/data/table/table-card-filter-template/table-card-filter-template.component.scss index 58a8243d..a1b8b40e 100755 --- a/src/app/webapp-common/shared/ui-components/data/table/table-card-filter-template/table-card-filter-template.component.scss +++ b/src/app/webapp-common/shared/ui-components/data/table/table-card-filter-template/table-card-filter-template.component.scss @@ -69,3 +69,8 @@ .clear-all { padding-left: 32px; } + +.column-explanation { + padding: 5px; + font-size: 10px; +} diff --git a/src/app/webapp-common/shared/ui-components/data/table/table-card-filter-template/table-card-filter-template.component.ts b/src/app/webapp-common/shared/ui-components/data/table/table-card-filter-template/table-card-filter-template.component.ts index 9ae8914c..b38ee4ad 100755 --- a/src/app/webapp-common/shared/ui-components/data/table/table-card-filter-template/table-card-filter-template.component.ts +++ b/src/app/webapp-common/shared/ui-components/data/table/table-card-filter-template/table-card-filter-template.component.ts @@ -1,7 +1,7 @@ import {ChangeDetectionStrategy, Component, EventEmitter, Input, Output, ViewChild} from '@angular/core'; import {ISmCol} from '../table.consts'; import {addOrRemoveFromArray} from '../../../../utils/shared-utils'; -import {MatLegacyMenuTrigger as MatMenuTrigger} from '@angular/material/legacy-menu'; +import {MatMenuTrigger} from '@angular/material/menu'; import {trackByKey} from '@common/shared/utils/forms-track-by'; @Component({ diff --git a/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-duration-sort.base.ts b/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-duration-sort-base.component.ts similarity index 66% rename from src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-duration-sort.base.ts rename to src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-duration-sort-base.component.ts index 46cf2db5..fe2f9d75 100644 --- a/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-duration-sort.base.ts +++ b/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-duration-sort-base.component.ts @@ -1,9 +1,10 @@ import {ChangeDetectorRef, Component, EventEmitter, Input, Output} from '@angular/core'; import {getValueOrDefault, hasValue} from '../../../../utils/helpers.util'; +import {ErrorStateMatcher} from '@angular/material/core'; export interface IDurationThan { checked: boolean; - value: number | '' | null; + value: any; } export const emptyDuration ={ @@ -13,12 +14,78 @@ export const emptyDuration ={ export type DurationParameters = 'lessThan' | 'greaterThan'; + +const enum SERVER_POSITION { + GREATER_THAN, + LESS_THAN +} +/** + * Server communication helper; + * to the server [greaterThan, lessThan] + * from the server [greaterThan, lessThan] -> {greaterThan, lessThan} + */ +export class DataInputOutputHelper { + static encodeToServerData( + data: { greaterThan: IDurationThan; lessThan: IDurationThan }, + prepareDataToServerFunction: (data) => string | number + ): Array { + let greaterThan = null; + let lessThan = null; + const positions = [] as Array; + + if (data?.greaterThan?.checked) { + greaterThan = prepareDataToServerFunction(data.greaterThan.value); + } + if (data?.lessThan?.checked) { + lessThan = prepareDataToServerFunction(data.lessThan.value); + } + + if (lessThan !== null || greaterThan !== null) { + positions[SERVER_POSITION.LESS_THAN] = lessThan; + positions[SERVER_POSITION.GREATER_THAN] = greaterThan; + } + + return positions; + } + static decodeFromServerData( + data: Array | null = [], + useOldValues?: {greaterThan?: IDurationThan; lessThan?: IDurationThan}, + parseServerDataFunction?: (data) => number + ): {greaterThan: IDurationThan; lessThan: IDurationThan} { + // no data from the store + if(data.length === 0) { + return { + greaterThan: { + value: useOldValues?.greaterThan.value ?? null, + checked: false + }, + lessThan: { + value: useOldValues?.lessThan.value ?? null, + checked: false + } + }; + } + // got data from the store + return { + greaterThan: { + value: (getValueOrDefault(parseServerDataFunction(data[SERVER_POSITION.GREATER_THAN]), useOldValues?.greaterThan.value ?? null) ), + checked: data[SERVER_POSITION.GREATER_THAN] !== null && data[SERVER_POSITION.GREATER_THAN] !== '' + }, + lessThan: { + value: (getValueOrDefault(parseServerDataFunction(data[SERVER_POSITION.LESS_THAN]), useOldValues?.lessThan.value ?? null) ), + checked: data[SERVER_POSITION.LESS_THAN] !== null && data[SERVER_POSITION.LESS_THAN] !== '' + } + }; + } +} + + @Component({ - template: '' + template: 'sm-table-duration-base' }) -export abstract class TableDurationSortBase { +export abstract class TableDurationSortBaseComponent { @Output() filterChanged = new EventEmitter<{ value: any }>(); - @Output() onHasError = new EventEmitter(); + @Output() hasError = new EventEmitter(); @Input() set value(value: Array) { this.updateValue(value); @@ -53,7 +120,7 @@ export abstract class TableDurationSortBase { if (this.isFirstTimeUpdate) { this.isFirstTimeUpdate = false; - const data = dataInputOutputHelper.decodeFromServerData(value, {greaterThan: this.greaterThan, lessThan: this.lessThan}, this.parseServerDataFunction); + const data = DataInputOutputHelper.decodeFromServerData(value, {greaterThan: this.greaterThan, lessThan: this.lessThan}, this.parseServerDataFunction); this.greaterThan = data.greaterThan; this.lessThan = data.lessThan; this._updateValue(); @@ -61,33 +128,18 @@ export abstract class TableDurationSortBase { } - /** - * If we need to have data adjustment after we have a new value; - * If no uses, keep it empty; - */ abstract _updateValue(): void; get isFiltered(): boolean { return this.shouldValidate(); } - /** - * Set checkbox as active or not and update the State; - * @param checked; - * @param checkBoxName - */ public setCheckBox(checked: boolean, checkBoxName: DurationParameters, shouldValidate = true): void { this[checkBoxName] = {...this[checkBoxName], checked}; shouldValidate && this.validateAfterChanges(); } - /** - * Set the time for the current object; - * If checked, update the Store; - * @param value - * @param valueName - */ - public timeStampChanged(value: number, valueName: DurationParameters): void { + public timeStampChanged(value: number | string | null, valueName: DurationParameters): void { if (this.checkIfSameValues(value, valueName)) { return; } @@ -105,25 +157,15 @@ export abstract class TableDurationSortBase { } - /** - * Prevent from updating if we have the same value from the input; - * @param value - * @param valueName - * @private - */ - private checkIfSameValues(value: number, valueName: DurationParameters) { + private checkIfSameValues(value: number | string | null, valueName: DurationParameters) { return value === this[valueName].value; } - /** - * After value changed \ checkbox active Validate if need to update the Store; - * @private - */ private validateAfterChanges() { if (this.shouldValidate()) { const isValidAfterChanges = this.isValidAfterChanges(); this.hasTimeError = !isValidAfterChanges; - this.onHasError.emit(!isValidAfterChanges); + this.hasError.emit(!isValidAfterChanges); if (isValidAfterChanges) { this.updateState(); } else { @@ -155,74 +197,17 @@ export abstract class TableDurationSortBase { /** * Update the Store; + * * @private */ private updateState() { - const value = dataInputOutputHelper.encodeToServerData({greaterThan: this.greaterThan, lessThan: this.lessThan}, this.prepareDataToServerFunction); + const value = DataInputOutputHelper.encodeToServerData({greaterThan: this.greaterThan, lessThan: this.lessThan}, this.prepareDataToServerFunction); this.filterChanged.emit({value}); } } -const enum SERVER_POSITION { - GREATER_THAN, - LESS_THAN -} -/** - * Server communication helper; - * to the server [greaterThan, lessThan] - * from the server [greaterThan, lessThan] -> {greaterThan, lessThan} - */ -export class dataInputOutputHelper { - static encodeToServerData( - data: { greaterThan: IDurationThan; lessThan: IDurationThan }, - prepareDataToServerFunction: (data) => string | number - ): Array { - let greaterThan = null; - let lessThan = null; - const positions = [] as Array; - - if (data?.greaterThan?.checked) { - greaterThan = prepareDataToServerFunction(data.greaterThan.value); - } - if (data?.lessThan?.checked) { - lessThan = prepareDataToServerFunction(data.lessThan.value); - } - - if (lessThan !== null || greaterThan !== null) { - positions[SERVER_POSITION.LESS_THAN] = lessThan; - positions[SERVER_POSITION.GREATER_THAN] = greaterThan; - } - - return positions; - } - static decodeFromServerData( - data: Array | null = [], - useOldValues?: {greaterThan?: IDurationThan; lessThan?: IDurationThan}, - parseServerDataFunction?: (data) => number): {greaterThan: IDurationThan; lessThan: IDurationThan} - { - // no data from the store - if(data.length === 0) { - return { - greaterThan: { - value: useOldValues?.greaterThan.value ?? null, - checked: false - }, - lessThan: { - value: useOldValues?.lessThan.value ?? null, - checked: false - } - }; - } - // got data from the store - return { - greaterThan: { - value: (getValueOrDefault(parseServerDataFunction(data[SERVER_POSITION.GREATER_THAN]), useOldValues?.greaterThan.value ?? null) ), - checked: data[SERVER_POSITION.GREATER_THAN] !== null && data[SERVER_POSITION.GREATER_THAN] !== '' - }, - lessThan: { - value: (getValueOrDefault(parseServerDataFunction(data[SERVER_POSITION.LESS_THAN]), useOldValues?.lessThan.value ?? null) ), - checked: data[SERVER_POSITION.LESS_THAN] !== null && data[SERVER_POSITION.LESS_THAN] !== '' - } - }; - } +export class ImmediateErrorStateMatcher implements ErrorStateMatcher { + isErrorState(control) { + return control && control.invalid; // will show error in every case when control is invalid. i.e. field will be red from the very beginning. + } } diff --git a/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration-date-time/table-filter-duration-date-time.component.html b/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration-date-time/table-filter-duration-date-time.component.html index 68f86905..6e23be3a 100644 --- a/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration-date-time/table-filter-duration-date-time.component.html +++ b/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration-date-time/table-filter-duration-date-time.component.html @@ -5,12 +5,12 @@
-
+
-
+
-->
-
+
-
+
{ const offset = myDate.getTimezoneOffset() * TIME_IN_MILLI.ONE_MIN; const withOffset = myDate.getTime(); - const withoutOffset = withOffset - offset; - return withoutOffset; + return withOffset - offset; }; -/** - * Remove Seconds, Minutes and Hours from Date object - * - * @param date - */ const mutedDateToNoHourMinutesSeconds = (_date: Date | number) => { const date = new Date(_date); date.setSeconds(0); @@ -71,7 +65,7 @@ export const getTimeInSecondsFromDate = (_date: number | Date): number => { ], changeDetection: ChangeDetectionStrategy.OnPush }) -export class TableFilterDurationDateTimeComponent extends TableDurationSortBase implements OnInit { +export class TableFilterDurationDateTimeComponent extends TableDurationSortBaseComponent implements OnInit { _selectedDate: Date; _selectedTimeInSeconds: number; diff --git a/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration-error/table-filter-duration-error.component.html b/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration-error/table-filter-duration-error.component.html index 1235ce70..e8653931 100644 --- a/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration-error/table-filter-duration-error.component.html +++ b/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration-error/table-filter-duration-error.component.html @@ -1 +1 @@ -
When two terms are specified, the first must precede (or equal) the second
+
When two terms are specified, the first must precede (or equal) the second
diff --git a/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration-numeric/table-filter-duration-numeric.component.html b/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration-numeric/table-filter-duration-numeric.component.html index 724a98ca..9a3580f6 100644 --- a/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration-numeric/table-filter-duration-numeric.component.html +++ b/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration-numeric/table-filter-duration-numeric.component.html @@ -1,65 +1,35 @@ -
- -
-
Equals or greater than
-
- -
-
- -
-
- -
-
- -
-
+ + + Equals or greater than + + + -
-
Equals or less than
-
- -
-
- -
-
- -
-
- -
-
+ + Equals or less than + + +
- diff --git a/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration-numeric/table-filter-duration-numeric.component.scss b/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration-numeric/table-filter-duration-numeric.component.scss index 9228d7f6..c9a720c1 100644 --- a/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration-numeric/table-filter-duration-numeric.component.scss +++ b/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration-numeric/table-filter-duration-numeric.component.scss @@ -11,12 +11,17 @@ position: relative; input { width: calc(100% - 15px); + + &:invalid { + background-color: $error-color; + } } + .reset { border: none; position: absolute; top: 0; - right: 0px; + right: 0; display: flex; align-items: center; } diff --git a/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration-numeric/table-filter-duration-numeric.component.ts b/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration-numeric/table-filter-duration-numeric.component.ts index b4e8a49d..ce833e93 100644 --- a/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration-numeric/table-filter-duration-numeric.component.ts +++ b/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration-numeric/table-filter-duration-numeric.component.ts @@ -5,13 +5,17 @@ import { OnDestroy, OnInit, } from '@angular/core'; -import {IDurationThan, DurationParameters, TableDurationSortBase} from '../table-duration-sort.base'; -import {UntypedFormControl, UntypedFormGroup} from '@angular/forms'; -import {distinctUntilChanged, debounceTime, map} from 'rxjs/operators'; -import {merge, Subscription} from 'rxjs'; +import { + IDurationThan, + ImmediateErrorStateMatcher, + TableDurationSortBaseComponent +} from '../table-duration-sort-base.component'; +import {FormControl, FormGroup, Validators} from '@angular/forms'; +import {distinctUntilChanged, debounceTime, filter} from 'rxjs/operators'; +import {Subscription} from 'rxjs'; import {isNil} from 'lodash-es'; -const getDurationValue = (data: IDurationThan) => isNil(data.value) || !data.checked ? '' : data.value; +const getDurationValue = (value: IDurationThan) => value.checked ? `${value.value}` : ''; @Component({ @@ -21,31 +25,32 @@ const getDurationValue = (data: IDurationThan) => isNil(data.value) || !data.che changeDetection: ChangeDetectionStrategy.OnPush }) -export class TableFilterDurationNumericComponent extends TableDurationSortBase implements OnInit, OnDestroy { - iterationsForm = new UntypedFormGroup( { - greaterThan: new UntypedFormControl(''), - lessThan: new UntypedFormControl('') - }); +export class TableFilterDurationNumericComponent extends TableDurationSortBaseComponent implements OnInit, OnDestroy { private subscription: Subscription; + immediate = new ImmediateErrorStateMatcher(); + numericPattern = '(|-?(0\\.|\\.|)\\d*)'; + + iterationsForm = new FormGroup( { + greaterThan: new FormControl('', [Validators.pattern(this.numericPattern)]), + lessThan: new FormControl('', [Validators.pattern(this.numericPattern)]) + }); constructor(cdr: ChangeDetectorRef) { super(cdr); } ngOnInit(): void { - const greaterThan$ = this.iterationsForm.get('greaterThan').valueChanges.pipe( map (value => ({name: 'greaterThan', value}))); - const lessThan$ = this.iterationsForm.get('lessThan').valueChanges.pipe( map (value => ({name: 'lessThan', value}))); - - this.subscription = merge(greaterThan$, lessThan$ ) + this.iterationsForm.valueChanges .pipe( debounceTime(200), + filter(() => this.iterationsForm.valid), distinctUntilChanged() ) - .subscribe( ({value, name}: {value: number; name: DurationParameters}) => { - if (this[name].checked !== !!value) { - this.setCheckBox(!!value, name, false); - } - this.timeStampChanged(value, name); + .subscribe( ({greaterThan, lessThan}) => { + !!greaterThan != this.greaterThan.checked && this.setCheckBox(!this.greaterThan.checked, 'greaterThan', false); + this.timeStampChanged(!!greaterThan ? parseInt(greaterThan, 10) : greaterThan, 'greaterThan'); + !!lessThan != this.lessThan.checked && this.setCheckBox(!this.lessThan.checked, 'lessThan', false); + this.timeStampChanged(!!lessThan ? parseInt(lessThan, 10) : lessThan, 'lessThan'); }); } @@ -55,6 +60,7 @@ export class TableFilterDurationNumericComponent extends TableDurationSortBase i prepareDataToServerFunction(data): string | number | null { return isNil(data) || data === '' ? null : +data ; } + _updateValue(): void { const greaterThan = getDurationValue(this.greaterThan); const lessThan = getDurationValue(this.lessThan); diff --git a/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration/table-filter-duration.component.html b/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration/table-filter-duration.component.html index bbd57b07..c400786a 100644 --- a/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration/table-filter-duration.component.html +++ b/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration/table-filter-duration.component.html @@ -5,7 +5,7 @@
@@ -30,7 +30,7 @@
diff --git a/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration/table-filter-duration.component.ts b/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration/table-filter-duration.component.ts index bb2d19fe..1b572379 100644 --- a/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration/table-filter-duration.component.ts +++ b/src/app/webapp-common/shared/ui-components/data/table/table-duration-sort-template/table-filter-duration/table-filter-duration.component.ts @@ -1,5 +1,5 @@ import {ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit} from '@angular/core'; -import {DurationParameters, TableDurationSortBase} from '../table-duration-sort.base'; +import {DurationParameters, TableDurationSortBaseComponent} from '../table-duration-sort-base.component'; import {isNil} from 'lodash-es'; @Component({ @@ -9,7 +9,7 @@ import {isNil} from 'lodash-es'; changeDetection: ChangeDetectionStrategy.OnPush }) -export class TableFilterDurationComponent extends TableDurationSortBase implements OnInit { +export class TableFilterDurationComponent extends TableDurationSortBaseComponent implements OnInit { constructor(cdr: ChangeDetectorRef) { super(cdr); diff --git a/src/app/webapp-common/shared/ui-components/data/table/table-filter-sort-template/table-filter-sort-template.component.html b/src/app/webapp-common/shared/ui-components/data/table/table-filter-sort-template/table-filter-sort-template.component.html index d3452984..64f5d0c2 100755 --- a/src/app/webapp-common/shared/ui-components/data/table/table-filter-sort-template/table-filter-sort-template.component.html +++ b/src/app/webapp-common/shared/ui-components/data/table/table-filter-sort-template/table-filter-sort-template.component.html @@ -20,14 +20,16 @@ [class.active]="isSorted || isFiltered()">{{header}}
- Any + Any All
@@ -56,6 +58,9 @@ [checkedList]="value" (filterChanged)="emitFilterChanged($event)" > +
+
+
; + public previousLength: number | undefined; + public noMoreOptions: boolean; + public filterPageSize: number; + private previousSearchValue: { label: string; value: string; tooltip?: string } | undefined; @Input() set column(col: ISmCol) { this.header = col.header; @@ -43,12 +50,14 @@ export class TableFilterSortTemplateComponent { this.supportAndFilter = col.andFilter; this.supportExcludeFilter = col.excludeFilter; this.columnExplain = col.columnExplain; + this.filterPageSize = col.paginatedFilterPageSize; } @Input() searchValue; @Input() fixedOptionsSubheader; @Input() set value(filters: Array) { + this.loading = false; if (Array.isArray(filters)) { this.formControl.setValue(filters); this._value = filters; @@ -65,7 +74,21 @@ export class TableFilterSortTemplateComponent { @Input() subValue: string[] = []; @Input() andFilter: boolean = null; - @Input() options: Array<{ label: string; value: string; tooltip?: string }>; + @Input() set options(options: Array<{ label: string; value: string; tooltip?: string }>) { + if (options) { + this.noMoreOptions = options?.length < this.filterPageSize || options?.length === this.previousLength && this.searchValue === this.previousSearchValue; + this.previousLength = options?.length; + this.previousSearchValue = this.searchValue; + this.searching = false; + this.loading = false; + } + this._options = options; + } + + get options() { + return this._options; + } + @Input() subOptions: Array<{ label: string; value: string }>; @Input() tooltip: boolean = false; @Output() filterChanged = new EventEmitter(); @@ -73,7 +96,7 @@ export class TableFilterSortTemplateComponent { @Output() menuClosed = new EventEmitter(); @Output() menuOpened = new EventEmitter(); @Output() sortOrderChanged = new EventEmitter(); - @Output() searchValueChanged = new EventEmitter(); + @Output() searchValueChanged = new EventEmitter<{ value: string; loadMore?: boolean }>(); constructor() { } @@ -121,4 +144,16 @@ export class TableFilterSortTemplateComponent { andFilter: this.andFilter }); } + + loadMore() { + this.loading = true; + this.searchValueChanged.emit({value: this.searchValue || '', loadMore: true}); + } + + onMenuClose() { + if (!this.noMoreOptions) { + this.previousLength = 0; + } + this.menuClosed.emit(); + } } diff --git a/src/app/webapp-common/shared/ui-components/data/table/table.component.html b/src/app/webapp-common/shared/ui-components/data/table/table.component.html index 86f8691e..aa4f0cc7 100755 --- a/src/app/webapp-common/shared/ui-components/data/table/table.component.html +++ b/src/app/webapp-common/shared/ui-components/data/table/table.component.html @@ -102,6 +102,7 @@ [pRowTogglerDisabled]="!expandableRows" [pSelectableRow]="rowData" [pContextMenuRow]="rowData" + [pContextMenuRowDisabled] = !rowRightClick.observed [style.height.px]="minView ? this.cardHeight : this.rowHeight" [class.even]="(index + 1) % 2 === 0" [class.checked]="isRowSelected(rowData)" diff --git a/src/app/webapp-common/shared/ui-components/data/table/table.component.ts b/src/app/webapp-common/shared/ui-components/data/table/table.component.ts index 8b8f0ecd..10051cc5 100755 --- a/src/app/webapp-common/shared/ui-components/data/table/table.component.ts +++ b/src/app/webapp-common/shared/ui-components/data/table/table.component.ts @@ -519,10 +519,12 @@ export class TableComponent implements AfterContentInit, AfterViewInit, OnInit, colResize({delta, element}: { delta: number; element: HTMLTableHeaderCellElement }) { if (delta) { - const width = element.clientWidth; - const columnId = element.attributes['data-col-id']?.value; - this.columnResized.emit({columnId, widthPx: width}); - // this.updateColumnsWidth(columnId, width, delta); + setTimeout( () => { + const width = element.clientWidth; + const columnId = element.attributes['data-col-id']?.value; + this.columnResized.emit({columnId, widthPx: width}); + // this.updateColumnsWidth(columnId, width, delta); + }, 0); } } diff --git a/src/app/webapp-common/shared/ui-components/data/table/table.consts.ts b/src/app/webapp-common/shared/ui-components/data/table/table.consts.ts index 1fbd31be..89dc1839 100755 --- a/src/app/webapp-common/shared/ui-components/data/table/table.consts.ts +++ b/src/app/webapp-common/shared/ui-components/data/table/table.consts.ts @@ -31,9 +31,9 @@ export interface ISmCol { filterType?: ColHeaderFilterTypeEnum; sortable?: boolean; // determine if the column shell be sortable searchableFilter?: boolean; + asyncFilter?: boolean; // adding filter change event emitter + paginatedFilterPageSize?: number; // paginated filter active and its size (for noMoreOptions) filterable?: boolean; // determine if the column shell be filterable - isFiltered?: boolean; // deprecated. - isSorted?: boolean; // deprecated. filterMatchMode?: FilterMatchModeEnum; // the filter method. style?: { width?: string; minWidth?: string; maxWidth?: string }; // the column style. headerStyleClass?: string; // the header css class name. diff --git a/src/app/webapp-common/shared/ui-components/directives/click-stop-propagation.directive.ts b/src/app/webapp-common/shared/ui-components/directives/click-stop-propagation.directive.ts index ab6588c8..286ace71 100755 --- a/src/app/webapp-common/shared/ui-components/directives/click-stop-propagation.directive.ts +++ b/src/app/webapp-common/shared/ui-components/directives/click-stop-propagation.directive.ts @@ -1,7 +1,8 @@ import {Directive, HostListener} from '@angular/core'; @Directive({ - selector: '[smClickStopPropagation]' + selector: '[smClickStopPropagation]', + standalone: true }) export class ClickStopPropagationDirective { @HostListener('click', ['$event']) diff --git a/src/app/webapp-common/shared/ui-components/directives/scroll-end.directive.ts b/src/app/webapp-common/shared/ui-components/directives/scroll-end.directive.ts index 5c9b91ae..4f509233 100644 --- a/src/app/webapp-common/shared/ui-components/directives/scroll-end.directive.ts +++ b/src/app/webapp-common/shared/ui-components/directives/scroll-end.directive.ts @@ -1,4 +1,5 @@ -import { Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Optional, Output } from '@angular/core'; +import {Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Optional, Output} from '@angular/core'; + export enum ScrollEndDirection { down = 'down', up = 'up', @@ -20,12 +21,14 @@ export class ScrollEndDirective implements OnInit, OnDestroy { constructor( private el: ElementRef, @Optional() private scrollEndRoot: ScrollEndRootDirective, - ) { } + ) { + } ngOnInit(): void { this.observer = new IntersectionObserver(entries => { entries.forEach(entry => { - this.scrollDirection = this.previousEntry?.boundingClientRect.bottom > entry.boundingClientRect.bottom ? ScrollEndDirection.down : ScrollEndDirection.up; + this.scrollDirection = (this.previousEntry?.boundingClientRect.bottom === 0 || this.previousEntry?.boundingClientRect.bottom > entry.boundingClientRect.bottom) + ? ScrollEndDirection.down : ScrollEndDirection.up; if (!this.previousEntry?.isIntersecting && entry.isIntersecting && this.scrollDirection === this.desiredDirection) { this.smScrollEnd.emit(); diff --git a/src/app/webapp-common/shared/ui-components/indicators/circle-status/circle-status.component.html b/src/app/webapp-common/shared/ui-components/indicators/circle-status/circle-status.component.html index 45902c23..3a298e1e 100755 --- a/src/app/webapp-common/shared/ui-components/indicators/circle-status/circle-status.component.html +++ b/src/app/webapp-common/shared/ui-components/indicators/circle-status/circle-status.component.html @@ -3,5 +3,5 @@
-
{{experimentsStatusLabels[(status|| type)]}}
+
{{experimentsStatusLabels[(status|| type)]}}
diff --git a/src/app/webapp-common/shared/ui-components/indicators/copy-clipboard/copy-clipboard.component.html b/src/app/webapp-common/shared/ui-components/indicators/copy-clipboard/copy-clipboard.component.html index 1874cb33..a8cfc5a1 100755 --- a/src/app/webapp-common/shared/ui-components/indicators/copy-clipboard/copy-clipboard.component.html +++ b/src/app/webapp-common/shared/ui-components/indicators/copy-clipboard/copy-clipboard.component.html @@ -11,6 +11,6 @@ [disabled]="disabled" (cbOnSuccess)="copyToClipboard()" > - + {{label}} diff --git a/src/app/webapp-common/shared/ui-components/indicators/copy-clipboard/copy-clipboard.component.ts b/src/app/webapp-common/shared/ui-components/indicators/copy-clipboard/copy-clipboard.component.ts index 25f7a98f..d7a9b9fc 100755 --- a/src/app/webapp-common/shared/ui-components/indicators/copy-clipboard/copy-clipboard.component.ts +++ b/src/app/webapp-common/shared/ui-components/indicators/copy-clipboard/copy-clipboard.component.ts @@ -1,5 +1,5 @@ import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Input} from '@angular/core'; -import { LegacyTooltipPosition as TooltipPosition } from '@angular/material/legacy-tooltip'; +import { TooltipPosition } from '@angular/material/tooltip'; @Component({ selector : 'sm-copy-clipboard', diff --git a/src/app/webapp-common/shared/ui-components/indicators/number-counter/number-counter.component.html b/src/app/webapp-common/shared/ui-components/indicators/number-counter/number-counter.component.html index 3c8148bd..a618e4bf 100755 --- a/src/app/webapp-common/shared/ui-components/indicators/number-counter/number-counter.component.html +++ b/src/app/webapp-common/shared/ui-components/indicators/number-counter/number-counter.component.html @@ -1,4 +1,4 @@
-
{{counter}}
+
{{counter}}
{{label}}
diff --git a/src/app/webapp-common/shared/ui-components/indicators/tooltip/tooltip.directive.ts b/src/app/webapp-common/shared/ui-components/indicators/tooltip/tooltip.directive.ts index 79446b40..006744dc 100755 --- a/src/app/webapp-common/shared/ui-components/indicators/tooltip/tooltip.directive.ts +++ b/src/app/webapp-common/shared/ui-components/indicators/tooltip/tooltip.directive.ts @@ -1,6 +1,6 @@ import {Directive, Input} from '@angular/core'; -import {MatLegacyTooltip as MatTooltip} from '@angular/material/legacy-tooltip'; -import {MAT_LEGACY_TOOLTIP_SCROLL_STRATEGY as MAT_TOOLTIP_SCROLL_STRATEGY} from '@angular/material/legacy-tooltip'; +import {MatTooltip} from '@angular/material/tooltip'; +import {MAT_TOOLTIP_SCROLL_STRATEGY} from '@angular/material/tooltip'; import {scrollFactory} from '@common/shared/utils/scroll-factory'; import {Overlay} from '@angular/cdk/overlay'; diff --git a/src/app/webapp-common/shared/ui-components/inputs/button-toggle/button-toggle.component.scss b/src/app/webapp-common/shared/ui-components/inputs/button-toggle/button-toggle.component.scss index b7b9d975..7c359150 100755 --- a/src/app/webapp-common/shared/ui-components/inputs/button-toggle/button-toggle.component.scss +++ b/src/app/webapp-common/shared/ui-components/inputs/button-toggle/button-toggle.component.scss @@ -2,9 +2,10 @@ :host { @include generate-button-toggle-group(); - ::ng-deep .mat-button-toggle-appearance-standard .mat-button-toggle-label-content { - line-height: 32px; + height: 32px; + display: flex; + align-items: center; } .label { diff --git a/src/app/webapp-common/shared/ui-components/inputs/color-picker/color-picker-wrapper.component.html b/src/app/webapp-common/shared/ui-components/inputs/color-picker/color-picker-wrapper.component.html index 764f3ff0..a9ea5ffd 100644 --- a/src/app/webapp-common/shared/ui-components/inputs/color-picker/color-picker-wrapper.component.html +++ b/src/app/webapp-common/shared/ui-components/inputs/color-picker/color-picker-wrapper.component.html @@ -11,7 +11,7 @@ [cpCancelButton]="true" [cpSaveClickOutside]="false" [cpOKButtonClass]="'btn btn-cml-primary btn-xs'" - [cpCancelButtonClass]="'btn btn-cml-primary btn-xs mr-1'" + [cpCancelButtonClass]="'btn btn-cml-primary btn-xs me-1'" [cpAlphaChannel]="'forced'" [cpDisableInput]="true" [cpPresetColors]="alphaPresetColors" diff --git a/src/app/webapp-common/shared/ui-components/inputs/inline-edit/inline-edit.component.html b/src/app/webapp-common/shared/ui-components/inputs/inline-edit/inline-edit.component.html index 36a2d06f..14535274 100755 --- a/src/app/webapp-common/shared/ui-components/inputs/inline-edit/inline-edit.component.html +++ b/src/app/webapp-common/shared/ui-components/inputs/inline-edit/inline-edit.component.html @@ -1,7 +1,7 @@
- +
diff --git a/src/app/webapp-common/shared/ui-components/inputs/search/search.component.html b/src/app/webapp-common/shared/ui-components/inputs/search/search.component.html index f71bdcb4..6e1abaac 100755 --- a/src/app/webapp-common/shared/ui-components/inputs/search/search.component.html +++ b/src/app/webapp-common/shared/ui-components/inputs/search/search.component.html @@ -19,7 +19,7 @@ (keydown)="onKeyDown($event)" > + class="icon-button al-icon al-ico-search" data-id="searchIcon"> diff --git a/src/app/webapp-common/shared/ui-components/inputs/search/search.component.scss b/src/app/webapp-common/shared/ui-components/inputs/search/search.component.scss index 908d5edb..b68af579 100755 --- a/src/app/webapp-common/shared/ui-components/inputs/search/search.component.scss +++ b/src/app/webapp-common/shared/ui-components/inputs/search/search.component.scss @@ -254,4 +254,4 @@ $search-font-size: 14px; margin: 0 12px; width: auto; } -} \ No newline at end of file +} diff --git a/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-for-template-forms/select-autocomplete-for-template-forms.component.html b/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-for-template-forms/select-autocomplete-for-template-forms.component.html index ad4700c8..d11059e9 100644 --- a/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-for-template-forms/select-autocomplete-for-template-forms.component.html +++ b/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-for-template-forms/select-autocomplete-for-template-forms.component.html @@ -1,5 +1,5 @@ - + "{{filterText}}" (Add item) - - {{option.label}} - + {{option.label}} + diff --git a/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-for-template-forms/select-autocomplete-for-template-forms.component.scss b/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-for-template-forms/select-autocomplete-for-template-forms.component.scss index 8bec7c15..b85e44e6 100644 --- a/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-for-template-forms/select-autocomplete-for-template-forms.component.scss +++ b/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-for-template-forms/select-autocomplete-for-template-forms.component.scss @@ -7,18 +7,4 @@ mat-form-field { display: block; } - - .narrow { - ::ng-deep .mat-form-field-flex { - margin-top: -16px; - height: 48px; - } - - ::ng-deep .mat-form-field-infix { - height: 42px; - border-top: 0; - line-height: 24px; - } - } - } diff --git a/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-for-template-forms/select-autocomplete-for-template-forms.component.ts b/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-for-template-forms/select-autocomplete-for-template-forms.component.ts index 937fe879..9feae7f0 100644 --- a/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-for-template-forms/select-autocomplete-for-template-forms.component.ts +++ b/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-for-template-forms/select-autocomplete-for-template-forms.component.ts @@ -2,11 +2,11 @@ import {ChangeDetectionStrategy, Component, ElementRef, EventEmitter, forwardRef import {TemplateFormSectionBase} from '../../template-forms-ui/templateFormSectionBase'; import {NG_VALUE_ACCESSOR, NgForm} from '@angular/forms'; import {COMMA, ENTER} from '@angular/cdk/keycodes'; -import {MatLegacyAutocompleteSelectedEvent as MatAutocompleteSelectedEvent} from '@angular/material/legacy-autocomplete'; +import {MatAutocompleteSelectedEvent} from '@angular/material/autocomplete'; import {filter, map, startWith} from 'rxjs/operators'; import {asyncScheduler} from 'rxjs'; import {Observable} from 'rxjs/internal/Observable'; -import {MatLegacyOptionSelectionChange as MatOptionSelectionChange} from '@angular/material/legacy-core'; +import {MatOptionSelectionChange} from '@angular/material/core'; export interface IOption { diff --git a/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-with-chips/select-autocomplete-with-chips.component.html b/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-with-chips/select-autocomplete-with-chips.component.html index 0af4d8bd..7235bda5 100644 --- a/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-with-chips/select-autocomplete-with-chips.component.html +++ b/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-with-chips/select-autocomplete-with-chips.component.html @@ -1,26 +1,28 @@ - -
- - - - + +
+ + + - - + + + - - - +
- -
diff --git a/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-with-chips/select-autocomplete-with-chips.component.scss b/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-with-chips/select-autocomplete-with-chips.component.scss index 37f6b1a8..105bca37 100644 --- a/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-with-chips/select-autocomplete-with-chips.component.scss +++ b/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-with-chips/select-autocomplete-with-chips.component.scss @@ -1,4 +1,8 @@ :host { + ::ng-deep .mdc-text-field--filled .mdc-line-ripple::before { + border-bottom: 0; + } + ng-form, mat-form-field { display: block; } @@ -10,18 +14,21 @@ padding: 0; } - .mat-form-field-appearance-fill { - ::ng-deep .mat-chip-list-wrapper { - line-height: 24px; + ::ng-deep .mat-mdc-chip-grid { + width: 100%; + + &.single { + width: calc(100% - 12px); + + .mdc-evolution-chip-set__chips { + flex-wrap: nowrap; + overflow: hidden; + } } - ::ng-deep &.mat-form-field-disabled .mat-form-field-flex { - background-color: #000; - } - ::ng-deep .mat-form-field-flex { - background-color: #000; - padding-top: 0; - margin-bottom: 1px; + .mdc-evolution-chip-set__chips { + align-items: center; + gap: 6px 0; } } } @@ -29,6 +36,6 @@ :host-context(.single-selection) { .chips-input { width: 100px; - flex: 0 0 100px; + flex: 1 1 100px; } } diff --git a/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-with-chips/select-autocomplete-with-chips.component.ts b/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-with-chips/select-autocomplete-with-chips.component.ts index 429ea2b9..37a28c13 100644 --- a/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-with-chips/select-autocomplete-with-chips.component.ts +++ b/src/app/webapp-common/shared/ui-components/inputs/select-autocomplete-with-chips/select-autocomplete-with-chips.component.ts @@ -16,10 +16,10 @@ import {COMMA, ENTER} from '@angular/cdk/keycodes'; import {map, startWith} from 'rxjs/operators'; import {fromEvent, Subscription} from 'rxjs'; import {Observable} from 'rxjs/internal/Observable'; -import {MatLegacyOptionModule as MatOptionModule, MatLegacyOptionSelectionChange as MatOptionSelectionChange} from '@angular/material/legacy-core'; -import {MatLegacyAutocompleteModule as MatAutocompleteModule, MatLegacyAutocompleteTrigger as MatAutocompleteTrigger} from '@angular/material/legacy-autocomplete'; -import {MatLegacyChipsModule as MatChipsModule} from '@angular/material/legacy-chips'; -import {MatLegacyFormFieldModule as MatFormFieldModule} from '@angular/material/legacy-form-field'; +import {MatOptionModule, MatOptionSelectionChange} from '@angular/material/core'; +import {MatAutocompleteModule, MatAutocompleteTrigger} from '@angular/material/autocomplete'; +import {MatChipsModule} from '@angular/material/chips'; +import {MatFormFieldModule} from '@angular/material/form-field'; import {AsyncPipe, NgFor, NgIf} from '@angular/common'; import {ChipsModule} from '@common/shared/ui-components/buttons/chips/chips.module'; diff --git a/src/app/webapp-common/shared/ui-components/overlay/alert-dialog/alert-dialog.component.ts b/src/app/webapp-common/shared/ui-components/overlay/alert-dialog/alert-dialog.component.ts index b358a4fc..7f2af8a1 100755 --- a/src/app/webapp-common/shared/ui-components/overlay/alert-dialog/alert-dialog.component.ts +++ b/src/app/webapp-common/shared/ui-components/overlay/alert-dialog/alert-dialog.component.ts @@ -1,5 +1,5 @@ import {Component, Inject} from '@angular/core'; -import {MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA} from '@angular/material/legacy-dialog'; +import {MAT_DIALOG_DATA} from '@angular/material/dialog'; import {isAnnotationTask} from '../../../utils/shared-utils'; @Component({ diff --git a/src/app/webapp-common/shared/ui-components/overlay/confirm-dialog/confirm-dialog.component.ts b/src/app/webapp-common/shared/ui-components/overlay/confirm-dialog/confirm-dialog.component.ts index 8209a792..b42b56df 100755 --- a/src/app/webapp-common/shared/ui-components/overlay/confirm-dialog/confirm-dialog.component.ts +++ b/src/app/webapp-common/shared/ui-components/overlay/confirm-dialog/confirm-dialog.component.ts @@ -1,5 +1,5 @@ import {Component, ElementRef, Inject, Input, Renderer2, TemplateRef} from '@angular/core'; -import {MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {ConfirmDialogConfig} from './confirm-dialog.model'; @Component({ diff --git a/src/app/webapp-common/shared/ui-components/overlay/dialog-template/dialog-template.component.scss b/src/app/webapp-common/shared/ui-components/overlay/dialog-template/dialog-template.component.scss index 78f2f535..b352420b 100755 --- a/src/app/webapp-common/shared/ui-components/overlay/dialog-template/dialog-template.component.scss +++ b/src/app/webapp-common/shared/ui-components/overlay/dialog-template/dialog-template.component.scss @@ -58,7 +58,7 @@ $generic-font-size: 11px; } } ::ng-deep .background-transparent { - .mat-dialog-container { + .mat-mdc-dialog-container { max-height: none !important; height: 97vh !important; background-color: transparent; diff --git a/src/app/webapp-common/shared/ui-components/overlay/dialog-template/dialog-template.component.ts b/src/app/webapp-common/shared/ui-components/overlay/dialog-template/dialog-template.component.ts index 24f3df50..23b5c5ea 100755 --- a/src/app/webapp-common/shared/ui-components/overlay/dialog-template/dialog-template.component.ts +++ b/src/app/webapp-common/shared/ui-components/overlay/dialog-template/dialog-template.component.ts @@ -1,5 +1,5 @@ import {Component, ElementRef, EventEmitter, Input, Output, ViewChild} from '@angular/core'; -import {MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MatDialogRef} from '@angular/material/dialog'; import {NgClass, NgIf} from '@angular/common'; import {CdkScrollableModule} from '@angular/cdk/scrolling'; diff --git a/src/app/webapp-common/shared/ui-components/overlay/edit-credential-label-dialog/edit-credential-label-dialog.component.html b/src/app/webapp-common/shared/ui-components/overlay/edit-credential-label-dialog/edit-credential-label-dialog.component.html index 5cad9353..ff5ae6bc 100755 --- a/src/app/webapp-common/shared/ui-components/overlay/edit-credential-label-dialog/edit-credential-label-dialog.component.html +++ b/src/app/webapp-common/shared/ui-components/overlay/edit-credential-label-dialog/edit-credential-label-dialog.component.html @@ -1,6 +1,6 @@
- + Label diff --git a/src/app/webapp-common/shared/ui-components/overlay/edit-credential-label-dialog/edit-credential-label-dialog.component.ts b/src/app/webapp-common/shared/ui-components/overlay/edit-credential-label-dialog/edit-credential-label-dialog.component.ts index 3c50c2f2..037e514f 100755 --- a/src/app/webapp-common/shared/ui-components/overlay/edit-credential-label-dialog/edit-credential-label-dialog.component.ts +++ b/src/app/webapp-common/shared/ui-components/overlay/edit-credential-label-dialog/edit-credential-label-dialog.component.ts @@ -1,5 +1,5 @@ import {AfterViewInit, ChangeDetectionStrategy, Component, Inject, Input, ViewChild} from '@angular/core'; -import {MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {ConfirmDialogComponent} from '@common/shared/ui-components/overlay/confirm-dialog/confirm-dialog.component'; @Component({ diff --git a/src/app/webapp-common/shared/ui-components/overlay/edit-json/edit-json.component.html b/src/app/webapp-common/shared/ui-components/overlay/edit-json/edit-json.component.html index 92187062..5b8f87c7 100644 --- a/src/app/webapp-common/shared/ui-components/overlay/edit-json/edit-json.component.html +++ b/src/app/webapp-common/shared/ui-components/overlay/edit-json/edit-json.component.html @@ -8,11 +8,7 @@
- - + +
diff --git a/src/app/webapp-common/shared/ui-components/overlay/edit-json/edit-json.component.ts b/src/app/webapp-common/shared/ui-components/overlay/edit-json/edit-json.component.ts index ed9bada1..538842c0 100644 --- a/src/app/webapp-common/shared/ui-components/overlay/edit-json/edit-json.component.ts +++ b/src/app/webapp-common/shared/ui-components/overlay/edit-json/edit-json.component.ts @@ -1,5 +1,5 @@ import {AfterViewInit, Component, ElementRef, HostListener, Inject, NgZone, ViewChild} from '@angular/core'; -import {MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {JsonPipe} from '@angular/common'; import {validateJson} from '../../../utils/validation-utils'; import {Store} from '@ngrx/store'; @@ -10,6 +10,13 @@ import {filter, Observable} from 'rxjs'; import {map, take} from 'rxjs/operators'; declare const ace; +export interface EditJsonData { + textData?: string | any; + readOnly?: boolean; + title: string; + format?: 'json' | 'yaml' | 'hocon'; + placeHolder?: string; +} @Component({ selector: 'sm-edit-json', @@ -31,6 +38,7 @@ export class EditJsonComponent implements AfterViewInit{ private aceEditor: Ace.Editor; private $aceCaretPosition: Observable<{ [key: string]: Ace.Point }>; private defaultPlaceHolder = ''; + private format?: 'json' | 'yaml' | 'hocon'; set readOnly(readOnly: boolean) { this._readOnly = readOnly; @@ -48,13 +56,14 @@ export class EditJsonComponent implements AfterViewInit{ } constructor( - @Inject(MAT_DIALOG_DATA) public data: { textData: string; readOnly: boolean; title: string; typeJson: boolean; placeHolder: string }, + @Inject(MAT_DIALOG_DATA) public data: EditJsonData, private dialogRef: MatDialogRef, private jsonPipe: JsonPipe, private store: Store, private zone: NgZone, ) { - this.typeJson = data.typeJson; + this.format = data.format; + this.typeJson = data.format === 'json'; if (this.typeJson) { this.defaultPlaceHolder = `e.g.: @@ -64,7 +73,7 @@ export class EditJsonComponent implements AfterViewInit{ }`; } this.placeHolder = data.placeHolder; - this.textData = data.textData ? (this.typeJson ? jsonPipe.transform(data.textData) : data.textData).slice() : undefined; + this.textData = data.textData ? (this.typeJson && typeof data.textData !== 'string' ? jsonPipe.transform(data.textData) : data.textData).slice() : undefined; this.readOnly = data.readOnly; this.title = data.title; this.$aceCaretPosition = this.store.select(selectAceCaretPosition); @@ -112,10 +121,18 @@ export class EditJsonComponent implements AfterViewInit{ (aceEditor.renderer.container.querySelector('.ace_cursor') as HTMLElement).style.color = 'white'; aceEditor.setTheme('ace/theme/monokai'); - if (this.typeJson) { - aceEditor.session.setMode('ace/mode/json'); - } else { - aceEditor.session.setMode('ace/mode/text'); + switch (this.format) { + case 'hocon': + aceEditor.session.setMode('ace/mode/ini'); + break; + case 'json': + aceEditor.session.setMode('ace/mode/json'); + break; + case 'yaml': + aceEditor.session.setMode('ace/mode/yaml'); + break; + default: + aceEditor.session.setMode('ace/mode/text'); } aceEditor.getSession().setValue(this.textData || ''); this.aceEditor = aceEditor; diff --git a/src/app/webapp-common/shared/ui-components/overlay/operation-error-dialog/operation-error-dialog.component.scss b/src/app/webapp-common/shared/ui-components/overlay/operation-error-dialog/operation-error-dialog.component.scss index 54d9e723..fb181fcd 100755 --- a/src/app/webapp-common/shared/ui-components/overlay/operation-error-dialog/operation-error-dialog.component.scss +++ b/src/app/webapp-common/shared/ui-components/overlay/operation-error-dialog/operation-error-dialog.component.scss @@ -23,7 +23,7 @@ .list-container { padding: 12px 12px 12px 30px; - border: 1px solid #D4D6E0; + border: 1px solid $cloudy-blue; border-radius: 4px; max-height: 180px; overflow: auto; diff --git a/src/app/webapp-common/shared/ui-components/overlay/operation-error-dialog/operation-error-dialog.component.ts b/src/app/webapp-common/shared/ui-components/overlay/operation-error-dialog/operation-error-dialog.component.ts index 07082744..413ce8d7 100755 --- a/src/app/webapp-common/shared/ui-components/overlay/operation-error-dialog/operation-error-dialog.component.ts +++ b/src/app/webapp-common/shared/ui-components/overlay/operation-error-dialog/operation-error-dialog.component.ts @@ -1,7 +1,7 @@ import {Component, Inject} from '@angular/core'; -import {MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {openMoreInfoPopup} from '@common/core/actions/projects.actions'; -import {htmlTextShorte} from '../../../utils/shared-utils'; +import {htmlTextShort} from '../../../utils/shared-utils'; @Component({ selector: 'sm-operation-error-dialog', @@ -30,6 +30,6 @@ export class OperationErrorDialogComponent { } getName(fail: any) { - return htmlTextShorte(this.action.parentAction.selectedEntities.find(entity => entity.id === fail.id)?.name); + return htmlTextShort(this.action.parentAction.selectedEntities.find(entity => entity.id === fail.id)?.name); } } diff --git a/src/app/webapp-common/shared/ui-components/overlay/share-dialog/share-dialog.component.ts b/src/app/webapp-common/shared/ui-components/overlay/share-dialog/share-dialog.component.ts index 2b41db19..d068ae30 100755 --- a/src/app/webapp-common/shared/ui-components/overlay/share-dialog/share-dialog.component.ts +++ b/src/app/webapp-common/shared/ui-components/overlay/share-dialog/share-dialog.component.ts @@ -1,5 +1,5 @@ import {Component, Inject} from '@angular/core'; -import {MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {IShareDialogConfig} from './share-dialog.model'; import {addMessage} from '@common/core/actions/layout.actions'; import {Store} from '@ngrx/store'; @@ -28,7 +28,7 @@ export class ShareDialogComponent { public dialogRef: MatDialogRef, private store: Store) { this.title = data.title || ''; - this.sharedSubtitle =`Any registered user with this link has read-only access to this task and all it’s contents (Artifacts, Results, etc.)`; + this.sharedSubtitle =`Any registered user with this link has read-only access to this task and all its contents (Artifacts, Results, etc.)`; this.privateSubtitle = `Create a shareable link to grant read access to any registered user you provide this link to.`; this.task = data.task; diff --git a/src/app/webapp-common/shared/ui-components/overlay/terms-of-use-dialog/terms-of-use-dialog.component.html b/src/app/webapp-common/shared/ui-components/overlay/terms-of-use-dialog/terms-of-use-dialog.component.html index 20b72438..ffc4b785 100644 --- a/src/app/webapp-common/shared/ui-components/overlay/terms-of-use-dialog/terms-of-use-dialog.component.html +++ b/src/app/webapp-common/shared/ui-components/overlay/terms-of-use-dialog/terms-of-use-dialog.component.html @@ -6,7 +6,7 @@ #checkboxInput="ngModel" [(ngModel)]="isApprove" name="isApprove" - class="mr-3" + class="me-3" >I have read and accept ClearML's Terms Of Use
diff --git a/src/app/webapp-common/shared/ui-components/overlay/terms-of-use-dialog/terms-of-use-dialog.component.ts b/src/app/webapp-common/shared/ui-components/overlay/terms-of-use-dialog/terms-of-use-dialog.component.ts index 23b6dc00..15ce6310 100644 --- a/src/app/webapp-common/shared/ui-components/overlay/terms-of-use-dialog/terms-of-use-dialog.component.ts +++ b/src/app/webapp-common/shared/ui-components/overlay/terms-of-use-dialog/terms-of-use-dialog.component.ts @@ -1,5 +1,5 @@ import {Component, Inject} from '@angular/core'; -import { MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialogRef as MatDialogRef } from '@angular/material/legacy-dialog'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; @Component({ selector : 'sm-terms-of-use-dialog', diff --git a/src/app/webapp-common/shared/ui-components/panel/card2/card-component2.component.scss b/src/app/webapp-common/shared/ui-components/panel/card2/card-component2.component.scss index 29243af0..4c9695a8 100644 --- a/src/app/webapp-common/shared/ui-components/panel/card2/card-component2.component.scss +++ b/src/app/webapp-common/shared/ui-components/panel/card2/card-component2.component.scss @@ -35,6 +35,7 @@ .card-body { padding: 15px; + min-height: 1px; } footer { diff --git a/src/app/webapp-common/shared/ui-components/panel/checkbox-three-state-list/checkbox-three-state-list.component.html b/src/app/webapp-common/shared/ui-components/panel/checkbox-three-state-list/checkbox-three-state-list.component.html index f7eaa483..34016e79 100644 --- a/src/app/webapp-common/shared/ui-components/panel/checkbox-three-state-list/checkbox-three-state-list.component.html +++ b/src/app/webapp-common/shared/ui-components/panel/checkbox-three-state-list/checkbox-three-state-list.component.html @@ -1,10 +1,22 @@ - - {{option.label}} - -
No item found
+ + + {{option.label}} + + +
No item found
+
+ +
diff --git a/src/app/webapp-common/shared/ui-components/panel/checkbox-three-state-list/checkbox-three-state-list.component.scss b/src/app/webapp-common/shared/ui-components/panel/checkbox-three-state-list/checkbox-three-state-list.component.scss index 9ebecaad..b0e68dd1 100644 --- a/src/app/webapp-common/shared/ui-components/panel/checkbox-three-state-list/checkbox-three-state-list.component.scss +++ b/src/app/webapp-common/shared/ui-components/panel/checkbox-three-state-list/checkbox-three-state-list.component.scss @@ -2,34 +2,38 @@ :host { width: 100%; + mat-checkbox { width: 100%; - padding-left: 16px; - padding-right: 32px; height: 40px; align-items: center; border-radius: 4px; + &:hover { background: $blue-50; } - ::ng-deep .mat-checkbox-layout { + } + + ::ng-deep .mat-mdc-checkbox { + .mdc-checkbox .mdc-checkbox__native-control:indeterminate ~ .mdc-checkbox__background { + background-image: url('~app/webapp-common/assets/icons/cbx-exlude.svg'); + background-size: 18px; + border: 0; + transition: none; + } + + .mdc-checkbox__mixedmark { + display: none; + } + + .mdc-form-field { width: 100%; } - ::ng-deep .mat-checkbox-label { - height: 40px; - width: 100%; - max-width: 400px; - display: flex; - align-items: center; - font-size: 14px; - line-height: normal; - color: rgba(0, 0, 0, 0.87) - } - &.mat-checkbox-indeterminate { - ::ng-deep .mat-checkbox-background { - color: red; - background-image: url('../../../../assets/icons/cbx-exlude.svg'); - } + + label { + max-width: 100%; + flex-grow: 1; + overflow: hidden; } } } diff --git a/src/app/webapp-common/shared/ui-components/panel/checkbox-three-state-list/checkbox-three-state-list.component.ts b/src/app/webapp-common/shared/ui-components/panel/checkbox-three-state-list/checkbox-three-state-list.component.ts index e7011cb5..eba60c42 100644 --- a/src/app/webapp-common/shared/ui-components/panel/checkbox-three-state-list/checkbox-three-state-list.component.ts +++ b/src/app/webapp-common/shared/ui-components/panel/checkbox-three-state-list/checkbox-three-state-list.component.ts @@ -26,7 +26,7 @@ export enum CheckboxState { changeDetection: ChangeDetectionStrategy.OnPush }) export class CheckboxThreeStateListComponent implements OnInit { - @Input() options: Array<{ label: string; value: string; tooltip?: string }> = []; + @Input() options: Array<{ label: string; value: string; tooltip?: string }>; @Input() supportExcludeFilter: boolean; @Input() set checkedList(checkedList: Array) { diff --git a/src/app/webapp-common/shared/ui-components/panel/compare-footer/compare-footer.component.html b/src/app/webapp-common/shared/ui-components/panel/compare-footer/compare-footer.component.html index 214cbd1f..b88ca390 100644 --- a/src/app/webapp-common/shared/ui-components/panel/compare-footer/compare-footer.component.html +++ b/src/app/webapp-common/shared/ui-components/panel/compare-footer/compare-footer.component.html @@ -1,5 +1,6 @@