From dad29e3fe46d583e16e1d6513febbb9b2d23888f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 09:43:57 +0000 Subject: [PATCH 1/6] Align Angular 21 dependencies and migrate core UI config Agent-Logs-Url: https://github.com/LearningHouseService/learninghouse/sessions/3748ec52-a045-4e41-a561-8202932dfbdd Co-authored-by: DerOetzi <2345662+DerOetzi@users.noreply.github.com> --- ui/angular.json | 19 ++++++++++--------- ui/package.json | 26 +++++++++++++------------- ui/src/main.ts | 6 ------ ui/tsconfig.json | 4 ++-- 4 files changed, 25 insertions(+), 30 deletions(-) diff --git a/ui/angular.json b/ui/angular.json index b688969a..4b7b576e 100644 --- a/ui/angular.json +++ b/ui/angular.json @@ -15,12 +15,14 @@ "prefix": "app", "architect": { "build": { - "builder": "@angular-devkit/build-angular:browser", + "builder": "@angular-devkit/build-angular:application", "options": { "outputPath": "dist/learninghouse", "index": "src/index.html", - "main": "src/main.ts", - "polyfills": "src/polyfills.ts", + "browser": "src/main.ts", + "polyfills": [ + "src/polyfills.ts" + ], "tsConfig": "tsconfig.app.json", "inlineStyleLanguage": "scss", "assets": [ @@ -56,12 +58,9 @@ "outputHashing": "all" }, "development": { - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, - "sourceMap": true, - "namedChunks": true + "sourceMap": true } }, "defaultConfiguration": "production" @@ -92,7 +91,9 @@ "builder": "@angular-devkit/build-angular:karma", "options": { "main": "src/test.ts", - "polyfills": "src/polyfills.ts", + "polyfills": [ + "src/polyfills.ts" + ], "tsConfig": "tsconfig.spec.json", "karmaConfig": "karma.conf.js", "inlineStyleLanguage": "scss", @@ -113,4 +114,4 @@ "cli": { "analytics": false } -} \ No newline at end of file +} diff --git a/ui/package.json b/ui/package.json index 846b2a1d..d430d975 100644 --- a/ui/package.json +++ b/ui/package.json @@ -14,28 +14,28 @@ }, "private": true, "dependencies": { - "@angular/animations": "^18.1.0", - "@angular/cdk": "^18.1.0", - "@angular/common": "^19.2.16", + "@angular/animations": "^21.2.12", + "@angular/cdk": "^21.2.10", + "@angular/common": "^21.2.12", "@angular/compiler": "^21.2.12", - "@angular/core": "^18.1.0", - "@angular/forms": "^18.1.0", + "@angular/core": "^21.2.12", + "@angular/forms": "^21.2.12", "@angular/material": "^21.2.10", "@angular/platform-browser": "^21.2.12", - "@angular/platform-browser-dynamic": "^18.2.8", - "@angular/router": "^18.1.0", + "@angular/platform-browser-dynamic": "^21.2.12", + "@angular/router": "^21.2.12", "@auth0/angular-jwt": "^5.2.0", - "@ngx-translate/core": "^15.0.0", - "@ngx-translate/http-loader": "^8.0.0", + "@ngx-translate/core": "^16.0.0", + "@ngx-translate/http-loader": "^16.0.0", "@w11k/git-info": "^1.1.2", "rxjs": "~7.8.1", "tslib": "^2.6.3", - "zone.js": "~0.14.10" + "zone.js": "~0.15.1" }, "devDependencies": { "@angular-devkit/build-angular": "^21.2.10", "@angular/cli": "~21.2.10", - "@angular/compiler-cli": "^18.1.0", + "@angular/compiler-cli": "^21.2.12", "@tailwindcss/aspect-ratio": "0.4.2", "@tailwindcss/forms": "0.5.7", "@tailwindcss/line-clamp": "0.4.4", @@ -52,6 +52,6 @@ "ngx-tailwind": "^4.0.0", "postcss": "^8.4.41", "tailwindcss": "^3.4.7", - "typescript": "~5.5.4" + "typescript": "~5.9.3" } -} \ No newline at end of file +} diff --git a/ui/src/main.ts b/ui/src/main.ts index c7b673cf..0a621147 100644 --- a/ui/src/main.ts +++ b/ui/src/main.ts @@ -1,12 +1,6 @@ -import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; -import { environment } from './environments/environment'; - -if (environment.production) { - enableProdMode(); -} platformBrowserDynamic().bootstrapModule(AppModule) .catch(err => console.error(err)); diff --git a/ui/tsconfig.json b/ui/tsconfig.json index 09e15c35..bed13f53 100644 --- a/ui/tsconfig.json +++ b/ui/tsconfig.json @@ -16,7 +16,7 @@ "declaration": false, "downlevelIteration": true, "experimentalDecorators": true, - "moduleResolution": "node", + "moduleResolution": "bundler", "importHelpers": true, "target": "ES2022", "module": "es2020", @@ -32,4 +32,4 @@ "strictInputAccessModifiers": true, "strictTemplates": true } -} \ No newline at end of file +} From b8667e9e7bec6542081b40281e62dfc731646d1d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 09:48:24 +0000 Subject: [PATCH 2/6] Fix Angular 21 standalone defaults for NgModule app and test deps Agent-Logs-Url: https://github.com/LearningHouseService/learninghouse/sessions/3748ec52-a045-4e41-a561-8202932dfbdd Co-authored-by: DerOetzi <2345662+DerOetzi@users.noreply.github.com> --- ui/package-lock.json | 656 +++++++++--------- ui/package.json | 1 + ui/src/app/app.component.ts | 1 + .../add-apikey-dialog.component.ts | 1 + .../auth/pages/apikeys/apikeys.component.ts | 1 + .../change-password.component.ts | 1 + .../auth/pages/login/login.component.ts | 1 + .../braininfo/braininfo.component.ts | 1 + .../add-edit-brain-dialog.component.ts | 1 + .../brains/pages/brains/brains.component.ts | 1 + .../pages/prediction/prediction.component.ts | 1 + .../pages/training/training.component.ts | 1 + .../add-edit-sensor-dialog.component.ts | 1 + .../pages/sensors/sensors.component.ts | 1 + .../info-dialog/info-dialog.component.ts | 1 + .../components/sidenav/sidenav.component.ts | 1 + .../components/toolbar/toolbar.component.ts | 1 + .../components/alert/alert.component.ts | 1 + .../button-group.component.spec.ts | 4 +- .../button-group/button-group.component.ts | 1 + .../edit-dialog/edit-dialog.component.ts | 1 + .../form-response/form-response.component.ts | 1 + .../components/input/input.component.ts | 1 + .../components/password/password.component.ts | 1 + .../components/select/select.component.ts | 1 + .../session-timer/session-timer.component.ts | 1 + .../delete-dialog/delete-dialog.component.ts | 1 + .../components/table/table.component.ts | 1 + .../components/yes-no/yes-no.component.ts | 1 + 29 files changed, 338 insertions(+), 349 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 6934a9ac..78038e9e 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -8,28 +8,28 @@ "name": "learninghouse", "version": "0.0.0", "dependencies": { - "@angular/animations": "^18.1.0", - "@angular/cdk": "^18.1.0", - "@angular/common": "^19.2.16", + "@angular/animations": "^21.2.12", + "@angular/cdk": "^21.2.10", + "@angular/common": "^21.2.12", "@angular/compiler": "^21.2.12", - "@angular/core": "^18.1.0", - "@angular/forms": "^18.1.0", + "@angular/core": "^21.2.12", + "@angular/forms": "^21.2.12", "@angular/material": "^21.2.10", "@angular/platform-browser": "^21.2.12", - "@angular/platform-browser-dynamic": "^18.2.8", - "@angular/router": "^18.1.0", + "@angular/platform-browser-dynamic": "^21.2.12", + "@angular/router": "^21.2.12", "@auth0/angular-jwt": "^5.2.0", - "@ngx-translate/core": "^15.0.0", - "@ngx-translate/http-loader": "^8.0.0", + "@ngx-translate/core": "^16.0.0", + "@ngx-translate/http-loader": "^16.0.0", "@w11k/git-info": "^1.1.2", "rxjs": "~7.8.1", "tslib": "^2.6.3", - "zone.js": "~0.14.10" + "zone.js": "~0.15.1" }, "devDependencies": { "@angular-devkit/build-angular": "^21.2.10", "@angular/cli": "~21.2.10", - "@angular/compiler-cli": "^18.1.0", + "@angular/compiler-cli": "^21.2.12", "@tailwindcss/aspect-ratio": "0.4.2", "@tailwindcss/forms": "0.5.7", "@tailwindcss/line-clamp": "0.4.4", @@ -43,10 +43,11 @@ "karma-chrome-launcher": "~3.2.0", "karma-coverage": "~2.2.1", "karma-jasmine": "~5.1.0", + "karma-jasmine-html-reporter": "~2.1.0", "ngx-tailwind": "^4.0.0", "postcss": "^8.4.41", "tailwindcss": "^3.4.7", - "typescript": "~5.5.4" + "typescript": "~5.9.3" } }, "node_modules/@algolia/abtesting": { @@ -707,47 +708,6 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@angular-devkit/build-angular/node_modules/@ngtools/webpack": { "version": "21.2.10", "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-21.2.10.tgz", @@ -825,13 +785,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@angular-devkit/build-angular/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, "node_modules/@angular-devkit/build-angular/node_modules/is-interactive": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", @@ -1531,32 +1484,33 @@ } }, "node_modules/@angular/animations": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.1.0.tgz", - "integrity": "sha512-K0BhvZ/SIVoGXZVuh1KOJDdgcGlHfFGMGrs58utndndAb+gYXReMfz4GR5cQs2OObH6TKmIOY2EH7Og1CY2tsw==", + "version": "21.2.12", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-21.2.12.tgz", + "integrity": "sha512-91mgQI15qStL38LijoKyAvNo61wB5rUpwqDVHoJQeISUChVYOY4hiofO6hW6ERg8MHQKUTyOrPDg5cN4yTcp9A==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "18.1.0" + "@angular/core": "21.2.12" } }, "node_modules/@angular/cdk": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-18.1.0.tgz", - "integrity": "sha512-GWUyJQ7KdOS0WwQPp7UKnRd7lUKvOrMvktqNWfSxBy/VEdyEeKlXfghk6GQ4u1RXFZ2RU0m1KhX8rY9srYJOwA==", + "version": "21.2.10", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-21.2.10.tgz", + "integrity": "sha512-yfCzUFNfeSMNnCkc0P5Pozqz1EViDe9KLPQyHVY/hApsNgBWvckpA+ZEWgKNfAf72f8bUJvZoHejaSMGYrpvuw==", + "license": "MIT", "dependencies": { + "parse5": "^8.0.0", "tslib": "^2.3.0" }, - "optionalDependencies": { - "parse5": "^7.1.2" - }, "peerDependencies": { - "@angular/common": "^18.0.0 || ^19.0.0", - "@angular/core": "^18.0.0 || ^19.0.0", + "@angular/common": "^21.0.0 || ^22.0.0", + "@angular/core": "^21.0.0 || ^22.0.0", + "@angular/platform-browser": "^21.0.0 || ^22.0.0", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -1641,41 +1595,6 @@ } } }, - "node_modules/@angular/cli/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@angular/cli/node_modules/cliui": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", - "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@angular/cli/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, "node_modules/@angular/cli/node_modules/semver": { "version": "7.7.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", @@ -1699,99 +1618,19 @@ "node": ">= 12" } }, - "node_modules/@angular/cli/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@angular/cli/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@angular/cli/node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/@angular/cli/node_modules/yargs": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", - "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^9.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "string-width": "^7.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^22.0.0" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" - } - }, - "node_modules/@angular/cli/node_modules/yargs-parser": { - "version": "22.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", - "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" - } - }, "node_modules/@angular/common": { - "version": "19.2.16", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-19.2.16.tgz", - "integrity": "sha512-sugztO7XIiLRoVjn0WJK9ooBm9zejsqlE5k4ZGvy1zFafM8LMjFHwD4KymN8JB3AOb7Ad4lJHVq1IvwWnpqeWw==", + "version": "21.2.12", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.12.tgz", + "integrity": "sha512-b7IRSM9fWPmZ1SLN0utVcW87IkhiRte3Wsnwr2nEsjum2soRMfvKqHwtEFGfCztlwOmZLgKiGW9pqKpzBkIjnQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "19.2.16", + "@angular/core": "21.2.12", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -1808,62 +1647,109 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.1.0.tgz", - "integrity": "sha512-BBsogLPJwxkPh7f8RVHsxyyqNE8XpHbAanjB5fAwnU4W6Sw1kR5rFzkeZM3xaRm2MDiC8DovIl6hlf+s/mKYOw==", + "version": "21.2.12", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-21.2.12.tgz", + "integrity": "sha512-YQ15Yp2OWBS1NnzZH77HLH1ZDn+/A5Mc1EobKl4CX8dYUEPIB/KwmGKLaKtbJ0KNcVsDlmsTTWodRgqe2n5erw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/core": "7.24.7", + "@babel/core": "7.29.0", "@jridgewell/sourcemap-codec": "^1.4.14", - "chokidar": "^3.0.0", + "chokidar": "^5.0.0", "convert-source-map": "^1.5.1", "reflect-metadata": "^0.2.0", "semver": "^7.0.0", "tslib": "^2.3.0", - "yargs": "^17.2.1" + "yargs": "^18.0.0" }, "bin": { "ng-xi18n": "bundles/src/bin/ng_xi18n.js", - "ngc": "bundles/src/bin/ngc.js", - "ngcc": "bundles/ngcc/index.js" + "ngc": "bundles/src/bin/ngc.js" }, "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "18.1.0", - "typescript": ">=5.4 <5.6" + "@angular/compiler": "21.2.12", + "typescript": ">=5.9 <6.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@angular/compiler-cli/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular/compiler-cli/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/@angular/core": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.1.0.tgz", - "integrity": "sha512-/57/s7CD/0CwlN+3FlhVmx7ypCWXjKi5UKtnlBAUg0D1denIf6ADxwTHFZABYZcYBqOTJgeQUtUw9u/A+0CIlg==", + "version": "21.2.12", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-21.2.12.tgz", + "integrity": "sha512-wcD6tzE30nwg58KmAU19347Jf/1F/vFg2CEd9Qcu5cA1Z4s3umzvaqs/7988ne4HaS4iJEpvTbRvGss7EYZEfA==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { + "@angular/compiler": "21.2.12", "rxjs": "^6.5.3 || ^7.4.0", - "zone.js": "~0.14.0" + "zone.js": "~0.15.0 || ~0.16.0" + }, + "peerDependenciesMeta": { + "@angular/compiler": { + "optional": true + }, + "zone.js": { + "optional": true + } } }, "node_modules/@angular/forms": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.1.0.tgz", - "integrity": "sha512-m+7m9wa+n5dEacd458eSZsZTz0B+HbOtr7/uqM0YTMQaPrhwl1epG5Y103mB6yr00JiJcLNlPLjP888cHFjldQ==", + "version": "21.2.12", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-21.2.12.tgz", + "integrity": "sha512-jhHaIgMWcgPcVFEPwhjLhByvA2xou6Th5PR6iC3H0YeLQyRmOFPWdczszytlWB1CeJ0UT9epxzOZT25zNcGSfg==", + "license": "MIT", "dependencies": { + "@standard-schema/spec": "^1.0.0", "tslib": "^2.3.0" }, "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "18.1.0", - "@angular/core": "18.1.0", - "@angular/platform-browser": "18.1.0", + "@angular/common": "21.2.12", + "@angular/core": "21.2.12", + "@angular/platform-browser": "21.2.12", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -1907,36 +1793,38 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "18.2.8", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.2.8.tgz", - "integrity": "sha512-poZoapDqyN/rxGKQ3C6esdPiPLMkSpP2v12hoEa12KHgfPk7T1e+a+NMyJjV8HeOY3WyvL7tGRhW0NPTajTkhw==", + "version": "21.2.12", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-21.2.12.tgz", + "integrity": "sha512-9WBflv/ewh7yjeXL3YrSQcrsquvBYSBzgpKpX39zH9YBDnSNAv7ic0psmfyLkb1bjrWM+CFJBbR543CLTCOCRA==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "18.2.8", - "@angular/compiler": "18.2.8", - "@angular/core": "18.2.8", - "@angular/platform-browser": "18.2.8" + "@angular/common": "21.2.12", + "@angular/compiler": "21.2.12", + "@angular/core": "21.2.12", + "@angular/platform-browser": "21.2.12" } }, "node_modules/@angular/router": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.1.0.tgz", - "integrity": "sha512-dl2cSxZkl4we+rWMxdm123TZzlor6yxwNFI2yT7b6DP2i+rXaaHBSSPet0ASp+UX6djz+Osr56Bifs6wi4rhiQ==", + "version": "21.2.12", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-21.2.12.tgz", + "integrity": "sha512-2/RDHt3GdW2ABNRVrgLX7IxgJLdF7u8Sbh11kAUn04QhNI/GObxIV4M5Hm/NTeDoi+hCXavkaHVBlj/dG5ANbw==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "18.1.0", - "@angular/core": "18.1.0", - "@angular/platform-browser": "18.1.0", + "@angular/common": "21.2.12", + "@angular/core": "21.2.12", + "@angular/platform-browser": "21.2.12", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -1977,21 +1865,22 @@ } }, "node_modules/@babel/core": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", - "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helpers": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -5779,30 +5668,29 @@ } }, "node_modules/@ngx-translate/core": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-15.0.0.tgz", - "integrity": "sha512-Am5uiuR0bOOxyoercDnAA3rJVizo4RRqJHo8N3RqJ+XfzVP/I845yEnMADykOHvM6HkVm4SZSnJBOiz0Anx5BA==", - "engines": { - "node": "^16.13.0 || >=18.10.0" + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-16.0.4.tgz", + "integrity": "sha512-s8llTL2SJvROhqttxvEs7Cg+6qSf4kvZPFYO+cTOY1d8DWTjlutRkWAleZcPPoeX927Dm7ALfL07G7oYDJ7z6w==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/common": ">=16.0.0", - "@angular/core": ">=16.0.0", - "rxjs": "^6.5.5 || ^7.4.0" + "@angular/common": ">=16", + "@angular/core": ">=16" } }, "node_modules/@ngx-translate/http-loader": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-8.0.0.tgz", - "integrity": "sha512-SFMsdUcmHF5OdZkL1CHEoSAwbP5EbAOPTLLboOCRRoOg21P4GJx+51jxGdJeGve6LSKLf4Pay7BkTwmE6vxYlg==", - "engines": { - "node": "^16.13.0 || >=18.10.0" + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-16.0.1.tgz", + "integrity": "sha512-xJEOUpvs6Zfc8G4cmQmegFOEpfYSoplTHHoisPNrATXjRBjpaKsBaPOXlZsuFUW2XV00s16gIyI4+9z1XkO5bw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/common": ">=16.0.0", - "@angular/core": ">=16.0.0", - "@ngx-translate/core": ">=15.0.0", - "rxjs": "^6.5.5 || ^7.4.0" + "@angular/common": ">=16", + "@angular/core": ">=16" } }, "node_modules/@noble/hashes": { @@ -7381,6 +7269,12 @@ "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", "dev": true }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, "node_modules/@tailwindcss/aspect-ratio": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/@tailwindcss/aspect-ratio/-/aspect-ratio-0.4.2.tgz", @@ -9108,46 +9002,87 @@ } }, "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", "dev": true, + "license": "ISC", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/cliui/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/cliui/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" @@ -9931,7 +9866,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.12" }, @@ -12054,6 +11989,18 @@ "karma": "^6.0.0" } }, + "node_modules/karma-jasmine-html-reporter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.1.0.tgz", + "integrity": "sha512-sPQE1+nlsn6Hwb5t+HHwyy0A1FNCVKuL1192b+XNauMYWThz2kweiBVW1DqloRpVvZIJkIoHVB7XRpK78n1xbQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "jasmine-core": "^4.0.0 || ^5.0.0", + "karma": "^6.0.0", + "karma-jasmine": "^5.0.0" + } + }, "node_modules/karma-jasmine/node_modules/jasmine-core": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.6.0.tgz", @@ -14161,12 +14108,12 @@ } }, "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "optional": true, + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "license": "MIT", "dependencies": { - "entities": "^4.4.0" + "entities": "^8.0.0" }, "funding": { "url": "https://github.com/inikulin/parse5?sponsor=1" @@ -14200,32 +14147,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/parse5-html-rewriting-stream/node_modules/parse5": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", - "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", - "dev": true, - "license": "MIT", - "dependencies": { - "entities": "^8.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5-html-rewriting-stream/node_modules/parse5/node_modules/entities": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", - "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=20.19.0" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/parse5-sax-parser": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-8.0.0.tgz", @@ -14239,11 +14160,10 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/parse5-sax-parser/node_modules/entities": { + "node_modules/parse5/node_modules/entities": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=20.19.0" @@ -14252,19 +14172,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/parse5-sax-parser/node_modules/parse5": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", - "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", - "dev": true, - "license": "MIT", - "dependencies": { - "entities": "^8.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -16816,9 +16723,9 @@ "dev": true }, "node_modules/typescript": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", - "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -17778,30 +17685,85 @@ } }, "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", "dev": true, + "license": "MIT", "dependencies": { - "cliui": "^8.0.1", + "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", + "string-width": "^7.2.0", "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "yargs-parser": "^22.0.0" }, "engines": { - "node": ">=12" + "node": "^20.19.0 || ^22.12.0 || >=23" } }, "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/yocto-queue": { @@ -17864,9 +17826,9 @@ } }, "node_modules/zone.js": { - "version": "0.14.10", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.14.10.tgz", - "integrity": "sha512-YGAhaO7J5ywOXW6InXNlLmfU194F8lVgu7bRntUF3TiG8Y3nBK0x1UJJuHUP/e8IyihkjCYqhCScpSwnlaSRkQ==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.1.tgz", + "integrity": "sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==", "license": "MIT" } } diff --git a/ui/package.json b/ui/package.json index d430d975..9a83c62c 100644 --- a/ui/package.json +++ b/ui/package.json @@ -49,6 +49,7 @@ "karma-chrome-launcher": "~3.2.0", "karma-coverage": "~2.2.1", "karma-jasmine": "~5.1.0", + "karma-jasmine-html-reporter": "~2.1.0", "ngx-tailwind": "^4.0.0", "postcss": "^8.4.41", "tailwindcss": "^3.4.7", diff --git a/ui/src/app/app.component.ts b/ui/src/app/app.component.ts index 34c1fb4a..871c223c 100644 --- a/ui/src/app/app.component.ts +++ b/ui/src/app/app.component.ts @@ -6,6 +6,7 @@ import { TranslateService } from "@ngx-translate/core"; import defaultLanguage from "./../assets/i18n/en.json"; @Component({ selector: 'app-root', + standalone: false, templateUrl: './app.component.html' }) export class AppComponent implements OnInit { diff --git a/ui/src/app/modules/auth/pages/apikeys/add-apikey-dialog/add-apikey-dialog.component.ts b/ui/src/app/modules/auth/pages/apikeys/add-apikey-dialog/add-apikey-dialog.component.ts index 262c16c4..5ac42052 100644 --- a/ui/src/app/modules/auth/pages/apikeys/add-apikey-dialog/add-apikey-dialog.component.ts +++ b/ui/src/app/modules/auth/pages/apikeys/add-apikey-dialog/add-apikey-dialog.component.ts @@ -17,6 +17,7 @@ interface APIKeyForm { } @Component({ selector: 'learninghouse-add-apikey', + standalone: false, templateUrl: './add-apikey-dialog.component.html' }) export class AddAPIKeyDialogComponent extends AbstractFormResponse implements OnDestroy { diff --git a/ui/src/app/modules/auth/pages/apikeys/apikeys.component.ts b/ui/src/app/modules/auth/pages/apikeys/apikeys.component.ts index 5ac6ccfb..ce9f662d 100644 --- a/ui/src/app/modules/auth/pages/apikeys/apikeys.component.ts +++ b/ui/src/app/modules/auth/pages/apikeys/apikeys.component.ts @@ -16,6 +16,7 @@ interface APIKeyTableModel extends APIKeyModel { @Component({ selector: 'learninghouse-apikeys', + standalone: false, templateUrl: './apikeys.component.html' }) export class APIKeysComponent implements AfterViewInit, OnDestroy { diff --git a/ui/src/app/modules/auth/pages/change-password/change-password.component.ts b/ui/src/app/modules/auth/pages/change-password/change-password.component.ts index a81effa5..eee7ea7d 100644 --- a/ui/src/app/modules/auth/pages/change-password/change-password.component.ts +++ b/ui/src/app/modules/auth/pages/change-password/change-password.component.ts @@ -18,6 +18,7 @@ export interface ChangePasswordForm { @Component({ selector: 'learninghouse-change-password', + standalone: false, templateUrl: './change-password.component.html', styleUrls: ['./change-password.component.scss'] }) diff --git a/ui/src/app/modules/auth/pages/login/login.component.ts b/ui/src/app/modules/auth/pages/login/login.component.ts index 0895bfeb..7e7ad1ed 100644 --- a/ui/src/app/modules/auth/pages/login/login.component.ts +++ b/ui/src/app/modules/auth/pages/login/login.component.ts @@ -18,6 +18,7 @@ interface NormalPasswordForm { @Component({ selector: 'learninghouse-login', + standalone: false, templateUrl: './login.component.html', styleUrls: ['./login.component.scss'] }) diff --git a/ui/src/app/modules/brains/components/braininfo/braininfo.component.ts b/ui/src/app/modules/brains/components/braininfo/braininfo.component.ts index c96531af..577e84da 100644 --- a/ui/src/app/modules/brains/components/braininfo/braininfo.component.ts +++ b/ui/src/app/modules/brains/components/braininfo/braininfo.component.ts @@ -3,6 +3,7 @@ import { BrainInfoModel } from '../../brains.model'; @Component({ selector: 'learninghouse-braininfo', + standalone: false, templateUrl: './braininfo.component.html' }) export class BraininfoComponent { diff --git a/ui/src/app/modules/brains/pages/brains/add-edit-brain-dialog/add-edit-brain-dialog.component.ts b/ui/src/app/modules/brains/pages/brains/add-edit-brain-dialog/add-edit-brain-dialog.component.ts index 6d1c4d5f..026c9450 100644 --- a/ui/src/app/modules/brains/pages/brains/add-edit-brain-dialog/add-edit-brain-dialog.component.ts +++ b/ui/src/app/modules/brains/pages/brains/add-edit-brain-dialog/add-edit-brain-dialog.component.ts @@ -23,6 +23,7 @@ interface BrainConfigurationForm { @Component({ selector: 'app-add-edit-brain-dialog', + standalone: false, templateUrl: './add-edit-brain-dialog.component.html', styleUrls: ['./add-edit-brain-dialog.component.scss'] }) diff --git a/ui/src/app/modules/brains/pages/brains/brains.component.ts b/ui/src/app/modules/brains/pages/brains/brains.component.ts index a4dc016a..edfb81d5 100644 --- a/ui/src/app/modules/brains/pages/brains/brains.component.ts +++ b/ui/src/app/modules/brains/pages/brains/brains.component.ts @@ -24,6 +24,7 @@ interface BrainsTableModel extends BrainInfoModel { @Component({ selector: 'app-brains', + standalone: false, templateUrl: './brains.component.html' }) export class BrainsComponent implements AfterViewInit, OnDestroy { diff --git a/ui/src/app/modules/brains/pages/prediction/prediction.component.ts b/ui/src/app/modules/brains/pages/prediction/prediction.component.ts index 4d9747c4..0724b031 100644 --- a/ui/src/app/modules/brains/pages/prediction/prediction.component.ts +++ b/ui/src/app/modules/brains/pages/prediction/prediction.component.ts @@ -2,6 +2,7 @@ import { Component } from '@angular/core'; @Component({ selector: 'app-prediction', + standalone: false, templateUrl: './prediction.component.html' }) export class PredictionComponent { diff --git a/ui/src/app/modules/brains/pages/training/training.component.ts b/ui/src/app/modules/brains/pages/training/training.component.ts index a4410143..8bd94f8d 100644 --- a/ui/src/app/modules/brains/pages/training/training.component.ts +++ b/ui/src/app/modules/brains/pages/training/training.component.ts @@ -5,6 +5,7 @@ import { ActivatedRoute } from '@angular/router'; @Component({ selector: 'app-training', + standalone: false, templateUrl: './training.component.html', styleUrls: ['./training.component.scss'] }) diff --git a/ui/src/app/modules/configuration/pages/sensors/add-edit-sensor-dialog/add-edit-sensor-dialog.component.ts b/ui/src/app/modules/configuration/pages/sensors/add-edit-sensor-dialog/add-edit-sensor-dialog.component.ts index d58bfa45..34af5bfe 100644 --- a/ui/src/app/modules/configuration/pages/sensors/add-edit-sensor-dialog/add-edit-sensor-dialog.component.ts +++ b/ui/src/app/modules/configuration/pages/sensors/add-edit-sensor-dialog/add-edit-sensor-dialog.component.ts @@ -17,6 +17,7 @@ interface SensorForm { @Component({ selector: 'app-add-edit-sensor-dialog', + standalone: false, templateUrl: './add-edit-sensor-dialog.component.html' }) export class AddEditSensorDialogComponent extends AbstractFormResponse implements OnInit, OnDestroy { diff --git a/ui/src/app/modules/configuration/pages/sensors/sensors.component.ts b/ui/src/app/modules/configuration/pages/sensors/sensors.component.ts index abe13193..9c9231cf 100644 --- a/ui/src/app/modules/configuration/pages/sensors/sensors.component.ts +++ b/ui/src/app/modules/configuration/pages/sensors/sensors.component.ts @@ -16,6 +16,7 @@ interface SensorTableModel extends SensorConfigurationModel { @Component({ selector: 'app-sensors', + standalone: false, templateUrl: './sensors.component.html' }) export class SensorsComponent implements AfterViewInit, OnDestroy { diff --git a/ui/src/app/modules/layout/components/info-dialog/info-dialog.component.ts b/ui/src/app/modules/layout/components/info-dialog/info-dialog.component.ts index d8821a26..a2fdd0d2 100644 --- a/ui/src/app/modules/layout/components/info-dialog/info-dialog.component.ts +++ b/ui/src/app/modules/layout/components/info-dialog/info-dialog.component.ts @@ -8,6 +8,7 @@ import { AppService } from 'src/app/shared/services/app.service'; @Component({ selector: 'lh-info-dialog', + standalone: false, templateUrl: './info-dialog.component.html', styleUrls: ['./info-dialog.component.scss'] }) diff --git a/ui/src/app/modules/layout/components/sidenav/sidenav.component.ts b/ui/src/app/modules/layout/components/sidenav/sidenav.component.ts index f88c42ea..a00aa688 100644 --- a/ui/src/app/modules/layout/components/sidenav/sidenav.component.ts +++ b/ui/src/app/modules/layout/components/sidenav/sidenav.component.ts @@ -16,6 +16,7 @@ export interface SidenavItem { @Component({ selector: 'app-sidenav', + standalone: false, templateUrl: './sidenav.component.html', styleUrls: ['./sidenav.component.scss'] }) diff --git a/ui/src/app/modules/layout/components/toolbar/toolbar.component.ts b/ui/src/app/modules/layout/components/toolbar/toolbar.component.ts index b3169855..816205aa 100644 --- a/ui/src/app/modules/layout/components/toolbar/toolbar.component.ts +++ b/ui/src/app/modules/layout/components/toolbar/toolbar.component.ts @@ -8,6 +8,7 @@ import { BreakpointService } from 'src/app/shared/services/breakpoint.service'; @Component({ selector: 'app-toolbar', + standalone: false, templateUrl: './toolbar.component.html' }) export class ToolbarComponent { diff --git a/ui/src/app/shared/components/alert/alert.component.ts b/ui/src/app/shared/components/alert/alert.component.ts index 8f3fc222..925d29bc 100644 --- a/ui/src/app/shared/components/alert/alert.component.ts +++ b/ui/src/app/shared/components/alert/alert.component.ts @@ -16,6 +16,7 @@ export class AlertType { @Component({ selector: 'learninghouse-alert', + standalone: false, templateUrl: './alert.component.html', styleUrls: ['./alert.component.scss'] }) diff --git a/ui/src/app/shared/components/button-group/button-group.component.spec.ts b/ui/src/app/shared/components/button-group/button-group.component.spec.ts index bc48d7f5..b302d0b0 100644 --- a/ui/src/app/shared/components/button-group/button-group.component.spec.ts +++ b/ui/src/app/shared/components/button-group/button-group.component.spec.ts @@ -3,8 +3,8 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ButtonGroupComponent } from './button-group.component'; describe('ButtonGroupComponent', () => { - let component: ButtonGroupComponent; - let fixture: ComponentFixture; + let component: ButtonGroupComponent; + let fixture: ComponentFixture>; beforeEach(async () => { await TestBed.configureTestingModule({ diff --git a/ui/src/app/shared/components/button-group/button-group.component.ts b/ui/src/app/shared/components/button-group/button-group.component.ts index e0727885..e111bd6f 100644 --- a/ui/src/app/shared/components/button-group/button-group.component.ts +++ b/ui/src/app/shared/components/button-group/button-group.component.ts @@ -8,6 +8,7 @@ import { SelectOption } from '../select/select.component'; @Component({ selector: 'learninghouse-button-group', + standalone: false, templateUrl: './button-group.component.html', styleUrls: ['./button-group.component.scss'], providers: [{ provide: MatFormFieldControl, useExisting: ButtonGroupComponent }], diff --git a/ui/src/app/shared/components/edit-dialog/edit-dialog.component.ts b/ui/src/app/shared/components/edit-dialog/edit-dialog.component.ts index df4312ce..b55dfeea 100644 --- a/ui/src/app/shared/components/edit-dialog/edit-dialog.component.ts +++ b/ui/src/app/shared/components/edit-dialog/edit-dialog.component.ts @@ -20,6 +20,7 @@ export interface EditDialogConfig { @Component({ selector: 'learninghouse-edit-dialog', + standalone: false, templateUrl: './edit-dialog.component.html', styleUrls: ['./edit-dialog.component.scss'] }) diff --git a/ui/src/app/shared/components/form-response/form-response.component.ts b/ui/src/app/shared/components/form-response/form-response.component.ts index eef6eed4..ad62c57e 100644 --- a/ui/src/app/shared/components/form-response/form-response.component.ts +++ b/ui/src/app/shared/components/form-response/form-response.component.ts @@ -7,6 +7,7 @@ export interface FormResponseConfig { } @Component({ selector: 'learninghouse-form-response', + standalone: false, templateUrl: './form-response.component.html', styleUrls: ['./form-response.component.scss'] }) diff --git a/ui/src/app/shared/components/input/input.component.ts b/ui/src/app/shared/components/input/input.component.ts index 8d586867..a5d7faa4 100644 --- a/ui/src/app/shared/components/input/input.component.ts +++ b/ui/src/app/shared/components/input/input.component.ts @@ -3,6 +3,7 @@ import { InputDirective } from './input.directive'; @Component({ selector: 'learninghouse-input', + standalone: false, templateUrl: './input.component.html', styleUrls: ['./input.component.scss'] }) diff --git a/ui/src/app/shared/components/password/password.component.ts b/ui/src/app/shared/components/password/password.component.ts index dbf7056c..a66eb9dd 100644 --- a/ui/src/app/shared/components/password/password.component.ts +++ b/ui/src/app/shared/components/password/password.component.ts @@ -3,6 +3,7 @@ import { InputDirective } from '../input/input.directive'; @Component({ selector: 'learninghouse-password', + standalone: false, templateUrl: './password.component.html' }) export class PasswordComponent extends InputDirective { diff --git a/ui/src/app/shared/components/select/select.component.ts b/ui/src/app/shared/components/select/select.component.ts index e17e4092..f5210749 100644 --- a/ui/src/app/shared/components/select/select.component.ts +++ b/ui/src/app/shared/components/select/select.component.ts @@ -8,6 +8,7 @@ export interface SelectOption { @Component({ selector: 'learninghouse-select', + standalone: false, templateUrl: './select.component.html', styleUrls: ['./select.component.scss'] }) diff --git a/ui/src/app/shared/components/session-timer/session-timer.component.ts b/ui/src/app/shared/components/session-timer/session-timer.component.ts index 51be155d..b7e34268 100644 --- a/ui/src/app/shared/components/session-timer/session-timer.component.ts +++ b/ui/src/app/shared/components/session-timer/session-timer.component.ts @@ -3,6 +3,7 @@ import { BehaviorSubject, ReplaySubject, interval, takeUntil } from 'rxjs'; @Component({ selector: 'learninghouse-session-timer', + standalone: false, templateUrl: './session-timer.component.html', styleUrls: ['./session-timer.component.scss'] }) diff --git a/ui/src/app/shared/components/table/delete-dialog/delete-dialog.component.ts b/ui/src/app/shared/components/table/delete-dialog/delete-dialog.component.ts index 87675bd5..7944c1b4 100644 --- a/ui/src/app/shared/components/table/delete-dialog/delete-dialog.component.ts +++ b/ui/src/app/shared/components/table/delete-dialog/delete-dialog.component.ts @@ -2,6 +2,7 @@ import { Component } from '@angular/core'; @Component({ selector: 'app-delete-dialog', + standalone: false, templateUrl: './delete-dialog.component.html', styleUrls: ['./delete-dialog.component.scss'] }) diff --git a/ui/src/app/shared/components/table/table.component.ts b/ui/src/app/shared/components/table/table.component.ts index 46705f3e..2c04991b 100644 --- a/ui/src/app/shared/components/table/table.component.ts +++ b/ui/src/app/shared/components/table/table.component.ts @@ -43,6 +43,7 @@ export interface TableConfig { @Component({ selector: 'learninghouse-table', + standalone: false, templateUrl: './table.component.html', styleUrls: ['./table.component.scss'] }) diff --git a/ui/src/app/shared/components/yes-no/yes-no.component.ts b/ui/src/app/shared/components/yes-no/yes-no.component.ts index 879612da..eef395eb 100644 --- a/ui/src/app/shared/components/yes-no/yes-no.component.ts +++ b/ui/src/app/shared/components/yes-no/yes-no.component.ts @@ -4,6 +4,7 @@ import { SelectOption } from "../select/select.component"; @Component({ selector: 'learninghouse-yes-no', + standalone: false, templateUrl: './yes-no.component.html' }) export class YesNoComponent extends InputDirective { From 6c5ff19137a4fd1aae70c163e5630b20aaa71d72 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 10:48:37 +0000 Subject: [PATCH 3/6] Fix workflow Node version and remaining Angular spec Agent-Logs-Url: https://github.com/LearningHouseService/learninghouse/sessions/2a14e06b-f4c3-4d68-8512-e8595f063ff2 Co-authored-by: DerOetzi <2345662+DerOetzi@users.noreply.github.com> --- .github/workflows/build_project.yml | 14 ++++---- ui/src/app/app.component.spec.ts | 24 ++++++++++++-- .../braininfo/braininfo.component.spec.ts | 10 +++++- .../add-edit-brain-dialog.component.spec.ts | 27 +++++++++++++++- .../pages/training/training.component.spec.ts | 15 ++++++++- .../add-edit-sensor-dialog.component.spec.ts | 27 +++++++++++++++- .../sidenav/sidenav.component.spec.ts | 31 +++++++++++++++++- .../toolbar/toolbar.component.spec.ts | 32 ++++++++++++++++++- .../components/alert/alert.component.spec.ts | 4 ++- .../button-group.component.spec.ts | 23 ++++++++++++- .../session-timer.component.spec.ts | 10 +++++- 11 files changed, 199 insertions(+), 18 deletions(-) diff --git a/.github/workflows/build_project.yml b/.github/workflows/build_project.yml index a991a664..cfaef2a2 100644 --- a/.github/workflows/build_project.yml +++ b/.github/workflows/build_project.yml @@ -34,12 +34,12 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '18' - cache: 'npm' - cache-dependency-path: ui/package-lock.json + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '24' + cache: 'npm' + cache-dependency-path: ui/package-lock.json - name: Install dependencies run: npm install @@ -206,4 +206,4 @@ jobs: tags: ${{github.event_name == 'release' && steps.meta_release.outputs.tags || steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - \ No newline at end of file + diff --git a/ui/src/app/app.component.spec.ts b/ui/src/app/app.component.spec.ts index 773f514d..06ab1d0e 100644 --- a/ui/src/app/app.component.spec.ts +++ b/ui/src/app/app.component.spec.ts @@ -1,16 +1,35 @@ +import { NO_ERRORS_SCHEMA } from '@angular/core'; import { TestBed } from '@angular/core/testing'; +import { MatIconRegistry } from '@angular/material/icon'; +import { DomSanitizer } from '@angular/platform-browser'; import { RouterTestingModule } from '@angular/router/testing'; +import { TranslateModule } from '@ngx-translate/core'; import { AppComponent } from './app.component'; +import { AuthService } from './modules/auth/auth.service'; describe('AppComponent', () => { + const authService = jasmine.createSpyObj('AuthService', ['restoreSession']); + const matIconRegistry = jasmine.createSpyObj('MatIconRegistry', ['addSvgIcon']); + beforeEach(async () => { await TestBed.configureTestingModule({ imports: [ - RouterTestingModule + RouterTestingModule, + TranslateModule.forRoot() ], declarations: [ AppComponent ], + providers: [ + { provide: AuthService, useValue: authService }, + { provide: MatIconRegistry, useValue: matIconRegistry }, + { + provide: DomSanitizer, useValue: { + bypassSecurityTrustResourceUrl: (value: string) => value + } + } + ], + schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); }); @@ -30,6 +49,7 @@ describe('AppComponent', () => { const fixture = TestBed.createComponent(AppComponent); fixture.detectChanges(); const compiled = fixture.nativeElement as HTMLElement; - expect(compiled.querySelector('.content span')?.textContent).toContain('learninghouse app is running!'); + expect(compiled.querySelector('app-toolbar')).not.toBeNull(); + expect(compiled.querySelector('app-sidenav')).not.toBeNull(); }); }); diff --git a/ui/src/app/modules/brains/components/braininfo/braininfo.component.spec.ts b/ui/src/app/modules/brains/components/braininfo/braininfo.component.spec.ts index a7978169..54eab87e 100644 --- a/ui/src/app/modules/brains/components/braininfo/braininfo.component.spec.ts +++ b/ui/src/app/modules/brains/components/braininfo/braininfo.component.spec.ts @@ -1,4 +1,7 @@ +import { CommonModule } from '@angular/common'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { TranslateModule } from '@ngx-translate/core'; import { BraininfoComponent } from './braininfo.component'; @@ -8,7 +11,12 @@ describe('BraininfoComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ BraininfoComponent ] + imports: [ + CommonModule, + TranslateModule.forRoot() + ], + declarations: [BraininfoComponent], + schemas: [NO_ERRORS_SCHEMA] }) .compileComponents(); diff --git a/ui/src/app/modules/brains/pages/brains/add-edit-brain-dialog/add-edit-brain-dialog.component.spec.ts b/ui/src/app/modules/brains/pages/brains/add-edit-brain-dialog/add-edit-brain-dialog.component.spec.ts index ff76c2c1..0e358579 100644 --- a/ui/src/app/modules/brains/pages/brains/add-edit-brain-dialog/add-edit-brain-dialog.component.spec.ts +++ b/ui/src/app/modules/brains/pages/brains/add-edit-brain-dialog/add-edit-brain-dialog.component.spec.ts @@ -1,14 +1,39 @@ +import { CommonModule } from '@angular/common'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { TranslateModule } from '@ngx-translate/core'; +import { of } from 'rxjs'; +import { EditDialogActionsService } from 'src/app/shared/services/edit-dialog-actions.service'; +import { BrainsService } from '../../../brains.service'; import { AddEditBrainDialogComponent } from './add-edit-brain-dialog.component'; describe('AddEditBrainDialogComponent', () => { let component: AddEditBrainDialogComponent; let fixture: ComponentFixture; + const dialogRef = { disableClose: false, close: jasmine.createSpy('close') }; + const brainsService = { + createBrain: jasmine.createSpy('createBrain').and.returnValue(of({})), + updateBrain: jasmine.createSpy('updateBrain').and.returnValue(of({})) + }; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ AddEditBrainDialogComponent ] + imports: [ + CommonModule, + ReactiveFormsModule, + TranslateModule.forRoot() + ], + declarations: [AddEditBrainDialogComponent], + providers: [ + { provide: MatDialogRef, useValue: dialogRef }, + { provide: MAT_DIALOG_DATA, useValue: null }, + { provide: BrainsService, useValue: brainsService }, + EditDialogActionsService + ], + schemas: [NO_ERRORS_SCHEMA] }) .compileComponents(); diff --git a/ui/src/app/modules/brains/pages/training/training.component.spec.ts b/ui/src/app/modules/brains/pages/training/training.component.spec.ts index 742a8a54..9f302304 100644 --- a/ui/src/app/modules/brains/pages/training/training.component.spec.ts +++ b/ui/src/app/modules/brains/pages/training/training.component.spec.ts @@ -1,4 +1,9 @@ +import { CommonModule } from '@angular/common'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ActivatedRoute } from '@angular/router'; +import { TranslateModule } from '@ngx-translate/core'; +import { of } from 'rxjs'; import { TrainingComponent } from './training.component'; @@ -8,7 +13,15 @@ describe('TrainingComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ TrainingComponent ] + imports: [ + CommonModule, + TranslateModule.forRoot() + ], + declarations: [TrainingComponent], + providers: [ + { provide: ActivatedRoute, useValue: { data: of({}) } } + ], + schemas: [NO_ERRORS_SCHEMA] }) .compileComponents(); diff --git a/ui/src/app/modules/configuration/pages/sensors/add-edit-sensor-dialog/add-edit-sensor-dialog.component.spec.ts b/ui/src/app/modules/configuration/pages/sensors/add-edit-sensor-dialog/add-edit-sensor-dialog.component.spec.ts index d39da53d..e7a4464e 100644 --- a/ui/src/app/modules/configuration/pages/sensors/add-edit-sensor-dialog/add-edit-sensor-dialog.component.spec.ts +++ b/ui/src/app/modules/configuration/pages/sensors/add-edit-sensor-dialog/add-edit-sensor-dialog.component.spec.ts @@ -1,14 +1,39 @@ +import { CommonModule } from '@angular/common'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { of } from 'rxjs'; +import { EditDialogActionsService } from 'src/app/shared/services/edit-dialog-actions.service'; +import { TranslateModule } from '@ngx-translate/core'; +import { SensorConfigurationService } from '../../../services/sensor-configuration.service'; import { AddEditSensorDialogComponent } from './add-edit-sensor-dialog.component'; describe('AddEditSensorDialogComponent', () => { let component: AddEditSensorDialogComponent; let fixture: ComponentFixture; + const dialogRef = { disableClose: false, close: jasmine.createSpy('close') }; + const configService = { + createSensor: jasmine.createSpy('createSensor').and.returnValue(of({})), + updateSensor: jasmine.createSpy('updateSensor').and.returnValue(of({})) + }; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ AddEditSensorDialogComponent ] + imports: [ + CommonModule, + ReactiveFormsModule, + TranslateModule.forRoot() + ], + declarations: [AddEditSensorDialogComponent], + providers: [ + { provide: MatDialogRef, useValue: dialogRef }, + { provide: MAT_DIALOG_DATA, useValue: null }, + { provide: SensorConfigurationService, useValue: configService }, + EditDialogActionsService + ], + schemas: [NO_ERRORS_SCHEMA] }) .compileComponents(); diff --git a/ui/src/app/modules/layout/components/sidenav/sidenav.component.spec.ts b/ui/src/app/modules/layout/components/sidenav/sidenav.component.spec.ts index 646caccd..80238169 100644 --- a/ui/src/app/modules/layout/components/sidenav/sidenav.component.spec.ts +++ b/ui/src/app/modules/layout/components/sidenav/sidenav.component.spec.ts @@ -1,14 +1,43 @@ +import { CommonModule } from '@angular/common'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { Router } from '@angular/router'; +import { TranslateModule } from '@ngx-translate/core'; +import { BehaviorSubject } from 'rxjs'; +import { AuthService } from 'src/app/modules/auth/auth.service'; +import { BreakpointService } from 'src/app/shared/services/breakpoint.service'; +import { SidenavService } from './sidenav.service'; import { SidenavComponent } from './sidenav.component'; describe('SidenavComponent', () => { let component: SidenavComponent; let fixture: ComponentFixture; + const sidenavService = { + isOpened$: new BehaviorSubject(false), + toggleNavigation: jasmine.createSpy('toggleNavigation') + }; + const authService = { + role$: new BehaviorSubject(null), + logout: jasmine.createSpy('logout') + }; + const breakpoints = { isSmall$: new BehaviorSubject(false) }; + const router = jasmine.createSpyObj('Router', ['navigate']); beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ SidenavComponent ] + imports: [ + CommonModule, + TranslateModule.forRoot() + ], + declarations: [SidenavComponent], + providers: [ + { provide: SidenavService, useValue: sidenavService }, + { provide: AuthService, useValue: authService }, + { provide: BreakpointService, useValue: breakpoints }, + { provide: Router, useValue: router } + ], + schemas: [NO_ERRORS_SCHEMA] }) .compileComponents(); diff --git a/ui/src/app/modules/layout/components/toolbar/toolbar.component.spec.ts b/ui/src/app/modules/layout/components/toolbar/toolbar.component.spec.ts index b02a01bf..3954f807 100644 --- a/ui/src/app/modules/layout/components/toolbar/toolbar.component.spec.ts +++ b/ui/src/app/modules/layout/components/toolbar/toolbar.component.spec.ts @@ -1,14 +1,44 @@ +import { CommonModule } from '@angular/common'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MatDialog } from '@angular/material/dialog'; +import { Router } from '@angular/router'; +import { TranslateModule } from '@ngx-translate/core'; +import { BehaviorSubject } from 'rxjs'; +import { AuthService } from 'src/app/modules/auth/auth.service'; +import { BreakpointService } from 'src/app/shared/services/breakpoint.service'; +import { SidenavService } from '../sidenav/sidenav.service'; import { ToolbarComponent } from './toolbar.component'; describe('ToolbarComponent', () => { let component: ToolbarComponent; let fixture: ComponentFixture; + const sidenavService = { toggleNavigation: jasmine.createSpy('toggleNavigation') }; + const authService = { + refreshTokenExpireDate$: new BehaviorSubject(null), + logout: jasmine.createSpy('logout'), + refreshToken: jasmine.createSpy('refreshToken').and.returnValue(null) + }; + const breakpoints = { isSmall$: new BehaviorSubject(false) }; + const dialog = { open: jasmine.createSpy('open') }; + const router = jasmine.createSpyObj('Router', ['navigate']); beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ ToolbarComponent ] + imports: [ + CommonModule, + TranslateModule.forRoot() + ], + declarations: [ToolbarComponent], + providers: [ + { provide: SidenavService, useValue: sidenavService }, + { provide: AuthService, useValue: authService }, + { provide: BreakpointService, useValue: breakpoints }, + { provide: MatDialog, useValue: dialog }, + { provide: Router, useValue: router } + ], + schemas: [NO_ERRORS_SCHEMA] }) .compileComponents(); diff --git a/ui/src/app/shared/components/alert/alert.component.spec.ts b/ui/src/app/shared/components/alert/alert.component.spec.ts index 49c8d86d..6183f1aa 100644 --- a/ui/src/app/shared/components/alert/alert.component.spec.ts +++ b/ui/src/app/shared/components/alert/alert.component.spec.ts @@ -1,3 +1,4 @@ +import { NO_ERRORS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { AlertComponent } from './alert.component'; @@ -8,7 +9,8 @@ describe('AlertComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ AlertComponent ] + declarations: [AlertComponent], + schemas: [NO_ERRORS_SCHEMA] }) .compileComponents(); diff --git a/ui/src/app/shared/components/button-group/button-group.component.spec.ts b/ui/src/app/shared/components/button-group/button-group.component.spec.ts index b302d0b0..fd79f9e8 100644 --- a/ui/src/app/shared/components/button-group/button-group.component.spec.ts +++ b/ui/src/app/shared/components/button-group/button-group.component.spec.ts @@ -1,4 +1,10 @@ +import { CommonModule } from '@angular/common'; +import { FocusMonitor } from '@angular/cdk/a11y'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MAT_FORM_FIELD } from '@angular/material/form-field'; +import { TranslateModule } from '@ngx-translate/core'; import { ButtonGroupComponent } from './button-group.component'; @@ -8,7 +14,22 @@ describe('ButtonGroupComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ ButtonGroupComponent ] + imports: [ + CommonModule, + ReactiveFormsModule, + TranslateModule.forRoot() + ], + declarations: [ButtonGroupComponent], + providers: [ + { + provide: FocusMonitor, useValue: { + stopMonitoring: () => undefined, + focusVia: () => undefined + } + }, + { provide: MAT_FORM_FIELD, useValue: { getLabelId: () => 'button-group-label' } } + ], + schemas: [NO_ERRORS_SCHEMA] }) .compileComponents(); diff --git a/ui/src/app/shared/components/session-timer/session-timer.component.spec.ts b/ui/src/app/shared/components/session-timer/session-timer.component.spec.ts index d3a4ec07..4b6ce39f 100644 --- a/ui/src/app/shared/components/session-timer/session-timer.component.spec.ts +++ b/ui/src/app/shared/components/session-timer/session-timer.component.spec.ts @@ -1,4 +1,7 @@ +import { CommonModule } from '@angular/common'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { TranslateModule } from '@ngx-translate/core'; import { SessionTimerComponent } from './session-timer.component'; @@ -8,7 +11,12 @@ describe('SessionTimerComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ SessionTimerComponent ] + imports: [ + CommonModule, + TranslateModule.forRoot() + ], + declarations: [SessionTimerComponent], + schemas: [NO_ERRORS_SCHEMA] }) .compileComponents(); From 01befd7b262ef6e86a141935007221084bb98961 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 10:49:46 +0000 Subject: [PATCH 4/6] Finalize Angular testbed fixes and align CI Node runtime Agent-Logs-Url: https://github.com/LearningHouseService/learninghouse/sessions/2a14e06b-f4c3-4d68-8512-e8595f063ff2 Co-authored-by: DerOetzi <2345662+DerOetzi@users.noreply.github.com> --- .../components/button-group/button-group.component.spec.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui/src/app/shared/components/button-group/button-group.component.spec.ts b/ui/src/app/shared/components/button-group/button-group.component.spec.ts index fd79f9e8..b67405d7 100644 --- a/ui/src/app/shared/components/button-group/button-group.component.spec.ts +++ b/ui/src/app/shared/components/button-group/button-group.component.spec.ts @@ -3,6 +3,8 @@ import { FocusMonitor } from '@angular/cdk/a11y'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { MAT_FORM_FIELD } from '@angular/material/form-field'; import { TranslateModule } from '@ngx-translate/core'; @@ -17,6 +19,8 @@ describe('ButtonGroupComponent', () => { imports: [ CommonModule, ReactiveFormsModule, + NoopAnimationsModule, + MatButtonToggleModule, TranslateModule.forRoot() ], declarations: [ButtonGroupComponent], From 332e4658bf9df594a3e942c1398926dbf21a416d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 10:54:24 +0000 Subject: [PATCH 5/6] Fix workflow YAML indentation Agent-Logs-Url: https://github.com/LearningHouseService/learninghouse/sessions/625c6002-8cd9-444a-b29d-ac2511e1f590 Co-authored-by: DerOetzi <2345662+DerOetzi@users.noreply.github.com> --- .github/workflows/build_project.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build_project.yml b/.github/workflows/build_project.yml index cfaef2a2..16fc3073 100644 --- a/.github/workflows/build_project.yml +++ b/.github/workflows/build_project.yml @@ -34,12 +34,12 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '24' - cache: 'npm' - cache-dependency-path: ui/package-lock.json + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '24' + cache: 'npm' + cache-dependency-path: ui/package-lock.json - name: Install dependencies run: npm install From cc75355d53011bfff030035bb514758d7a956288 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 11:02:41 +0000 Subject: [PATCH 6/6] Fix UI artifact path for core package build Agent-Logs-Url: https://github.com/LearningHouseService/learninghouse/sessions/b94fe940-fefb-4e73-9cec-76a1a8616e68 Co-authored-by: DerOetzi <2345662+DerOetzi@users.noreply.github.com> --- .github/workflows/build_project.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_project.yml b/.github/workflows/build_project.yml index 16fc3073..e0fdba70 100644 --- a/.github/workflows/build_project.yml +++ b/.github/workflows/build_project.yml @@ -54,7 +54,7 @@ jobs: with: name: ui-artifacts-${{ env.REF_NAME }} path: | - ui/dist/learninghouse + ui/dist/learninghouse/browser/** build-core: runs-on: ubuntu-latest