From ecb3f32ccb1332e8af1ba96328af4cece7fa99eb Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Sat, 10 Aug 2024 08:00:53 +0200 Subject: [PATCH] Development: Update typescript (#9051) --- package-lock.json | 932 ++++++++---------- package.json | 50 +- .../init/password-reset-init.component.ts | 6 +- .../metrics-modal-threads.component.ts | 2 +- .../user-management.component.ts | 17 +- src/main/webapp/app/app.main.ts | 8 - .../app/core/theme/theme-switch.component.ts | 7 +- .../import-course-competencies.component.ts | 2 +- .../course/course-access-storage.service.ts | 2 +- .../course-scores/course-scores.component.ts | 2 +- .../manage/course-management.component.html | 6 +- .../manage/course-management.component.ts | 6 +- .../course-detail-line-chart.component.ts | 4 +- .../course-management-card.component.html | 8 +- .../course-management-card.component.ts | 14 +- ...ourse-management-exercise-row.component.ts | 2 +- ...giarism-cases-instructor-view.component.ts | 13 +- ...ps-registration-import-dialog.component.ts | 2 +- .../exercise-detail.directive.ts | 4 +- .../webapp/app/entities/feedback.model.ts | 2 +- .../metis/conversation/channel.model.ts | 4 +- .../exercise-groups.component.ts | 2 +- .../assess/modeling-assessment.util.ts | 8 +- .../modeling-submission.component.html | 4 +- .../modeling-submission.component.ts | 4 +- ...a-category-distribution-chart.component.ts | 4 +- .../test-case-distribution-chart.component.ts | 6 +- ...ng-exercise-configure-grading.component.ts | 12 +- ...-exercise-grading-tasks-table.component.ts | 15 +- ...gramming-exercise-participation.service.ts | 2 +- .../services/programming-exercise.service.ts | 6 +- .../shared/service/aeolus.service.ts | 6 +- .../short-answer-question-edit.component.ts | 14 +- ...ort-answer-question-statistic.component.ts | 2 +- .../quiz-participation.component.ts | 2 +- .../shared/fit-text/fit-text.directive.ts | 8 +- .../split-pane-header.component.ts | 4 +- .../exercises/shared/result/result.service.ts | 4 +- .../teams-import-from-file-form.component.ts | 2 +- .../base-grading-system.component.ts | 19 +- .../iris/about-iris/about-iris.component.ts | 2 +- .../lecture-unit-management.component.ts | 2 +- .../build-queue/build-queue.component.ts | 10 +- .../app/lti/lti13-deep-linking.component.ts | 7 +- .../lti/lti13-exercise-launch.component.ts | 16 +- .../dialogs/abstract-dialog.component.ts | 2 +- .../conversation-info.component.ts | 14 +- .../conversation-thread-sidebar.component.ts | 6 +- .../course-dashboard.service.ts | 4 +- .../course-group/course-group.component.ts | 27 +- .../app/shared/export/export-row-builder.ts | 2 +- .../interfaces/cropper-options.interface.ts | 2 +- .../interfaces/cropper.settings.ts | 82 +- .../shared/layouts/navbar/navbar.component.ts | 4 +- .../layouts/profiles/profile.service.ts | 8 +- .../shared/orion/orion-connector.service.ts | 6 +- .../app/shared/pipes/average-by.pipe.ts | 15 - .../app/shared/pipes/shared-pipes.module.ts | 3 - .../sidebar-accordion.component.html | 4 +- .../sidebar-accordion.component.ts | 9 +- .../shared/sidebar/sidebar-card.directive.ts | 10 +- .../app/shared/sidebar/sidebar.component.ts | 5 +- .../users-import-dialog.component.ts | 36 +- .../shared/util/markdown.conversion.util.ts | 2 +- src/main/webapp/app/types/sidebar.ts | 8 +- .../admin/user-management.component.spec.ts | 6 +- .../competency-search.component.spec.ts | 21 +- .../course-management-card.component.spec.ts | 2 +- .../exam-exercise-import.component.spec.ts | 10 +- .../text-unit-form.component.spec.ts | 6 +- .../lecture-attachments.component.spec.ts | 4 +- .../build-queue/build-queue.component.spec.ts | 4 +- ...multiple-choice-question.component.spec.ts | 5 +- .../conversation-info.component.spec.ts | 10 +- .../dialogs/dialog-test-helpers.ts | 8 +- ...ercise-update-plagiarism.component.spec.ts | 6 +- .../split-pane-header.component.spec.ts | 2 +- ...ng-exercise-reset-dialog.component.spec.ts | 4 +- .../shared/course-group.component.spec.ts | 12 +- .../short-answer-question.component.spec.ts | 10 +- .../knowledge-area-edit.component.spec.ts | 2 +- .../standardized-competency-edit.spec.ts | 2 +- .../text-exercise-update.component.spec.ts | 2 +- ...orial-group-session-form.component.spec.ts | 2 +- ...roups-configuration-form.component.spec.ts | 2 +- .../tutorial-group-form.component.spec.ts | 13 +- .../service/mock-local-storage.service.ts | 2 +- .../service/mock-sync-storage.service.ts | 4 +- src/test/javascript/spec/jest-test-setup.ts | 5 +- ...-participation-live-events.service.spec.ts | 5 +- .../exam-participation.service.spec.ts | 4 +- .../modeling-assessment.service.spec.ts | 90 +- .../spec/service/profile.service.spec.ts | 2 +- .../programming-exercise.service.spec.ts | 6 +- .../service/quiz-exercise.service.spec.ts | 7 +- .../spec/service/result.service.spec.ts | 3 +- tsconfig.json | 1 - 97 files changed, 917 insertions(+), 848 deletions(-) delete mode 100644 src/main/webapp/app/shared/pipes/average-by.pipe.ts diff --git a/package-lock.json b/package-lock.json index 80bd7b5211aa..0984482e5a68 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,18 +10,18 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { - "@angular/animations": "18.1.3", - "@angular/cdk": "18.1.3", - "@angular/common": "18.1.3", - "@angular/compiler": "18.1.3", - "@angular/core": "18.1.3", - "@angular/forms": "18.1.3", - "@angular/localize": "18.1.3", - "@angular/material": "18.1.3", - "@angular/platform-browser": "18.1.3", - "@angular/platform-browser-dynamic": "18.1.3", - "@angular/router": "18.1.3", - "@angular/service-worker": "18.1.3", + "@angular/animations": "18.1.4", + "@angular/cdk": "18.1.4", + "@angular/common": "18.1.4", + "@angular/compiler": "18.1.4", + "@angular/core": "18.1.4", + "@angular/forms": "18.1.4", + "@angular/localize": "18.1.4", + "@angular/material": "18.1.4", + "@angular/platform-browser": "18.1.4", + "@angular/platform-browser-dynamic": "18.1.4", + "@angular/router": "18.1.4", + "@angular/service-worker": "18.1.4", "@ctrl/ngx-emoji-mart": "9.2.0", "@danielmoncada/angular-datetime-picker": "18.0.0", "@fingerprintjs/fingerprintjs": "4.4.3", @@ -34,7 +34,7 @@ "@ng-bootstrap/ng-bootstrap": "17.0.0", "@ngx-translate/core": "15.0.0", "@ngx-translate/http-loader": "8.0.0", - "@sentry/angular": "8.22.0", + "@sentry/angular": "8.24.0", "@swimlane/ngx-charts": "20.5.0", "@swimlane/ngx-graph": "8.4.0", "@vscode/codicons": "0.0.36", @@ -42,7 +42,7 @@ "bootstrap": "5.3.3", "brace": "0.11.1", "compare-versions": "6.1.1", - "core-js": "3.37.1", + "core-js": "3.38.0", "crypto-js": "4.2.0", "dayjs": "1.11.12", "diff-match-patch-typescript": "1.0.8", @@ -61,7 +61,7 @@ "ngx-infinite-scroll": "18.0.0", "ngx-webstorage": "18.0.0", "papaparse": "5.4.1", - "posthog-js": "1.154.2", + "posthog-js": "1.154.5", "rxjs": "7.8.1", "showdown": "2.1.0", "showdown-highlight": "3.1.0", @@ -75,20 +75,20 @@ "uuid": "10.0.0", "webstomp-client": "1.2.6", "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz", - "zone.js": "0.14.8" + "zone.js": "0.14.10" }, "devDependencies": { "@angular-builders/jest": "18.0.0", - "@angular-devkit/build-angular": "18.1.3", + "@angular-devkit/build-angular": "18.1.4", "@angular-eslint/builder": "18.2.0", "@angular-eslint/eslint-plugin": "18.2.0", "@angular-eslint/eslint-plugin-template": "18.2.0", "@angular-eslint/schematics": "18.2.0", "@angular-eslint/template-parser": "18.2.0", - "@angular/cli": "18.1.3", - "@angular/compiler-cli": "18.1.3", - "@angular/language-service": "18.1.3", - "@sentry/types": "8.22.0", + "@angular/cli": "18.1.4", + "@angular/compiler-cli": "18.1.4", + "@angular/language-service": "18.1.4", + "@sentry/types": "8.24.0", "@types/crypto-js": "4.2.2", "@types/d3-shape": "3.1.6", "@types/dompurify": "3.0.5", @@ -100,12 +100,12 @@ "@types/smoothscroll-polyfill": "0.3.4", "@types/sockjs-client": "1.5.4", "@types/uuid": "10.0.0", - "@typescript-eslint/eslint-plugin": "8.0.0", - "@typescript-eslint/parser": "8.0.0", + "@typescript-eslint/eslint-plugin": "8.0.1", + "@typescript-eslint/parser": "8.0.1", "eslint": "9.8.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-deprecation": "3.0.0", - "eslint-plugin-jest": "28.6.0", + "eslint-plugin-jest": "28.8.0", "eslint-plugin-jest-extended": "2.4.0", "eslint-plugin-prettier": "5.2.1", "folder-hash": "4.0.4", @@ -122,7 +122,7 @@ "prettier": "3.3.3", "sass": "1.77.8", "ts-jest": "29.2.4", - "typescript": "5.4.5", + "typescript": "5.5.4", "weak-napi": "2.0.2" }, "engines": { @@ -211,13 +211,13 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1801.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1801.3.tgz", - "integrity": "sha512-4yba7x315GKim7OuBgv89ZtG50hE3hw64KuRLSGuW+RvwcwLV24VanmdWmFiLC4RKYNSH13E0wZqDNJkrMQepw==", + "version": "0.1801.4", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1801.4.tgz", + "integrity": "sha512-Ch1ZwRh1N/vcCKHm4ErLcgZly3tlwdLUDGBaAIlhE3YFGq543Swv6a5IcDw0veD6iGFceJAmbrp+z5hmzI8p5A==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.1.3", + "@angular-devkit/core": "18.1.4", "rxjs": "7.8.1" }, "engines": { @@ -227,17 +227,17 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.1.3.tgz", - "integrity": "sha512-1avnneitUEfC2A9HX24X6a7Ag8sHkxomVEBsggITFNQoGnZAZHCOBRzm3b9QiqTi1c1eH3p8teW8EAufEjFPKQ==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.1.4.tgz", + "integrity": "sha512-CCoPT2fFw1DD3j9eSP3GKbp9KfvxQQfY6kV2aec0pqL/c6byz4/ku+rsV4lwE0N/dcaglwhttq4Xf+u+pkEpiw==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1801.3", - "@angular-devkit/build-webpack": "0.1801.3", - "@angular-devkit/core": "18.1.3", - "@angular/build": "18.1.3", + "@angular-devkit/architect": "0.1801.4", + "@angular-devkit/build-webpack": "0.1801.4", + "@angular-devkit/core": "18.1.4", + "@angular/build": "18.1.4", "@babel/core": "7.24.7", "@babel/generator": "7.24.7", "@babel/helper-annotate-as-pure": "7.24.7", @@ -248,7 +248,7 @@ "@babel/preset-env": "7.24.7", "@babel/runtime": "7.24.7", "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "18.1.3", + "@ngtools/webpack": "18.1.4", "@vitejs/plugin-basic-ssl": "1.1.0", "ansi-colors": "4.1.3", "autoprefixer": "10.4.19", @@ -375,13 +375,13 @@ } }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1801.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1801.3.tgz", - "integrity": "sha512-JezRR72P4QAc4mnkT60/+kVANCYNKcr2sZyX0/9aBHJsR7lIqgOKz5Dft3FgWHwAJcQFtsZ7OLGVOW3P1LpFkw==", + "version": "0.1801.4", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1801.4.tgz", + "integrity": "sha512-Srhs/PcnuUaMiO9FLQLi1QiGZqtnG5NTpkufjJuWxolSLGNRmb/h/ZeCYgRnxeH/4jd8GCD31RD78qy+pviiLQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1801.3", + "@angular-devkit/architect": "0.1801.4", "rxjs": "7.8.1" }, "engines": { @@ -395,9 +395,9 @@ } }, "node_modules/@angular-devkit/core": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.1.3.tgz", - "integrity": "sha512-S0UzNNVLbHPaiSVXHjCd2wX+eERj/YR7jJCc40PHs1gINA7Gtd2q3VDm3bUEWe4P6fP6GNp43qSXmWJFQD0+Yg==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.1.4.tgz", + "integrity": "sha512-lKBsvbqW2QFL8terzNuSDSmKBo8//QNRO4qU5mVJ1fFf4xBJanXKoiAMuADhx+/owVIptnYT59IZ8jUAna+Srg==", "dev": true, "license": "MIT", "dependencies": { @@ -423,13 +423,13 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.1.3.tgz", - "integrity": "sha512-ElzCfiYW9P3xPRNRbPRSrOTGm+G7X8ta1ce3srqi00yPX39Y0WSM95SACqqF8j9dxL6BqazBMyAgNQUaVSbWjw==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.1.4.tgz", + "integrity": "sha512-0ekArCeYqJngCKWZ9I+RtNObP/33zGkzWdJOmCB6nj9/ZevALZ6F4RDkHp0TqDYhOt+A2muI29ZK/cILmKA+sA==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.1.3", + "@angular-devkit/core": "18.1.4", "jsonc-parser": "3.3.1", "magic-string": "0.30.10", "ora": "5.4.1", @@ -548,9 +548,9 @@ } }, "node_modules/@angular/animations": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.1.3.tgz", - "integrity": "sha512-jF4jGHZxV/REnymB11wg5q/DMXewJ0byihmvNQ3OPLHGkWnvE9MdrX44vUzI7RkzqO0suaAg8shxJlkY3OHjeA==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.1.4.tgz", + "integrity": "sha512-m0yusB7BI3wrotx9F9rf7YUD5bvhF+lT2fLNF1QCzCU819rtLnDoj0b4/z+D0i5qe7gQjtAJ42e/Hv7eGuq0VQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -559,18 +559,18 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.1.3" + "@angular/core": "18.1.4" } }, "node_modules/@angular/build": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.1.3.tgz", - "integrity": "sha512-jmTQC7lecJ6c2mJobb5nY2CN6jvdeFFHXN/jif0RkNI8dP60uV1QdMKJtTGbxEtAKXdMgOTReYICVYl6m9Q56Q==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.1.4.tgz", + "integrity": "sha512-jkqccHpGhxUOe0zIHpA1nPdeuPUxnBK7Wvazc2rA+ccI30BPrROkEDbrHP8yD8JeviUCFwwLE+hM+rRg+NneVw==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1801.3", + "@angular-devkit/architect": "0.1801.4", "@babel/core": "7.24.7", "@babel/helper-annotate-as-pure": "7.24.7", "@babel/helper-split-export-declaration": "7.24.7", @@ -652,9 +652,9 @@ } }, "node_modules/@angular/cdk": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-18.1.3.tgz", - "integrity": "sha512-u14xbuXQz+36nBeHSwRcwRoS64WNhOdK97H47nI1WaIZZaGGvKHR1Wwk2XletDRtIHv2622sJm8h+dbaBNeTGQ==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-18.1.4.tgz", + "integrity": "sha512-xFOg2wT2iLyJXqgeNRK1uF4Lxn0B1wzBjaEQoOwFm1EHOdu5D4mNOTwfuB3DkH4KWM+mI3Qtxd7vOhOXNwB3Dg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -669,18 +669,18 @@ } }, "node_modules/@angular/cli": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.1.3.tgz", - "integrity": "sha512-vsEc3cGDUYcc+adfvBHSqKdI8uiaa86Y9pLWGHfqaD+N0q/k17d/47AFvXTDKLmKucMZrto/4088Y1y+yM9eOg==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.1.4.tgz", + "integrity": "sha512-ppX4iilA6k+sKD6iRMRYnt2bH9Jpik+hJlndRBCjWo2EmEUQ04CBRKYONh8BLbnmwBxPG+/osUpcFrbkPCjQUw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1801.3", - "@angular-devkit/core": "18.1.3", - "@angular-devkit/schematics": "18.1.3", + "@angular-devkit/architect": "0.1801.4", + "@angular-devkit/core": "18.1.4", + "@angular-devkit/schematics": "18.1.4", "@inquirer/prompts": "5.0.7", "@listr2/prompt-adapter-inquirer": "2.0.13", - "@schematics/angular": "18.1.3", + "@schematics/angular": "18.1.4", "@yarnpkg/lockfile": "1.1.0", "ini": "4.1.3", "jsonc-parser": "3.3.1", @@ -703,9 +703,9 @@ } }, "node_modules/@angular/common": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.1.3.tgz", - "integrity": "sha512-TC71jVph4L+QaXlyJTrW27nbqis4sWwr9hD/RDSNkfY9XCvYDb2MjYjKrpbN03FWiv7lmcKT9zgse1fYENFsKQ==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.1.4.tgz", + "integrity": "sha512-No4lCrL80WlAGg0DAyuPW+jsfA6EIQ06CFrRgt3R6YFrKbIuU0NKUt+D8IB7UNgTLNYXmurxapNf8jef8rq1wg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -714,14 +714,14 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.1.3", + "@angular/core": "18.1.4", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.1.3.tgz", - "integrity": "sha512-Mrcd+YGsz02GVnVlVbzYp7EJIVoPOIHMvhll1OiylhjQElNVeJCLPIvjVYdylzOUDctXNlchkGf/LbA7BYMbXg==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.1.4.tgz", + "integrity": "sha512-Xdvm9trEmrWZaxCk3a7bt5kN/jdXBPukVsibFpu5lKl9ZL7j2sn4JUd7j/dVNRUIVsPahQMATAOgl8xdUJzh4Q==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -730,7 +730,7 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.1.3" + "@angular/core": "18.1.4" }, "peerDependenciesMeta": { "@angular/core": { @@ -739,9 +739,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.1.3.tgz", - "integrity": "sha512-e9t5v/L1KqPLUQL+WU+d70MBBFcSRuwqbkluZgdDjdW5VelYjzlVzXdrzV6jFElP48T3kQCxJN1dAJkAvKjdOg==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.1.4.tgz", + "integrity": "sha512-wOOLzxPLsDYsD+f6Bqr31ol8K7I4cm4k5uuaQl+wkLBpX9AD1rMi/7CPJrXAWBdgOW67uPzAdLBsK+axKfg91w==", "license": "MIT", "dependencies": { "@babel/core": "7.24.9", @@ -762,7 +762,7 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/compiler": "18.1.3", + "@angular/compiler": "18.1.4", "typescript": ">=5.4 <5.6" } }, @@ -818,9 +818,9 @@ } }, "node_modules/@angular/core": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.1.3.tgz", - "integrity": "sha512-1tFTyGLwio5oYAP2sMVDiOvy5wl/v0a4om7RTCpP2Bjro0ynuYe8FK7ilcmdyPXR1DF7GVdo/0R/eCIQJZ2PwA==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.1.4.tgz", + "integrity": "sha512-+N3oWYFubT3GdCkBfD/CmH4DGjr/fGFQZChWbph2ZuPpK7JYNgfyvXS4SjLtdL4WTjjBevBTgR70GyLH/5EbKA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -834,9 +834,9 @@ } }, "node_modules/@angular/forms": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.1.3.tgz", - "integrity": "sha512-4kic/9hpS0HkbTORIkrdox7K40EcVT9VIbBruPoxX7jbfiW5jFaJ/05hLRvRt9RF8Sd9G+g5Uohmkcq/5hmsng==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.1.4.tgz", + "integrity": "sha512-PYaQ7/2toAwgJWIznVWgJAd3l8mjAreilGOVIMbBIaotL/EHRQjhlikitJEFDGXeVUarY/rm3IlLWBYnLyliyg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -845,16 +845,16 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.1.3", - "@angular/core": "18.1.3", - "@angular/platform-browser": "18.1.3", + "@angular/common": "18.1.4", + "@angular/core": "18.1.4", + "@angular/platform-browser": "18.1.4", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/language-service": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-18.1.3.tgz", - "integrity": "sha512-1s1VQHJ6Gh84lCqgSEU6pNuPBpvee1mhfIZEE2lqxFu/tLe5gqvtTescFaTFLWY6I4e2RGAOU8WtRnFgFNxzGg==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-18.1.4.tgz", + "integrity": "sha512-nvO6lG/vMWRXUj+nY2HyvhOSlSYqBx1ER2rk5MezzYo3I0qgiNuV9YfgTyXLWywDAvc9jcTrIyi4nxBm6a0xvQ==", "dev": true, "license": "MIT", "engines": { @@ -862,9 +862,9 @@ } }, "node_modules/@angular/localize": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-18.1.3.tgz", - "integrity": "sha512-C7D7m9LkcvK0byVXmBrLBlAhEBFO5ZCIQJ+tDd/vUq1ALdkMlG4RkwVsrQxLIIatp88p21V0M0ZQNc3IfgileQ==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-18.1.4.tgz", + "integrity": "sha512-GqrVYc3PwYFd9nDbOV0nL2ZhsLfb1LOZLnpsGqTBJT6zfmbqTUnwQWjHmj6SoGzTQl9r9OAvawaMrICzB6Rrfw==", "license": "MIT", "dependencies": { "@babel/core": "7.24.9", @@ -881,8 +881,8 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/compiler": "18.1.3", - "@angular/compiler-cli": "18.1.3" + "@angular/compiler": "18.1.4", + "@angular/compiler-cli": "18.1.4" } }, "node_modules/@angular/localize/node_modules/@babel/core": { @@ -937,16 +937,16 @@ "license": "MIT" }, "node_modules/@angular/material": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-18.1.3.tgz", - "integrity": "sha512-4xsn84orqtJwE9c2kgHeMxP/rOEvs8XrUOcyA89WE025uDXk69lAsm7XsCpwOL9iDjTBFPTOXFIbR+s9jvU39w==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-18.1.4.tgz", + "integrity": "sha512-xmKIVOKZA8yFXrw4PsBvShFSYFQCnuVNGGuJlc8S8xvURh/f9P6hAo1Ua9pSBkOKz2W2dHE+726zOqL+o4kNxg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/animations": "^18.0.0 || ^19.0.0", - "@angular/cdk": "18.1.3", + "@angular/cdk": "18.1.4", "@angular/common": "^18.0.0 || ^19.0.0", "@angular/core": "^18.0.0 || ^19.0.0", "@angular/forms": "^18.0.0 || ^19.0.0", @@ -955,9 +955,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.1.3.tgz", - "integrity": "sha512-/k5Xt/WjOk6OlRqb1Wd0ZUQ3NjSbafQyDC9Icy0Mb8qJtiXZjA4VCMkZIiQD7cBxO0F/BsAiYnYNjWrIkCZICA==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.1.4.tgz", + "integrity": "sha512-zGx33St0JVYT8EZOaf0s8Twr0RgfU2cqEAc9Wwx9HVJ0pF5y4VnftK3pewwiHWDHkPfiJy0jBKbtrkVUSbgZfg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -966,9 +966,9 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/animations": "18.1.3", - "@angular/common": "18.1.3", - "@angular/core": "18.1.3" + "@angular/animations": "18.1.4", + "@angular/common": "18.1.4", + "@angular/core": "18.1.4" }, "peerDependenciesMeta": { "@angular/animations": { @@ -977,9 +977,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.1.3.tgz", - "integrity": "sha512-VhYfyPcdKrsLrkd5Lq7W+pqE49DZBpUeCqM/Q+s9rhTSiCCKe9Ikktq8yPZ9iHDpFr203P+T1EMHmILnLvf+gQ==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.1.4.tgz", + "integrity": "sha512-ZQQcKXGIriOzILTZxIbmDpGnwuiwfJ0xh2EmmnfC0zh/NB+li6whgplOLEciaHgsUKtDn7kNZFn2vKrx+B/cDQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -988,16 +988,16 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.1.3", - "@angular/compiler": "18.1.3", - "@angular/core": "18.1.3", - "@angular/platform-browser": "18.1.3" + "@angular/common": "18.1.4", + "@angular/compiler": "18.1.4", + "@angular/core": "18.1.4", + "@angular/platform-browser": "18.1.4" } }, "node_modules/@angular/router": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.1.3.tgz", - "integrity": "sha512-6fXiTgdUnaGGF32Un4+7LttG1N9rziansigvLBzFG//qYU0Ihk49phqDdWxz11iaJ+uK1YVafkjSFvV7z9cgDA==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.1.4.tgz", + "integrity": "sha512-982+bnO3uGFYjRFcQDoKmnWvUcZUvFxEpX/I2Yu+WmPJrY7fPJ693mBaWgwVFa0xIBNfjvJjNXdikGBz5UrMsw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1006,16 +1006,16 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.1.3", - "@angular/core": "18.1.3", - "@angular/platform-browser": "18.1.3", + "@angular/common": "18.1.4", + "@angular/core": "18.1.4", + "@angular/platform-browser": "18.1.4", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/service-worker": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-18.1.3.tgz", - "integrity": "sha512-fWpFMNOBUTFpRWYf6Tlc6HXr6UG8YTFqXIBs2Wmcwv0oVwj6ZQX6+ieI14fYI8lYpuAx8L+oh6oKMQ3gOiH08Q==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-18.1.4.tgz", + "integrity": "sha512-7knx0I82ud6IWu2NOEtmtikApm/Ix8YEbXk2/J8YiN7ozGSTjTK5X8cpvFUzfG4MbARH6sxVAPffNJduzW4ZAw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1027,8 +1027,8 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.1.3", - "@angular/core": "18.1.3" + "@angular/common": "18.1.4", + "@angular/core": "18.1.4" } }, "node_modules/@babel/code-frame": { @@ -3657,15 +3657,15 @@ } }, "node_modules/@inquirer/checkbox": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-2.4.5.tgz", - "integrity": "sha512-+YlCyS6JBWeZugIvReh/YL5HJcowlklz5RykQuYKQfgWQeCJh5Us0nWcRddvIVkjmYa0I/8bwWioSLu850J8sA==", + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-2.4.7.tgz", + "integrity": "sha512-5YwCySyV1UEgqzz34gNsC38eKxRBtlRDpJLlKcRtTjlYA/yDKuc1rfw+hjw+2WJxbAZtaDPsRl5Zk7J14SBoBw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.8", + "@inquirer/core": "^9.0.10", "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.1", + "@inquirer/type": "^1.5.2", "ansi-escapes": "^4.3.2", "yoctocolors-cjs": "^2.1.2" }, @@ -3674,16 +3674,16 @@ } }, "node_modules/@inquirer/checkbox/node_modules/@inquirer/core": { - "version": "9.0.8", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.8.tgz", - "integrity": "sha512-ttnI/BGlP9SxjbQnv1nssv7dPAwiR82KmjJZx2SxSZyi2mGbaEvh4jg0I4yU/4mVQf7QvCVGGr/hGuJFEYhwnw==", + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", + "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", "dev": true, "license": "MIT", "dependencies": { "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.1", + "@inquirer/type": "^1.5.2", "@types/mute-stream": "^0.0.4", - "@types/node": "^22.0.0", + "@types/node": "^22.1.0", "@types/wrap-ansi": "^3.0.0", "ansi-escapes": "^4.3.2", "cli-spinners": "^2.9.2", @@ -3755,14 +3755,14 @@ "license": "MIT" }, "node_modules/@inquirer/editor": { - "version": "2.1.20", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-2.1.20.tgz", - "integrity": "sha512-vtIN9NwXldX8SWbPt5biJhnTpHJCzF5nSymcv4hcOxiCrOpXmgOvFYGpAY729KODF+5e1OLqPbJ8ApiwPu/peQ==", + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-2.1.22.tgz", + "integrity": "sha512-K1QwTu7GCK+nKOVRBp5HY9jt3DXOfPGPr6WRDrPImkcJRelG9UTx2cAtK1liXmibRrzJlTWOwqgWT3k2XnS62w==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.8", - "@inquirer/type": "^1.5.1", + "@inquirer/core": "^9.0.10", + "@inquirer/type": "^1.5.2", "external-editor": "^3.1.0" }, "engines": { @@ -3770,16 +3770,16 @@ } }, "node_modules/@inquirer/editor/node_modules/@inquirer/core": { - "version": "9.0.8", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.8.tgz", - "integrity": "sha512-ttnI/BGlP9SxjbQnv1nssv7dPAwiR82KmjJZx2SxSZyi2mGbaEvh4jg0I4yU/4mVQf7QvCVGGr/hGuJFEYhwnw==", + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", + "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", "dev": true, "license": "MIT", "dependencies": { "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.1", + "@inquirer/type": "^1.5.2", "@types/mute-stream": "^0.0.4", - "@types/node": "^22.0.0", + "@types/node": "^22.1.0", "@types/wrap-ansi": "^3.0.0", "ansi-escapes": "^4.3.2", "cli-spinners": "^2.9.2", @@ -3795,14 +3795,14 @@ } }, "node_modules/@inquirer/expand": { - "version": "2.1.20", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-2.1.20.tgz", - "integrity": "sha512-ruUTCUGKhe6TvDM3/gKjX9v7D5cWbiuawFE6aF/cFmNO79R/zMjrFFVoueDM8FRw8yXqnREb0jFkYF1LUxnDNA==", + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-2.1.22.tgz", + "integrity": "sha512-wTZOBkzH+ItPuZ3ZPa9lynBsdMp6kQ9zbjVPYEtSBG7UulGjg2kQiAnUjgyG4SlntpTce5bOmXAPvE4sguXjpA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.8", - "@inquirer/type": "^1.5.1", + "@inquirer/core": "^9.0.10", + "@inquirer/type": "^1.5.2", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -3810,16 +3810,16 @@ } }, "node_modules/@inquirer/expand/node_modules/@inquirer/core": { - "version": "9.0.8", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.8.tgz", - "integrity": "sha512-ttnI/BGlP9SxjbQnv1nssv7dPAwiR82KmjJZx2SxSZyi2mGbaEvh4jg0I4yU/4mVQf7QvCVGGr/hGuJFEYhwnw==", + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", + "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", "dev": true, "license": "MIT", "dependencies": { "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.1", + "@inquirer/type": "^1.5.2", "@types/mute-stream": "^0.0.4", - "@types/node": "^22.0.0", + "@types/node": "^22.1.0", "@types/wrap-ansi": "^3.0.0", "ansi-escapes": "^4.3.2", "cli-spinners": "^2.9.2", @@ -3845,30 +3845,30 @@ } }, "node_modules/@inquirer/input": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-2.2.7.tgz", - "integrity": "sha512-QFk31Gq4Wr+Ve9ilMiFGGrSjGZQBilV0cgTN1zubD98Bx65fsNrh8++Biy/9mjNKRaqHFbZBw5baAcQvOmW8OQ==", + "version": "2.2.9", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-2.2.9.tgz", + "integrity": "sha512-7Z6N+uzkWM7+xsE+3rJdhdG/+mQgejOVqspoW+w0AbSZnL6nq5tGMEVASaYVWbkoSzecABWwmludO2evU3d31g==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.8", - "@inquirer/type": "^1.5.1" + "@inquirer/core": "^9.0.10", + "@inquirer/type": "^1.5.2" }, "engines": { "node": ">=18" } }, "node_modules/@inquirer/input/node_modules/@inquirer/core": { - "version": "9.0.8", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.8.tgz", - "integrity": "sha512-ttnI/BGlP9SxjbQnv1nssv7dPAwiR82KmjJZx2SxSZyi2mGbaEvh4jg0I4yU/4mVQf7QvCVGGr/hGuJFEYhwnw==", + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", + "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", "dev": true, "license": "MIT", "dependencies": { "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.1", + "@inquirer/type": "^1.5.2", "@types/mute-stream": "^0.0.4", - "@types/node": "^22.0.0", + "@types/node": "^22.1.0", "@types/wrap-ansi": "^3.0.0", "ansi-escapes": "^4.3.2", "cli-spinners": "^2.9.2", @@ -3884,14 +3884,14 @@ } }, "node_modules/@inquirer/password": { - "version": "2.1.20", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-2.1.20.tgz", - "integrity": "sha512-il2TG7xDlfiLE3cnOCxfDfrwvsiSmXjVd26hvf4tdzHvdisgLiEjbN6mi51/TnlSQ+2Qc69+9jIq3ws93nhS2w==", + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-2.1.22.tgz", + "integrity": "sha512-5Fxt1L9vh3rAKqjYwqsjU4DZsEvY/2Gll+QkqR4yEpy6wvzLxdSgFhUcxfDAOtO4BEoTreWoznC0phagwLU5Kw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.8", - "@inquirer/type": "^1.5.1", + "@inquirer/core": "^9.0.10", + "@inquirer/type": "^1.5.2", "ansi-escapes": "^4.3.2" }, "engines": { @@ -3899,16 +3899,16 @@ } }, "node_modules/@inquirer/password/node_modules/@inquirer/core": { - "version": "9.0.8", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.8.tgz", - "integrity": "sha512-ttnI/BGlP9SxjbQnv1nssv7dPAwiR82KmjJZx2SxSZyi2mGbaEvh4jg0I4yU/4mVQf7QvCVGGr/hGuJFEYhwnw==", + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", + "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", "dev": true, "license": "MIT", "dependencies": { "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.1", + "@inquirer/type": "^1.5.2", "@types/mute-stream": "^0.0.4", - "@types/node": "^22.0.0", + "@types/node": "^22.1.0", "@types/wrap-ansi": "^3.0.0", "ansi-escapes": "^4.3.2", "cli-spinners": "^2.9.2", @@ -3944,14 +3944,14 @@ } }, "node_modules/@inquirer/rawlist": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-2.2.2.tgz", - "integrity": "sha512-U4OsvqjdLB6nmf5ZDshPYMq0b+qd6JWxTrvRTiMfwUY6cFxkR9YWKarLXFhndf7tawQ8f3DwU9P9wryDc2ESSA==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-2.2.4.tgz", + "integrity": "sha512-pb6w9pWrm7EfnYDgQObOurh2d2YH07+eDo3xQBsNAM2GRhliz6wFXGi1thKQ4bN6B0xDd6C3tBsjdr3obsCl3Q==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.8", - "@inquirer/type": "^1.5.1", + "@inquirer/core": "^9.0.10", + "@inquirer/type": "^1.5.2", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -3959,16 +3959,16 @@ } }, "node_modules/@inquirer/rawlist/node_modules/@inquirer/core": { - "version": "9.0.8", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.8.tgz", - "integrity": "sha512-ttnI/BGlP9SxjbQnv1nssv7dPAwiR82KmjJZx2SxSZyi2mGbaEvh4jg0I4yU/4mVQf7QvCVGGr/hGuJFEYhwnw==", + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", + "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", "dev": true, "license": "MIT", "dependencies": { "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.1", + "@inquirer/type": "^1.5.2", "@types/mute-stream": "^0.0.4", - "@types/node": "^22.0.0", + "@types/node": "^22.1.0", "@types/wrap-ansi": "^3.0.0", "ansi-escapes": "^4.3.2", "cli-spinners": "^2.9.2", @@ -3984,15 +3984,15 @@ } }, "node_modules/@inquirer/select": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-2.4.5.tgz", - "integrity": "sha512-DbCthH3l7vrrK+Ewll3bgzxC3dzMle8xkWYta4if31p9NOmFNhZKhSfdYMjaOtGFBCUEwo4D5LMgN6sPKgUWIw==", + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-2.4.7.tgz", + "integrity": "sha512-JH7XqPEkBpNWp3gPCqWqY8ECbyMoFcCZANlL6pV9hf59qK6dGmkOlx1ydyhY+KZ0c5X74+W6Mtp+nm2QX0/MAQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.8", + "@inquirer/core": "^9.0.10", "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.1", + "@inquirer/type": "^1.5.2", "ansi-escapes": "^4.3.2", "yoctocolors-cjs": "^2.1.2" }, @@ -4001,16 +4001,16 @@ } }, "node_modules/@inquirer/select/node_modules/@inquirer/core": { - "version": "9.0.8", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.8.tgz", - "integrity": "sha512-ttnI/BGlP9SxjbQnv1nssv7dPAwiR82KmjJZx2SxSZyi2mGbaEvh4jg0I4yU/4mVQf7QvCVGGr/hGuJFEYhwnw==", + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", + "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", "dev": true, "license": "MIT", "dependencies": { "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.1", + "@inquirer/type": "^1.5.2", "@types/mute-stream": "^0.0.4", - "@types/node": "^22.0.0", + "@types/node": "^22.1.0", "@types/wrap-ansi": "^3.0.0", "ansi-escapes": "^4.3.2", "cli-spinners": "^2.9.2", @@ -4026,9 +4026,9 @@ } }, "node_modules/@inquirer/type": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.5.1.tgz", - "integrity": "sha512-m3YgGQlKNS0BM+8AFiJkCsTqHEFCWn6s/Rqye3mYwvqY6LdfUv12eSwbsgNzrYyrLXiy7IrrjDLPysaSBwEfhw==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.5.2.tgz", + "integrity": "sha512-w9qFkumYDCNyDZmNQjf/n6qQuvQ4dMC3BJesY4oF+yr0CxR5vxujflAVeIcS6U336uzi9GM0kAfZlLrZ9UTkpA==", "dev": true, "license": "MIT", "dependencies": { @@ -5027,9 +5027,9 @@ } }, "node_modules/@jsonjoy.com/json-pack": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.0.4.tgz", - "integrity": "sha512-aOcSN4MeAtFROysrbqG137b7gaDDSmVrl5mpo6sT/w+kcXpWnzhMjmY/Fh/sDx26NBxyIE7MB1seqLeCAzy9Sg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.1.0.tgz", + "integrity": "sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -5332,9 +5332,9 @@ } }, "node_modules/@ngtools/webpack": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.1.3.tgz", - "integrity": "sha512-VmqOO8CcXKL06anNYlL0OkrqIuBNZQu5n0YVP4z8oneJhDBqwK2++dK0WpcNyIFcg3HsQ7w3BuqUWJ4iPiWxEQ==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.1.4.tgz", + "integrity": "sha512-suoeZjd+7qd3ivzbNGGSzHtY/WMxTKU6ZD1gIIya0Un8Ve1eVxfq6Si6ReKqhygO8zN3paJMATn8sMmAV7qVrw==", "dev": true, "license": "MIT", "engines": { @@ -5680,23 +5680,23 @@ } }, "node_modules/@nrwl/devkit": { - "version": "19.5.6", - "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.5.6.tgz", - "integrity": "sha512-H7LGlwAktfL2GR4scwCfehuppmzcHJJt4C2PpiGEsfA74MKBw2/VGX15b29Mf36XbGS+Bx9vjvooZEt5HPCusw==", + "version": "19.5.7", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.5.7.tgz", + "integrity": "sha512-sTEwqsAT6bMturU14o/0O6v509OkwGOglxpbiL/zIYO/fDkMoNgnhlHBIT87i4YVuofMz2Z+hTfjDskzDPRSYw==", "dev": true, "license": "MIT", "dependencies": { - "@nx/devkit": "19.5.6" + "@nx/devkit": "19.5.7" } }, "node_modules/@nrwl/tao": { - "version": "19.5.6", - "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-19.5.6.tgz", - "integrity": "sha512-p1bxEjW32bIHAiTp+PVdJpa2V9En2s9FigepHXyvmT2Aipisz96CKiDjexhPTjOZHUKtqA9FgmOIuVl3sBME3g==", + "version": "19.5.7", + "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-19.5.7.tgz", + "integrity": "sha512-c1rN6HY97+cEwoM5Q9412399Ac1rw7pI/3IS5iJSYkeI5TTGOobIpdCavJPZVcfqo4+wegXPA3F/OmulgbOUJA==", "dev": true, "license": "MIT", "dependencies": { - "nx": "19.5.6", + "nx": "19.5.7", "tslib": "^2.3.0" }, "bin": { @@ -5704,13 +5704,13 @@ } }, "node_modules/@nx/devkit": { - "version": "19.5.6", - "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.5.6.tgz", - "integrity": "sha512-zSToXLkhbAOQmqVTgUNHdLO0uOZz/iGwqEK4tuAhU5hhqTcpN1TZUI9BlINvtFJBLvbNroGrnIh0gTq9CPzVHw==", + "version": "19.5.7", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.5.7.tgz", + "integrity": "sha512-mUtZQcdqbF0Q9HfyG14jmpPCtZ1GnVaLNIADZv5SLpFyfh4ZjaBw6wdjPj7Sp3imLoyqMrcd9nCRNO2hlem8bw==", "dev": true, "license": "MIT", "dependencies": { - "@nrwl/devkit": "19.5.6", + "@nrwl/devkit": "19.5.7", "ejs": "^3.1.7", "enquirer": "~2.3.6", "ignore": "^5.0.4", @@ -5725,9 +5725,9 @@ } }, "node_modules/@nx/nx-darwin-arm64": { - "version": "19.5.6", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-19.5.6.tgz", - "integrity": "sha512-evEpUq571PQkhaLBR7ul5iqE2l97QS7Q37/rxoBuwJzyQ/QKHfNu5t032bR3KLyEOrv7golT10jMeoQlNeF7eQ==", + "version": "19.5.7", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-19.5.7.tgz", + "integrity": "sha512-5jFAZSfV8QVNoxOXayZw4/jNJbxMMctNOYZW8Qj4eU8Ti+OmhsLgouxz/9enCh5SDITriOMZ7IHZ9rhrlGQoig==", "cpu": [ "arm64" ], @@ -5742,9 +5742,9 @@ } }, "node_modules/@nx/nx-darwin-x64": { - "version": "19.5.6", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-19.5.6.tgz", - "integrity": "sha512-o1tu0dOW7TZ80VN9N11FQL/3gHd1+t6NqtEmRClN0/sAh2MZyiBdbXv7UeN5HoKE7HAusiVFIxK3c1lxOvFtsQ==", + "version": "19.5.7", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-19.5.7.tgz", + "integrity": "sha512-Ss+rF2+MQxyKrNnSYAeEGhtdE9hUHiTqyjJo4n1lvIWJ++TairOCtk5QRHrYLgAxE1XTf0OabcsDzegxv7yk3Q==", "cpu": [ "x64" ], @@ -5759,9 +5759,9 @@ } }, "node_modules/@nx/nx-freebsd-x64": { - "version": "19.5.6", - "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-19.5.6.tgz", - "integrity": "sha512-IUL0ROGpLUol9cuVJ7VeUvaB/ptxg7DOjMef1+LJeOgxl/SFNa0bj0kKpA/AQwujz6cLI7Ei7xLTVQOboNh1DA==", + "version": "19.5.7", + "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-19.5.7.tgz", + "integrity": "sha512-FMLXcUr3mw/v4LvmNqHMAXy2k+T/hp2YpdBUq9ExteMfRywFsnKNlm39n/quniFsgKthEMdvvzxSQppRKaVwIw==", "cpu": [ "x64" ], @@ -5776,9 +5776,9 @@ } }, "node_modules/@nx/nx-linux-arm-gnueabihf": { - "version": "19.5.6", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-19.5.6.tgz", - "integrity": "sha512-TGf1+cpWg5QiPEGW5kgxa1fVNyASMuqu+LvQ9CKhNYNz5EPD15yr/k6C0tOjgSXro3wi8TikTeG0Ln2hpmn6pw==", + "version": "19.5.7", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-19.5.7.tgz", + "integrity": "sha512-LhJ342HutpR258lBLVTkXd6x2Uj4ZPJ6xKdfEm+FYQvG1byPr2L0TlNXcfSBkYtd7wRn0qg9eQZoCV/5+w415Q==", "cpu": [ "arm" ], @@ -5793,9 +5793,9 @@ } }, "node_modules/@nx/nx-linux-arm64-gnu": { - "version": "19.5.6", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-19.5.6.tgz", - "integrity": "sha512-4hZI5NmnBEAzr3NV/BtlPjbSVffLWGGCJ5tB/JB/NpW/vMtzOPCZ4RvsHuJMPprqHcXOdUnBgZFEcLbEMUXz0A==", + "version": "19.5.7", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-19.5.7.tgz", + "integrity": "sha512-Q6gN+VNLisg7mYPTXC5JuGCP/s9tLjJFclKdH6FoP5K1Hgy88KK1uUoivDIfI8xaEgyLqphD1AAqokiFWZNWsg==", "cpu": [ "arm64" ], @@ -5810,9 +5810,9 @@ } }, "node_modules/@nx/nx-linux-arm64-musl": { - "version": "19.5.6", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-19.5.6.tgz", - "integrity": "sha512-n0oIBblMN+nlcBUbrFUkRSyzKZVR+G1lzdZ3PuHVwLC664hkbijEBAdF2E321yRfv5ohQVY0UIYDZVFN2XhFUg==", + "version": "19.5.7", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-19.5.7.tgz", + "integrity": "sha512-BsYNcYujNKb+uE7PrJp4PrX8a3G9oy+THaUr0t5+L435HjuZDBiK+tK9JzYGvM0bR5FOYm5K99I1DVD/Hv0snw==", "cpu": [ "arm64" ], @@ -5827,9 +5827,9 @@ } }, "node_modules/@nx/nx-linux-x64-gnu": { - "version": "19.5.6", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-19.5.6.tgz", - "integrity": "sha512-IuoNo1bDHyJEeHom/n2m4+AA+UQ+Rlryvt9+bTdADclSFjmBLYCgbJwQRy7q9+vQk2mpQm0pQJv4d3XKCpDH+g==", + "version": "19.5.7", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-19.5.7.tgz", + "integrity": "sha512-ILaLU8b5lUokYVF3vxAVj62qFok1hexiNzBdLGJPI1OkPGELtLyb8RymI3939iJoNMk1DS3/6dqK7NHXvHX8Mw==", "cpu": [ "x64" ], @@ -5844,9 +5844,9 @@ } }, "node_modules/@nx/nx-linux-x64-musl": { - "version": "19.5.6", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-19.5.6.tgz", - "integrity": "sha512-FXtB8m/CSRkXLtDOAGfImO9OCUDIwYBssnvCVqX6PyPTBaVWo/GvX1O9WRbXSqSVIaJJTPn1aY/p6vptlGbDFw==", + "version": "19.5.7", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-19.5.7.tgz", + "integrity": "sha512-LfTnO4JZebLugioMk+GTptv3N38Wj2i2Pko0bdRZaKba+INGSlUgFqoRuO0KqZEmVIUGrxfkfqIN3HghVQ4D/Q==", "cpu": [ "x64" ], @@ -5861,9 +5861,9 @@ } }, "node_modules/@nx/nx-win32-arm64-msvc": { - "version": "19.5.6", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-19.5.6.tgz", - "integrity": "sha512-aIDU84rjvxoqyUDIdN4VwS91Yec8bAtXOxjOFlF2acY2tXh0RjzmM+mkEP44nVAzFy0V1/cjzBKb6643FsEqdA==", + "version": "19.5.7", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-19.5.7.tgz", + "integrity": "sha512-cCTttdbf1AKuDU8j108SpIMWs53A/0mOVDPOPpa+oKkvBaI8ruZkxOceMjWZjWULd2gi1nS+5nJePpbrdQ8mkg==", "cpu": [ "arm64" ], @@ -5878,9 +5878,9 @@ } }, "node_modules/@nx/nx-win32-x64-msvc": { - "version": "19.5.6", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-19.5.6.tgz", - "integrity": "sha512-zWB/2TjhNYKHbuPh++5hYitno3EpSFXrPND0I0VLec27WW7voRY9XQFFznA3omForU4FfmVhITcKCqzIb3EtpA==", + "version": "19.5.7", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-19.5.7.tgz", + "integrity": "sha512-EqSnjpq1PNR/C8/YkL+Gn79dDfQ+HwJM8VJOt4qoCOQ9gQZqNJphjW2hg0H8WxLYezMScx3fbL99mvJO7ab2Cw==", "cpu": [ "x64" ], @@ -6210,14 +6210,14 @@ ] }, "node_modules/@schematics/angular": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.1.3.tgz", - "integrity": "sha512-VyoL7O+3eL+BazmoWzexFpVy9k0MoOAmff3XqKLhP3/V7eXPc9s7znIDpPp28QF0V/Y2xMaGDWhqTx2CFcz4Qg==", + "version": "18.1.4", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.1.4.tgz", + "integrity": "sha512-M3edVYKiAGWAAKs7XDLpz1OKUy4STVMT+46Y44ydYz06hI8m/dJfS8ZHTvXPl7JhkrIrSDEMed+WidZtGPIxMg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.1.3", - "@angular-devkit/schematics": "18.1.3", + "@angular-devkit/core": "18.1.4", + "@angular-devkit/schematics": "18.1.4", "jsonc-parser": "3.3.1" }, "engines": { @@ -6227,73 +6227,73 @@ } }, "node_modules/@sentry-internal/browser-utils": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.22.0.tgz", - "integrity": "sha512-R0u8KPaSivueIwUOhmYxcisKaJq3gx+I0xOcWoluDB3OI1Ds/QOSP/vmTsMg/mjwG/nUJ8RRM8pj0s8vlqCrjg==", + "version": "8.24.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.24.0.tgz", + "integrity": "sha512-U5dVZ4JM+UeN3YWBUHZcNLF038C3ccTTsTICIw+zfCQbpPhPms8DOEDVpd0So18XoNDzYmLo07hC1BwByRAfGw==", "license": "MIT", "dependencies": { - "@sentry/core": "8.22.0", - "@sentry/types": "8.22.0", - "@sentry/utils": "8.22.0" + "@sentry/core": "8.24.0", + "@sentry/types": "8.24.0", + "@sentry/utils": "8.24.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/feedback": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.22.0.tgz", - "integrity": "sha512-Sy2+v0xBmVnZ5LQ48603CvLy5vVQvAZ+hc9xQSAHexts07NkvApMU1qv26YNwxlAWfDha1wXiW6ryd4YDzaoVA==", + "version": "8.24.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.24.0.tgz", + "integrity": "sha512-0tWRp8SOSTSPTViRJnB6+HHixFgkEWjKPciuLsAZkobRhi+VVedPj3zVztORy5AvARGr6AgyVSdnviilcrKl6g==", "license": "MIT", "dependencies": { - "@sentry/core": "8.22.0", - "@sentry/types": "8.22.0", - "@sentry/utils": "8.22.0" + "@sentry/core": "8.24.0", + "@sentry/types": "8.24.0", + "@sentry/utils": "8.24.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/replay": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.22.0.tgz", - "integrity": "sha512-sF8RyMPJP1fSIyyBDAbtybvKCu0dy8ZAfMwLP7ZqEnWrhZqktVuqM7/++EAFMlD5YaWJXm1IDuOXjgSQjUtSIQ==", + "version": "8.24.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.24.0.tgz", + "integrity": "sha512-+3d+3Ln7iDOZo2wOBv7EWojVHigEskjKsz8vR3WFdxYyue8e3zPQ/xg/t9A6BtEVRPQsEyhM3oN6LyjqFv2nfg==", "license": "MIT", "dependencies": { - "@sentry-internal/browser-utils": "8.22.0", - "@sentry/core": "8.22.0", - "@sentry/types": "8.22.0", - "@sentry/utils": "8.22.0" + "@sentry-internal/browser-utils": "8.24.0", + "@sentry/core": "8.24.0", + "@sentry/types": "8.24.0", + "@sentry/utils": "8.24.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/replay-canvas": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.22.0.tgz", - "integrity": "sha512-/gV8qN3JqWw0LXTMuCGB8RDI8Bx1VESNRBdh/7Cmc5+hxYBfcketuix3S8mHWcE/JO+Ed9g1Abzys6GphTB9LA==", + "version": "8.24.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.24.0.tgz", + "integrity": "sha512-MI+j9tUab1d5oer2xKQ2lxdXSzBeZ1DF2dwlVxQDOfSAQqRfZJpmLcmSPb6M+GJsf2xHg6n4dAQvWQuM0qGQPQ==", "license": "MIT", "dependencies": { - "@sentry-internal/replay": "8.22.0", - "@sentry/core": "8.22.0", - "@sentry/types": "8.22.0", - "@sentry/utils": "8.22.0" + "@sentry-internal/replay": "8.24.0", + "@sentry/core": "8.24.0", + "@sentry/types": "8.24.0", + "@sentry/utils": "8.24.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry/angular": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@sentry/angular/-/angular-8.22.0.tgz", - "integrity": "sha512-4b6lhtUpkCJ0+YDTsAHtvEYcbOPlDOTgdw80DRsTjOx6In8+ykLE8GAuWioWRCEGfkWpQJn5Wb1/We1JBAfqzg==", + "version": "8.24.0", + "resolved": "https://registry.npmjs.org/@sentry/angular/-/angular-8.24.0.tgz", + "integrity": "sha512-/V7EWkrczZXZgtK4JPkP9/FSWs9R4oeCDEXs3pnL5gswkQXqUXBE+jXlAPaAMIW5r6zj4AcoC9XgrMcjqk7QiQ==", "license": "MIT", "dependencies": { - "@sentry/browser": "8.22.0", - "@sentry/core": "8.22.0", - "@sentry/types": "8.22.0", - "@sentry/utils": "8.22.0", + "@sentry/browser": "8.24.0", + "@sentry/core": "8.24.0", + "@sentry/types": "8.24.0", + "@sentry/utils": "8.24.0", "tslib": "^2.4.1" }, "engines": { @@ -6307,52 +6307,52 @@ } }, "node_modules/@sentry/browser": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.22.0.tgz", - "integrity": "sha512-t3b+/9WWcP9SQTWwrHrB57B33ENgmUjyFlW2+JSlCXkSJBSmAoquPZ/GPjOuPaSr3HIA0mu9uEr4A41d5diASQ==", + "version": "8.24.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.24.0.tgz", + "integrity": "sha512-WdCLUoMAE0ZWsZDb3G/FQI5YgkH59VVEpnPqrWI08m2KuqLz8eU724JZvNzaDv/L2yzksgS4HDDUXkNRzDeCrQ==", "license": "MIT", "dependencies": { - "@sentry-internal/browser-utils": "8.22.0", - "@sentry-internal/feedback": "8.22.0", - "@sentry-internal/replay": "8.22.0", - "@sentry-internal/replay-canvas": "8.22.0", - "@sentry/core": "8.22.0", - "@sentry/types": "8.22.0", - "@sentry/utils": "8.22.0" + "@sentry-internal/browser-utils": "8.24.0", + "@sentry-internal/feedback": "8.24.0", + "@sentry-internal/replay": "8.24.0", + "@sentry-internal/replay-canvas": "8.24.0", + "@sentry/core": "8.24.0", + "@sentry/types": "8.24.0", + "@sentry/utils": "8.24.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry/core": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.22.0.tgz", - "integrity": "sha512-fYPnxp7UkY2tckaOtivIySxnJvlbekuxs+Qi6rkUv9JpF+TYKpt7OPNUAbgVIhS0xazAEN6iKTfmnmpUbFRLmQ==", + "version": "8.24.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.24.0.tgz", + "integrity": "sha512-nyy7po78Ef5KNzehHJCCyLGGR/FceHyw2IRzDQUVD6M4tos8G1OML1gcnALChWhyeq1SIoDsC1ofxFlbkIWuog==", "license": "MIT", "dependencies": { - "@sentry/types": "8.22.0", - "@sentry/utils": "8.22.0" + "@sentry/types": "8.24.0", + "@sentry/utils": "8.24.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry/types": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-8.22.0.tgz", - "integrity": "sha512-1MLK3xO+uF2oJaa+M98aLIrQsEHzV7xnVWPfE3MhejYLNQebj4rQnQKTut/xZNIF9W0Q+bRcakLarC3ce2a74g==", + "version": "8.24.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-8.24.0.tgz", + "integrity": "sha512-5QWXARoFrvTvnS19ip+ha0x4nWIv/RvoCTnqCsgrNTjypbk1+KMSMQQhGMo8OuEBFhdGyTs1BqfxVV82URHh3w==", "license": "MIT", "engines": { "node": ">=14.18" } }, "node_modules/@sentry/utils": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-8.22.0.tgz", - "integrity": "sha512-0ITG2+3EtyMtyc/nQG8aB9z9eIQ4L43nM/KuNgYSnM1vPl/zegbaLT0Ek/xkQB1OLIOLkEPQ6x9GWe+248/n3g==", + "version": "8.24.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-8.24.0.tgz", + "integrity": "sha512-AGo5PldxCJYn3g0IYXeBkeALNa+NieJaaCDpYyzrKAFdxoA6Qp+Z/wmN9m5BYZ9eHx9N+xMOoz2aIh4hG48VbQ==", "license": "MIT", "dependencies": { - "@sentry/types": "8.22.0" + "@sentry/types": "8.24.0" }, "engines": { "node": ">=14.18" @@ -6880,9 +6880,9 @@ "license": "MIT" }, "node_modules/@types/http-proxy": { - "version": "1.17.14", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", - "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "version": "1.17.15", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", + "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7170,9 +7170,9 @@ } }, "node_modules/@types/yargs": { - "version": "17.0.32", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", - "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", "dev": true, "license": "MIT", "dependencies": { @@ -7187,17 +7187,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.0.0.tgz", - "integrity": "sha512-STIZdwEQRXAHvNUS6ILDf5z3u95Gc8jzywunxSNqX00OooIemaaNIA0vEgynJlycL5AjabYLLrIyHd4iazyvtg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.0.1.tgz", + "integrity": "sha512-5g3Y7GDFsJAnY4Yhvk8sZtFfV6YNF2caLzjrRPUBzewjPCaj0yokePB4LJSobyCzGMzjZZYFbwuzbfDHlimXbQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.0.0", - "@typescript-eslint/type-utils": "8.0.0", - "@typescript-eslint/utils": "8.0.0", - "@typescript-eslint/visitor-keys": "8.0.0", + "@typescript-eslint/scope-manager": "8.0.1", + "@typescript-eslint/type-utils": "8.0.1", + "@typescript-eslint/utils": "8.0.1", + "@typescript-eslint/visitor-keys": "8.0.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -7221,16 +7221,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.0.0.tgz", - "integrity": "sha512-pS1hdZ+vnrpDIxuFXYQpLTILglTjSYJ9MbetZctrUawogUsPdz31DIIRZ9+rab0LhYNTsk88w4fIzVheiTbWOQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.0.1.tgz", + "integrity": "sha512-5IgYJ9EO/12pOUwiBKFkpU7rS3IU21mtXzB81TNwq2xEybcmAZrE9qwDtsb5uQd9aVO9o0fdabFyAmKveXyujg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "8.0.0", - "@typescript-eslint/types": "8.0.0", - "@typescript-eslint/typescript-estree": "8.0.0", - "@typescript-eslint/visitor-keys": "8.0.0", + "@typescript-eslint/scope-manager": "8.0.1", + "@typescript-eslint/types": "8.0.1", + "@typescript-eslint/typescript-estree": "8.0.1", + "@typescript-eslint/visitor-keys": "8.0.1", "debug": "^4.3.4" }, "engines": { @@ -7250,14 +7250,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.0.tgz", - "integrity": "sha512-V0aa9Csx/ZWWv2IPgTfY7T4agYwJyILESu/PVqFtTFz9RIS823mAze+NbnBI8xiwdX3iqeQbcTYlvB04G9wyQw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.1.tgz", + "integrity": "sha512-NpixInP5dm7uukMiRyiHjRKkom5RIFA4dfiHvalanD2cF0CLUuQqxfg8PtEUo9yqJI2bBhF+pcSafqnG3UBnRQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.0.0", - "@typescript-eslint/visitor-keys": "8.0.0" + "@typescript-eslint/types": "8.0.1", + "@typescript-eslint/visitor-keys": "8.0.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7268,14 +7268,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.0.0.tgz", - "integrity": "sha512-mJAFP2mZLTBwAn5WI4PMakpywfWFH5nQZezUQdSKV23Pqo6o9iShQg1hP2+0hJJXP2LnZkWPphdIq4juYYwCeg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.0.1.tgz", + "integrity": "sha512-+/UT25MWvXeDX9YaHv1IS6KI1fiuTto43WprE7pgSMswHbn1Jm9GEM4Txp+X74ifOWV8emu2AWcbLhpJAvD5Ng==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.0.0", - "@typescript-eslint/utils": "8.0.0", + "@typescript-eslint/typescript-estree": "8.0.1", + "@typescript-eslint/utils": "8.0.1", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -7293,9 +7293,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.0.tgz", - "integrity": "sha512-wgdSGs9BTMWQ7ooeHtu5quddKKs5Z5dS+fHLbrQI+ID0XWJLODGMHRfhwImiHoeO2S5Wir2yXuadJN6/l4JRxw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.1.tgz", + "integrity": "sha512-PpqTVT3yCA/bIgJ12czBuE3iBlM3g4inRSC5J0QOdQFAn07TYrYEQBBKgXH1lQpglup+Zy6c1fxuwTk4MTNKIw==", "dev": true, "license": "MIT", "engines": { @@ -7307,14 +7307,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0.tgz", - "integrity": "sha512-5b97WpKMX+Y43YKi4zVcCVLtK5F98dFls3Oxui8LbnmRsseKenbbDinmvxrWegKDMmlkIq/XHuyy0UGLtpCDKg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.1.tgz", + "integrity": "sha512-8V9hriRvZQXPWU3bbiUV4Epo7EvgM6RTs+sUmxp5G//dBGy402S7Fx0W0QkB2fb4obCF8SInoUzvTYtc3bkb5w==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.0.0", - "@typescript-eslint/visitor-keys": "8.0.0", + "@typescript-eslint/types": "8.0.1", + "@typescript-eslint/visitor-keys": "8.0.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -7352,16 +7352,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.0.0.tgz", - "integrity": "sha512-k/oS/A/3QeGLRvOWCg6/9rATJL5rec7/5s1YmdS0ZU6LHveJyGFwBvLhSRBv6i9xaj7etmosp+l+ViN1I9Aj/Q==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.0.1.tgz", + "integrity": "sha512-CBFR0G0sCt0+fzfnKaciu9IBsKvEKYwN9UZ+eeogK1fYHg4Qxk1yf/wLQkLXlq8wbU2dFlgAesxt8Gi76E8RTA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.0.0", - "@typescript-eslint/types": "8.0.0", - "@typescript-eslint/typescript-estree": "8.0.0" + "@typescript-eslint/scope-manager": "8.0.1", + "@typescript-eslint/types": "8.0.1", + "@typescript-eslint/typescript-estree": "8.0.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7375,13 +7375,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0.tgz", - "integrity": "sha512-oN0K4nkHuOyF3PVMyETbpP5zp6wfyOvm7tWhTMfoqxSSsPmJIh6JNASuZDlODE8eE+0EB9uar+6+vxr9DBTYOA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.1.tgz", + "integrity": "sha512-W5E+o0UfUcK5EgchLZsyVWqARmsM7v54/qEq6PY3YI5arkgmCzHiuk0zKSJJbm71V0xdRna4BGomkCTXz2/LkQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.0.0", + "@typescript-eslint/types": "8.0.1", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -8213,14 +8213,14 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", - "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.1", - "core-js-compat": "^3.36.1" + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -8723,9 +8723,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001647", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001647.tgz", - "integrity": "sha512-n83xdNiyeNcHpzWY+1aFbqCK7LuLfBricc4+alSQL2Xb6OR3XpnQAmlDG+pQcdTfiHRuLcQ96VOfrPSGiNJYSg==", + "version": "1.0.30001651", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", + "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==", "funding": [ { "type": "opencollective", @@ -9325,9 +9325,9 @@ } }, "node_modules/core-js": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.37.1.tgz", - "integrity": "sha512-Xn6qmxrQZyB0FFY8E3bgRXei3lWDJHhvI+u0q9TKIYM49G8pAr0FgnnrFRAmsbptZL1yxRADVXn+x5AGsbBfyw==", + "version": "3.38.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.38.0.tgz", + "integrity": "sha512-XPpwqEodRljce9KswjZShh95qJ1URisBeKCjUdq27YdenkslVe7OO0ZJhlYXAChW7OhXaRLl8AAba7IBfoIHug==", "hasInstallScript": true, "license": "MIT", "funding": { @@ -9336,13 +9336,13 @@ } }, "node_modules/core-js-compat": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", - "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", + "version": "3.38.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.0.tgz", + "integrity": "sha512-75LAicdLa4OJVwFxFbQR3NdnZjNgX6ILpVcVzcC4T2smerB5lELMrJQQQoWV6TiuC/vlaFqgU2tKQx9w5s0e0A==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.23.0" + "browserslist": "^4.23.3" }, "funding": { "type": "opencollective", @@ -10432,9 +10432,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz", - "integrity": "sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.5.tgz", + "integrity": "sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA==", "license": "ISC" }, "node_modules/emittery": { @@ -10913,19 +10913,19 @@ } }, "node_modules/eslint-plugin-jest": { - "version": "28.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.6.0.tgz", - "integrity": "sha512-YG28E1/MIKwnz+e2H7VwYPzHUYU4aMa19w0yGcwXnnmJH6EfgHahTJ2un3IyraUxNfnz/KUhJAFXNNwWPo12tg==", + "version": "28.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.8.0.tgz", + "integrity": "sha512-Tubj1hooFxCl52G4qQu0edzV/+EZzPUeN8p2NnW5uu4fbDs+Yo7+qDVDc4/oG3FbCqEBmu/OC3LSsyiU22oghw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/utils": "^6.0.0 || ^7.0.0" + "@typescript-eslint/utils": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "engines": { "node": "^16.10.0 || ^18.12.0 || >=20.0.0" }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^6.0.0 || ^7.0.0", + "@typescript-eslint/eslint-plugin": "^6.0.0 || ^7.0.0 || ^8.0.0", "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0", "jest": "*" }, @@ -11083,124 +11083,6 @@ "node": ">=4.0" } }, - "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/scope-manager": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", - "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/types": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", - "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/utils": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", - "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, - "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", - "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-jest/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/eslint-plugin-prettier": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", @@ -12004,9 +11886,9 @@ } }, "node_modules/foreground-child": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", - "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dev": true, "license": "ISC", "dependencies": { @@ -15638,9 +15520,9 @@ } }, "node_modules/launch-editor": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.0.tgz", - "integrity": "sha512-vJranOAJrI/llyWGRQqiDM+adrw+k83fvmmx3+nV47g3+36xM15jE+zyZ6Ffel02+xSvuM0b2GDRosXZkbb6wA==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.1.tgz", + "integrity": "sha512-elBx2l/tp9z99X5H/qev8uyDywVh0VXAwEbjk8kJhnc5grOFkGh7aW6q55me9xnYbss261XtnUrysZ+XvGbhQA==", "dev": true, "license": "MIT", "dependencies": { @@ -17533,15 +17415,15 @@ "license": "MIT" }, "node_modules/nx": { - "version": "19.5.6", - "resolved": "https://registry.npmjs.org/nx/-/nx-19.5.6.tgz", - "integrity": "sha512-qjP17aa5ViXSpo0bDgJ7O3b8EY/0+PbX7ZIKvG1g6qasohtfM1y4Sx2bbSow0zCKU0+r1LnR53Q0lyX4OOgtUg==", + "version": "19.5.7", + "resolved": "https://registry.npmjs.org/nx/-/nx-19.5.7.tgz", + "integrity": "sha512-AUmGgE19NB4m/7oHYQVdzZHtclVevD8w0/nNzzjDJE823T8oeoNhmc9MfCLz+/2l2KOp+Wqm+8LiG9/xWpXk0g==", "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { "@napi-rs/wasm-runtime": "0.2.4", - "@nrwl/tao": "19.5.6", + "@nrwl/tao": "19.5.7", "@yarnpkg/lockfile": "^1.1.0", "@yarnpkg/parsers": "3.0.0-rc.46", "@zkochan/js-yaml": "0.0.7", @@ -17581,16 +17463,16 @@ "nx-cloud": "bin/nx-cloud.js" }, "optionalDependencies": { - "@nx/nx-darwin-arm64": "19.5.6", - "@nx/nx-darwin-x64": "19.5.6", - "@nx/nx-freebsd-x64": "19.5.6", - "@nx/nx-linux-arm-gnueabihf": "19.5.6", - "@nx/nx-linux-arm64-gnu": "19.5.6", - "@nx/nx-linux-arm64-musl": "19.5.6", - "@nx/nx-linux-x64-gnu": "19.5.6", - "@nx/nx-linux-x64-musl": "19.5.6", - "@nx/nx-win32-arm64-msvc": "19.5.6", - "@nx/nx-win32-x64-msvc": "19.5.6" + "@nx/nx-darwin-arm64": "19.5.7", + "@nx/nx-darwin-x64": "19.5.7", + "@nx/nx-freebsd-x64": "19.5.7", + "@nx/nx-linux-arm-gnueabihf": "19.5.7", + "@nx/nx-linux-arm64-gnu": "19.5.7", + "@nx/nx-linux-arm64-musl": "19.5.7", + "@nx/nx-linux-x64-gnu": "19.5.7", + "@nx/nx-linux-x64-musl": "19.5.7", + "@nx/nx-win32-arm64-msvc": "19.5.7", + "@nx/nx-win32-x64-msvc": "19.5.7" }, "peerDependencies": { "@swc-node/register": "^1.8.0", @@ -18760,9 +18642,9 @@ "license": "MIT" }, "node_modules/posthog-js": { - "version": "1.154.2", - "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.154.2.tgz", - "integrity": "sha512-EM8xn5V86fTg/pUhCyyMCRotI07tXDLQryc5TDQinT9kCRz8799G1n+Bq7drOEYdD/xbvcKfcfTWmlMrTZCZ6A==", + "version": "1.154.5", + "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.154.5.tgz", + "integrity": "sha512-YYhWckDIRObfCrQpiLq+fdcDTIbQp8ebiKi0ueGohMRgugIG9LJVSpBgCeCHZm2C7sOxDUNcAr3T5VBDUSQoOg==", "license": "MIT", "dependencies": { "fflate": "^0.4.8", @@ -21536,9 +21418,9 @@ "license": "MIT" }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -21981,9 +21863,9 @@ "license": "MIT" }, "node_modules/web-vitals": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.2.tgz", - "integrity": "sha512-nYfoOqb4EmElljyXU2qdeE76KsvoHdftQKY4DzA9Aw8DervCg2bG634pHLrJ/d6+B4mE3nWTSJv8Mo7B2mbZkw==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.3.tgz", + "integrity": "sha512-/CFAm1mNxSmOj6i0Co+iGFJ58OS4NRGVP+AWS/l509uIK5a1bSoIVaHz/ZumpHTfHSZBpgrJ+wjfpAOrTHok5Q==", "license": "Apache-2.0" }, "node_modules/webcola": { @@ -22816,9 +22698,9 @@ } }, "node_modules/zone.js": { - "version": "0.14.8", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.14.8.tgz", - "integrity": "sha512-48uh7MnVp4/OQDuCHeFdXw5d8xwPqFTvlHgPJ1LBFb5GaustLSZV+YUH0to5ygNyGpqTsjpbpt141U/j3pCfqQ==", + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.14.10.tgz", + "integrity": "sha512-YGAhaO7J5ywOXW6InXNlLmfU194F8lVgu7bRntUF3TiG8Y3nBK0x1UJJuHUP/e8IyihkjCYqhCScpSwnlaSRkQ==", "license": "MIT" } } diff --git a/package.json b/package.json index ff4ff97fc68c..fc8c583b7688 100644 --- a/package.json +++ b/package.json @@ -13,18 +13,18 @@ "node_modules" ], "dependencies": { - "@angular/animations": "18.1.3", - "@angular/cdk": "18.1.3", - "@angular/common": "18.1.3", - "@angular/compiler": "18.1.3", - "@angular/core": "18.1.3", - "@angular/forms": "18.1.3", - "@angular/localize": "18.1.3", - "@angular/material": "18.1.3", - "@angular/platform-browser-dynamic": "18.1.3", - "@angular/platform-browser": "18.1.3", - "@angular/router": "18.1.3", - "@angular/service-worker": "18.1.3", + "@angular/animations": "18.1.4", + "@angular/cdk": "18.1.4", + "@angular/common": "18.1.4", + "@angular/compiler": "18.1.4", + "@angular/core": "18.1.4", + "@angular/forms": "18.1.4", + "@angular/localize": "18.1.4", + "@angular/material": "18.1.4", + "@angular/platform-browser-dynamic": "18.1.4", + "@angular/platform-browser": "18.1.4", + "@angular/router": "18.1.4", + "@angular/service-worker": "18.1.4", "@ctrl/ngx-emoji-mart": "9.2.0", "@danielmoncada/angular-datetime-picker": "18.0.0", "@fingerprintjs/fingerprintjs": "4.4.3", @@ -37,7 +37,7 @@ "@ng-bootstrap/ng-bootstrap": "17.0.0", "@ngx-translate/core": "15.0.0", "@ngx-translate/http-loader": "8.0.0", - "@sentry/angular": "8.22.0", + "@sentry/angular": "8.24.0", "@swimlane/ngx-charts": "20.5.0", "@swimlane/ngx-graph": "8.4.0", "@vscode/codicons": "0.0.36", @@ -45,7 +45,7 @@ "bootstrap": "5.3.3", "brace": "0.11.1", "compare-versions": "6.1.1", - "core-js": "3.37.1", + "core-js": "3.38.0", "crypto-js": "4.2.0", "dayjs": "1.11.12", "diff-match-patch-typescript": "1.0.8", @@ -64,7 +64,7 @@ "ngx-infinite-scroll": "18.0.0", "ngx-webstorage": "18.0.0", "papaparse": "5.4.1", - "posthog-js": "1.154.2", + "posthog-js": "1.154.5", "rxjs": "7.8.1", "showdown": "2.1.0", "showdown-highlight": "3.1.0", @@ -78,7 +78,7 @@ "uuid": "10.0.0", "webstomp-client": "1.2.6", "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz", - "zone.js": "0.14.8" + "zone.js": "0.14.10" }, "overrides": { "@swimlane/ngx-graph": { @@ -118,16 +118,16 @@ }, "devDependencies": { "@angular-builders/jest": "18.0.0", - "@angular-devkit/build-angular": "18.1.3", + "@angular-devkit/build-angular": "18.1.4", "@angular-eslint/builder": "18.2.0", "@angular-eslint/eslint-plugin": "18.2.0", "@angular-eslint/eslint-plugin-template": "18.2.0", "@angular-eslint/schematics": "18.2.0", "@angular-eslint/template-parser": "18.2.0", - "@angular/cli": "18.1.3", - "@angular/compiler-cli": "18.1.3", - "@angular/language-service": "18.1.3", - "@sentry/types": "8.22.0", + "@angular/cli": "18.1.4", + "@angular/compiler-cli": "18.1.4", + "@angular/language-service": "18.1.4", + "@sentry/types": "8.24.0", "@types/crypto-js": "4.2.2", "@types/d3-shape": "3.1.6", "@types/dompurify": "3.0.5", @@ -139,12 +139,12 @@ "@types/smoothscroll-polyfill": "0.3.4", "@types/sockjs-client": "1.5.4", "@types/uuid": "10.0.0", - "@typescript-eslint/eslint-plugin": "8.0.0", - "@typescript-eslint/parser": "8.0.0", + "@typescript-eslint/eslint-plugin": "8.0.1", + "@typescript-eslint/parser": "8.0.1", "eslint": "9.8.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-deprecation": "3.0.0", - "eslint-plugin-jest": "28.6.0", + "eslint-plugin-jest": "28.8.0", "eslint-plugin-jest-extended": "2.4.0", "eslint-plugin-prettier": "5.2.1", "folder-hash": "4.0.4", @@ -161,7 +161,7 @@ "prettier": "3.3.3", "sass": "1.77.8", "ts-jest": "29.2.4", - "typescript": "5.4.5", + "typescript": "5.5.4", "weak-napi": "2.0.2" }, "engines": { diff --git a/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts b/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts index a6505b2ad3b5..07e63dbea65d 100644 --- a/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts +++ b/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts @@ -38,10 +38,10 @@ export class PasswordResetInitComponent implements OnInit, AfterViewInit { this.externalCredentialProvider = profileInfo.externalCredentialProvider; const lang = this.translateService.currentLang; const linkMap = profileInfo.externalPasswordResetLinkMap; - if (linkMap[lang]) { - this.externalPasswordResetLink = linkMap[lang]; + if (linkMap.get(lang)) { + this.externalPasswordResetLink = linkMap.get(lang); } else { - this.externalPasswordResetLink = linkMap['en']; + this.externalPasswordResetLink = linkMap.get('en'); } } }); diff --git a/src/main/webapp/app/admin/metrics/blocks/metrics-modal-threads/metrics-modal-threads.component.ts b/src/main/webapp/app/admin/metrics/blocks/metrics-modal-threads/metrics-modal-threads.component.ts index ded26f95f9d0..a373c7af13c4 100644 --- a/src/main/webapp/app/admin/metrics/blocks/metrics-modal-threads/metrics-modal-threads.component.ts +++ b/src/main/webapp/app/admin/metrics/blocks/metrics-modal-threads/metrics-modal-threads.component.ts @@ -84,7 +84,7 @@ export class MetricsModalThreadsComponent implements OnInit { const filteredAttributes = ['threadName', 'threadId', 'blockedTime', 'blockedCount', 'waitedTime', 'waitedCount', 'lockName']; return Object.keys(thread) .filter((key) => filteredAttributes.includes(key)) - .some((key) => thread[key]?.toString().toLowerCase().includes(this.threadFilter!.toLowerCase())); + .some((key) => thread[key as keyof Thread]?.toString().toLowerCase().includes(this.threadFilter!.toLowerCase())); } private isMatchingSelectedThreadState(thread: Thread): boolean { diff --git a/src/main/webapp/app/admin/user-management/user-management.component.ts b/src/main/webapp/app/admin/user-management/user-management.component.ts index 70b3f51311a8..de20a76e0b74 100644 --- a/src/main/webapp/app/admin/user-management/user-management.component.ts +++ b/src/main/webapp/app/admin/user-management/user-management.component.ts @@ -218,7 +218,7 @@ export class UserManagementComponent implements OnInit, OnDestroy { const tempInStorage = temp ? temp .split(',') - .map((filter: string) => type[filter]) + .map((filter: keyof Filter) => type[filter]) .filter(Boolean) : new Set(); return new Set(tempInStorage); @@ -291,36 +291,29 @@ export class UserManagementComponent implements OnInit, OnDestroy { } } - /** - * Generic method to return all possible filter values per category. - */ - getFilter(type: Filter) { - return Object.keys(type).map((value) => type[value]); - } - /** * Get all filter options for authorities. */ get authorityFilters() { - return this.getFilter(AuthorityFilter); + return Object.values(AuthorityFilter); } /** * Get all filter options for origin. */ get originFilters() { - return this.getFilter(OriginFilter); + return Object.values(OriginFilter); } /** * Get all filter options for status. */ get statusFilters() { - return this.getFilter(StatusFilter); + return Object.values(StatusFilter); } get registrationNumberFilters() { - return this.getFilter(RegistrationNumberFilter); + return Object.values(RegistrationNumberFilter); } /** diff --git a/src/main/webapp/app/app.main.ts b/src/main/webapp/app/app.main.ts index 045ac365023c..1c2b479d3a8a 100644 --- a/src/main/webapp/app/app.main.ts +++ b/src/main/webapp/app/app.main.ts @@ -8,14 +8,6 @@ import { ArtemisAppModule } from './app.module'; import { MonacoConfig } from 'app/core/config/monaco.config'; ProdConfig(); - -if (module['hot']) { - module['hot'].accept(); - if ('production' !== process.env.NODE_ENV) { - console.clear(); - } -} - MonacoConfig(); platformBrowserDynamic() diff --git a/src/main/webapp/app/core/theme/theme-switch.component.ts b/src/main/webapp/app/core/theme/theme-switch.component.ts index 13207630cb20..06aa8bab270c 100644 --- a/src/main/webapp/app/core/theme/theme-switch.component.ts +++ b/src/main/webapp/app/core/theme/theme-switch.component.ts @@ -55,13 +55,8 @@ export class ThemeSwitchComponent implements OnInit { }); } - /** - * Open the popover if this is not a cypress test - */ openPopover() { - if (!window['Cypress']) { - this.popover?.open(); - } + this.popover?.open(); clearTimeout(this.closeTimeout); } diff --git a/src/main/webapp/app/course/competencies/import-competencies/import-course-competencies.component.ts b/src/main/webapp/app/course/competencies/import-competencies/import-course-competencies.component.ts index c88ded806dfd..d7187b4338b0 100644 --- a/src/main/webapp/app/course/competencies/import-competencies/import-course-competencies.component.ts +++ b/src/main/webapp/app/course/competencies/import-competencies/import-course-competencies.component.ts @@ -64,7 +64,7 @@ export abstract class ImportCourseCompetenciesComponent implements OnInit, Compo //Other constants protected readonly ButtonType = ButtonType; //used for sorting of the selected course competencies - protected readonly columnMapping = { + protected readonly columnMapping: { [key: string]: string } = { ID: 'id', TITLE: 'title', DESCRIPTION: 'description', diff --git a/src/main/webapp/app/course/course-access-storage.service.ts b/src/main/webapp/app/course/course-access-storage.service.ts index b0660d7f748b..dcbf08e519df 100644 --- a/src/main/webapp/app/course/course-access-storage.service.ts +++ b/src/main/webapp/app/course/course-access-storage.service.ts @@ -20,7 +20,7 @@ export class CourseAccessStorageService { if (Object.keys(courseAccessMap).length > maxAccessedCourses) { const oldestEntry = Object.entries(courseAccessMap).reduce((prev, curr) => (prev[1] < curr[1] ? prev : curr)); - delete courseAccessMap[oldestEntry[0]]; + delete courseAccessMap[Number(oldestEntry[0])]; } this.localStorage.store(storageKey, courseAccessMap); diff --git a/src/main/webapp/app/course/course-scores/course-scores.component.ts b/src/main/webapp/app/course/course-scores/course-scores.component.ts index 0c36a22a8a58..530e70f9ab0e 100644 --- a/src/main/webapp/app/course/course-scores/course-scores.component.ts +++ b/src/main/webapp/app/course/course-scores/course-scores.component.ts @@ -577,7 +577,7 @@ export class CourseScoresComponent implements OnInit, OnDestroy { } private createStudentPlagiarismMap(plagiarismCases?: PlagiarismCase[]): { [id: number]: boolean } { - const plagiarismMap = {}; + const plagiarismMap: { [id: number]: boolean } = {}; plagiarismCases?.forEach((plagiarismCase) => { if (plagiarismCase.verdict === PlagiarismVerdict.PLAGIARISM && plagiarismCase.student?.id) { plagiarismMap[plagiarismCase.student.id] = true; diff --git a/src/main/webapp/app/course/manage/course-management.component.html b/src/main/webapp/app/course/manage/course-management.component.html index 0725378ff331..608facb98435 100644 --- a/src/main/webapp/app/course/manage/course-management.component.html +++ b/src/main/webapp/app/course/manage/course-management.component.html @@ -53,9 +53,9 @@

} diff --git a/src/main/webapp/app/course/manage/course-management.component.ts b/src/main/webapp/app/course/manage/course-management.component.ts index 7d7b0d9b9604..e6706bd2b2ee 100644 --- a/src/main/webapp/app/course/manage/course-management.component.ts +++ b/src/main/webapp/app/course/manage/course-management.component.ts @@ -183,7 +183,7 @@ export class CourseManagementComponent implements OnInit, OnDestroy, AfterViewIn // We use this extra map of courses to improve performance by allowing us to use OnPush change detection result.body!.forEach((course) => { if (course.id) { - this.coursesWithExercises[course.id] = course; + this.coursesWithExercises.set(course.id, course); } }); }, @@ -199,7 +199,7 @@ export class CourseManagementComponent implements OnInit, OnDestroy, AfterViewIn next: (result: HttpResponse) => { result.body!.forEach((statisticsDTO) => { if (statisticsDTO.courseId) { - this.statistics[statisticsDTO.courseId] = statisticsDTO; + this.statistics.set(statisticsDTO.courseId, statisticsDTO); } }); }, @@ -216,7 +216,7 @@ export class CourseManagementComponent implements OnInit, OnDestroy, AfterViewIn // We use this extra map of courses to improve performance by allowing us to use OnPush change detection result.body!.forEach((course) => { if (course.id) { - this.coursesWithUsers[course.id] = course; + this.coursesWithUsers.set(course.id, course); } }); }, diff --git a/src/main/webapp/app/course/manage/detail/course-detail-line-chart.component.ts b/src/main/webapp/app/course/manage/detail/course-detail-line-chart.component.ts index 66d195b84fa6..60c30010f7de 100644 --- a/src/main/webapp/app/course/manage/detail/course-detail-line-chart.component.ts +++ b/src/main/webapp/app/course/manage/detail/course-detail-line-chart.component.ts @@ -53,14 +53,14 @@ export class CourseDetailLineChartComponent extends ActiveStudentsChart implemen data: any[]; // Data changes will be stored in the copy first, to trigger change detection when ready - dataCopy = [ + dataCopy: { name: string; series: { name?: string; value?: number }[] }[] = [ { name: '', series: [{}], }, ]; // Used for storing absolute values to display in tooltip - absoluteSeries = [{}]; + absoluteSeries: { absoluteValue?: number; name?: string }[] = [{}]; curve: any = shape.curveMonotoneX; average = { name: 'Mean', value: 0 }; startDateDisplayed = false; diff --git a/src/main/webapp/app/course/manage/overview/course-management-card.component.html b/src/main/webapp/app/course/manage/overview/course-management-card.component.html index 11e2a64556ec..3619d90a93d8 100644 --- a/src/main/webapp/app/course/manage/overview/course-management-card.component.html +++ b/src/main/webapp/app/course/manage/overview/course-management-card.component.html @@ -125,7 +125,7 @@

{{ course.title }} ({{ [course]="course" [rowType]="exerciseRowType.FUTURE" [details]="exercise" - [statistic]="statisticsPerExercise[exercise.id!]" + [statistic]="statisticsPerExercise.get(exercise.id!)" /> } @@ -148,7 +148,7 @@

{{ course.title }} ({{ [course]="course" [rowType]="exerciseRowType.CURRENT" [details]="exercise" - [statistic]="statisticsPerExercise[exercise.id!]" + [statistic]="statisticsPerExercise.get(exercise.id!)" /> } @@ -171,7 +171,7 @@

{{ course.title }} ({{ [course]="course" [rowType]="exerciseRowType.ASSESSING" [details]="exercise" - [statistic]="statisticsPerExercise[exercise.id!]" + [statistic]="statisticsPerExercise.get(exercise.id!)" /> } @@ -194,7 +194,7 @@

{{ course.title }} ({{ [course]="course" [rowType]="exerciseRowType.PAST" [details]="exercise" - [statistic]="statisticsPerExercise[exercise.id!]" + [statistic]="statisticsPerExercise.get(exercise.id!)" /> } diff --git a/src/main/webapp/app/course/manage/overview/course-management-card.component.ts b/src/main/webapp/app/course/manage/overview/course-management-card.component.ts index d8170704b191..32dca0a3fc2d 100644 --- a/src/main/webapp/app/course/manage/overview/course-management-card.component.ts +++ b/src/main/webapp/app/course/manage/overview/course-management-card.component.ts @@ -12,7 +12,6 @@ import { faAngleUp, faChartBar, faClipboard, - faComment, faComments, faFilePdf, faFlag, @@ -38,9 +37,9 @@ export class CourseManagementCardComponent implements OnChanges { CachingStrategy = CachingStrategy; // TODO: can we merge the 3 courses here? @Input() course: Course; - @Input() courseStatistics: CourseManagementOverviewStatisticsDto; - @Input() courseWithExercises: Course; - @Input() courseWithUsers: Course; + @Input() courseStatistics?: CourseManagementOverviewStatisticsDto; + @Input() courseWithExercises: Course | undefined; + @Input() courseWithUsers: Course | undefined; @Input() isGuidedTour: boolean; statisticsPerExercise = new Map(); @@ -71,7 +70,6 @@ export class CourseManagementCardComponent implements OnChanges { faListAlt = faListAlt; faChartBar = faChartBar; faFilePdf = faFilePdf; - faComment = faComment; faComments = faComments; faClipboard = faClipboard; faGraduationCap = faGraduationCap; @@ -96,7 +94,11 @@ export class CourseManagementCardComponent implements OnChanges { // Only sort one time once loaded if (!this.statisticsSorted && this.courseStatistics && this.courseStatistics.exerciseDTOS?.length > 0) { this.statisticsSorted = true; - this.courseStatistics.exerciseDTOS.forEach((dto) => (this.statisticsPerExercise[dto.exerciseId!] = dto)); + this.courseStatistics.exerciseDTOS.forEach((dto) => { + if (dto.exerciseId !== undefined) { + this.statisticsPerExercise.set(dto.exerciseId, dto); + } + }); } // Only sort one time once loaded diff --git a/src/main/webapp/app/course/manage/overview/course-management-exercise-row.component.ts b/src/main/webapp/app/course/manage/overview/course-management-exercise-row.component.ts index 97f010e30cf1..1a2b62285a3a 100644 --- a/src/main/webapp/app/course/manage/overview/course-management-exercise-row.component.ts +++ b/src/main/webapp/app/course/manage/overview/course-management-exercise-row.component.ts @@ -23,7 +23,7 @@ export enum ExerciseRowType { export class CourseManagementExerciseRowComponent implements OnChanges { @Input() course: Course; @Input() details: Exercise; - @Input() statistic: CourseManagementOverviewExerciseStatisticsDTO; + @Input() statistic?: CourseManagementOverviewExerciseStatisticsDTO; @Input() rowType: ExerciseRowType; // Expose enums to the template diff --git a/src/main/webapp/app/course/plagiarism-cases/instructor-view/plagiarism-cases-instructor-view.component.ts b/src/main/webapp/app/course/plagiarism-cases/instructor-view/plagiarism-cases-instructor-view.component.ts index 9b61adaaa325..1b218cb534f5 100644 --- a/src/main/webapp/app/course/plagiarism-cases/instructor-view/plagiarism-cases-instructor-view.component.ts +++ b/src/main/webapp/app/course/plagiarism-cases/instructor-view/plagiarism-cases-instructor-view.component.ts @@ -37,15 +37,20 @@ export class PlagiarismCasesInstructorViewComponent implements OnInit { plagiarismCasesForInstructor$.subscribe({ next: (res: HttpResponse) => { this.plagiarismCases = res.body!; - this.groupedPlagiarismCases = this.plagiarismCases.reduce((acc, plagiarismCase) => { + this.groupedPlagiarismCases = this.plagiarismCases.reduce((acc: { [exerciseId: number]: PlagiarismCase[] }, plagiarismCase) => { + const caseExerciseId = plagiarismCase.exercise?.id; + if (caseExerciseId === undefined) { + return acc; + } + // Group initialization - if (!acc[plagiarismCase.exercise!.id!]) { - acc[plagiarismCase.exercise!.id!] = []; + if (!acc[caseExerciseId]) { + acc[caseExerciseId] = []; this.exercisesWithPlagiarismCases.push(plagiarismCase.exercise!); } // Grouping - acc[plagiarismCase.exercise!.id!].push(plagiarismCase); + acc[caseExerciseId].push(plagiarismCase); return acc; }, {}); diff --git a/src/main/webapp/app/course/tutorial-groups/tutorial-groups-management/tutorial-groups/tutorial-groups-management/tutorial-groups-import-dialog/tutorial-groups-registration-import-dialog.component.ts b/src/main/webapp/app/course/tutorial-groups/tutorial-groups-management/tutorial-groups/tutorial-groups-management/tutorial-groups-import-dialog/tutorial-groups-registration-import-dialog.component.ts index fda702a1de7d..2f48df4e9970 100644 --- a/src/main/webapp/app/course/tutorial-groups/tutorial-groups-management/tutorial-groups/tutorial-groups-management/tutorial-groups-import-dialog/tutorial-groups-registration-import-dialog.component.ts +++ b/src/main/webapp/app/course/tutorial-groups/tutorial-groups-management/tutorial-groups/tutorial-groups-management/tutorial-groups-import-dialog/tutorial-groups-registration-import-dialog.component.ts @@ -22,7 +22,7 @@ import { CsvDownloadService } from 'app/shared/util/CsvDownloadService'; * "Column Header 2": "bar" * } */ -type ParsedCSVRow = object; +type ParsedCSVRow = { [header: string]: string }; // ToDo: Idea for future: Let the specify the column names / values in the dialog const POSSIBLE_TUTORIAL_GROUP_TITLE_HEADERS = ['gruppe', 'titel', 'group', 'title', 'tutorialgroups']; diff --git a/src/main/webapp/app/detail-overview-list/exercise-detail.directive.ts b/src/main/webapp/app/detail-overview-list/exercise-detail.directive.ts index d6b0afe5d738..069882e56eb4 100644 --- a/src/main/webapp/app/detail-overview-list/exercise-detail.directive.ts +++ b/src/main/webapp/app/detail-overview-list/exercise-detail.directive.ts @@ -1,4 +1,4 @@ -import { ComponentRef, Directive, Input, OnDestroy, OnInit, ViewContainerRef } from '@angular/core'; +import { ComponentRef, Directive, Input, OnDestroy, OnInit, Type, ViewContainerRef } from '@angular/core'; import type { Detail, ShownDetail } from 'app/detail-overview-list/detail.model'; import { DetailType } from 'app/detail-overview-list/detail-overview-list.component'; import { TextDetailComponent } from 'app/detail-overview-list/components/text-detail.component'; @@ -23,7 +23,7 @@ export class ExerciseDetailDirective implements OnInit, OnDestroy { } this.detail = this.detail as ShownDetail; - const detailTypeToComponent = { + const detailTypeToComponent: { [key in DetailType]?: Type } = { [DetailType.Text]: TextDetailComponent, [DetailType.Date]: DateDetailComponent, [DetailType.Link]: LinkDetailComponent, diff --git a/src/main/webapp/app/entities/feedback.model.ts b/src/main/webapp/app/entities/feedback.model.ts index b7540ec6fc13..7666973744e9 100644 --- a/src/main/webapp/app/entities/feedback.model.ts +++ b/src/main/webapp/app/entities/feedback.model.ts @@ -313,7 +313,7 @@ export const buildFeedbackTextForReview = (feedback: Feedback, addFeedbackText = * @param feedbacks the list of feedbacks */ export const checkSubsequentFeedbackInAssessment = (feedbacks: Feedback[]) => { - const gradingInstructions = {}; // { instructionId: number of encounters } + const gradingInstructions: { [key: number]: number } = {}; // { instructionId: number of encounters } for (const feedback of feedbacks) { if (feedback.gradingInstruction && feedback.gradingInstruction.credits !== 0) { if (gradingInstructions[feedback.gradingInstruction!.id!]) { diff --git a/src/main/webapp/app/entities/metis/conversation/channel.model.ts b/src/main/webapp/app/entities/metis/conversation/channel.model.ts index eaa19be630e0..450cfc266691 100644 --- a/src/main/webapp/app/entities/metis/conversation/channel.model.ts +++ b/src/main/webapp/app/entities/metis/conversation/channel.model.ts @@ -66,11 +66,11 @@ export class ChannelIdAndNameDTO { public name?: string; } -export function isChannelDTO(conversation: ConversationDTO): conversation is ChannelDTO { +export function isChannelDTO(conversation: ConversationDTO | Conversation): conversation is ChannelDTO { return conversation.type === ConversationType.CHANNEL; } -export function getAsChannelDTO(conversation: ConversationDTO | undefined): ChannelDTO | undefined { +export function getAsChannelDTO(conversation: ConversationDTO | Conversation | undefined): ChannelDTO | undefined { if (!conversation) { return undefined; } diff --git a/src/main/webapp/app/exam/manage/exercise-groups/exercise-groups.component.ts b/src/main/webapp/app/exam/manage/exercise-groups/exercise-groups.component.ts index 906c8ec190ea..b2c563ecbfd1 100644 --- a/src/main/webapp/app/exam/manage/exercise-groups/exercise-groups.component.ts +++ b/src/main/webapp/app/exam/manage/exercise-groups/exercise-groups.component.ts @@ -157,7 +157,7 @@ export class ExerciseGroupsComponent implements OnInit { }); this.dialogErrorSource.next(''); this.exerciseGroups = this.exerciseGroups!.filter((exerciseGroup) => exerciseGroup.id !== exerciseGroupId); - delete this.exerciseGroupToExerciseTypesDict[exerciseGroupId]; + this.exerciseGroupToExerciseTypesDict.delete(exerciseGroupId); }, error: (error: HttpErrorResponse) => this.dialogErrorSource.next(error.message), }); diff --git a/src/main/webapp/app/exercises/modeling/assess/modeling-assessment.util.ts b/src/main/webapp/app/exercises/modeling/assess/modeling-assessment.util.ts index dfcb90a81bce..a1566f9a3918 100644 --- a/src/main/webapp/app/exercises/modeling/assess/modeling-assessment.util.ts +++ b/src/main/webapp/app/exercises/modeling/assess/modeling-assessment.util.ts @@ -2,12 +2,14 @@ import { Result } from 'app/entities/result.model'; import { UMLElementType, UMLModelCompat, UMLRelationshipType, findElement, findRelationship } from '@ls1intum/apollon'; import { Feedback } from 'app/entities/feedback.model'; +export type AssessmentNamesForModelId = { [modelId: string]: { type: string; name: string } | undefined }; + /** * Creates the labels for the assessment elements for displaying them in the modeling and assessment editor. */ // TODO: define a mapping or simplify this complex monster in a another way so that we can support other diagram types as well -export function getNamesForAssessments(result: Result, model: UMLModelCompat): Map> { - const assessmentsNames = new Map>(); +export function getNamesForAssessments(result: Result, model: UMLModelCompat): AssessmentNamesForModelId { + const assessmentsNames: AssessmentNamesForModelId = {}; for (const feedback of result.feedbacks!) { const referencedModelType = feedback.referenceType! as UMLElementType; const referencedModelId = feedback.referenceId!; @@ -106,7 +108,7 @@ export function getNamesForAssessments(result: Result, model: UMLModelCompat): M } assessmentsNames[referencedModelId] = { type, name: source + relation + target }; } else { - assessmentsNames[referencedModelId] = { type: referencedModelType, name: '' }; + assessmentsNames[referencedModelId] = { type: `${referencedModelType}`, name: '' }; } } return assessmentsNames; diff --git a/src/main/webapp/app/exercises/modeling/participate/modeling-submission.component.html b/src/main/webapp/app/exercises/modeling/participate/modeling-submission.component.html index c89d47aeb5dc..9543ffd3c411 100644 --- a/src/main/webapp/app/exercises/modeling/participate/modeling-submission.component.html +++ b/src/main/webapp/app/exercises/modeling/participate/modeling-submission.component.html @@ -106,10 +106,10 @@

@if (feedback.reference) { - {{ assessmentsNames[feedback.referenceId!]['type'] }} + {{ assessmentsNames[feedback.referenceId!]?.type }} } @if (feedback.reference) { - {{ assessmentsNames[feedback.referenceId!]['name'] }} + {{ assessmentsNames[feedback.referenceId!]?.name }} } @if (feedback.reference) {
diff --git a/src/main/webapp/app/exercises/modeling/participate/modeling-submission.component.ts b/src/main/webapp/app/exercises/modeling/participate/modeling-submission.component.ts index 0d8a0de7c4f8..95cc45ed2483 100644 --- a/src/main/webapp/app/exercises/modeling/participate/modeling-submission.component.ts +++ b/src/main/webapp/app/exercises/modeling/participate/modeling-submission.component.ts @@ -30,7 +30,7 @@ import dayjs from 'dayjs/esm'; import { AlertService } from 'app/core/util/alert.service'; import { getCourseFromExercise } from 'app/entities/exercise.model'; import { Course } from 'app/entities/course.model'; -import { getNamesForAssessments } from '../assess/modeling-assessment.util'; +import { AssessmentNamesForModelId, getNamesForAssessments } from '../assess/modeling-assessment.util'; import { faExclamationTriangle, faGripLines } from '@fortawesome/free-solid-svg-icons'; import { faListAlt } from '@fortawesome/free-regular-svg-icons'; import { onError } from 'app/shared/util/global.utils'; @@ -76,7 +76,7 @@ export class ModelingSubmissionComponent implements OnInit, OnDestroy, Component submission: ModelingSubmission; assessmentResult?: Result; - assessmentsNames: Map>; + assessmentsNames: AssessmentNamesForModelId = {}; totalScore: number; umlModel: UMLModel; // input model for Apollon diff --git a/src/main/webapp/app/exercises/programming/manage/grading/charts/sca-category-distribution-chart.component.ts b/src/main/webapp/app/exercises/programming/manage/grading/charts/sca-category-distribution-chart.component.ts index c01a9cbffcc7..6385cf5773e7 100644 --- a/src/main/webapp/app/exercises/programming/manage/grading/charts/sca-category-distribution-chart.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/grading/charts/sca-category-distribution-chart.component.ts @@ -104,7 +104,7 @@ export class ScaCategoryDistributionChartComponent extends ProgrammingGradingCha @Input() categoryIssuesMap?: CategoryIssuesMap; @Input() exercise: ProgrammingExercise; - @Output() categoryColorsChange = new EventEmitter(); + @Output() categoryColorsChange = new EventEmitter<{ [key: string]: string }>(); @Output() scaCategoryFilter = new EventEmitter(); readonly scaChartBarTitle = ScaChartBarTitle; @@ -126,7 +126,7 @@ export class ScaCategoryDistributionChartComponent extends ProgrammingGradingCha this.ngxData = []; this.ngxColors.domain = []; // update colors for category table - const categoryColors = {}; + const categoryColors: { [key: string]: string } = {}; const categoryPenalties = this.categories .map((category) => ({ ...category, diff --git a/src/main/webapp/app/exercises/programming/manage/grading/charts/test-case-distribution-chart.component.ts b/src/main/webapp/app/exercises/programming/manage/grading/charts/test-case-distribution-chart.component.ts index 8f6b52cee249..5aceb9c57804 100644 --- a/src/main/webapp/app/exercises/programming/manage/grading/charts/test-case-distribution-chart.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/grading/charts/test-case-distribution-chart.component.ts @@ -16,6 +16,10 @@ enum TestCaseBarTitle { WEIGHT_AND_BONUS_DE = 'Gewichtung & Bonus', } +type TestCaseColors = { + [label: string]: string; +}; + @Component({ selector: 'jhi-test-case-distribution-chart', styleUrls: ['./sca-category-distribution-chart.scss'], @@ -94,7 +98,7 @@ export class TestCaseDistributionChartComponent extends ProgrammingGradingCharts }); if (this.ngxWeightData[0].series.length !== testCaseScores.length) { - const testCaseColors = {}; + const testCaseColors: TestCaseColors = {}; this.ngxWeightData = []; this.ngxPointsData = []; diff --git a/src/main/webapp/app/exercises/programming/manage/grading/programming-exercise-configure-grading.component.ts b/src/main/webapp/app/exercises/programming/manage/grading/programming-exercise-configure-grading.component.ts index 1de2cd807c2a..c242b861d14e 100644 --- a/src/main/webapp/app/exercises/programming/manage/grading/programming-exercise-configure-grading.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/grading/programming-exercise-configure-grading.component.ts @@ -48,7 +48,7 @@ enum TestCaseView { SAVE_VALUES, } -const DefaultFieldValues = { +const DefaultFieldValues: { [key: string]: number } = { [EditableField.WEIGHT]: 1, [EditableField.BONUS_MULTIPLIER]: 1, [EditableField.BONUS_POINTS]: 0, @@ -117,7 +117,7 @@ export class ProgrammingExerciseConfigureGradingComponent implements OnInit, OnD categoryStateList = Object.entries(StaticCodeAnalysisCategoryState).map(([name, value]) => ({ value, name })); testCaseColors = {}; - categoryColors = {}; + categoryColors: { [key: string]: string } = {}; totalWeight = 0; submissionPolicy?: SubmissionPolicy; @@ -304,9 +304,9 @@ export class ProgrammingExerciseConfigureGradingComponent implements OnInit, OnD */ updateEditedField(editedTestCase: ProgrammingExerciseTestCase, field: EditableField) { return (newValue: any) => { - newValue = this.checkFieldValue(newValue, editedTestCase[field], field); + newValue = this.checkFieldValue(newValue, editedTestCase[field as keyof ProgrammingExerciseTestCase], field); // Only mark the testcase as changed, if the field has changed. - if (newValue !== editedTestCase[field]) { + if (newValue !== editedTestCase[field as keyof ProgrammingExerciseTestCase]) { this.changedTestCaseIds = this.changedTestCaseIds.includes(editedTestCase.id!) ? this.changedTestCaseIds : [...this.changedTestCaseIds, editedTestCase.id!]; this.updateAllTestCaseViewsAfterEditing(editedTestCase, field, newValue); this.updateTestPoints(editedTestCase, field, newValue); @@ -324,9 +324,9 @@ export class ProgrammingExerciseConfigureGradingComponent implements OnInit, OnD */ updateEditedCategoryField(editedCategory: StaticCodeAnalysisCategory, field: EditableField) { return (newValue: any) => { - newValue = this.checkFieldValue(newValue, editedCategory[field], field); + newValue = this.checkFieldValue(newValue, editedCategory[field as keyof StaticCodeAnalysisCategory], field); // Only mark the category as changed, if the field has changed. - if (newValue !== editedCategory[field]) { + if (newValue !== editedCategory[field as keyof StaticCodeAnalysisCategory]) { this.changedCategoryIds = this.changedCategoryIds.includes(editedCategory.id) ? this.changedCategoryIds : [...this.changedCategoryIds, editedCategory.id]; this.updateStaticCodeAnalysisCategories(editedCategory, field, newValue); } diff --git a/src/main/webapp/app/exercises/programming/manage/grading/tasks/programming-exercise-grading-tasks-table.component.ts b/src/main/webapp/app/exercises/programming/manage/grading/tasks/programming-exercise-grading-tasks-table.component.ts index 8b4941a0e9fa..a40d38cade8e 100644 --- a/src/main/webapp/app/exercises/programming/manage/grading/tasks/programming-exercise-grading-tasks-table.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/grading/tasks/programming-exercise-grading-tasks-table.component.ts @@ -8,6 +8,7 @@ import { ProgrammingExerciseTask } from './programming-exercise-task'; import { Observable, Subject } from 'rxjs'; import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; import { isExamExercise } from 'app/shared/util/utils'; +import { ProgrammingExerciseServerSideTask } from 'app/entities/hestia/programming-exercise-task.model'; type Sort = { by: 'name' | 'weight' | 'multiplier' | 'bonusPoints' | 'visibility' | 'resulting' | 'type'; @@ -137,14 +138,20 @@ export class ProgrammingExerciseGradingTasksTableComponent implements OnInit { this.tasks.filter(({ testCases }) => testCases).forEach((task) => task.testCases.sort(comparator)); }; - private compareNumForAttribute = (attributeKey: string): TaskComparator => { - return (a, b) => { + private compareNumForAttribute = (attributeKey: keyof T): TaskComparator => { + return (a: T, b: T) => { return ((a[attributeKey] as number) ?? 0) - ((b[attributeKey] as number) ?? 0); }; }; - private compareStringForAttribute = (attributeKey: string): TaskComparator => { - return (a, b) => { + /** + * {@link ProgrammingExerciseTask} extends {@link ProgrammingExerciseServerSideTask} which is why we need to explicitly add it here for the type + * @param attributeKey + */ + private compareStringForAttribute = ( + attributeKey: keyof T, + ): TaskComparator => { + return (a: T, b: T) => { const aType = a[attributeKey] ?? ''; const bType = b[attributeKey] ?? ''; diff --git a/src/main/webapp/app/exercises/programming/manage/services/programming-exercise-participation.service.ts b/src/main/webapp/app/exercises/programming/manage/services/programming-exercise-participation.service.ts index dad187c13a01..7af098d1a5a7 100644 --- a/src/main/webapp/app/exercises/programming/manage/services/programming-exercise-participation.service.ts +++ b/src/main/webapp/app/exercises/programming/manage/services/programming-exercise-participation.service.ts @@ -121,7 +121,7 @@ export class ProgrammingExerciseParticipationService implements IProgrammingExer commitId: string, repositoryType?: string, ): Observable | undefined> { - const params = {}; + const params: { [key: string]: number | string } = {}; if (repositoryType) { params['repositoryType'] = repositoryType; } diff --git a/src/main/webapp/app/exercises/programming/manage/services/programming-exercise.service.ts b/src/main/webapp/app/exercises/programming/manage/services/programming-exercise.service.ts index e5710a37db11..39fa4800ecb6 100644 --- a/src/main/webapp/app/exercises/programming/manage/services/programming-exercise.service.ts +++ b/src/main/webapp/app/exercises/programming/manage/services/programming-exercise.service.ts @@ -586,12 +586,12 @@ export class ProgrammingExerciseService { newerCommitHash: string, repositoryType?: string, ): Observable { - const params = {}; + const params: { repositoryType?: string; participationId?: number } = {}; if (repositoryType !== undefined) { - params['repositoryType'] = repositoryType; + params.repositoryType = repositoryType; } if (participationId !== undefined && !isNaN(participationId)) { - params['participationId'] = participationId; + params.participationId = participationId; } return this.http diff --git a/src/main/webapp/app/exercises/programming/shared/service/aeolus.service.ts b/src/main/webapp/app/exercises/programming/shared/service/aeolus.service.ts index d1bee8770a5f..5871d4ca94f1 100644 --- a/src/main/webapp/app/exercises/programming/shared/service/aeolus.service.ts +++ b/src/main/webapp/app/exercises/programming/shared/service/aeolus.service.ts @@ -70,8 +70,10 @@ export class AeolusService { actions.push(action); } }); - // somehow, the returned content has a scriptActions field, which is not defined in the WindFile class - delete windFile['scriptActions']; + // somehow, the returned content may have a scriptActions field, which is not a field of the WindFile class + if ('scriptActions' in windFile) { + delete windFile['scriptActions']; + } windFile.actions = actions; return windFile; } catch (SyntaxError) { diff --git a/src/main/webapp/app/exercises/quiz/manage/short-answer-question/short-answer-question-edit.component.ts b/src/main/webapp/app/exercises/quiz/manage/short-answer-question/short-answer-question-edit.component.ts index 6622a489c7be..6e99de7c0fb8 100644 --- a/src/main/webapp/app/exercises/quiz/manage/short-answer-question/short-answer-question-edit.component.ts +++ b/src/main/webapp/app/exercises/quiz/manage/short-answer-question/short-answer-question-edit.component.ts @@ -430,6 +430,9 @@ export class ShortAnswerQuestionEditComponent implements OnInit, OnChanges, Afte // ID 'element-row-column' is divided into array of [row, column] const selectedTextRowColumn = selection.focusNode!.parentNode!.parentElement!.id.split('-').slice(1); + const row = Number(selectedTextRowColumn[0]); + const column = Number(selectedTextRowColumn[1]); + if (selectedTextRowColumn.length === 0) { return; } @@ -449,8 +452,8 @@ export class ShortAnswerQuestionEditComponent implements OnInit, OnChanges, Afte const startOfRange = markdownForHtml(htmlContent).length - selection.toString().length; const endOfRange = startOfRange + selection.toString().length; - const markedTextHTML = this.textParts[selectedTextRowColumn[0]][selectedTextRowColumn[1]]; - const markedText = markdownForHtml(markedTextHTML).substring(startOfRange, endOfRange); + const markedTextHTML = this.textParts[row][column]; + const markedText = markdownForHtml(markedTextHTML!).substring(startOfRange, endOfRange); const currentSpotNumber = this.numberOfSpot; @@ -460,9 +463,8 @@ export class ShortAnswerQuestionEditComponent implements OnInit, OnChanges, Afte .split(/\[-option /g)[0] .trim(); this.textParts = this.shortAnswerQuestionUtil.divideQuestionTextIntoTextParts(questionText); - const textOfSelectedRow = this.textParts[selectedTextRowColumn[0]][selectedTextRowColumn[1]]; - this.textParts[selectedTextRowColumn[0]][selectedTextRowColumn[1]] = - textOfSelectedRow.substring(0, startOfRange) + '[-spot ' + currentSpotNumber + ']' + textOfSelectedRow.substring(endOfRange); + const textOfSelectedRow = this.textParts[row][column]; + this.textParts[row][column] = textOfSelectedRow?.substring(0, startOfRange) + '[-spot ' + currentSpotNumber + ']' + textOfSelectedRow?.substring(endOfRange); // recreation of question text from array and update textParts and parse textParts to html this.shortAnswerQuestion.text = this.textParts.map((textPart) => textPart.join(' ')).join('\n'); @@ -743,7 +745,7 @@ export class ShortAnswerQuestionEditComponent implements OnInit, OnChanges, Afte */ setQuestionText(textPartId: string): void { const rowColumn: string[] = textPartId.split('-').slice(1); - this.textParts[rowColumn[0]][rowColumn[1]] = (document.getElementById(textPartId)).value; + this.textParts[Number(rowColumn[0])][Number(rowColumn[1])] = (document.getElementById(textPartId)).value; this.shortAnswerQuestion.text = this.textParts.map((textPart) => textPart.join(' ')).join('\n'); this.textParts = this.parseQuestionTextIntoTextBlocks(this.shortAnswerQuestion.text); } diff --git a/src/main/webapp/app/exercises/quiz/manage/statistics/short-answer-question-statistic/short-answer-question-statistic.component.ts b/src/main/webapp/app/exercises/quiz/manage/statistics/short-answer-question-statistic/short-answer-question-statistic.component.ts index 8ed02dcd0634..1f60773b9d81 100644 --- a/src/main/webapp/app/exercises/quiz/manage/statistics/short-answer-question-statistic/short-answer-question-statistic.component.ts +++ b/src/main/webapp/app/exercises/quiz/manage/statistics/short-answer-question-statistic/short-answer-question-statistic.component.ts @@ -83,7 +83,7 @@ export class ShortAnswerQuestionStatisticComponent extends QuestionStatisticComp generateLettersForSolutions() { for (const mapping of this.question.correctMappings || []) { for (const i in this.question.spots) { - if (mapping.spot!.id === this.question.spots[i].id) { + if (mapping.spot?.id === this.question.spots[+i].id) { this.lettersForSolutions.push(+i); break; } diff --git a/src/main/webapp/app/exercises/quiz/participate/quiz-participation.component.ts b/src/main/webapp/app/exercises/quiz/participate/quiz-participation.component.ts index be055ed181f6..be9c13bf4a40 100644 --- a/src/main/webapp/app/exercises/quiz/participate/quiz-participation.component.ts +++ b/src/main/webapp/app/exercises/quiz/participate/quiz-participation.component.ts @@ -94,7 +94,7 @@ export class QuizParticipationComponent implements OnInit, OnDestroy { dragAndDropMappings = new Map(); shortAnswerSubmittedTexts = new Map(); result: Result; - questionScores = {}; + questionScores: { [id: number]: number } = {}; quizId: number; courseId: number; interval?: number; diff --git a/src/main/webapp/app/exercises/quiz/shared/fit-text/fit-text.directive.ts b/src/main/webapp/app/exercises/quiz/shared/fit-text/fit-text.directive.ts index 94aa8e9a1135..eb0c9fc9ba89 100644 --- a/src/main/webapp/app/exercises/quiz/shared/fit-text/fit-text.directive.ts +++ b/src/main/webapp/app/exercises/quiz/shared/fit-text/fit-text.directive.ts @@ -33,8 +33,8 @@ export class FitTextDirective implements AfterViewInit, OnInit, OnChanges { this.fitTextParent = this.fitTextElement.parentElement!; this.computed = window.getComputedStyle(this.fitTextElement); this.newlines = this.fitTextElement.childElementCount > 0 ? this.fitTextElement.childElementCount : 1; - this.lineHeight = this.computed['line-height']; - this.display = this.computed['display']; + this.lineHeight = this.computed.lineHeight; + this.display = this.computed.display; } @HostListener('window:resize') @@ -45,8 +45,8 @@ export class FitTextDirective implements AfterViewInit, OnInit, OnChanges { }; public ngOnInit() { - this.fitTextMinFontSize = this.minFontSize === 'inherit' ? this.computed['font-size'] : this.minFontSize; - this.fitTextMaxFontSize = this.maxFontSize === 'inherit' ? this.computed['font-size'] : this.maxFontSize; + this.fitTextMinFontSize = this.minFontSize === 'inherit' ? Number(this.computed.fontSize) : this.minFontSize!; + this.fitTextMaxFontSize = this.maxFontSize === 'inherit' ? Number(this.computed.fontSize) : this.maxFontSize!; } public ngAfterViewInit() { diff --git a/src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.ts b/src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.ts index 9d290af1a8e4..773a297e53e5 100644 --- a/src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.ts +++ b/src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/split-pane-header/split-pane-header.component.ts @@ -27,12 +27,12 @@ export class SplitPaneHeaderComponent implements OnChanges { ngOnChanges(changes: SimpleChanges) { if (changes.files) { - const files: FileWithHasMatch = changes.files.currentValue; + const fileWithHasMatch: FileWithHasMatch[] = changes.files.currentValue; this.activeFileIndex = 0; if (this.hasFiles()) { - this.selectFile.emit(files[0].file); + this.selectFile.emit(fileWithHasMatch[0].file); } } } diff --git a/src/main/webapp/app/exercises/shared/result/result.service.ts b/src/main/webapp/app/exercises/shared/result/result.service.ts index fbf55093ee9c..72390f6979c8 100644 --- a/src/main/webapp/app/exercises/shared/result/result.service.ts +++ b/src/main/webapp/app/exercises/shared/result/result.service.ts @@ -238,8 +238,8 @@ export class ResultService implements IResultService { this.convertResultDatesFromServer(resultWithPoints.result); const pointsMap = new Map(); if (resultWithPoints.pointsPerCriterion) { - Object.keys(resultWithPoints.pointsPerCriterion).forEach((key) => { - pointsMap.set(Number(key), resultWithPoints.pointsPerCriterion[key]); + resultWithPoints.pointsPerCriterion.forEach((value, key) => { + pointsMap.set(Number(key), value); }); } resultWithPoints.pointsPerCriterion = pointsMap; diff --git a/src/main/webapp/app/exercises/shared/team/teams-import-dialog/teams-import-from-file-form.component.ts b/src/main/webapp/app/exercises/shared/team/teams-import-dialog/teams-import-from-file-form.component.ts index ffc9b2b834df..479e7ed9e882 100644 --- a/src/main/webapp/app/exercises/shared/team/teams-import-dialog/teams-import-from-file-form.component.ts +++ b/src/main/webapp/app/exercises/shared/team/teams-import-dialog/teams-import-from-file-form.component.ts @@ -27,7 +27,7 @@ const csvColumns = Object.freeze({ gruppe: 'gruppe', }); -type CsvEntry = object; +type CsvEntry = { [column: string]: string }; @Component({ selector: 'jhi-teams-import-from-file-form', diff --git a/src/main/webapp/app/grading-system/base-grading-system/base-grading-system.component.ts b/src/main/webapp/app/grading-system/base-grading-system/base-grading-system.component.ts index 628ea0ede572..a53bc9c26f75 100644 --- a/src/main/webapp/app/grading-system/base-grading-system/base-grading-system.component.ts +++ b/src/main/webapp/app/grading-system/base-grading-system/base-grading-system.component.ts @@ -738,7 +738,7 @@ export abstract class BaseGradingSystemComponent implements OnInit { } // parse and set the grade type - const gradeType = csvGradeSteps[0]['bonusPoints'] === undefined ? GradeType.GRADE : GradeType.BONUS; + const gradeType = csvGradeSteps[0]['bonusPoints' as keyof CsvGradeStep] === undefined ? GradeType.GRADE : GradeType.BONUS; if (gradeType === GradeType.BONUS) { this.gradingScale.gradeType = GradeType.BONUS; } else { @@ -756,12 +756,19 @@ export abstract class BaseGradingSystemComponent implements OnInit { */ mapCsvGradeStepsToGradeSteps(csvGradeSteps: CsvGradeStep[], gradeType: GradeType): GradeStep[] { return csvGradeSteps.map( - (csvGradeStep) => + (csvGradeStep: CsvGradeStep) => ({ - gradeName: gradeType === GradeType.GRADE ? String(csvGradeStep[csvColumnsGrade.gradeName] ?? '') : String(csvGradeStep[csvColumnsBonus.bonusPoints] ?? ''), - lowerBoundPercentage: csvGradeStep[csvColumnsGrade.lowerBoundPercentage] ? Number(csvGradeStep[csvColumnsGrade.lowerBoundPercentage]) : undefined, - upperBoundPercentage: csvGradeStep[csvColumnsGrade.upperBoundPercentage] ? Number(csvGradeStep[csvColumnsGrade.upperBoundPercentage]) : undefined, - ...(gradeType === GradeType.GRADE && { isPassingGrade: csvGradeStep[csvColumnsGrade.isPassingGrade] === 'TRUE' }), + gradeName: + gradeType === GradeType.GRADE + ? String(csvGradeStep[csvColumnsGrade.gradeName as keyof CsvGradeStep] ?? '') + : String(csvGradeStep[csvColumnsBonus.bonusPoints as keyof CsvGradeStep] ?? ''), + lowerBoundPercentage: csvGradeStep[csvColumnsGrade.lowerBoundPercentage as keyof CsvGradeStep] + ? Number(csvGradeStep[csvColumnsGrade.lowerBoundPercentage as keyof CsvGradeStep]) + : undefined, + upperBoundPercentage: csvGradeStep[csvColumnsGrade.upperBoundPercentage as keyof CsvGradeStep] + ? Number(csvGradeStep[csvColumnsGrade.upperBoundPercentage as keyof CsvGradeStep]) + : undefined, + ...(gradeType === GradeType.GRADE && { isPassingGrade: csvGradeStep[csvColumnsGrade.isPassingGrade as keyof CsvGradeStep] === 'TRUE' }), }) as GradeStep, ); } diff --git a/src/main/webapp/app/iris/about-iris/about-iris.component.ts b/src/main/webapp/app/iris/about-iris/about-iris.component.ts index c4148368398b..e2dc8d39ac15 100644 --- a/src/main/webapp/app/iris/about-iris/about-iris.component.ts +++ b/src/main/webapp/app/iris/about-iris/about-iris.component.ts @@ -10,7 +10,7 @@ import { IrisLogoSize } from '../iris-logo/iris-logo.component'; export class AboutIrisComponent { faRobot = faRobot; // How many bullet points each heading has - bulletPoints = { '1': 2, '2': 5, '3': 3, '4': 5 }; + bulletPoints: { [key: string]: number } = { '1': 2, '2': 5, '3': 3, '4': 5 }; objectKeys = Object.keys; array = Array; diff --git a/src/main/webapp/app/lecture/lecture-unit/lecture-unit-management/lecture-unit-management.component.ts b/src/main/webapp/app/lecture/lecture-unit/lecture-unit-management/lecture-unit-management.component.ts index 6b2d25e8a991..66ddcf166ced 100644 --- a/src/main/webapp/app/lecture/lecture-unit/lecture-unit-management/lecture-unit-management.component.ts +++ b/src/main/webapp/app/lecture/lecture-unit/lecture-unit-management/lecture-unit-management.component.ts @@ -41,7 +41,7 @@ export class LectureUnitManagementComponent implements OnInit, OnDestroy { private dialogErrorSource = new Subject(); dialogError$ = this.dialogErrorSource.asObservable(); - routerEditLinksBase = { + routerEditLinksBase: { [key: string]: string } = { [LectureUnitType.ATTACHMENT]: 'attachment-units', [LectureUnitType.VIDEO]: 'video-units', [LectureUnitType.TEXT]: 'text-units', diff --git a/src/main/webapp/app/localci/build-queue/build-queue.component.ts b/src/main/webapp/app/localci/build-queue/build-queue.component.ts index 8219094560d1..2ab4ae9bc7f8 100644 --- a/src/main/webapp/app/localci/build-queue/build-queue.component.ts +++ b/src/main/webapp/app/localci/build-queue/build-queue.component.ts @@ -4,22 +4,20 @@ import { BuildJob, BuildJobStatistics, FinishedBuildJob, SpanType } from 'app/en import { faAngleDown, faAngleRight, faCircleCheck, faExclamationCircle, faExclamationTriangle, faFilter, faSort, faSync, faTimes } from '@fortawesome/free-solid-svg-icons'; import { JhiWebsocketService } from 'app/core/websocket/websocket.service'; import { BuildQueueService } from 'app/localci/build-queue/build-queue.service'; -import { take } from 'rxjs/operators'; +import { debounceTime, distinctUntilChanged, map, switchMap, take, tap } from 'rxjs/operators'; import { TriggeredByPushTo } from 'app/entities/repository-info.model'; import { ITEMS_PER_PAGE } from 'app/shared/constants/pagination.constants'; import { SortingOrder } from 'app/shared/table/pageable-table'; import { onError } from 'app/shared/util/global.utils'; -import { HttpErrorResponse, HttpHeaders, HttpResponse } from '@angular/common/http'; +import { HttpErrorResponse, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http'; import { AlertService } from 'app/core/util/alert.service'; import dayjs from 'dayjs/esm'; import { GraphColors } from 'app/entities/statistics.model'; import { Color, ScaleType } from '@swimlane/ngx-charts'; import { NgxChartsSingleSeriesDataEntry } from 'app/shared/chart/ngx-charts-datatypes'; import { NgbModal, NgbTypeahead } from '@ng-bootstrap/ng-bootstrap'; -import { HttpParams } from '@angular/common/http'; import { LocalStorageService } from 'ngx-webstorage'; import { Observable, OperatorFunction, Subject, Subscription, merge } from 'rxjs'; -import { debounceTime, distinctUntilChanged, map, switchMap, tap } from 'rxjs/operators'; import { UI_RELOAD_TIME } from 'app/shared/constants/exercise-exam-constants'; export class FinishedBuildJobFilter { @@ -491,8 +489,10 @@ export class BuildQueueComponent implements OnInit, OnDestroy { */ loadFilterFromLocalStorage() { this.finishedBuildJobFilter.numberOfAppliedFilters = 0; + // Iterate over all keys of the filter and load the values from the local storage if they exist. - for (const key in FinishedBuildJobFilterStorageKey) { + const keys = Object.keys(FinishedBuildJobFilterStorageKey) as Array; + for (const key of keys) { const value = this.localStorage.retrieve(FinishedBuildJobFilterStorageKey[key]); if (value) { this.finishedBuildJobFilter[key] = key.includes('Date') ? dayjs(value) : value; diff --git a/src/main/webapp/app/lti/lti13-deep-linking.component.ts b/src/main/webapp/app/lti/lti13-deep-linking.component.ts index 1c8e7e0d7b85..55be442a98f5 100644 --- a/src/main/webapp/app/lti/lti13-deep-linking.component.ts +++ b/src/main/webapp/app/lti/lti13-deep-linking.component.ts @@ -137,11 +137,14 @@ export class Lti13DeepLinkingComponent implements OnInit { const httpParams = new HttpParams().set('exerciseIds', exerciseIds).set('ltiIdToken', ltiIdToken!).set('clientRegistrationId', clientRegistrationId!); - this.http.post(`api/lti13/deep-linking/${this.courseId}`, null, { observe: 'response', params: httpParams }).subscribe({ + type DeepLinkingResponse = { + targetLinkUri: string; + }; + this.http.post(`api/lti13/deep-linking/${this.courseId}`, null, { observe: 'response', params: httpParams }).subscribe({ next: (response) => { if (response.status === 200) { if (response.body) { - const targetLink = response.body['targetLinkUri']; + const targetLink = response.body.targetLinkUri; window.location.replace(targetLink); } } else { diff --git a/src/main/webapp/app/lti/lti13-exercise-launch.component.ts b/src/main/webapp/app/lti/lti13-exercise-launch.component.ts index 61cea51cf6ee..6c9af31bc0c4 100644 --- a/src/main/webapp/app/lti/lti13-exercise-launch.component.ts +++ b/src/main/webapp/app/lti/lti13-exercise-launch.component.ts @@ -5,6 +5,12 @@ import { AccountService } from 'app/core/auth/account.service'; import { captureException } from '@sentry/angular'; import { SessionStorageService } from 'ngx-webstorage'; +type LtiLaunchResponse = { + targetLinkUri: string; + ltiIdToken: string; + clientRegistrationId: string; +}; + @Component({ selector: 'jhi-lti-exercise-launch', templateUrl: './lti13-exercise-launch.component.html', @@ -42,7 +48,7 @@ export class Lti13ExerciseLaunchComponent implements OnInit { const requestBody = new HttpParams().set('state', state).set('id_token', idToken); this.http - .post('api/public/lti13/auth-login', requestBody.toString(), { + .post('api/public/lti13/auth-login', requestBody.toString(), { headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded'), }) .subscribe({ @@ -95,10 +101,10 @@ export class Lti13ExerciseLaunchComponent implements OnInit { }); } - handleLtiLaunchSuccess(data: NonNullable): void { - const targetLinkUri = data['targetLinkUri']; - const ltiIdToken = data['ltiIdToken']; - const clientRegistrationId = data['clientRegistrationId']; + handleLtiLaunchSuccess(data: LtiLaunchResponse): void { + const targetLinkUri = data.targetLinkUri; + const ltiIdToken = data.ltiIdToken; + const clientRegistrationId = data.clientRegistrationId; window.sessionStorage.removeItem('state'); this.storeLtiSessionData(ltiIdToken, clientRegistrationId); diff --git a/src/main/webapp/app/overview/course-conversations/dialogs/abstract-dialog.component.ts b/src/main/webapp/app/overview/course-conversations/dialogs/abstract-dialog.component.ts index 258564ed2992..a42b8aa465ef 100644 --- a/src/main/webapp/app/overview/course-conversations/dialogs/abstract-dialog.component.ts +++ b/src/main/webapp/app/overview/course-conversations/dialogs/abstract-dialog.component.ts @@ -6,7 +6,7 @@ export abstract class AbstractDialogComponent { isInitialized = false; initialize(requiredInputs?: string[]) { - const allInputsSet = (requiredInputs ?? []).every((input) => this[input] !== undefined); + const allInputsSet = (requiredInputs ?? []).every((input) => this[input as keyof this] !== undefined); if (!allInputsSet) { console.error('Error: Dialog not fully configured'); } else { diff --git a/src/main/webapp/app/overview/course-conversations/dialogs/conversation-detail-dialog/tabs/conversation-info/conversation-info.component.ts b/src/main/webapp/app/overview/course-conversations/dialogs/conversation-detail-dialog/tabs/conversation-info/conversation-info.component.ts index 64d4d5d01dfd..5c0abe66d1c5 100644 --- a/src/main/webapp/app/overview/course-conversations/dialogs/conversation-detail-dialog/tabs/conversation-info/conversation-info.component.ts +++ b/src/main/webapp/app/overview/course-conversations/dialogs/conversation-detail-dialog/tabs/conversation-info/conversation-info.component.ts @@ -144,9 +144,9 @@ export class ConversationInfoComponent implements OnInit, OnDestroy { modalRef.componentInstance.translationKeys = translationKeys; modalRef.componentInstance.isRequired = isRequired; modalRef.componentInstance.regexPattern = regexPattern; - - if (get(channelOrGroupChat, propertyName) && get(channelOrGroupChat, propertyName).length > 0) { - modalRef.componentInstance.initialValue = get(channelOrGroupChat, propertyName); + const property = get(channelOrGroupChat, propertyName); + if (property && typeof property === 'string' && property.length > 0) { + modalRef.componentInstance.initialValue = property; } modalRef.componentInstance.initialize(); from(modalRef.result) @@ -162,14 +162,14 @@ export class ConversationInfoComponent implements OnInit, OnDestroy { updateValue = ''; } if (isChannelDTO(channelOrGroupChat)) { - this.updateChannel(channelOrGroupChat, propertyName, updateValue); + this.updateChannel(channelOrGroupChat, propertyName as keyof ChannelDTO, updateValue); } else { - this.updateGroupChat(channelOrGroupChat, propertyName, updateValue); + this.updateGroupChat(channelOrGroupChat, propertyName as keyof GroupChatDTO, updateValue); } }); } - private updateGroupChat(groupChat: GroupChatDTO, propertyName: string, updateValue: string) { + private updateGroupChat(groupChat: GroupChatDTO, propertyName: K, updateValue: GroupChatDTO[K]) { const updateDTO = new GroupChatDTO(); updateDTO[propertyName] = updateValue; @@ -188,7 +188,7 @@ export class ConversationInfoComponent implements OnInit, OnDestroy { }); } - private updateChannel(channel: ChannelDTO, propertyName: string, updateValue: string) { + private updateChannel(channel: ChannelDTO, propertyName: K, updateValue: ChannelDTO[K]) { const updateDTO = new ChannelDTO(); updateDTO[propertyName] = updateValue; this.channelService diff --git a/src/main/webapp/app/overview/course-conversations/layout/conversation-thread-sidebar/conversation-thread-sidebar.component.ts b/src/main/webapp/app/overview/course-conversations/layout/conversation-thread-sidebar/conversation-thread-sidebar.component.ts index de0adc0483c5..40f1dc298d6c 100644 --- a/src/main/webapp/app/overview/course-conversations/layout/conversation-thread-sidebar/conversation-thread-sidebar.component.ts +++ b/src/main/webapp/app/overview/course-conversations/layout/conversation-thread-sidebar/conversation-thread-sidebar.component.ts @@ -3,7 +3,7 @@ import interact from 'interactjs'; import { Post } from 'app/entities/metis/post.model'; import { faArrowLeft, faChevronLeft, faGripLinesVertical, faXmark } from '@fortawesome/free-solid-svg-icons'; import { AnswerPost } from 'app/entities/metis/answer-post.model'; -import { ConversationDTO } from 'app/entities/metis/conversation/conversation.model'; +import { Conversation, ConversationDTO } from 'app/entities/metis/conversation/conversation.model'; import { getAsChannelDTO } from 'app/entities/metis/conversation/channel.model'; @Component({ @@ -17,8 +17,8 @@ export class ConversationThreadSidebarComponent implements AfterViewInit { @Input() readOnlyMode = false; @Input() - set activeConversation(conversation: ConversationDTO) { - this.conversation = conversation; + set activeConversation(conversation: ConversationDTO | Conversation) { + this.conversation = conversation as ConversationDTO; this.hasChannelModerationRights = getAsChannelDTO(this.conversation)?.hasChannelModerationRights ?? false; } @Input() diff --git a/src/main/webapp/app/overview/course-dashboard/course-dashboard.service.ts b/src/main/webapp/app/overview/course-dashboard/course-dashboard.service.ts index 3d2f7a36134d..1aa46499cfb3 100644 --- a/src/main/webapp/app/overview/course-dashboard/course-dashboard.service.ts +++ b/src/main/webapp/app/overview/course-dashboard/course-dashboard.service.ts @@ -81,8 +81,8 @@ export class CourseDashboardService { private filterJolWhereMasteryChanged(competencyMetrics: CompetencyMetrics): { [key: string]: CompetencyJol } { return Object.fromEntries( Object.entries(competencyMetrics.currentJolValues ?? {}).filter(([key, value]) => { - const progress = competencyMetrics?.progress?.[key] ?? 0; - const confidence = competencyMetrics?.confidence?.[key] ?? 1; + const progress = competencyMetrics?.progress?.[Number(key)] ?? 0; + const confidence = competencyMetrics?.confidence?.[Number(key)] ?? 1; return value.competencyProgress === progress && value.competencyConfidence === confidence; }), ); diff --git a/src/main/webapp/app/shared/course-group/course-group.component.ts b/src/main/webapp/app/shared/course-group/course-group.component.ts index 78df5cbc0700..dfd4a21a995a 100644 --- a/src/main/webapp/app/shared/course-group/course-group.component.ts +++ b/src/main/webapp/app/shared/course-group/course-group.component.ts @@ -10,17 +10,20 @@ import { iconsAsHTML } from 'app/utils/icons.utils'; import { download, generateCsv, mkConfig } from 'export-to-csv'; import { faDownload, faUserSlash } from '@fortawesome/free-solid-svg-icons'; import { TutorialGroup } from 'app/entities/tutorial-group/tutorial-group.model'; - -const NAME_KEY = 'Name'; -const USERNAME_KEY = 'Username'; -const EMAIL_KEY = 'Email'; -const REGISTRATION_NUMBER_KEY = 'Registration Number'; +import { EMAIL_KEY, NAME_KEY, REGISTRATION_NUMBER_KEY, USERNAME_KEY } from 'app/shared/export/export-constants'; const cssClasses = { alreadyMember: 'already-member', newlyAddedMember: 'newly-added-member', }; +export type GroupUserInformationRow = { + [NAME_KEY]: string; + [USERNAME_KEY]: string; + [EMAIL_KEY]: string; + [REGISTRATION_NUMBER_KEY]: string; +}; + @Component({ selector: 'jhi-course-group', templateUrl: './course-group.component.html', @@ -225,13 +228,13 @@ export class CourseGroupComponent implements OnDestroy { */ exportUserInformation = () => { if (this.allGroupUsers.length > 0) { - const rows: any[] = this.allGroupUsers.map((user: User) => { - const data = {}; - data[NAME_KEY] = user.name?.trim() ?? ''; - data[USERNAME_KEY] = user.login?.trim() ?? ''; - data[EMAIL_KEY] = user.email?.trim() ?? ''; - data[REGISTRATION_NUMBER_KEY] = user.visibleRegistrationNumber?.trim() ?? ''; - return data; + const rows: any[] = this.allGroupUsers.map((user: User): GroupUserInformationRow => { + return { + [NAME_KEY]: user.name?.trim() ?? '', + [USERNAME_KEY]: user.login?.trim() ?? '', + [EMAIL_KEY]: user.email?.trim() ?? '', + [REGISTRATION_NUMBER_KEY]: user.visibleRegistrationNumber?.trim() ?? '', + }; }); const keys = [NAME_KEY, USERNAME_KEY, EMAIL_KEY, REGISTRATION_NUMBER_KEY]; this.exportAsCsv(rows, keys); diff --git a/src/main/webapp/app/shared/export/export-row-builder.ts b/src/main/webapp/app/shared/export/export-row-builder.ts index 26d021aed62a..373a78219ef0 100644 --- a/src/main/webapp/app/shared/export/export-row-builder.ts +++ b/src/main/webapp/app/shared/export/export-row-builder.ts @@ -7,7 +7,7 @@ export type ExportRow = any; * Builds rows for exporting student scores. */ export abstract class ExportRowBuilder { - private exportRow = {}; + private exportRow: { [key: string]: unknown } = {}; readonly accuracyOfScores: number; diff --git a/src/main/webapp/app/shared/image-cropper/interfaces/cropper-options.interface.ts b/src/main/webapp/app/shared/image-cropper/interfaces/cropper-options.interface.ts index d8a4b7b60b56..b5517765c140 100644 --- a/src/main/webapp/app/shared/image-cropper/interfaces/cropper-options.interface.ts +++ b/src/main/webapp/app/shared/image-cropper/interfaces/cropper-options.interface.ts @@ -19,7 +19,7 @@ export interface CropperOptions { onlyScaleDown: boolean; imageQuality: number; autoCrop: boolean; - backgroundColor: string; + backgroundColor?: string; containWithinAspectRatio: boolean; hideResizeSquares: boolean; alignImage: 'left' | 'center'; diff --git a/src/main/webapp/app/shared/image-cropper/interfaces/cropper.settings.ts b/src/main/webapp/app/shared/image-cropper/interfaces/cropper.settings.ts index c0ba3618af18..f45913147bf2 100644 --- a/src/main/webapp/app/shared/image-cropper/interfaces/cropper.settings.ts +++ b/src/main/webapp/app/shared/image-cropper/interfaces/cropper.settings.ts @@ -2,7 +2,7 @@ import { CropperOptions, OutputFormat } from './cropper-options.interface'; import { ImageTransform } from './image-transform.interface'; import { SimpleChanges } from '@angular/core'; -export class CropperSettings { +export class CropperSettings implements CropperOptions { // From options format: OutputFormat = 'png'; maintainAspectRatio = true; @@ -34,18 +34,82 @@ export class CropperSettings { cropperScaledMaxHeight = 20; stepSize = this.initialStepSize; - setOptions(options: Partial): void { - Object.keys(options) - .filter((k) => k in this) - .forEach((k) => (this[k] = options[k])); + /** + * Updates the properties of the target object with the values from the source object. + * This method only updates the properties that exist in both the source and target objects. + * + * @template T - A type extending CropperOptions, representing the shape of the objects being updated. + * @param {Partial} source - The source object containing the new property values. Only properties that are defined will be considered. + * @param {T} target - The target object that will be updated with values from the source. It should be a complete object of type T. + * + * @remarks + * This method is used to update an instance of an object with new values from a partial object, + * such as updating configuration settings or applying changes. It ensures that only properties + * common to both the source and target are updated, preserving other properties of the target. + * After applying the new options, it validates the updated configuration to ensure + * all constraints and rules are maintained. + * + * @example + * const sourceOptions = { resizeToWidth: 200, imageQuality: 90 }; + * const cropperSettings = new CropperSettings(); + * updateProperties(sourceOptions, cropperSettings); + * // cropperSettings.resizeToWidth is now 200 + * // cropperSettings.imageQuality is now 90 + */ + private updateProperties(source: Partial, target: Partial) { + Object.assign(target, source); this.validateOptions(); } + /** + * Sets the cropper settings options by updating the current instance with new values. + * This method applies new configuration settings from a partial `CropperOptions` object + * to the existing instance, preserving any unspecified properties. + * + * @param {Partial} options - An object containing the new option values to be applied. + * Only properties specified in this object will be updated. + * + * @returns {void} This method does not return a value. + * + * @remarks + * This method is intended to be used for updating the cropper settings dynamically. + * + * @example + * const newOptions = { format: 'jpeg', aspectRatio: 16/9 }; + * cropperSettings.setOptions(newOptions); + * // cropperSettings.format is now 'jpeg' + * // cropperSettings.aspectRatio is now 16/9 + * // Other settings remain unchanged. + */ + setOptions(options: Partial): void { + this.updateProperties(options, this); + } + + /** + * Updates the cropper settings using changes detected in Angular's `SimpleChanges`. + * This method extracts the current values from the `SimpleChanges` object and applies + * them to the current instance of cropper settings. + * + * @param {SimpleChanges} changes - An object containing the changes detected by Angular, + * typically from an `ngOnChanges` lifecycle hook. Each change includes the previous and current values. + * + * @returns {void} This method does not return a value. + * + * @remarks + * This method is particularly useful when using Angular's two-way data binding and input properties. + * It efficiently updates the cropper settings based on changes to input properties, ensuring + * that the cropper configuration remains consistent with the external state. + * + * @example + * ngOnChanges(changes: SimpleChanges) { + * this.cropperSettings.setOptionsFromChanges(changes); + * } + * // Any changes to input properties bound to cropper settings will be applied automatically. + */ setOptionsFromChanges(changes: SimpleChanges): void { - Object.keys(changes) - .filter((k) => k in this) - .forEach((k) => (this[k] = changes[k].currentValue)); - this.validateOptions(); + const entries = Object.entries(changes).map(([key, change]) => [key, change.currentValue]); + const changedValues = Object.fromEntries(entries) as Partial; + this.updateProperties(changedValues, this); } private validateOptions(): void { diff --git a/src/main/webapp/app/shared/layouts/navbar/navbar.component.ts b/src/main/webapp/app/shared/layouts/navbar/navbar.component.ts index 2f7bb492d948..05bfc73dbaa9 100644 --- a/src/main/webapp/app/shared/layouts/navbar/navbar.component.ts +++ b/src/main/webapp/app/shared/layouts/navbar/navbar.component.ts @@ -248,7 +248,7 @@ export class NavbarComponent implements OnInit, OnDestroy { this.examStartedSubscription?.unsubscribe(); } - breadcrumbTranslation = { + breadcrumbTranslation: { [key: string]: string } = { new: 'global.generic.create', process: 'artemisApp.attachmentUnit.createAttachmentUnits.pageTitle', verify_attendance: 'artemisApp.examManagement.examStudents.verifyChecks', @@ -365,7 +365,7 @@ export class NavbarComponent implements OnInit, OnDestroy { import_standardized: 'artemisApp.standardizedCompetency.courseImport.title', }; - studentPathBreadcrumbTranslations = { + studentPathBreadcrumbTranslations: { [key: string]: string } = { exams: 'artemisApp.courseOverview.menu.exams', test_exam: 'artemisApp.courseOverview.menu.testExam', exercises: 'artemisApp.courseOverview.menu.exercises', diff --git a/src/main/webapp/app/shared/layouts/profiles/profile.service.ts b/src/main/webapp/app/shared/layouts/profiles/profile.service.ts index ae501656b70f..1767be3bb8e9 100644 --- a/src/main/webapp/app/shared/layouts/profiles/profile.service.ts +++ b/src/main/webapp/app/shared/layouts/profiles/profile.service.ts @@ -31,7 +31,7 @@ export class ProfileService { const data = res.body!; const profileInfo = new ProfileInfo(); profileInfo.activeProfiles = data.activeProfiles; - const displayRibbonOnProfiles = data['display-ribbon-on-profiles'].split(','); + const displayRibbonOnProfiles = data.ribbonEnv?.split(',') ?? []; this.mapGuidedTourConfig(data, profileInfo); this.mapAllowedOrionVersions(data, profileInfo); @@ -49,7 +49,7 @@ export class ProfileService { profileInfo.ribbonEnv = profileInfo.ribbonEnv ?? ''; profileInfo.sentry = data.sentry; - profileInfo.postHog = data['post-hog']; + profileInfo.postHog = data.postHog; profileInfo.features = data.features; profileInfo.buildPlanURLTemplate = data.buildPlanURLTemplate; profileInfo.commitHashURLTemplate = data.commitHashURLTemplate; @@ -73,8 +73,8 @@ export class ProfileService { profileInfo.versionControlAccessToken = data.versionControlAccessToken; profileInfo.continuousIntegrationName = data.continuousIntegrationName; profileInfo.programmingLanguageFeatures = data.programmingLanguageFeatures; - profileInfo.textAssessmentAnalyticsEnabled = data['text-assessment-analytics-enabled']; - profileInfo.studentExamStoreSessionData = data['student-exam-store-session-data']; + profileInfo.textAssessmentAnalyticsEnabled = data.textAssessmentAnalyticsEnabled; + profileInfo.studentExamStoreSessionData = data.studentExamStoreSessionData; profileInfo.useExternal = data.useExternal; profileInfo.externalCredentialProvider = data.externalCredentialProvider; diff --git a/src/main/webapp/app/shared/orion/orion-connector.service.ts b/src/main/webapp/app/shared/orion/orion-connector.service.ts index de40eacda51b..b49f8745e8db 100644 --- a/src/main/webapp/app/shared/orion/orion-connector.service.ts +++ b/src/main/webapp/app/shared/orion/orion-connector.service.ts @@ -112,9 +112,9 @@ export class OrionConnectorService { * Gets called by the IDE. Informs the Angular app about a newly opened exercise. * * @param opened The ID of the exercise that was opened by the user. - * @param viewString ExerciseView which is currently open in the IDE as string + * @param viewString ExerciseView which is currently open in the IDE as string. Must be one of the keys of ExerciseView */ - onExerciseOpened(opened: number, viewString: string): void { + onExerciseOpened(opened: number, viewString: keyof typeof ExerciseView): void { const view = ExerciseView[viewString]; this.setIDEStateParameter({ view }); this.setIDEStateParameter({ opened }); @@ -146,7 +146,7 @@ export class OrionConnectorService { JSON.stringify({ errors: buildErrors.reduce( // Group annotations by filename - (buildLogErrors, { fileName, timestamp, ...rest }) => ({ + (buildLogErrors: Record, { fileName, timestamp, ...rest }) => ({ ...buildLogErrors, [fileName]: [...(buildLogErrors[fileName] || []), { ...rest, ts: timestamp }], }), diff --git a/src/main/webapp/app/shared/pipes/average-by.pipe.ts b/src/main/webapp/app/shared/pipes/average-by.pipe.ts deleted file mode 100644 index 238d060b2c6a..000000000000 --- a/src/main/webapp/app/shared/pipes/average-by.pipe.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -@Pipe({ - name: 'averageBy', -}) -export class AverageByPipe implements PipeTransform { - /** - * Provides the average of an attribute. In the example below the result would be (4 + 8) / 2 = 6. - * @param arr e.g. = [{a: 4, b: 1}, {a: 8, b: 2}] - * @param attr e.g. = 'a' - */ - transform(arr: T[], attr: string): number { - return arr.reduce((acc, val) => val[attr] + acc, 0) / arr.length; - } -} diff --git a/src/main/webapp/app/shared/pipes/shared-pipes.module.ts b/src/main/webapp/app/shared/pipes/shared-pipes.module.ts index 0f8fbb8099af..21f41cd9ff06 100644 --- a/src/main/webapp/app/shared/pipes/shared-pipes.module.ts +++ b/src/main/webapp/app/shared/pipes/shared-pipes.module.ts @@ -3,7 +3,6 @@ import { SafeResourceUrlPipe } from 'app/shared/pipes/safe-resource-url.pipe'; import { KeysPipe } from 'app/shared/pipes/keys.pipe'; import { RemoveKeysPipe } from 'app/shared/pipes/remove-keys.pipe'; import { TypeCheckPipe } from 'app/shared/pipes/type-check.pipe'; -import { AverageByPipe } from 'app/shared/pipes/average-by.pipe'; import { SafeHtmlPipe } from 'app/shared/pipes/safe-html.pipe'; import { SafeUrlPipe } from 'app/shared/pipes/safe-url.pipe'; import { TruncatePipe } from 'app/shared/pipes/truncate.pipe'; @@ -27,7 +26,6 @@ import { AsPipe } from 'app/shared/pipes/as.pipe'; TypeCheckPipe, NegatedTypeCheckPipe, TruncatePipe, - AverageByPipe, GradeStepBoundsPipe, SearchFilterPipe, AsPipe, @@ -43,7 +41,6 @@ import { AsPipe } from 'app/shared/pipes/as.pipe'; NegatedTypeCheckPipe, TruncatePipe, SafeResourceUrlPipe, - AverageByPipe, GradeStepBoundsPipe, SearchFilterPipe, AsPipe, diff --git a/src/main/webapp/app/shared/sidebar/sidebar-accordion/sidebar-accordion.component.html b/src/main/webapp/app/shared/sidebar/sidebar-accordion/sidebar-accordion.component.html index 6a69b8839003..bb8af797054e 100644 --- a/src/main/webapp/app/shared/sidebar/sidebar-accordion/sidebar-accordion.component.html +++ b/src/main/webapp/app/shared/sidebar/sidebar-accordion/sidebar-accordion.component.html @@ -11,13 +11,13 @@ >
@if (showLeadingIcon) { - + } {{ 'artemisApp.courseOverview.sidebar.' + groupKey | artemisTranslate | titlecase }} ({{ (groupedData[groupKey].entityData | searchFilter: ['title', 'type'] : searchValue)?.length }})
- +
diff --git a/src/main/webapp/app/shared/sidebar/sidebar-accordion/sidebar-accordion.component.ts b/src/main/webapp/app/shared/sidebar/sidebar-accordion/sidebar-accordion.component.ts index efb277e3e703..5fef73b00b99 100644 --- a/src/main/webapp/app/shared/sidebar/sidebar-accordion/sidebar-accordion.component.ts +++ b/src/main/webapp/app/shared/sidebar/sidebar-accordion/sidebar-accordion.component.ts @@ -1,6 +1,6 @@ import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core'; import { faChevronRight, faFile } from '@fortawesome/free-solid-svg-icons'; -import { AccordionGroups, ChannelAccordionShowAdd, ChannelTypeIcons, CollapseState, SidebarCardElement, SidebarTypes } from 'app/types/sidebar'; +import { AccordionGroups, ChannelAccordionShowAdd, ChannelGroupCategory, ChannelTypeIcons, CollapseState, SidebarCardElement, SidebarTypes } from 'app/types/sidebar'; import { Params } from '@angular/router'; @Component({ @@ -72,4 +72,11 @@ export class SidebarAccordionComponent implements OnChanges, OnInit { this.collapseState[groupCategoryKey] = !this.collapseState[groupCategoryKey]; sessionStorage.setItem('sidebar.accordion.collapseState.' + this.storageId + '.byCourse.' + this.courseId, JSON.stringify(this.collapseState)); } + + getGroupKey(groupKey: string): boolean { + if (!this.showAddOption) { + return false; + } + return this.showAddOption[groupKey as ChannelGroupCategory]; + } } diff --git a/src/main/webapp/app/shared/sidebar/sidebar-card.directive.ts b/src/main/webapp/app/shared/sidebar/sidebar-card.directive.ts index 3329eb3d65df..d197f711bc6b 100644 --- a/src/main/webapp/app/shared/sidebar/sidebar-card.directive.ts +++ b/src/main/webapp/app/shared/sidebar/sidebar-card.directive.ts @@ -1,4 +1,4 @@ -import { ComponentRef, Directive, EventEmitter, Input, OnDestroy, OnInit, Output, ViewContainerRef } from '@angular/core'; +import { ComponentRef, Directive, EventEmitter, Input, OnDestroy, OnInit, Output, Type, ViewContainerRef } from '@angular/core'; import { SidebarCardSmallComponent } from 'app/shared/sidebar/sidebar-card-small/sidebar-card-small.component'; import { SidebarCardMediumComponent } from 'app/shared/sidebar/sidebar-card-medium/sidebar-card-medium.component'; import { SidebarCardLargeComponent } from 'app/shared/sidebar/sidebar-card-large/sidebar-card-large.component'; @@ -21,10 +21,10 @@ export class SidebarCardDirective implements OnInit, OnDestroy { constructor(public viewContainerRef: ViewContainerRef) {} ngOnInit() { - const cards = { - ['S']: SidebarCardSmallComponent, - ['M']: SidebarCardMediumComponent, - ['L']: SidebarCardLargeComponent, + const cards: { [key: string]: Type } = { + S: SidebarCardSmallComponent, + M: SidebarCardMediumComponent, + L: SidebarCardLargeComponent, }; const cardType = cards[this.size]; diff --git a/src/main/webapp/app/shared/sidebar/sidebar.component.ts b/src/main/webapp/app/shared/sidebar/sidebar.component.ts index b03a9541cbee..fdb0d9adcaaa 100644 --- a/src/main/webapp/app/shared/sidebar/sidebar.component.ts +++ b/src/main/webapp/app/shared/sidebar/sidebar.component.ts @@ -3,7 +3,7 @@ import { faChevronRight, faFilter, faMagnifyingGlass } from '@fortawesome/free-s import { ActivatedRoute, Params } from '@angular/router'; import { Subscription, distinctUntilChanged } from 'rxjs'; import { ProfileService } from '../layouts/profiles/profile.service'; -import { ChannelAccordionShowAdd, ChannelTypeIcons, CollapseState, SidebarData } from 'app/types/sidebar'; +import { ChannelAccordionShowAdd, ChannelTypeIcons, CollapseState, SidebarCardSize, SidebarData, SidebarTypes } from 'app/types/sidebar'; import { SidebarEventService } from './sidebar-event.service'; @Component({ @@ -101,11 +101,12 @@ export class SidebarComponent implements OnDestroy, OnChanges, OnInit { } getSize() { - const size = { + const size: Record = { ['exercise']: 'M', ['default']: 'M', ['conversation']: 'S', ['exam']: 'L', + ['inExam']: 'M', }; return this.sidebarData.sidebarType ? size[this.sidebarData.sidebarType] : 'M'; } diff --git a/src/main/webapp/app/shared/user-import/users-import-dialog.component.ts b/src/main/webapp/app/shared/user-import/users-import-dialog.component.ts index 8b20359186ca..cb8287d7b74d 100644 --- a/src/main/webapp/app/shared/user-import/users-import-dialog.component.ts +++ b/src/main/webapp/app/shared/user-import/users-import-dialog.component.ts @@ -25,7 +25,9 @@ const POSSIBLE_LAST_NAME_HEADERS = ['familyname', 'lastname', 'familynameofstude const POSSIBLE_ROOM_HEADERS = ['actualroom', 'actualRoom', 'raum', 'room', 'Room']; const POSSIBLE_SEAT_HEADERS = ['actualseat', 'actualSeat', 'sitzplatz', 'sitz', 'seat', 'Seat']; -type CsvUser = object; +interface CsvUser { + [key: string]: string; +} @Component({ selector: 'jhi-users-import-dialog', @@ -137,26 +139,26 @@ export class UsersImportDialogComponent implements OnDestroy { if (this.examUserMode) { return csvUsers.map( - (users) => + (user: CsvUser) => ({ - registrationNumber: users[registrationNumberHeader]?.trim() || '', - login: users[loginHeader]?.trim() || '', - email: users[emailHeader]?.trim() || '', - firstName: users[firstNameHeader]?.trim() || '', - lastName: users[lastNameHeader]?.trim() || '', - room: users[roomHeader]?.trim() || '', - seat: users[seatHeader]?.trim() || '', + registrationNumber: user[registrationNumberHeader]?.trim() || '', + login: user[loginHeader]?.trim() || '', + email: user[emailHeader]?.trim() || '', + firstName: user[firstNameHeader]?.trim() || '', + lastName: user[lastNameHeader]?.trim() || '', + room: user[roomHeader]?.trim() || '', + seat: user[seatHeader]?.trim() || '', }) as ExamUserDTO, ); } else { return csvUsers.map( - (users) => + (user: CsvUser) => ({ - registrationNumber: users[registrationNumberHeader]?.trim() || '', - login: users[loginHeader]?.trim() || '', - email: users[emailHeader]?.trim() || '', - firstName: users[firstNameHeader]?.trim() || '', - lastName: users[lastNameHeader]?.trim() || '', + registrationNumber: user[registrationNumberHeader]?.trim() || '', + login: user[loginHeader]?.trim() || '', + email: user[emailHeader]?.trim() || '', + firstName: user[firstNameHeader]?.trim() || '', + lastName: user[lastNameHeader]?.trim() || '', }) as StudentDTO, ); } @@ -210,11 +212,11 @@ export class UsersImportDialogComponent implements OnDestroy { */ private parseCSVFile(csvFile: File): Promise { return new Promise((resolve, reject) => { - parse(csvFile, { + parse(csvFile, { header: true, transformHeader: (header: string) => cleanString(header), skipEmptyLines: true, - complete: (results) => resolve(results.data as CsvUser[]), + complete: (results) => resolve(results.data), error: (error) => reject(error), }); }); diff --git a/src/main/webapp/app/shared/util/markdown.conversion.util.ts b/src/main/webapp/app/shared/util/markdown.conversion.util.ts index f7ca19804eb4..658574db088b 100644 --- a/src/main/webapp/app/shared/util/markdown.conversion.util.ts +++ b/src/main/webapp/app/shared/util/markdown.conversion.util.ts @@ -7,7 +7,7 @@ import DOMPurify, { Config } from 'dompurify'; * showdown will add the classes to the converted html * see: https://github.com/showdownjs/showdown/wiki/Add-default-classes-for-each-HTML-element */ -const classMap = { +const classMap: { [key: string]: string } = { table: 'table', }; /** diff --git a/src/main/webapp/app/types/sidebar.ts b/src/main/webapp/app/types/sidebar.ts index e81b128ae53b..cdaae8d3b99f 100644 --- a/src/main/webapp/app/types/sidebar.ts +++ b/src/main/webapp/app/types/sidebar.ts @@ -20,11 +20,9 @@ export type ChannelGroupCategory = | 'directMessages' | 'examChannels' | 'hiddenChannels'; -export type CollapseState = - | Record - | Record - | Record - | Record; +export type CollapseState = { + [key: string]: boolean; +} & (Record | Record | Record | Record); export type ChannelAccordionShowAdd = Record; export type ChannelTypeIcons = Record; diff --git a/src/test/javascript/spec/component/admin/user-management.component.spec.ts b/src/test/javascript/spec/component/admin/user-management.component.spec.ts index 632eac82d5c3..29189fad046b 100644 --- a/src/test/javascript/spec/component/admin/user-management.component.spec.ts +++ b/src/test/javascript/spec/component/admin/user-management.component.spec.ts @@ -329,9 +329,9 @@ describe('UserManagementComponent', () => { it('should return correct filter values', () => { comp.initFilters(); - expect(comp.authorityFilters).toEqual(Object.keys(AuthorityFilter).map((key) => AuthorityFilter[key])); - expect(comp.originFilters).toEqual(Object.keys(OriginFilter).map((key) => OriginFilter[key])); - expect(comp.statusFilters).toEqual(Object.keys(StatusFilter).map((key) => StatusFilter[key])); + expect(comp.authorityFilters).toEqual(Object.values(AuthorityFilter)); + expect(comp.originFilters).toEqual(Object.values(OriginFilter)); + expect(comp.statusFilters).toEqual(Object.values(StatusFilter)); }); it('should select and deselect all roles', () => { diff --git a/src/test/javascript/spec/component/competencies/import/competency-search.component.spec.ts b/src/test/javascript/spec/component/competencies/import/competency-search.component.spec.ts index 49ef1292024e..a3c0c3c37bbc 100644 --- a/src/test/javascript/spec/component/competencies/import/competency-search.component.spec.ts +++ b/src/test/javascript/spec/component/competencies/import/competency-search.component.spec.ts @@ -6,6 +6,7 @@ import { CompetencySearchComponent } from 'app/course/competencies/import-compet import { NgbCollapseMocksModule } from '../../../helpers/mocks/directive/ngbCollapseMocks.module'; import { ButtonComponent } from 'app/shared/components/button.component'; import { FormsModule } from 'app/forms/forms.module'; +import { CourseCompetencyFilter } from 'app/shared/table/pageable-table'; describe('CompetencySearchComponent', () => { let componentFixture: ComponentFixture; @@ -41,14 +42,12 @@ describe('CompetencySearchComponent', () => { it('should reset', () => { componentFixture.detectChanges(); - for (const key in component.search) { - component.search[key] = 'any value'; - } + initializeSearch(); componentFixture.debugElement.nativeElement.querySelector('#resetFilterButton > .jhi-btn').click(); for (const key in component.search) { - expect(component.search[key]).toBe(''); + expect(component.search[key as keyof CourseCompetencyFilter]).toBe(''); } }); @@ -56,9 +55,7 @@ describe('CompetencySearchComponent', () => { componentFixture.detectChanges(); const searchChangeEmitSpy = jest.spyOn(component.searchChange, 'emit'); - for (const key in component.search) { - component.search[key] = 'any value'; - } + initializeSearch(); componentFixture.debugElement.nativeElement.querySelector('#submitFilterButton > .jhi-btn').click(); expect(searchChangeEmitSpy).toHaveBeenCalledWith({ title: 'any value', description: '', courseTitle: '', semester: '' }); @@ -68,9 +65,7 @@ describe('CompetencySearchComponent', () => { componentFixture.detectChanges(); const searchChangeEmitSpy = jest.spyOn(component.searchChange, 'emit'); - for (const key in component.search) { - component.search[key] = 'any value'; - } + initializeSearch(); component.advancedSearchEnabled = true; componentFixture.debugElement.nativeElement.querySelector('#submitFilterButton > .jhi-btn').click(); @@ -87,4 +82,10 @@ describe('CompetencySearchComponent', () => { advancedSearchToggle.click(); expect(component.advancedSearchEnabled).toBeFalse(); }); + + function initializeSearch(): void { + for (const key in component.search) { + component.search[key as keyof CourseCompetencyFilter] = 'any value'; + } + } }); diff --git a/src/test/javascript/spec/component/course/course-management-card.component.spec.ts b/src/test/javascript/spec/component/course/course-management-card.component.spec.ts index e1b1b26434f8..7a709536a1a6 100644 --- a/src/test/javascript/spec/component/course/course-management-card.component.spec.ts +++ b/src/test/javascript/spec/component/course/course-management-card.component.spec.ts @@ -73,7 +73,7 @@ describe('CourseManagementCardComponent', () => { it('should correctly categorize past, current, and future exercises and update statisticsPerExercise', () => { component.courseStatistics = courseStatisticsDTO; component.ngOnChanges(); - expect(component.statisticsPerExercise[exerciseDTO.exerciseId!]).toEqual(exerciseDTO); + expect(component.statisticsPerExercise.get(exerciseDTO.exerciseId!)).toEqual(exerciseDTO); component.courseWithExercises = course; component.ngOnChanges(); diff --git a/src/test/javascript/spec/component/exam/manage/exam-exercise-import.component.spec.ts b/src/test/javascript/spec/component/exam/manage/exam-exercise-import.component.spec.ts index d584dfed1a92..304a86ef1639 100644 --- a/src/test/javascript/spec/component/exam/manage/exam-exercise-import.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/exam-exercise-import.component.spec.ts @@ -15,6 +15,8 @@ import { Exercise } from 'app/entities/exercise.model'; import { faCheckDouble, faFileUpload, faFont, faKeyboard, faProjectDiagram } from '@fortawesome/free-solid-svg-icons'; import { UMLDiagramType } from '@ls1intum/apollon'; +type DuplicateType = keyof Pick; + describe('Exam Exercise Import Component', () => { let component: ExamExerciseImportComponent; let fixture: ComponentFixture; @@ -339,7 +341,7 @@ describe('Exam Exercise Import Component', () => { expect(programmingExercise3.title).toBe(''); }); - it.each(['exercisesWithDuplicatedTitles', 'exercisesWithDuplicatedShortNames'])( + it.each(['exercisesWithDuplicatedTitles', 'exercisesWithDuplicatedShortNames'])( 'should check for programming exercise duplicated titles and short names when entering input', (attrToCheck) => { const duplicatesToCheck = component[attrToCheck]; @@ -362,7 +364,7 @@ describe('Exam Exercise Import Component', () => { }, ); - it.each([ + it.each<[DuplicateType, boolean]>([ ['exercisesWithDuplicatedShortNames', false], ['exercisesWithDuplicatedShortNames', true], ['exercisesWithDuplicatedTitles', false], @@ -388,7 +390,7 @@ describe('Exam Exercise Import Component', () => { expect(duplicatesToCheck.size).toBe(additionalDuplicate ? 2 : 0); }); - it.each(['exercisesWithDuplicatedTitles', 'exercisesWithDuplicatedShortNames'])( + it.each(['exercisesWithDuplicatedTitles', 'exercisesWithDuplicatedShortNames'])( 'should check for programming exercise duplicated titles and short names when unselecting exercises', (attrToCheck) => { const duplicatesToCheck = component[attrToCheck]; @@ -413,7 +415,7 @@ describe('Exam Exercise Import Component', () => { }, ); - it.each(['exercisesWithDuplicatedTitles', 'exercisesWithDuplicatedShortNames'])('should ignore unselected exercises', (attrToCheck) => { + it.each(['exercisesWithDuplicatedTitles', 'exercisesWithDuplicatedShortNames'])('should ignore unselected exercises', (attrToCheck) => { const duplicatesToCheck = component[attrToCheck]; const duplicatedTitles = attrToCheck === 'exercisesWithDuplicatedTitles'; diff --git a/src/test/javascript/spec/component/lecture-unit/text-unit/text-unit-form.component.spec.ts b/src/test/javascript/spec/component/lecture-unit/text-unit/text-unit-form.component.spec.ts index aeb86865058f..0dfc849da228 100644 --- a/src/test/javascript/spec/component/lecture-unit/text-unit/text-unit-form.component.spec.ts +++ b/src/test/javascript/spec/component/lecture-unit/text-unit/text-unit-form.component.spec.ts @@ -19,8 +19,12 @@ class MarkdownEditorStubComponent { @Output() markdownChange = new EventEmitter(); } +type Store = { + [key: string]: any; +}; + describe('TextUnitFormComponent', () => { - let store = {}; + let store: Store = {}; let textUnitFormComponentFixture: ComponentFixture; let textUnitFormComponent: TextUnitFormComponent; diff --git a/src/test/javascript/spec/component/lecture/lecture-attachments.component.spec.ts b/src/test/javascript/spec/component/lecture/lecture-attachments.component.spec.ts index 74a63588cfd0..773142efa909 100644 --- a/src/test/javascript/spec/component/lecture/lecture-attachments.component.spec.ts +++ b/src/test/javascript/spec/component/lecture/lecture-attachments.component.spec.ts @@ -165,9 +165,7 @@ describe('LectureAttachmentsComponent', () => { expect(addAttachmentButton).not.toBeNull(); addAttachmentButton.nativeElement.click(); fixture.detectChanges(); - const fakeBlob = {}; - fakeBlob['name'] = 'Test-File.pdf'; - fakeBlob['size'] = 100000000000000000; + const fakeBlob = { name: 'Test-File.pdf', size: 100000000000000000 }; comp.attachmentFile = fakeBlob as File; const uploadAttachmentButton = fixture.debugElement.query(By.css('#upload-attachment')); expect(uploadAttachmentButton).not.toBeNull(); diff --git a/src/test/javascript/spec/component/localci/build-queue/build-queue.component.spec.ts b/src/test/javascript/spec/component/localci/build-queue/build-queue.component.spec.ts index 4eb3f4d976ab..966e1cdeb551 100644 --- a/src/test/javascript/spec/component/localci/build-queue/build-queue.component.spec.ts +++ b/src/test/javascript/spec/component/localci/build-queue/build-queue.component.spec.ts @@ -45,7 +45,9 @@ describe('BuildQueueComponent', () => { const mockLocalStorageService = new MockLocalStorageService(); mockLocalStorageService.clear = (key?: string) => { if (key) { - delete mockLocalStorageService.storage[key]; + if (key in mockLocalStorageService.storage) { + delete mockLocalStorageService.storage[key]; + } } else { mockLocalStorageService.storage = {}; } diff --git a/src/test/javascript/spec/component/multiple-choice-question/multiple-choice-question.component.spec.ts b/src/test/javascript/spec/component/multiple-choice-question/multiple-choice-question.component.spec.ts index 7b9a80956d42..f5499aafa5a1 100644 --- a/src/test/javascript/spec/component/multiple-choice-question/multiple-choice-question.component.spec.ts +++ b/src/test/javascript/spec/component/multiple-choice-question/multiple-choice-question.component.spec.ts @@ -88,7 +88,10 @@ describe('MultipleChoiceQuestionComponent', () => { } function safeHtmlToString(safeHtml: SafeHtml) { - return safeHtml['changingThisBreaksApplicationSecurity'] ?? ''; + if (safeHtml && 'changingThisBreaksApplicationSecurity' in safeHtml) { + return safeHtml.changingThisBreaksApplicationSecurity; + } + return ''; } it('should return true is if the answer option was selected', () => { diff --git a/src/test/javascript/spec/component/overview/course-conversations/dialogs/conversation-detail-dialog/tabs/conversation-info/conversation-info.component.spec.ts b/src/test/javascript/spec/component/overview/course-conversations/dialogs/conversation-detail-dialog/tabs/conversation-info/conversation-info.component.spec.ts index d29d59062f07..b06aea67f4ef 100644 --- a/src/test/javascript/spec/component/overview/course-conversations/dialogs/conversation-detail-dialog/tabs/conversation-info/conversation-info.component.spec.ts +++ b/src/test/javascript/spec/component/overview/course-conversations/dialogs/conversation-detail-dialog/tabs/conversation-info/conversation-info.component.spec.ts @@ -167,7 +167,7 @@ examples.forEach((activeConversation) => { expect(section).toBeFalsy(); } - function genericEditPropertyDialogTest(sectionName: string, expectedComponentInstance: object) { + function genericEditPropertyDialogTest(sectionName: string, expectedComponentInstance: any) { const button = fixture.nativeElement.querySelector(`#${sectionName}-section .action-button`); const modalService = TestBed.inject(NgbModal); const mockModalRef = { @@ -191,23 +191,23 @@ examples.forEach((activeConversation) => { expect(openDialogSpy).toHaveBeenCalledOnce(); expect(openDialogSpy).toHaveBeenCalledWith(GenericUpdateTextPropertyDialogComponent, defaultSecondLayerDialogOptions); for (const [key, value] of Object.entries(expectedComponentInstance)) { - expect(mockModalRef.componentInstance[key]).toEqual(value); + expect(mockModalRef.componentInstance[key as keyof typeof mockModalRef.componentInstance]).toEqual(value); } if (isGroupChatDTO(activeConversation)) { const expectedUpdateDTO = new GroupChatDTO(); - expectedUpdateDTO[expectedComponentInstance['propertyName']] = 'updated'; + (expectedUpdateDTO as any)[expectedComponentInstance['propertyName']] = 'updated'; expect(updateGroupChatSpy).toHaveBeenCalledOnce(); expect(updateGroupChatSpy).toHaveBeenCalledWith(course.id, activeConversation.id, expectedUpdateDTO); } if (isChannelDTO(activeConversation)) { const expectedUpdateDTO = new ChannelDTO(); - expectedUpdateDTO[expectedComponentInstance['propertyName']] = 'updated'; + (expectedUpdateDTO as any)[expectedComponentInstance['propertyName']] = 'updated'; expect(updateChannelSpy).toHaveBeenCalledOnce(); expect(updateChannelSpy).toHaveBeenCalledWith(course.id, activeConversation.id, expectedUpdateDTO); } - expect(activeConversation[expectedComponentInstance['propertyName']]).toBe('updated'); + expect((activeConversation as any)[expectedComponentInstance['propertyName']]).toBe('updated'); }); } }); diff --git a/src/test/javascript/spec/component/overview/course-conversations/dialogs/dialog-test-helpers.ts b/src/test/javascript/spec/component/overview/course-conversations/dialogs/dialog-test-helpers.ts index 04943771eac8..3e919081752f 100644 --- a/src/test/javascript/spec/component/overview/course-conversations/dialogs/dialog-test-helpers.ts +++ b/src/test/javascript/spec/component/overview/course-conversations/dialogs/dialog-test-helpers.ts @@ -1,7 +1,11 @@ import { AbstractDialogComponent } from 'app/overview/course-conversations/dialogs/abstract-dialog.component'; import { ComponentFixture } from '@angular/core/testing'; -export function initializeDialog(component: AbstractDialogComponent, fixture: ComponentFixture, requiredInputs: object) { +type RequiredInputs = { + [key: string]: any; +}; + +export function initializeDialog(component: AbstractDialogComponent, fixture: ComponentFixture, requiredInputs: RequiredInputs) { // expect console.err to be called const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); component.initialize(); @@ -13,7 +17,7 @@ export function initializeDialog(component: AbstractDialogComponent, fixture: Co // expect console.err not to be called // loop over required inputs and set on component Object.keys(requiredInputs).forEach((key) => { - component[key] = requiredInputs[key]; + component[key as keyof AbstractDialogComponent] = requiredInputs[key]; }); component.initialize(); diff --git a/src/test/javascript/spec/component/plagiarism/exercise-update-plagiarism.component.spec.ts b/src/test/javascript/spec/component/plagiarism/exercise-update-plagiarism.component.spec.ts index 3c5d6f57c4d7..feeb959ee591 100644 --- a/src/test/javascript/spec/component/plagiarism/exercise-update-plagiarism.component.spec.ts +++ b/src/test/javascript/spec/component/plagiarism/exercise-update-plagiarism.component.spec.ts @@ -90,11 +90,11 @@ describe('Exercise Update Plagiarism Component', () => { // initialize for (const fieldName of inputFieldNames) { - comp[fieldName] = { valueChanges: new Subject(), valid: false }; + (comp as any)[fieldName] = { valueChanges: new Subject(), valid: false }; } comp.ngAfterViewInit(); for (const fieldName of inputFieldNames) { - expect((comp[fieldName].valueChanges! as Subject).observed).toBeTrue(); + expect(((comp as any)[fieldName].valueChanges! as Subject).observed).toBeTrue(); } (comp.fieldCPCEnabled!.valueChanges! as Subject).next(false); @@ -112,7 +112,7 @@ describe('Exercise Update Plagiarism Component', () => { comp.ngOnDestroy(); for (const fieldName of inputFieldNames) { - expect((comp[fieldName].valueChanges! as Subject).observed).toBeFalse(); + expect(((comp as any)[fieldName].valueChanges! as Subject).observed).toBeFalse(); } }); }); diff --git a/src/test/javascript/spec/component/plagiarism/split-pane-header.component.spec.ts b/src/test/javascript/spec/component/plagiarism/split-pane-header.component.spec.ts index 14717f09be5a..31953315113a 100644 --- a/src/test/javascript/spec/component/plagiarism/split-pane-header.component.spec.ts +++ b/src/test/javascript/spec/component/plagiarism/split-pane-header.component.spec.ts @@ -11,7 +11,7 @@ import { PlagiarismRunDetailsComponent } from 'app/exercises/shared/plagiarism/p import { PlagiarismSidebarComponent } from 'app/exercises/shared/plagiarism/plagiarism-sidebar/plagiarism-sidebar.component'; import { MockComponent, MockDirective, MockPipe } from 'ng-mocks'; -describe('Plagiarism Split Pane Header Component', () => { +describe('SplitPaneHeaderComponent', () => { let comp: SplitPaneHeaderComponent; let fixture: ComponentFixture; diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-reset-dialog.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-reset-dialog.component.spec.ts index 1b21b1b353d1..6f1c53159b02 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-reset-dialog.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-reset-dialog.component.spec.ts @@ -8,7 +8,7 @@ import { ArtemisTestModule } from '../../test.module'; import { ProgrammingExerciseResetDialogComponent } from 'app/exercises/programming/manage/reset/programming-exercise-reset-dialog.component'; import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; import { Course } from 'app/entities/course.model'; -import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; +import { ProgrammingExerciseResetOptions, ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; import { AlertService } from 'app/core/util/alert.service'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; @@ -189,7 +189,7 @@ describe('ProgrammingExerciseResetDialogComponent', () => { deleteParticipationsSubmissionsAndResults: false, recreateBuildPlans: false, }; - comp.programmingExerciseResetOptions[option] = true; + comp.programmingExerciseResetOptions[option as keyof ProgrammingExerciseResetOptions] = true; expect(comp.hasSelectedOptions).toBeTrue(); }); }); diff --git a/src/test/javascript/spec/component/shared/course-group.component.spec.ts b/src/test/javascript/spec/component/shared/course-group.component.spec.ts index 1e35080acb37..511ef22ccef6 100644 --- a/src/test/javascript/spec/component/shared/course-group.component.spec.ts +++ b/src/test/javascript/spec/component/shared/course-group.component.spec.ts @@ -6,7 +6,7 @@ import { TranslateService } from '@ngx-translate/core'; import { NgxDatatableModule } from '@flaviosantoro92/ngx-datatable'; import { User } from 'app/core/user/user.model'; import { UserService } from 'app/core/user/user.service'; -import { CourseGroupComponent } from 'app/shared/course-group/course-group.component'; +import { CourseGroupComponent, GroupUserInformationRow } from 'app/shared/course-group/course-group.component'; import { CourseManagementService } from 'app/course/manage/course-management.service'; import { CourseGroup } from 'app/entities/course.model'; import { HasAnyAuthorityDirective } from 'app/shared/auth/has-any-authority.directive'; @@ -28,7 +28,7 @@ import { TranslateDirective } from 'app/shared/language/translate.directive'; import { AlertService } from 'app/core/util/alert.service'; import { EMAIL_KEY, NAME_KEY, REGISTRATION_NUMBER_KEY, USERNAME_KEY } from 'app/shared/export/export-constants'; -describe('Course Group Component', () => { +describe('CourseGroupComponent', () => { let comp: CourseGroupComponent; let fixture: ComponentFixture; let userService: UserService; @@ -224,15 +224,15 @@ describe('Course Group Component', () => { expect(exportAsCsvMock).toHaveBeenCalledOnce(); const generatedRows = exportAsCsvMock.mock.calls[0][0]; - const expectedRow1 = {}; + const expectedRow1 = {} as GroupUserInformationRow; expectedRow1[NAME_KEY] = ''; - expectedRow1[USERNAME_KEY] = courseGroupUser.login; + expectedRow1[USERNAME_KEY] = courseGroupUser.login ?? ''; expectedRow1[EMAIL_KEY] = ''; expectedRow1[REGISTRATION_NUMBER_KEY] = ''; - const expectedRow2 = {}; + const expectedRow2 = {} as GroupUserInformationRow; expectedRow2[NAME_KEY] = ''; - expectedRow2[USERNAME_KEY] = courseGroupUser2.login; + expectedRow2[USERNAME_KEY] = courseGroupUser2.login ?? ''; expectedRow2[EMAIL_KEY] = ''; expectedRow2[REGISTRATION_NUMBER_KEY] = ''; diff --git a/src/test/javascript/spec/component/short-answer-question/short-answer-question.component.spec.ts b/src/test/javascript/spec/component/short-answer-question/short-answer-question.component.spec.ts index d9421fc514a3..2013cc1e52c2 100644 --- a/src/test/javascript/spec/component/short-answer-question/short-answer-question.component.spec.ts +++ b/src/test/javascript/spec/component/short-answer-question/short-answer-question.component.spec.ts @@ -9,6 +9,7 @@ import { ShortAnswerMapping } from 'app/entities/quiz/short-answer-mapping.model import { ShortAnswerSolution } from 'app/entities/quiz/short-answer-solution.model'; import { ShortAnswerSubmittedText } from 'app/entities/quiz/short-answer-submitted-text.model'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; +import { SafeHtml } from '@angular/platform-browser'; const question = new ShortAnswerQuestion(); question.id = 1; @@ -41,6 +42,9 @@ describe('ShortAnswerQuestionComponent', () => { }); it('should initialize', () => { + const extractSafeHtmlText = (safeHtml: SafeHtml) => { + return 'changingThisBreaksApplicationSecurity' in safeHtml ? safeHtml.changingThisBreaksApplicationSecurity : ''; + }; const alternativeQuestion = new ShortAnswerQuestion(); alternativeQuestion.id = 10; const text = 'Please explain this question about stuff'; @@ -54,9 +58,9 @@ describe('ShortAnswerQuestionComponent', () => { expect(component.textParts).toStrictEqual([[`

${text}

`]]); expect(component.shortAnswerQuestion).toStrictEqual(alternativeQuestion); - expect(component.renderedQuestion.text['changingThisBreaksApplicationSecurity']).toBe(`

${text}

`); - expect(component.renderedQuestion.hint['changingThisBreaksApplicationSecurity']).toBe(`

${hint}

`); - expect(component.renderedQuestion.explanation['changingThisBreaksApplicationSecurity']).toBe(`

${explanation}

`); + expect(extractSafeHtmlText(component.renderedQuestion.text)).toBe(`

${text}

`); + expect(extractSafeHtmlText(component.renderedQuestion.hint)).toBe(`

${hint}

`); + expect(extractSafeHtmlText(component.renderedQuestion.explanation)).toBe(`

${explanation}

`); }); it('should set submitted texts', () => { diff --git a/src/test/javascript/spec/component/standardized-competencies/detail/knowledge-area-edit.component.spec.ts b/src/test/javascript/spec/component/standardized-competencies/detail/knowledge-area-edit.component.spec.ts index 5fb6e6d72767..1dcb3a517efd 100644 --- a/src/test/javascript/spec/component/standardized-competencies/detail/knowledge-area-edit.component.spec.ts +++ b/src/test/javascript/spec/component/standardized-competencies/detail/knowledge-area-edit.component.spec.ts @@ -173,7 +173,7 @@ describe('KnowledgeAreaEditComponent', () => { function compareFormValues(formValues: any, knowledgeArea: KnowledgeAreaDTO) { for (const key in formValues) { //needed to ensure null becomes undefined - expect(formValues[key] ?? undefined).toEqual(knowledgeArea[key]); + expect(formValues[key] ?? undefined).toEqual(knowledgeArea[key as keyof KnowledgeAreaDTO]); } } }); diff --git a/src/test/javascript/spec/component/standardized-competencies/detail/standardized-competency-edit.spec.ts b/src/test/javascript/spec/component/standardized-competencies/detail/standardized-competency-edit.spec.ts index 36f8774f82d1..b33c93d1eabd 100644 --- a/src/test/javascript/spec/component/standardized-competencies/detail/standardized-competency-edit.spec.ts +++ b/src/test/javascript/spec/component/standardized-competencies/detail/standardized-competency-edit.spec.ts @@ -140,7 +140,7 @@ describe('StandardizedCompetencyEditComponent', () => { function compareFormValues(formValues: any, competency: StandardizedCompetencyDTO) { for (const key in formValues) { //needed to ensure null becomes undefined - expect(formValues[key] ?? undefined).toEqual(competency[key]); + expect(formValues[key] ?? undefined).toEqual(competency[key as keyof StandardizedCompetencyDTO]); } } }); diff --git a/src/test/javascript/spec/component/text-exercise/text-exercise-update.component.spec.ts b/src/test/javascript/spec/component/text-exercise/text-exercise-update.component.spec.ts index d090ed295b1d..aa0f2c889832 100644 --- a/src/test/javascript/spec/component/text-exercise/text-exercise-update.component.spec.ts +++ b/src/test/javascript/spec/component/text-exercise/text-exercise-update.component.spec.ts @@ -176,7 +176,7 @@ describe('TextExercise Management Update Component', () => { comp.validateDate(); expect(calculatValidationSectionsSpy).toHaveBeenCalledOnce(); for (const errorName of dateErrorNames) { - expect(comp.textExercise[errorName]).toBeFalsy(); + expect(comp.textExercise[errorName as keyof TextExercise]).toBeFalsy(); } })); }); diff --git a/src/test/javascript/spec/component/tutorial-groups/tutorial-groups-management/tutorial-group-sessions/crud/tutorial-group-session-form.component.spec.ts b/src/test/javascript/spec/component/tutorial-groups/tutorial-groups-management/tutorial-group-sessions/crud/tutorial-group-session-form.component.spec.ts index 7a3de34489af..c1139fec76c6 100644 --- a/src/test/javascript/spec/component/tutorial-groups/tutorial-groups-management/tutorial-group-sessions/crud/tutorial-group-session-form.component.spec.ts +++ b/src/test/javascript/spec/component/tutorial-groups/tutorial-groups-management/tutorial-group-sessions/crud/tutorial-group-session-form.component.spec.ts @@ -69,7 +69,7 @@ describe('TutorialGroupSessionForm', () => { const formControlNames = ['date', 'startTime', 'endTime']; formControlNames.forEach((control) => { - expect(component.form.get(control)!.value).toEqual(formData[control]); + expect(component.form.get(control)?.value).toEqual(formData[control as keyof TutorialGroupSessionFormData]); }); }); diff --git a/src/test/javascript/spec/component/tutorial-groups/tutorial-groups-management/tutorial-groups-configuration/crud/tutorial-groups-configuration-form.component.spec.ts b/src/test/javascript/spec/component/tutorial-groups/tutorial-groups-management/tutorial-groups-configuration/crud/tutorial-groups-configuration-form.component.spec.ts index 47d019ff20fa..8deb6bc1350b 100644 --- a/src/test/javascript/spec/component/tutorial-groups/tutorial-groups-management/tutorial-groups-configuration/crud/tutorial-groups-configuration-form.component.spec.ts +++ b/src/test/javascript/spec/component/tutorial-groups/tutorial-groups-management/tutorial-groups-configuration/crud/tutorial-groups-configuration-form.component.spec.ts @@ -68,7 +68,7 @@ describe('TutorialGroupsConfigurationFormComponent', () => { const formControlNames = ['period', 'usePublicTutorialGroupChannels', 'useTutorialGroupChannels']; formControlNames.forEach((control) => { - expect(component.form.get(control)!.value).toEqual(formData[control]); + expect(component.form.get(control)?.value).toEqual(formData[control as keyof TutorialGroupsConfigurationFormData]); }); }); diff --git a/src/test/javascript/spec/component/tutorial-groups/tutorial-groups-management/tutorial-groups/crud/tutorial-group-form.component.spec.ts b/src/test/javascript/spec/component/tutorial-groups/tutorial-groups-management/tutorial-groups/crud/tutorial-group-form.component.spec.ts index 61973eb5c64d..04d2c353f042 100644 --- a/src/test/javascript/spec/component/tutorial-groups/tutorial-groups-management/tutorial-groups/crud/tutorial-group-form.component.spec.ts +++ b/src/test/javascript/spec/component/tutorial-groups/tutorial-groups-management/tutorial-groups/crud/tutorial-group-form.component.spec.ts @@ -15,7 +15,10 @@ import { NgbTimepickerModule, NgbTypeaheadModule } from '@ng-bootstrap/ng-bootst import { TutorialGroupsService } from 'app/course/tutorial-groups/services/tutorial-groups.service'; import { Component, EventEmitter, Input, Output } from '@angular/core'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; -import { ScheduleFormComponent } from 'app/course/tutorial-groups/tutorial-groups-management/tutorial-groups/crud/tutorial-group-form/schedule-form/schedule-form.component'; +import { + ScheduleFormComponent, + ScheduleFormData, +} from 'app/course/tutorial-groups/tutorial-groups-management/tutorial-groups/crud/tutorial-group-form/schedule-form/schedule-form.component'; import { OwlDateTimeModule, OwlNativeDateTimeModule } from '@danielmoncada/angular-datetime-picker'; import '@angular/localize/init'; import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe'; @@ -176,13 +179,13 @@ describe('TutorialGroupFormComponent', () => { component.formData = formData; component.ngOnChanges(); - const groupFormControlNames = ['title', 'teachingAssistant', 'campus', 'capacity', 'isOnline', 'language']; + const groupFormControlNames: Array = ['title', 'teachingAssistant', 'campus', 'capacity', 'isOnline', 'language']; for (const controlName of groupFormControlNames) { - expect(component.form.get(controlName)!.value).toEqual(formData[controlName]); + expect(component.form.get(controlName)?.value).toEqual(formData[controlName]); } expect(component.additionalInformation).toEqual(formData.additionalInformation); - const scheduleFormControlNames = ['dayOfWeek', 'startTime', 'endTime', 'repetitionFrequency', 'period', 'location']; + const scheduleFormControlNames: Array = ['dayOfWeek', 'startTime', 'endTime', 'repetitionFrequency', 'period', 'location']; for (const controlName of scheduleFormControlNames) { expect(component.form.get('schedule')!.get(controlName)!.value).toEqual(formData.schedule![controlName]); } @@ -240,7 +243,7 @@ describe('TutorialGroupFormComponent', () => { component.formData = formData; component.ngOnChanges(); - const formControlNames = ['title', 'teachingAssistant', 'campus', 'capacity', 'isOnline', 'language']; + const formControlNames: Array = ['title', 'teachingAssistant', 'campus', 'capacity', 'isOnline', 'language']; for (const controlName of formControlNames) { expect(component.form.get(controlName)!.value).toEqual(formData[controlName]); } diff --git a/src/test/javascript/spec/helpers/mocks/service/mock-local-storage.service.ts b/src/test/javascript/spec/helpers/mocks/service/mock-local-storage.service.ts index 53f746b8567b..34f2a954fa6c 100644 --- a/src/test/javascript/spec/helpers/mocks/service/mock-local-storage.service.ts +++ b/src/test/javascript/spec/helpers/mocks/service/mock-local-storage.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class MockLocalStorageService { - storage = {}; + storage: { [key: string]: any } = {}; store = (key: string, value: string) => (this.storage[key] = value); retrieve = (key: string) => this.storage[key]; clear = (key?: string) => {}; diff --git a/src/test/javascript/spec/helpers/mocks/service/mock-sync-storage.service.ts b/src/test/javascript/spec/helpers/mocks/service/mock-sync-storage.service.ts index 69ca4c4aab12..a80f213406a9 100644 --- a/src/test/javascript/spec/helpers/mocks/service/mock-sync-storage.service.ts +++ b/src/test/javascript/spec/helpers/mocks/service/mock-sync-storage.service.ts @@ -2,7 +2,7 @@ import { StorageService } from 'ngx-webstorage/lib/core/interfaces/storageServic import { Observable } from 'rxjs'; export class MockSyncStorage implements StorageService { - private static storage = {}; + private static storage: { [key: string]: any } = {}; clear(key?: string): any {} @@ -21,7 +21,7 @@ export class MockSyncStorage implements StorageService { MockSyncStorage.storage[key] = `${value}`; } - static retrieve(key: string) { + static retrieve(key: string): any { return this.storage[key]; } } diff --git a/src/test/javascript/spec/jest-test-setup.ts b/src/test/javascript/spec/jest-test-setup.ts index 0695db06d4c3..7c4a0ed4fe46 100644 --- a/src/test/javascript/spec/jest-test-setup.ts +++ b/src/test/javascript/spec/jest-test-setup.ts @@ -16,7 +16,7 @@ import { MockClipboardItem } from './helpers/mocks/service/mock-clipboard-item'; * on the document. */ document.queryCommandSupported = () => false; -import 'monaco-editor/esm/vs/editor/edcore.main'; +import 'monaco-editor/esm/vs/editor/edcore.main'; // Do not move this import. failOnConsole({ shouldFailOnWarn: true, @@ -27,7 +27,8 @@ failOnConsole({ const noop = () => {}; const mock = () => { - let storage = {}; + let storage: { [key: string]: any } = {}; + return { getItem: (key: any) => (key in storage ? storage[key] : null), setItem: (key: any, value: any) => (storage[key] = value || ''), diff --git a/src/test/javascript/spec/service/exam-participation-live-events.service.spec.ts b/src/test/javascript/spec/service/exam-participation-live-events.service.spec.ts index 2ad209583ab2..7950c0c96bdb 100644 --- a/src/test/javascript/spec/service/exam-participation-live-events.service.spec.ts +++ b/src/test/javascript/spec/service/exam-participation-live-events.service.spec.ts @@ -29,8 +29,9 @@ describe('ExamParticipationLiveEventsService', () => { retrieve: jest.fn(), } as unknown as LocalStorageService; - mockWebsocketService = new MockWebsocketService() as any as JhiWebsocketService; - mockWebsocketService['state'] = websocketConnectionStateSubject.asObservable(); + const tmpMockWebsocketService = new MockWebsocketService(); + tmpMockWebsocketService.state = websocketConnectionStateSubject.asObservable(); + mockWebsocketService = tmpMockWebsocketService as unknown as JhiWebsocketService; TestBed.configureTestingModule({ imports: [HttpClientTestingModule], diff --git a/src/test/javascript/spec/service/exam-participation.service.spec.ts b/src/test/javascript/spec/service/exam-participation.service.spec.ts index 4e189a17351b..8a06fa6654d6 100644 --- a/src/test/javascript/spec/service/exam-participation.service.spec.ts +++ b/src/test/javascript/spec/service/exam-participation.service.spec.ts @@ -20,7 +20,7 @@ import { getLatestSubmissionResult } from 'app/entities/submission.model'; import { StudentExamWithGradeDTO, StudentResult } from 'app/exam/exam-scores/exam-score-dtos.model'; import { GradeType } from 'app/entities/grading-scale.model'; -describe('Exam Participation Service', () => { +describe('ExamParticipationService', () => { let service: ExamParticipationService; let httpMock: HttpTestingController; let exam: Exam; @@ -241,7 +241,7 @@ describe('Exam Participation Service', () => { const expected = Object.assign({}, sendToService); service.saveStudentExamToLocalStorage(1, 1, sendToService); jest.spyOn(localStorage, 'store').mockImplementation(() => { - expect(localStorage['artemis_student_exam_1_1']).toBe(expected); + expect(localStorage.retrieve('artemis_student_exam_1_1')).toBe(expected); }); }); it('should load StudentExam from localStorage', async () => { diff --git a/src/test/javascript/spec/service/modeling-assessment.service.spec.ts b/src/test/javascript/spec/service/modeling-assessment.service.spec.ts index c88825e48db5..e2579b0b93c9 100644 --- a/src/test/javascript/spec/service/modeling-assessment.service.spec.ts +++ b/src/test/javascript/spec/service/modeling-assessment.service.spec.ts @@ -12,9 +12,92 @@ import { Feedback } from 'app/entities/feedback.model'; import { ModelingAssessmentService } from 'app/exercises/modeling/assess/modeling-assessment.service'; import { ComplaintResponse } from 'app/entities/complaint-response.model'; import { UMLElementType, UMLModel, UMLRelationshipType } from '@ls1intum/apollon'; -import { getNamesForAssessments } from 'app/exercises/modeling/assess/modeling-assessment.util'; +import { AssessmentNamesForModelId, getNamesForAssessments } from 'app/exercises/modeling/assess/modeling-assessment.util'; -describe('Modeling Assessment Service', () => { +const assessmentNames: AssessmentNamesForModelId = { + '6': { + name: 'Dominik', + type: 'class', + }, + '7': { + name: 'Dominik', + type: 'package', + }, + '8': { + name: 'Dominik', + type: 'interface', + }, + '9': { + name: 'Dominik', + type: 'abstract class', + }, + '10': { + name: 'Dominik', + type: 'enum', + }, + '11': { + name: 'Dominik', + type: 'attribute', + }, + '12': { + name: 'Dominik', + type: 'method', + }, + '13': { + name: 'Dominik', + type: 'initial node', + }, + '14': { + name: 'Dominik', + type: 'final node', + }, + '15': { + name: 'Dominik', + type: 'object', + }, + '16': { + name: 'Dominik', + type: 'action', + }, + '17': { + name: 'Dominik', + type: 'fork node', + }, + '18': { + name: 'Dominik', + type: 'merge node', + }, + '19': { + name: 'Dominik <-> Dominik', + type: 'association', + }, + '20': { + name: 'Dominik --> Dominik', + type: 'association', + }, + '21': { + name: 'Dominik --◇ Dominik', + type: 'association', + }, + '22': { + name: 'Dominik --▷ Dominik', + type: 'association', + }, + '23': { + name: 'Dominik ╌╌> Dominik', + type: 'association', + }, + '24': { + name: 'Dominik --◆ Dominik', + type: 'association', + }, + '25': { + name: 'Dominik --> Dominik', + type: 'control flow', + }, +}; + +describe('ModelingAssessmentService', () => { let httpMock: HttpTestingController; let service: ModelingAssessmentService; let expectedResult: any; @@ -158,7 +241,6 @@ describe('Modeling Assessment Service', () => { }); it('should get names for assessment', async () => { - const expected = new Map(); elemDefault.feedbacks = [ { id: 0, credits: 3, referenceId: '6', referenceType: UMLElementType.ActivityActionNode } as Feedback, { id: 0, credits: 3, referenceId: '7', referenceType: UMLElementType.ActivityActionNode } as Feedback, @@ -210,7 +292,7 @@ describe('Modeling Assessment Service', () => { } as unknown as UMLModel; expectedResult = getNamesForAssessments(elemDefault, uml); - expect(expectedResult).toEqual(expected); + expect(expectedResult).toEqual(assessmentNames); }); }); diff --git a/src/test/javascript/spec/service/profile.service.spec.ts b/src/test/javascript/spec/service/profile.service.spec.ts index 521a80fe0d30..00296fdba322 100644 --- a/src/test/javascript/spec/service/profile.service.spec.ts +++ b/src/test/javascript/spec/service/profile.service.spec.ts @@ -10,7 +10,7 @@ import { FeatureToggle } from 'app/shared/feature-toggle/feature-toggle.service' import { ProgrammingLanguage, ProjectType } from 'app/entities/programming-exercise.model'; import { BrowserFingerprintService } from 'app/shared/fingerprint/browser-fingerprint.service'; -describe('Profile Service', () => { +describe('ProfileService', () => { let service: ProfileService; let httpMock: HttpTestingController; diff --git a/src/test/javascript/spec/service/programming-exercise.service.spec.ts b/src/test/javascript/spec/service/programming-exercise.service.spec.ts index 2ae94e3233d4..66ca8a1e0d44 100644 --- a/src/test/javascript/spec/service/programming-exercise.service.spec.ts +++ b/src/test/javascript/spec/service/programming-exercise.service.spec.ts @@ -427,7 +427,11 @@ describe('ProgrammingExercise Service', () => { ])('should call correct exercise endpoint', (test) => fakeAsync(() => { const exerciseId = 1; - service[test.method](exerciseId).subscribe(); + const functionToCall = service[test.method as keyof ProgrammingExerciseService]; + if (typeof functionToCall !== 'function') { + throw new Error(`Method ${test.method} does not exist on service`); + } + functionToCall.bind(service, exerciseId).apply().subscribe(); const url = `${resourceUrl}/${exerciseId}/${test.uri}`; const req = httpMock.expectOne({ method: 'GET', url }); req.flush({}); diff --git a/src/test/javascript/spec/service/quiz-exercise.service.spec.ts b/src/test/javascript/spec/service/quiz-exercise.service.spec.ts index 37f0d95039d2..c1fe73c1139b 100644 --- a/src/test/javascript/spec/service/quiz-exercise.service.spec.ts +++ b/src/test/javascript/spec/service/quiz-exercise.service.spec.ts @@ -167,8 +167,11 @@ describe('QuizExercise Service', () => { ['recalculate', [123], quizEx, 'GET', '/recalculate-statistics'], ['find', [123], quizEx, 'GET', ''], ])('should perform a http request for %p', async (method, args, response, httpMethod, urlSuffix) => { - // eslint-disable-next-line prefer-spread - const result = firstValueFrom(service[method].apply(service, args)) as Promise>; + const functionToCall = service[method as keyof QuizExerciseService]; + if (typeof functionToCall !== 'function') { + throw new Error(`Method ${method} not found in service`); + } + const result = firstValueFrom(functionToCall.apply(service, args)) as Promise>; const req = httpMock.expectOne({ method: httpMethod }); expect(req.request.url).toEndWith(urlSuffix); req.flush(response); diff --git a/src/test/javascript/spec/service/result.service.spec.ts b/src/test/javascript/spec/service/result.service.spec.ts index 6c9f82f838fd..00e6ff3ea277 100644 --- a/src/test/javascript/spec/service/result.service.spec.ts +++ b/src/test/javascript/spec/service/result.service.spec.ts @@ -153,8 +153,7 @@ describe('ResultService', () => { const resultWithPoints2 = new ResultWithPointsPerGradingCriterion(); resultWithPoints2.result = result2; resultWithPoints2.totalPoints = 50; - // @ts-ignore - resultWithPoints2.pointsPerCriterion = { '1': 20, '2': 30 }; + resultWithPoints2.pointsPerCriterion = new Map(Object.entries({ '1': 20, '2': 30 }).map(([key, value]) => [Number(key), value])); const results = [resultWithPoints1, resultWithPoints2]; diff --git a/tsconfig.json b/tsconfig.json index e8d82522b345..134720389f6c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,7 +15,6 @@ "noImplicitReturns": false, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, - "suppressImplicitAnyIndexErrors": true, "strictNullChecks": true, "resolveJsonModule": true, "skipLibCheck": true,