From d93004396555c271a59cf524068db62d5840bcd4 Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Thu, 27 Nov 2025 17:59:19 -0800 Subject: [PATCH 01/27] feat: converted project to zoneless --- angular.json | 1 - eslint.config.mjs | 7 - npm-shrinkwrap.json | 1026 +++++++---------- package.json | 5 +- src/app/_helpers/toast.service.ts | 15 +- .../_helpers/toasts-container.component.ts | 27 +- .../domain-list/domain-list.component.html | 24 +- .../domain-list/domain-list.component.ts | 54 +- .../changelog/changelog.component.html | 8 +- .../changelog/changelog.component.ts | 24 +- .../domain-module/common/basic-component.ts | 5 + .../domain-module/common/detail-component.ts | 12 +- .../element-autocomplete.component.ts | 4 +- .../domain-module/common/list-component.ts | 15 +- .../components/components.component.html | 22 +- .../components/components.component.ts | 56 +- .../config-detail.component.html | 24 +- .../config-detail/config-detail.component.ts | 100 +- .../config-list/config-list.component.html | 22 +- .../config-list/config-list.component.ts | 35 +- .../relay-detail/relay-detail.component.html | 26 +- .../relay-detail/relay-detail.component.ts | 34 +- .../strategy-clone.component.html | 2 +- .../strategy-clone.component.ts | 8 +- .../strategy-create.component.html | 10 +- .../strategy-create.component.ts | 43 +- .../strategy-detail.component.html | 26 +- .../strategy-detail.component.ts | 50 +- .../strategy-list.component.html | 4 +- .../strategy-list/strategy-list.component.ts | 13 +- .../domain-detail.component.html | 8 +- .../domain-detail/domain-detail.component.ts | 12 +- .../domain-transfer-dialog.component.ts | 2 +- .../domain/domain.component.html | 36 +- .../domain-module/domain/domain.component.ts | 72 +- .../environments/environments.component.html | 20 +- .../environments/environments.component.ts | 50 +- .../ext-gitops/ext-gitops.component.html | 4 +- .../ext-gitops/ext-gitops.component.ts | 8 +- .../ext-slack/ext-slack.component.html | 2 +- .../ext-slack/ext-slack.component.ts | 6 +- .../group-detail/group-detail.component.html | 10 +- .../group-detail/group-detail.component.ts | 14 +- .../group-list/group-list.component.html | 20 +- .../group/group-list/group-list.component.ts | 35 +- .../metric-filter.component.html | 4 +- .../metric-statistics.component.ts | 2 +- .../team-detail/team-detail.component.html | 30 +- .../team-detail/team-detail.component.ts | 72 +- .../team-invite-dialog.component.ts | 2 +- .../team-members/team-members.component.html | 6 +- .../team-members/team-members.component.ts | 20 +- .../team-pending-members.component.html | 2 +- .../team-pending-members.component.ts | 10 +- .../team-permission-create.component.html | 8 +- .../team-permission-create.component.ts | 28 +- .../team-permissions.component.html | 2 +- .../team-permissions.component.ts | 12 +- .../team-preview/team-preview.component.html | 8 +- .../team-preview/team-preview.component.ts | 14 +- .../team-module/team/team.component.html | 22 +- .../team-module/team/team.component.ts | 64 +- .../documentation.module.ts | 7 +- src/app/login/login.component.html | 2 +- src/app/login/login.component.ts | 6 +- .../settings-account.component.html | 14 +- .../settings-account.component.ts | 29 +- .../signup-domain/signup-domain.component.ts | 2 +- .../lib/recaptcha-value-accessor.directive.ts | 2 +- .../lib/recaptcha.component.ts | 4 +- .../ng2-charts/src/lib/ng-charts.provider.ts | 2 +- src/main.ts | 3 +- tsconfig.json | 4 +- 73 files changed, 1132 insertions(+), 1250 deletions(-) diff --git a/angular.json b/angular.json index fe516430..c3010355 100644 --- a/angular.json +++ b/angular.json @@ -18,7 +18,6 @@ }, "index": "src/index.html", "polyfills": [ - "zone.js", "@angular/localize/init" ], "tsConfig": "tsconfig.app.json", diff --git a/eslint.config.mjs b/eslint.config.mjs index f50af548..d34c5d4f 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -13,13 +13,6 @@ export default defineConfig({ ], processor: angular.processInlineTemplates, rules: { - "@angular-eslint/directive-selector": [ - "error", - { - type: "attribute", - prefix: "app" - }, - ], "@angular-eslint/component-selector": [ "error", { diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 0ec388ef..a627d0e2 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -15,6 +15,7 @@ "@angular/compiler": "~20.3.9", "@angular/core": "~20.3.9", "@angular/forms": "~20.3.9", + "@angular/localize": "~20.3.9", "@angular/material": "~20.2.11", "@angular/platform-browser": "~20.3.9", "@angular/platform-browser-dynamic": "~20.3.9", @@ -25,7 +26,7 @@ "@types/grecaptcha": "^3.0.9", "apollo-angular": "^12.1.0", "chart.js": "^4.5.1", - "core-js": "^3.46.0", + "core-js": "^3.47.0", "graphql": "^16.12.0", "graphql-tag": "^2.12.6", "ngx-markdown": "^20.1.0", @@ -42,7 +43,7 @@ "eslint": "^9.39.0", "ts-node": "^10.9.2", "typescript": "^5.9.3", - "typescript-eslint": "8.46.2" + "typescript-eslint": "8.48.0" } }, "node_modules/@algolia/abtesting": { @@ -268,13 +269,13 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.2003.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2003.8.tgz", - "integrity": "sha512-pbXQ2NlZQwzjsSIEoRQMGB1WrgZFCyM0zoD9h+rDjyR8PEB1Evl4evZ4Q5CJzjEBxC8IEG61PHKHjh8GdLb+sg==", + "version": "0.2003.12", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2003.12.tgz", + "integrity": "sha512-5H40lAFF4CKY32C4HOp6bTlOF1f4WsGCwe7FjFQp9A+T7yoCBiHpIWt2JKTwV4sBoTKVDZOnuf0GG+UVKjQT4A==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "20.3.8", + "@angular-devkit/core": "20.3.12", "rxjs": "7.8.2" }, "engines": { @@ -284,9 +285,9 @@ } }, "node_modules/@angular-devkit/core": { - "version": "20.3.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-20.3.8.tgz", - "integrity": "sha512-+YFpJdvlL4gxnMm/++8rseE7ZNRHlYPmOqpoiXSuP5eGPSmdklEoQGTQvpMw42S3bll1g6/029DmV2FCZ/dtEQ==", + "version": "20.3.12", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-20.3.12.tgz", + "integrity": "sha512-ReFxd/UOoVDr3+kIUjmYILQZF89qg62POdY7a7OqBH7plmInFlYVSEDouJvGqj3LVCPiqTk2ZOSChbhS/eLxXA==", "dev": true, "license": "MIT", "dependencies": { @@ -312,13 +313,13 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "20.3.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-20.3.8.tgz", - "integrity": "sha512-Ymv7nWLTDB1gBh2laRveO912eUpQ/rUIzKRr8VQFMVG/wNipL88vzyrlKhJa7WhQ3CdKxLD7kplFIjdev7XUVg==", + "version": "20.3.12", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-20.3.12.tgz", + "integrity": "sha512-JqJ1u59y+Ud51k/8MHYzSP+aQOeC2PJBaDmMnvqfWVaIt6n3x4gc/VtuhqhpJ0SKulbFuOWgAfI6QbPFrgUYQQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "20.3.8", + "@angular-devkit/core": "20.3.12", "jsonc-parser": "3.3.1", "magic-string": "0.30.17", "ora": "8.2.0", @@ -449,9 +450,9 @@ } }, "node_modules/@angular/animations": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-20.3.9.tgz", - "integrity": "sha512-ckpRdtRV16u96ULipXTF0ZTMSe3kBZL7+Q6OYi2AsNPlrO4CUhdM8XWH0CE2lZVDkg7XNstjswfikeH8UaQVTw==", + "version": "20.3.14", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-20.3.14.tgz", + "integrity": "sha512-Sx3/XNu2rR+R8T8JkJEaIpZDZPk0IecS0Ayt6HTanNUZXuw0HVou3vkjR5B2St5nM4MXs0gh+S6aLNuArtqJTQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -460,18 +461,18 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "20.3.9" + "@angular/core": "20.3.14" } }, "node_modules/@angular/build": { - "version": "20.3.8", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-20.3.8.tgz", - "integrity": "sha512-wE6/T1FIjDSXljyNPh7KEwK5ysH3/uq2h8ZB5UCAAUkPHcQ/Y1unk27TUYePO7++KjkYXUX6XwwYZksXCZFJjA==", + "version": "20.3.12", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-20.3.12.tgz", + "integrity": "sha512-iAZve4VPviC8y6RFctyh3qFXSlP5mth9K46/0zasB4LV4pcmu8BrzIHERxIn/jCDNdVdPh973kxo1ksO4WpyuA==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2003.8", + "@angular-devkit/architect": "0.2003.12", "@babel/core": "7.28.3", "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-split-export-declaration": "7.24.7", @@ -513,7 +514,7 @@ "@angular/platform-browser": "^20.0.0", "@angular/platform-server": "^20.0.0", "@angular/service-worker": "^20.0.0", - "@angular/ssr": "^20.3.8", + "@angular/ssr": "^20.3.12", "karma": "^6.4.0", "less": "^4.2.0", "ng-packagr": "^20.0.0", @@ -563,9 +564,9 @@ } }, "node_modules/@angular/cdk": { - "version": "20.2.11", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-20.2.11.tgz", - "integrity": "sha512-+zcP6eq9+h6f09rZWHNIj2nap9P6S38mm75/WjdGZbl1BJy7vaASDnr4fwXKi2JvTyap/vj6mMuadFXEivavPw==", + "version": "20.2.14", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-20.2.14.tgz", + "integrity": "sha512-7bZxc01URbiPiIBWThQ69XwOxVduqEKN4PhpbF2AAyfMc/W8Hcr4VoIJOwL0O1Nkq5beS8pCAqoOeIgFyXd/kg==", "license": "MIT", "dependencies": { "parse5": "^8.0.0", @@ -578,19 +579,19 @@ } }, "node_modules/@angular/cli": { - "version": "20.3.8", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-20.3.8.tgz", - "integrity": "sha512-UUNmwDCrRknE+50Gwwt66o4T/l0KfLWOzxlYdLn9l2PIVNhpspg+5CUkO0juRyRyCxCnojic1s9pPTD1Eq4rtg==", + "version": "20.3.12", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-20.3.12.tgz", + "integrity": "sha512-vqVyVjbFPCRMjA5evL7tV2JeR6Anuzb9WcXTMB17fr7uzKNNAvo7KyRaOJjp+TU4JDARTNyGPy0aywfPx7R60A==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.2003.8", - "@angular-devkit/core": "20.3.8", - "@angular-devkit/schematics": "20.3.8", + "@angular-devkit/architect": "0.2003.12", + "@angular-devkit/core": "20.3.12", + "@angular-devkit/schematics": "20.3.12", "@inquirer/prompts": "7.8.2", "@listr2/prompt-adapter-inquirer": "3.0.1", "@modelcontextprotocol/sdk": "1.17.3", - "@schematics/angular": "20.3.8", + "@schematics/angular": "20.3.12", "@yarnpkg/lockfile": "1.1.0", "algoliasearch": "5.35.0", "ini": "5.0.0", @@ -613,9 +614,9 @@ } }, "node_modules/@angular/common": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-20.3.9.tgz", - "integrity": "sha512-PgKEnv30TxvpfTJ3d4h5LEjUHpKSYcs3Rc4OvK7p5A7waBkXzfqCBmy54nomzfcf4dlEjb6wSoXxlJbR7Y34Iw==", + "version": "20.3.14", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-20.3.14.tgz", + "integrity": "sha512-OOUvjTtnpktJLsNupA+GFT2q5zNocPdpOENA8aSrXvAheNybLjgi+otO3U3sQsvB1VwaoEZ9GT5O3lZlstnA/A==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -624,14 +625,14 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "20.3.9", + "@angular/core": "20.3.14", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-20.3.9.tgz", - "integrity": "sha512-nfzR/JpI77Yr4opRimnnTys//taZiibEco1ihV1C02eM4FDCQMOEp8WB+DT/yUESb6MRBlZe1MjeelwSfHlB7g==", + "version": "20.3.14", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-20.3.14.tgz", + "integrity": "sha512-KFbfPPAbclzGDujCVruflCD9j4Zwwxvrg7Y4C9GJYs3LZ85t+BfIMDDnvpBUM07ZLnfY4TO4gQdHmJAcaGGXDQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -641,9 +642,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-20.3.9.tgz", - "integrity": "sha512-Fe7MIg2NWXoK+M4GtclxaYNoTdZX2U8f/Fd3N8zxtEMcRsvliJOnJ4oQtpx5kqMAuZVO4zY3wuIY1wAGXYCUbQ==", + "version": "20.3.14", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-20.3.14.tgz", + "integrity": "sha512-lFg9ikwRClzDPjdFiwynbVFIi1RJZf/0i+OHa3Ns2gzXxJeHNKMJrHHjWZ2DU4N2UpxH0YAPe22N9Bie28IuQQ==", "license": "MIT", "dependencies": { "@babel/core": "7.28.3", @@ -663,7 +664,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "20.3.9", + "@angular/compiler": "20.3.14", "typescript": ">=5.8 <6.0" }, "peerDependenciesMeta": { @@ -673,9 +674,9 @@ } }, "node_modules/@angular/core": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-20.3.9.tgz", - "integrity": "sha512-zZb7wUexBIIUojr1helzXsL25ilAoASm8aPOjBNHPLYr4ndDjMD/wogmH/dA7EzuCdmZf30ZmZZpuX149WdrpA==", + "version": "20.3.14", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-20.3.14.tgz", + "integrity": "sha512-rpyEbhWF6Fj/xI9IvNLZh5QBUYnoXuF7vX54CCtyQ2MHALxRR/aa1WRxjRM96cF2OqodQ/Gj3oYW8ei8hlBh4w==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -684,7 +685,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "20.3.9", + "@angular/compiler": "20.3.14", "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0" }, @@ -698,9 +699,9 @@ } }, "node_modules/@angular/forms": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-20.3.9.tgz", - "integrity": "sha512-jSlhU1IyuxxSYNN5Gg3oBb0nAqIl5Mwf1hywtkbyMay+3sENYGvBRseWp00R308isKe+n8bKi6hF54A1lhozzg==", + "version": "20.3.14", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-20.3.14.tgz", + "integrity": "sha512-fGrJ589tU+AKoxf+kaRrEw7wlSfVr1/z/Fz625ggFCc6ySQEityKW3JsnLfNkh5qGrdxib4BOfF78f9J7Pyk+w==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -709,18 +710,17 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "20.3.9", - "@angular/core": "20.3.9", - "@angular/platform-browser": "20.3.9", + "@angular/common": "20.3.14", + "@angular/core": "20.3.14", + "@angular/platform-browser": "20.3.14", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/localize": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-20.3.9.tgz", - "integrity": "sha512-YtjsOIOUChGCb1XUNb0CLQQVFTQjxgAR8ihLVHQb0M1pJhhkTJGWJAvf3Qr1+1aLJjyAC4wve+zkj5Z9eR9A1A==", + "version": "20.3.14", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-20.3.14.tgz", + "integrity": "sha512-tSYZmFhjCHwifWE+R1VHg3zaemUX2tNjpQd9Ha6BvISyzyGWw/sQirIAxC4uoa2RVZ3jexos5sbw8rFT6iIEYg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "7.28.3", "@types/babel__core": "7.20.5", @@ -736,20 +736,20 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "20.3.9", - "@angular/compiler-cli": "20.3.9" + "@angular/compiler": "20.3.14", + "@angular/compiler-cli": "20.3.14" } }, "node_modules/@angular/material": { - "version": "20.2.11", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-20.2.11.tgz", - "integrity": "sha512-lrmudo8n06o6UBVKx/slAfUIjJghwub5JZfIOmQd2js0Vz+eBJYcDJsgBB8lG/LSXKLlPkNwe6o6nJBMVBZg1g==", + "version": "20.2.14", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-20.2.14.tgz", + "integrity": "sha512-IbAgV6XLsvmHiJzxycVhcNC1PA4M30qi+ERCOir6cT333Bxm8vDV32gsOjfL52uzG5YRARroPC+8s1XqR2oxeA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/cdk": "20.2.11", + "@angular/cdk": "20.2.14", "@angular/common": "^20.0.0 || ^21.0.0", "@angular/core": "^20.0.0 || ^21.0.0", "@angular/forms": "^20.0.0 || ^21.0.0", @@ -758,9 +758,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.3.9.tgz", - "integrity": "sha512-q9uyNIKto3PmIh3q9/OX0HYN/SMYqCJ7MyQHBuF9Rel0vXi0gWyk2dgsWAl/tSTLlqHWtGZZ3rvJyxYQmxFo4w==", + "version": "20.3.14", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.3.14.tgz", + "integrity": "sha512-Lviz9GfsIyOIBDal8QhIBKU8OMH29A0RhFw2opTC50sqKadXLN9CD7iSaAwQbNLc4mc3JAF4zth0AzKdHLbz7Q==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -769,9 +769,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/animations": "20.3.9", - "@angular/common": "20.3.9", - "@angular/core": "20.3.9" + "@angular/animations": "20.3.14", + "@angular/common": "20.3.14", + "@angular/core": "20.3.14" }, "peerDependenciesMeta": { "@angular/animations": { @@ -780,9 +780,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-20.3.9.tgz", - "integrity": "sha512-XLGDmloD25eEeQM3hrCnU+2TqXpFLp36xOPqVSyBNso0YFXBtAX/lc2tcOFX3fLslje3LT0nyObAlV45YfBiGA==", + "version": "20.3.14", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-20.3.14.tgz", + "integrity": "sha512-g9z/g8gIOrBCX1SQ/GWwB0+JXBC6CKe0+yRyy9GGeBLm/YXWZHxTkmnDmueXXfPtUl8TOAInE22wlLcfunWTrg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -791,16 +791,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "20.3.9", - "@angular/compiler": "20.3.9", - "@angular/core": "20.3.9", - "@angular/platform-browser": "20.3.9" + "@angular/common": "20.3.14", + "@angular/compiler": "20.3.14", + "@angular/core": "20.3.14", + "@angular/platform-browser": "20.3.14" } }, "node_modules/@angular/router": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-20.3.9.tgz", - "integrity": "sha512-wsilSrTtR85OFd6XP0b9rMakx1pEw5sHEYBrfoSQc+NfYCsP5a5qFBJ5CWOQKgWjKlfPgpkaheD6JdqN9WpFoQ==", + "version": "20.3.14", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-20.3.14.tgz", + "integrity": "sha512-gi7/NuHRS9n9RCwh03VuVFizVMa2lKL/s+7yP3Ecq2nQ5uSeTMWb/91OmGEBwncI3wKPkYdQ9g3n6PvK/O8uDQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -809,16 +809,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "20.3.9", - "@angular/core": "20.3.9", - "@angular/platform-browser": "20.3.9", + "@angular/common": "20.3.14", + "@angular/core": "20.3.14", + "@angular/platform-browser": "20.3.14", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/service-worker": { - "version": "20.3.9", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-20.3.9.tgz", - "integrity": "sha512-NdDoweeswYPoiWmqUsgcdpj+iHIdgI6XXM4ujJs0tFoO2kbs9OLu1mupuYdd0slzMQr6ni7bq+A17964PY1ipA==", + "version": "20.3.14", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-20.3.14.tgz", + "integrity": "sha512-deqrAszJ534/wUTjb7UByoX0SgOJAWPE6g+y1HZv6Uy9OJYakkbwBt4lKqftHkga9guBsHkZydDfJNBIrSAbkw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -830,7 +830,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "20.3.9", + "@angular/core": "20.3.14", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -848,16 +848,6 @@ "url": "https://github.com/sponsors/antfu" } }, - "node_modules/@antfu/utils": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-9.3.0.tgz", - "integrity": "sha512-9hFT4RauhcUzqOE4f1+frMKLZrgNog5b06I7VmZQV1BkvwvqrbC8EBZf3L1eEL2AKb6rNKjER0sEvJiSP1FXEA==", - "license": "MIT", - "optional": true, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, "node_modules/@apollo/client": { "version": "4.0.9", "resolved": "https://registry.npmjs.org/@apollo/client/-/client-4.0.9.tgz", @@ -1868,9 +1858,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.39.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.0.tgz", - "integrity": "sha512-BIhe0sW91JGPiaF1mOuPy5v8NflqfjIcDNpC+LbW9f609WVRX1rArrhi6Z2ymvrAry9jw+5POTj4t2t62o8Bmw==", + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", + "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", "dev": true, "license": "MIT", "engines": { @@ -1973,39 +1963,21 @@ "optional": true }, "node_modules/@iconify/utils": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.0.2.tgz", - "integrity": "sha512-EfJS0rLfVuRuJRn4psJHtK2A9TqVnkxPpHY6lYHiB9+8eSuudsxbwMiavocG45ujOo6FJ+CIRlRnlOGinzkaGQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.0.tgz", + "integrity": "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==", "license": "MIT", "optional": true, "dependencies": { "@antfu/install-pkg": "^1.1.0", - "@antfu/utils": "^9.2.0", "@iconify/types": "^2.0.0", - "debug": "^4.4.1", - "globals": "^15.15.0", - "kolorist": "^1.8.0", - "local-pkg": "^1.1.1", - "mlly": "^1.7.4" - } - }, - "node_modules/@iconify/utils/node_modules/globals": { - "version": "15.15.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", - "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "mlly": "^1.8.0" } }, "node_modules/@inquirer/ansi": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.1.tgz", - "integrity": "sha512-yqq0aJW/5XPhi5xOAL1xRCpe1eh8UFVgYFpFsjEqmIR8rKLyP+HINvFXwUaxYICflJrVlxnp7lLN6As735kVpw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", + "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", "dev": true, "license": "MIT", "engines": { @@ -2013,17 +1985,17 @@ } }, "node_modules/@inquirer/checkbox": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.0.tgz", - "integrity": "sha512-5+Q3PKH35YsnoPTh75LucALdAxom6xh5D1oeY561x4cqBuH24ZFVyFREPe14xgnrtmGu3EEt1dIi60wRVSnGCw==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", + "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.1", - "@inquirer/core": "^10.3.0", - "@inquirer/figures": "^1.0.14", - "@inquirer/type": "^3.0.9", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -2060,20 +2032,20 @@ } }, "node_modules/@inquirer/core": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.0.tgz", - "integrity": "sha512-Uv2aPPPSK5jeCplQmQ9xadnFx2Zhj9b5Dj7bU6ZeCdDNNY11nhYy4btcSdtDguHqCT2h5oNeQTcUNSGGLA7NTA==", + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.1", - "@inquirer/figures": "^1.0.14", - "@inquirer/type": "^3.0.9", + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", "cli-width": "^4.1.0", "mute-stream": "^2.0.0", "signal-exit": "^4.1.0", "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -2088,15 +2060,15 @@ } }, "node_modules/@inquirer/editor": { - "version": "4.2.21", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.21.tgz", - "integrity": "sha512-MjtjOGjr0Kh4BciaFShYpZ1s9400idOdvQ5D7u7lE6VztPFoyLcVNE5dXBmEEIQq5zi4B9h2kU+q7AVBxJMAkQ==", + "version": "4.2.23", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", + "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/external-editor": "^1.0.2", - "@inquirer/type": "^3.0.9" + "@inquirer/core": "^10.3.2", + "@inquirer/external-editor": "^1.0.3", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -2111,15 +2083,15 @@ } }, "node_modules/@inquirer/expand": { - "version": "4.0.21", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.21.tgz", - "integrity": "sha512-+mScLhIcbPFmuvU3tAGBed78XvYHSvCl6dBiYMlzCLhpr0bzGzd8tfivMMeqND6XZiaZ1tgusbUHJEfc6YzOdA==", + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", + "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -2134,13 +2106,13 @@ } }, "node_modules/@inquirer/external-editor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.2.tgz", - "integrity": "sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", "dev": true, "license": "MIT", "dependencies": { - "chardet": "^2.1.0", + "chardet": "^2.1.1", "iconv-lite": "^0.7.0" }, "engines": { @@ -2156,9 +2128,9 @@ } }, "node_modules/@inquirer/figures": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.14.tgz", - "integrity": "sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ==", + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", + "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", "dev": true, "license": "MIT", "engines": { @@ -2166,14 +2138,14 @@ } }, "node_modules/@inquirer/input": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.5.tgz", - "integrity": "sha512-7GoWev7P6s7t0oJbenH0eQ0ThNdDJbEAEtVt9vsrYZ9FulIokvd823yLyhQlWHJPGce1wzP53ttfdCZmonMHyA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", + "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -2188,14 +2160,14 @@ } }, "node_modules/@inquirer/number": { - "version": "3.0.21", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.21.tgz", - "integrity": "sha512-5QWs0KGaNMlhbdhOSCFfKsW+/dcAVC2g4wT/z2MCiZM47uLgatC5N20kpkDQf7dHx+XFct/MJvvNGy6aYJn4Pw==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", + "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -2210,15 +2182,15 @@ } }, "node_modules/@inquirer/password": { - "version": "4.0.21", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.21.tgz", - "integrity": "sha512-xxeW1V5SbNFNig2pLfetsDb0svWlKuhmr7MPJZMYuDnCTkpVBI+X/doudg4pznc1/U+yYmWFFOi4hNvGgUo7EA==", + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", + "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.1", - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -2263,15 +2235,15 @@ } }, "node_modules/@inquirer/rawlist": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.9.tgz", - "integrity": "sha512-AWpxB7MuJrRiSfTKGJ7Y68imYt8P9N3Gaa7ySdkFj1iWjr6WfbGAhdZvw/UnhFXTHITJzxGUI9k8IX7akAEBCg==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", + "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -2286,16 +2258,16 @@ } }, "node_modules/@inquirer/search": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.0.tgz", - "integrity": "sha512-a5SzB/qrXafDX1Z4AZW3CsVoiNxcIYCzYP7r9RzrfMpaLpB+yWi5U8BWagZyLmwR0pKbbL5umnGRd0RzGVI8bQ==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", + "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/figures": "^1.0.14", - "@inquirer/type": "^3.0.9", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -2310,17 +2282,17 @@ } }, "node_modules/@inquirer/select": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.0.tgz", - "integrity": "sha512-kaC3FHsJZvVyIjYBs5Ih8y8Bj4P/QItQWrZW22WJax7zTN+ZPXVGuOM55vzbdCP9zKUiBd9iEJVdesujfF+cAA==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", + "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.1", - "@inquirer/core": "^10.3.0", - "@inquirer/figures": "^1.0.14", - "@inquirer/type": "^3.0.9", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -2335,9 +2307,9 @@ } }, "node_modules/@inquirer/type": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.9.tgz", - "integrity": "sha512-QPaNt/nmE2bLGQa9b7wwyRJoLZ7pN6rcyXvzU0YCmivmJyq1BVo94G98tStRWkoD1RgDX5C+dPlhhHzNdu/W/w==", + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", "dev": true, "license": "MIT", "engines": { @@ -3110,44 +3082,6 @@ "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/@npmcli/agent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-3.0.0.tgz", @@ -4060,14 +3994,14 @@ ] }, "node_modules/@schematics/angular": { - "version": "20.3.8", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-20.3.8.tgz", - "integrity": "sha512-lmdh1JywRl0BK1VcYwGDrNre78OpduNhsV4N5afELvrNPKSk/ixCb3iZq4MCY3yBZ3RV5Uso+vrJwwEeqe02JQ==", + "version": "20.3.12", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-20.3.12.tgz", + "integrity": "sha512-ikl+nkWUab/Z4eSkBHgq9FLIUH8qh4OcYKeBQ0fyWqIUFHyjjK0JOfwmH1g/3zAmuUMtkthHCehAtyKzCTQjVA==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "20.3.8", - "@angular-devkit/schematics": "20.3.8", + "@angular-devkit/core": "20.3.12", + "@angular-devkit/schematics": "20.3.12", "jsonc-parser": "3.3.1" }, "engines": { @@ -4157,9 +4091,9 @@ } }, "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", "dev": true, "license": "MIT" }, @@ -4213,7 +4147,6 @@ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -4227,7 +4160,6 @@ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/types": "^7.0.0" } @@ -4237,7 +4169,6 @@ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "license": "MIT", - "peer": true, "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" @@ -4248,7 +4179,6 @@ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "license": "MIT", - "peer": true, "dependencies": { "@babel/types": "^7.28.2" } @@ -4565,9 +4495,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.9.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.2.tgz", - "integrity": "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==", + "version": "24.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", + "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4575,13 +4505,13 @@ } }, "node_modules/@types/react": { - "version": "19.2.2", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", - "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", + "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", "dev": true, "license": "MIT", "dependencies": { - "csstype": "^3.0.2" + "csstype": "^3.2.2" } }, "node_modules/@types/trusted-types": { @@ -4592,17 +4522,17 @@ "optional": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.2.tgz", - "integrity": "sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.0.tgz", + "integrity": "sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.46.2", - "@typescript-eslint/type-utils": "8.46.2", - "@typescript-eslint/utils": "8.46.2", - "@typescript-eslint/visitor-keys": "8.46.2", + "@typescript-eslint/scope-manager": "8.48.0", + "@typescript-eslint/type-utils": "8.48.0", + "@typescript-eslint/utils": "8.48.0", + "@typescript-eslint/visitor-keys": "8.48.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -4616,22 +4546,22 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.46.2", + "@typescript-eslint/parser": "^8.48.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.2.tgz", - "integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.0.tgz", + "integrity": "sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.46.2", - "@typescript-eslint/types": "8.46.2", - "@typescript-eslint/typescript-estree": "8.46.2", - "@typescript-eslint/visitor-keys": "8.46.2", + "@typescript-eslint/scope-manager": "8.48.0", + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/typescript-estree": "8.48.0", + "@typescript-eslint/visitor-keys": "8.48.0", "debug": "^4.3.4" }, "engines": { @@ -4647,14 +4577,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.2.tgz", - "integrity": "sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.0.tgz", + "integrity": "sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.46.2", - "@typescript-eslint/types": "^8.46.2", + "@typescript-eslint/tsconfig-utils": "^8.48.0", + "@typescript-eslint/types": "^8.48.0", "debug": "^4.3.4" }, "engines": { @@ -4669,14 +4599,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.2.tgz", - "integrity": "sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.0.tgz", + "integrity": "sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.2", - "@typescript-eslint/visitor-keys": "8.46.2" + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/visitor-keys": "8.48.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4687,9 +4617,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.2.tgz", - "integrity": "sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.0.tgz", + "integrity": "sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w==", "dev": true, "license": "MIT", "engines": { @@ -4704,15 +4634,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.2.tgz", - "integrity": "sha512-HbPM4LbaAAt/DjxXaG9yiS9brOOz6fabal4uvUmaUYe6l3K1phQDMQKBRUrr06BQkxkvIZVVHttqiybM9nJsLA==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.48.0.tgz", + "integrity": "sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.2", - "@typescript-eslint/typescript-estree": "8.46.2", - "@typescript-eslint/utils": "8.46.2", + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/typescript-estree": "8.48.0", + "@typescript-eslint/utils": "8.48.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -4729,9 +4659,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.2.tgz", - "integrity": "sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.0.tgz", + "integrity": "sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA==", "dev": true, "license": "MIT", "engines": { @@ -4743,21 +4673,20 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.2.tgz", - "integrity": "sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.0.tgz", + "integrity": "sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.46.2", - "@typescript-eslint/tsconfig-utils": "8.46.2", - "@typescript-eslint/types": "8.46.2", - "@typescript-eslint/visitor-keys": "8.46.2", + "@typescript-eslint/project-service": "8.48.0", + "@typescript-eslint/tsconfig-utils": "8.48.0", + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/visitor-keys": "8.48.0", "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", + "tinyglobby": "^0.2.15", "ts-api-utils": "^2.1.0" }, "engines": { @@ -4771,17 +4700,34 @@ "typescript": ">=4.8.4 <6.0.0" } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, "node_modules/@typescript-eslint/utils": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.2.tgz", - "integrity": "sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.48.0.tgz", + "integrity": "sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.46.2", - "@typescript-eslint/types": "8.46.2", - "@typescript-eslint/typescript-estree": "8.46.2" + "@typescript-eslint/scope-manager": "8.48.0", + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/typescript-estree": "8.48.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4796,13 +4742,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.2.tgz", - "integrity": "sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.0.tgz", + "integrity": "sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/types": "8.48.0", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -5049,9 +4995,9 @@ } }, "node_modules/ansi-escapes": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.1.1.tgz", - "integrity": "sha512-Zhl0ErHcSRUaVfGUeUdDuLgpkEo8KIFjB4Y9uAc46ScOpdDiU1Dbyplh7qWJeJ/ZHpbyMSM26+X3BySgnIz40Q==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz", + "integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==", "dev": true, "license": "MIT", "dependencies": { @@ -5152,9 +5098,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.23", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.23.tgz", - "integrity": "sha512-616V5YX4bepJFzNyOfce5Fa8fDJMfoxzOIzDCZwaGL8MKVpFrXqfNUoIpRn9YMI5pXf/VKgzjB4htFMsFKKdiQ==", + "version": "2.8.31", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.31.tgz", + "integrity": "sha512-a28v2eWrrRWPpJSzxc+mKwm0ZtVx/G8SepdQZDArnXYU/XS+IF6mp8aB/4E+hH1tyGCoDo3KlUCdlSxGDsRkAw==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -5181,37 +5127,28 @@ } }, "node_modules/body-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", - "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", + "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", "dev": true, "license": "MIT", "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", - "debug": "^4.4.0", + "debug": "^4.4.3", "http-errors": "^2.0.0", - "iconv-lite": "^0.6.3", + "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.0", - "raw-body": "^3.0.0", - "type-is": "^2.0.0" + "raw-body": "^3.0.1", + "type-is": "^2.0.1" }, "engines": { "node": ">=18" - } - }, - "node_modules/body-parser/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/boolbase": { @@ -5237,6 +5174,7 @@ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "fill-range": "^7.1.1" }, @@ -5245,9 +5183,9 @@ } }, "node_modules/browserslist": { - "version": "4.27.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.27.0.tgz", - "integrity": "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==", + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", + "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", "funding": [ { "type": "opencollective", @@ -5264,10 +5202,10 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.8.19", - "caniuse-lite": "^1.0.30001751", - "electron-to-chromium": "^1.5.238", - "node-releases": "^2.0.26", + "baseline-browser-mapping": "^2.8.25", + "caniuse-lite": "^1.0.30001754", + "electron-to-chromium": "^1.5.249", + "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": { @@ -5404,9 +5342,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001752", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001752.tgz", - "integrity": "sha512-vKUk7beoukxE47P5gcVNKkDRzXdVofotshHwfR9vmpeFKxmI5PBpgOMC18LUJUA/DvJ70Y7RveasIBraqsyO/g==", + "version": "1.0.30001757", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001757.tgz", + "integrity": "sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ==", "funding": [ { "type": "opencollective", @@ -5668,23 +5606,24 @@ "license": "MIT" }, "node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", "license": "MIT", "optional": true }, "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "dev": true, "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/content-type": { @@ -5724,9 +5663,9 @@ } }, "node_modules/core-js": { - "version": "3.46.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.46.0.tgz", - "integrity": "sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA==", + "version": "3.47.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.47.0.tgz", + "integrity": "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==", "hasInstallScript": true, "license": "MIT", "funding": { @@ -5811,9 +5750,9 @@ } }, "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "dev": true, "license": "MIT" }, @@ -6559,9 +6498,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.244", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.244.tgz", - "integrity": "sha512-OszpBN7xZX4vWMPJwB9illkN/znA8M36GQqQxi6MNy9axWxhOfJyZZJtSLQCpEFLHP2xK33BiWx9aIuIEXVCcw==", + "version": "1.5.262", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.262.tgz", + "integrity": "sha512-NlAsMteRHek05jRUxUR0a5jpjYq9ykk6+kO0yRaMi5moe7u0fVIOeQ3Y30A8dIiWFBNUoQGi1ljb1i5VtS9WQQ==", "license": "ISC" }, "node_modules/emoji-regex": { @@ -6760,9 +6699,9 @@ } }, "node_modules/eslint": { - "version": "9.39.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.0.tgz", - "integrity": "sha512-iy2GE3MHrYTL5lrCtMZ0X1KLEKKUjmK0kzwcnefhR66txcEmXZD2YWgR5GNdcEwkNx3a0siYkSvl0vIC+Svjmg==", + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", + "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, "license": "MIT", "dependencies": { @@ -6772,7 +6711,7 @@ "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.0", + "@eslint/js": "9.39.1", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -7103,13 +7042,6 @@ "express": ">= 4.11" } }, - "node_modules/exsolve": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", - "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", - "license": "MIT", - "optional": true - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -7117,36 +7049,6 @@ "dev": true, "license": "MIT" }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -7178,16 +7080,6 @@ ], "license": "BSD-3-Clause" }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -7224,6 +7116,7 @@ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -7432,9 +7325,9 @@ } }, "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "license": "ISC", "dependencies": { @@ -7653,30 +7546,24 @@ "license": "BSD-2-Clause" }, "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "dev": true, "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" - } - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/http-proxy-agent": { @@ -7825,9 +7712,9 @@ } }, "node_modules/ip-address": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", - "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", "dev": true, "license": "MIT", "engines": { @@ -7915,6 +7802,7 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.12.0" } @@ -7996,9 +7884,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -8113,13 +8001,6 @@ "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==", "optional": true }, - "node_modules/kolorist": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", - "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", - "license": "MIT", - "optional": true - }, "node_modules/langium": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/langium/-/langium-3.3.1.tgz", @@ -8235,24 +8116,6 @@ "@lmdb/lmdb-win32-x64": "3.4.2" } }, - "node_modules/local-pkg": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", - "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", - "license": "MIT", - "optional": true, - "dependencies": { - "mlly": "^1.7.4", - "pkg-types": "^2.3.0", - "quansync": "^0.2.11" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -8460,9 +8323,9 @@ } }, "node_modules/marked": { - "version": "16.4.1", - "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.1.tgz", - "integrity": "sha512-ntROs7RaN3EvWfy3EZi14H4YxmT6A5YvywfhO+0pm+cH/dnSQRmdAmoFIc3B9aiwTehyk7pESH4ofyBY+V5hZg==", + "version": "16.4.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz", + "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", "license": "MIT", "bin": { "marked": "bin/marked.js" @@ -8504,16 +8367,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, "node_modules/mermaid": { "version": "11.12.1", "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.12.1.tgz", @@ -8549,6 +8402,7 @@ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -8563,6 +8417,7 @@ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=8.6" }, @@ -8581,16 +8436,20 @@ } }, "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "dev": true, "license": "MIT", "dependencies": { "mime-db": "^1.54.0" }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/mimic-function": { @@ -8801,25 +8660,6 @@ "ufo": "^1.6.1" } }, - "node_modules/mlly/node_modules/confbox": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", - "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", - "license": "MIT", - "optional": true - }, - "node_modules/mlly/node_modules/pkg-types": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", - "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "confbox": "^0.1.8", - "mlly": "^1.7.4", - "pathe": "^2.0.1" - } - }, "node_modules/mrmime": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", @@ -9141,9 +8981,9 @@ } }, "node_modules/npm-packlist/node_modules/proc-log": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.0.0.tgz", - "integrity": "sha512-KG/XsTDN901PNfPfAMmj6N/Ywg9tM+bHK8pAz+27fS4N4Pcr+4zoYBOcGSBu6ceXYNPxkLpa4ohtfxV1XcLAfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", + "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", "dev": true, "license": "ISC", "engines": { @@ -9441,9 +9281,9 @@ } }, "node_modules/p-map": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz", - "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", "dev": true, "license": "MIT", "engines": { @@ -9461,9 +9301,9 @@ "license": "BlueOak-1.0.0" }, "node_modules/package-manager-detector": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.5.0.tgz", - "integrity": "sha512-uBj69dVlYe/+wxj8JOpr97XfsxH/eumMt6HqjNTmJDf/6NO9s+0uxeOneIz3AsPt2m6y9PqzDzd3ATcU17MNfw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", + "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", "license": "MIT", "optional": true }, @@ -9731,9 +9571,9 @@ } }, "node_modules/pkce-challenge": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", - "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", "dev": true, "license": "MIT", "engines": { @@ -9741,15 +9581,15 @@ } }, "node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", "license": "MIT", "optional": true, "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", - "pathe": "^2.0.3" + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" } }, "node_modules/points-on-curve": { @@ -9890,44 +9730,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/quansync": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", - "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/antfu" - }, - { - "type": "individual", - "url": "https://github.com/sponsors/sxzz" - } - ], - "license": "MIT", - "optional": true - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -9939,16 +9741,16 @@ } }, "node_modules/raw-body": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", - "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.7.0", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.10" @@ -10041,17 +9843,6 @@ "node": ">= 4" } }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, "node_modules/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", @@ -10138,30 +9929,6 @@ "node": ">= 18" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, "node_modules/rw": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", @@ -10178,27 +9945,6 @@ "tslib": "^2.1.0" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -10860,11 +10606,14 @@ "optional": true }, "node_modules/tinyexec": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", - "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", "license": "MIT", - "optional": true + "optional": true, + "engines": { + "node": ">=18" + } }, "node_modules/tinyglobby": { "version": "0.2.14", @@ -10888,6 +10637,7 @@ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "is-number": "^7.0.0" }, @@ -11036,16 +10786,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.46.2.tgz", - "integrity": "sha512-vbw8bOmiuYNdzzV3lsiWv6sRwjyuKJMQqWulBOU7M0RrxedXledX8G8kBbQeiOYDnTfiXz0Y4081E1QMNB6iQg==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.48.0.tgz", + "integrity": "sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.46.2", - "@typescript-eslint/parser": "8.46.2", - "@typescript-eslint/typescript-estree": "8.46.2", - "@typescript-eslint/utils": "8.46.2" + "@typescript-eslint/eslint-plugin": "8.48.0", + "@typescript-eslint/parser": "8.48.0", + "@typescript-eslint/typescript-estree": "8.48.0", + "@typescript-eslint/utils": "8.48.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -11635,13 +11385,13 @@ } }, "node_modules/zod-to-json-schema": { - "version": "3.24.6", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz", - "integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==", + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.0.tgz", + "integrity": "sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==", "dev": true, "license": "ISC", "peerDependencies": { - "zod": "^3.24.1" + "zod": "^3.25 || ^4" } }, "node_modules/zone.js": { diff --git a/package.json b/package.json index 1eb03f1a..4858d691 100644 --- a/package.json +++ b/package.json @@ -35,12 +35,13 @@ "@angular/platform-browser-dynamic": "~20.3.9", "@angular/router": "~20.3.9", "@angular/service-worker": "~20.3.9", + "@angular/localize": "~20.3.9", "@apollo/client": "^4.0.9", "@ng-bootstrap/ng-bootstrap": "~19.0.1", "@types/grecaptcha": "^3.0.9", "apollo-angular": "^12.1.0", "chart.js": "^4.5.1", - "core-js": "^3.46.0", + "core-js": "^3.47.0", "graphql": "^16.12.0", "graphql-tag": "^2.12.6", "ngx-markdown": "^20.1.0", @@ -57,7 +58,7 @@ "eslint": "^9.39.0", "ts-node": "^10.9.2", "typescript": "^5.9.3", - "typescript-eslint": "8.46.2" + "typescript-eslint": "8.48.0" }, "repository": { "type": "git", diff --git a/src/app/_helpers/toast.service.ts b/src/app/_helpers/toast.service.ts index ad277835..93c1ccbc 100644 --- a/src/app/_helpers/toast.service.ts +++ b/src/app/_helpers/toast.service.ts @@ -1,11 +1,17 @@ -import { Injectable, TemplateRef } from '@angular/core'; +import { Injectable, TemplateRef, signal } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class ToastService { - toasts: any[] = []; + private readonly _toasts = signal([]); + + // Expose toasts as a getter to maintain compatibility + get toasts() { + return this._toasts(); + } show(textOrTpl: string | TemplateRef, options: any = {}) { - this.toasts.push({ textOrTpl, ...options }); + const currentToasts = this._toasts(); + this._toasts.set([...currentToasts, { textOrTpl, ...options }]); } showSuccess(textOrTpl: string | TemplateRef) { @@ -17,6 +23,7 @@ export class ToastService { } remove(toast: any) { - this.toasts = this.toasts.filter(t => t !== toast); + const currentToasts = this._toasts(); + this._toasts.set(currentToasts.filter(t => t !== toast)); } } \ No newline at end of file diff --git a/src/app/_helpers/toasts-container.component.ts b/src/app/_helpers/toasts-container.component.ts index f3ebfff5..471b1a2b 100644 --- a/src/app/_helpers/toasts-container.component.ts +++ b/src/app/_helpers/toasts-container.component.ts @@ -1,7 +1,8 @@ -import { Component, TemplateRef, inject } from '@angular/core'; +import { Component, TemplateRef, inject, ChangeDetectorRef, OnInit, OnDestroy } from '@angular/core'; import { ToastService } from './toast.service'; import { NgTemplateOutlet } from '@angular/common'; import { NgbToast } from '@ng-bootstrap/ng-bootstrap'; +import { Subject } from 'rxjs'; @Component({ selector: 'app-toasts', @@ -27,8 +28,30 @@ import { NgbToast } from '@ng-bootstrap/ng-bootstrap'; }, imports: [NgbToast, NgTemplateOutlet] }) -export class ToastsContainerComponent { +export class ToastsContainerComponent implements OnInit, OnDestroy { + private readonly cdr = inject(ChangeDetectorRef, { optional: true }); + private readonly unsubscribe = new Subject(); + private intervalId: any; + toastService = inject(ToastService); + ngOnInit() { + // Monitor toasts array for changes and trigger change detection + // This ensures UI updates when toasts are added/removed in zoneless mode + if (this.cdr) { + this.intervalId = setInterval(() => { + this.cdr.detectChanges(); + }, 50); // Check every 50ms for toast changes + } + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + if (this.intervalId) { + clearInterval(this.intervalId); + } + } + isTemplate(toast: { textOrTpl: any; }) { return toast.textOrTpl instanceof TemplateRef; } } diff --git a/src/app/dashboard-module/domain-list/domain-list.component.html b/src/app/dashboard-module/domain-list/domain-list.component.html index 67b3cbb0..e9005f1d 100644 --- a/src/app/dashboard-module/domain-list/domain-list.component.html +++ b/src/app/dashboard-module/domain-list/domain-list.component.html @@ -1,5 +1,5 @@
-
+

@@ -11,23 +11,23 @@

- @if (loading) { + @if (loading()) {
} - @if (error) { -
{{ error }}
+ @if (error()) { +
{{ error() }}
} - @if (!loading) { - @for (domain of domains; track domain) { + @if (!loading()) { + @for (domain of domains(); track domain) { } }
-
+

@@ -35,17 +35,17 @@

- @if (loadingCollab) { + @if (loadingCollab()) {
} - @if (errorCollab) { -
{{ errorCollab }}
+ @if (errorCollab()) { +
{{ errorCollab() }}
} - @if (!loadingCollab) { - @for (domain of collabDomains; track domain) { + @if (!loadingCollab()) { + @for (domain of collabDomains(); track domain) { } } diff --git a/src/app/dashboard-module/domain-list/domain-list.component.ts b/src/app/dashboard-module/domain-list/domain-list.component.ts index f1588ed3..27c510ee 100644 --- a/src/app/dashboard-module/domain-list/domain-list.component.ts +++ b/src/app/dashboard-module/domain-list/domain-list.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, OnDestroy, inject } from '@angular/core'; +import { Component, OnInit, OnDestroy, inject, signal } from '@angular/core'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { ToastService } from 'src/app/_helpers/toast.service'; @@ -31,21 +31,21 @@ export class DomainListComponent implements OnInit, OnDestroy { private readonly unsubscribe = new Subject(); - domains: Domain[]; - collabDomains: Domain[] = []; + domains = signal([]); + collabDomains = signal([]); - cardListContainerStyle = 'card mt-4 loading'; - cardCollabListContainerStyle = 'card mt-4 loading'; - loading = false; - loadingCollab = false; - error = ''; - errorCollab = ''; + cardListContainerStyle = signal('card mt-4 loading'); + cardCollabListContainerStyle = signal('card mt-4 loading'); + loading = signal(false); + loadingCollab = signal(false); + error = signal(''); + errorCollab = signal(''); ngOnInit() { - this.loading = true; - this.loadingCollab = true; - this.error = ''; - this.errorCollab = ''; + this.loading.set(true); + this.loadingCollab.set(true); + this.error.set(''); + this.errorCollab.set(''); this.loadDomain(); this.loadCollabDomain(); } @@ -64,7 +64,7 @@ export class DomainListComponent implements OnInit, OnDestroy { dialogRef.afterClosed().subscribe(result => { if (result) { - this.loading = true; + this.loading.set(true); this.domainService.createDomain(result.name, result.description).subscribe({ next: domain => { if (domain) { @@ -73,7 +73,7 @@ export class DomainListComponent implements OnInit, OnDestroy { } }, error: error => { - this.loading = false; + this.loading.set(false); this.toastService.showError(`Unable to create a new domain. ${error.error}`); ConsoleLogger.printError(error); } @@ -86,39 +86,39 @@ export class DomainListComponent implements OnInit, OnDestroy { this.domainService.getDomains().pipe(takeUntil(this.unsubscribe)).subscribe({ next: (data) => { if (data) { - this.domains = data; + this.domains.set(data); } }, error: (error) => { ConsoleLogger.printError(error); - this.loading = false; - this.error = this.errorHandler.doError(error); + this.loading.set(false); + this.error.set(this.errorHandler.doError(error)); }, complete: () => { - if (!this.domains) { - this.error = 'Failed to connect to Switcher API'; + if (!this.domains().length) { + this.error.set('Failed to connect to Switcher API'); } - this.loading = false; - this.cardListContainerStyle = 'card mt-4 ready'; + this.loading.set(false); + this.cardListContainerStyle.set('card mt-4 ready'); } }); } private loadCollabDomain(): void { - this.collabDomains = []; + this.collabDomains.set([]); this.domainService.getDomainsCollab().pipe(takeUntil(this.unsubscribe)).subscribe({ next: (data) => { if (data?.length) { - this.collabDomains = data; - this.cardCollabListContainerStyle = 'card mt-4 ready'; + this.collabDomains.set(data); + this.cardCollabListContainerStyle.set('card mt-4 ready'); } }, error: (error) => { ConsoleLogger.printError(error); - this.loadingCollab = false; + this.loadingCollab.set(false); }, complete: () => { - this.loadingCollab = false; + this.loadingCollab.set(false); } }); } diff --git a/src/app/dashboard-module/domain-module/changelog/changelog.component.html b/src/app/dashboard-module/domain-module/changelog/changelog.component.html index 0b30fd56..6101239b 100644 --- a/src/app/dashboard-module/domain-module/changelog/changelog.component.html +++ b/src/app/dashboard-module/domain-module/changelog/changelog.component.html @@ -5,14 +5,14 @@ } -@if (loading) { +@if (loading()) {
} -
- @if (!loading && dataSource) { +
+ @if (!loading() && dataSource) { @@ -73,7 +73,7 @@

After

- +
\ No newline at end of file diff --git a/src/app/settings-module/settings-account/settings-account.component.ts b/src/app/settings-module/settings-account/settings-account.component.ts index aa55b70a..f5af05cf 100644 --- a/src/app/settings-module/settings-account/settings-account.component.ts +++ b/src/app/settings-module/settings-account/settings-account.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, OnDestroy, inject } from '@angular/core'; +import { Component, OnInit, OnDestroy, inject, signal } from '@angular/core'; import { Subject } from 'rxjs'; import { AdminService } from 'src/app/services/admin.service'; import { takeUntil } from 'rxjs/operators'; @@ -37,23 +37,22 @@ export class SettingsAccountComponent extends BasicComponent implements OnInit, private readonly unsubscribe = new Subject(); accountForm: FormGroup; - domains = 1; + domains = signal(1); - userEmail: string; - userPlatform: string; - profileAvatar: string; + userEmail = signal(''); + userPlatform = signal(''); + profileAvatar = signal(''); constructor() { super(); - } - - ngOnInit(): void { - this.setBlockUI(true); - + // Initialize FormGroup immediately to avoid template errors this.accountForm = this.formBuilder.group({ name: ['', Validators.required] }); + } + ngOnInit(): void { + this.setBlockUI(true); this.loadDomains(); this.loadAdmin(); this.setBlockUI(false); @@ -112,7 +111,7 @@ export class SettingsAccountComponent extends BasicComponent implements OnInit, } getPlatformIcon(): string { - switch (this.userPlatform) { + switch (this.userPlatform()) { case 'Bitbucket': return String.raw`assets\bitbucket.svg`; case 'GitHub': return String.raw`assets\github.svg`; case 'SAML': return String.raw`assets\saml.svg`; @@ -126,11 +125,11 @@ export class SettingsAccountComponent extends BasicComponent implements OnInit, private loadAdmin() { this.accountFormControl.name.setValue(this.authService.getUserInfo('name')); - this.userEmail = this.authService.getUserInfo('email'); - this.userPlatform = this.authService.getUserInfo('platform'); + this.userEmail.set(this.authService.getUserInfo('email')); + this.userPlatform.set(this.authService.getUserInfo('platform')); const avatar = this.authService.getUserInfo('avatar'); - this.profileAvatar = avatar || String.raw`assets\switcherapi_mark_icon.png`; + this.profileAvatar.set(avatar || String.raw`assets\switcherapi_mark_icon.png`); } private loadDomains(): void { @@ -138,7 +137,7 @@ export class SettingsAccountComponent extends BasicComponent implements OnInit, .subscribe({ next: data => { if (data) { - this.domains = data.length; + this.domains.set(data.length); } }, error: error => { diff --git a/src/app/signup-domain/signup-domain.component.ts b/src/app/signup-domain/signup-domain.component.ts index b2f8ad47..b2d68b67 100644 --- a/src/app/signup-domain/signup-domain.component.ts +++ b/src/app/signup-domain/signup-domain.component.ts @@ -9,7 +9,7 @@ import { MatFormField, MatLabel, MatInput } from '@angular/material/input'; import { MatButton } from '@angular/material/button'; @Component({ - selector: 'signup-domain', + selector: 'app-signup-domain', templateUrl: './signup-domain.component.html', styleUrls: ['./signup-domain.component.css'], imports: [MatFormField, MatLabel, MatInput, MatButton] diff --git a/src/libs/ng-recaptcha-module/lib/recaptcha-value-accessor.directive.ts b/src/libs/ng-recaptcha-module/lib/recaptcha-value-accessor.directive.ts index 828c6f5d..5bc97b67 100644 --- a/src/libs/ng-recaptcha-module/lib/recaptcha-value-accessor.directive.ts +++ b/src/libs/ng-recaptcha-module/lib/recaptcha-value-accessor.directive.ts @@ -11,7 +11,7 @@ import { RecaptchaComponent } from "./recaptcha.component"; useExisting: forwardRef(() => RecaptchaValueAccessorDirective), }, ], - selector: "re-captcha[formControlName],re-captcha[formControl],re-captcha[ngModel]" + selector: "app-re-captcha[formControlName],app-re-captcha[formControl],app-re-captcha[ngModel]" }) export class RecaptchaValueAccessorDirective implements ControlValueAccessor { private readonly host = inject(RecaptchaComponent); diff --git a/src/libs/ng-recaptcha-module/lib/recaptcha.component.ts b/src/libs/ng-recaptcha-module/lib/recaptcha.component.ts index 9921396b..ca7dce50 100644 --- a/src/libs/ng-recaptcha-module/lib/recaptcha.component.ts +++ b/src/libs/ng-recaptcha-module/lib/recaptcha.component.ts @@ -14,8 +14,8 @@ export type NeverUndefined = T extends undefined ? never : T; export type RecaptchaErrorParameters = Parameters>; @Component({ - exportAs: "reCaptcha", - selector: "re-captcha", + exportAs: 'reCaptcha', + selector: 'app-re-captcha', template: `` }) export class RecaptchaComponent implements AfterViewInit, OnDestroy { diff --git a/src/libs/ng2-charts/src/lib/ng-charts.provider.ts b/src/libs/ng2-charts/src/lib/ng-charts.provider.ts index cd6450af..ae58eb90 100644 --- a/src/libs/ng2-charts/src/lib/ng-charts.provider.ts +++ b/src/libs/ng2-charts/src/lib/ng-charts.provider.ts @@ -1,10 +1,10 @@ import { InjectionToken } from '@angular/core'; +import { DeepPartial } from '@apollo/client/utilities'; import { ChartComponentLike, Defaults, registerables as defaultRegisterables, } from 'chart.js'; -import { DeepPartial } from 'chart.js/dist/types/utils'; import { merge } from 'lodash-es'; export const NG_CHARTS_CONFIGURATION = diff --git a/src/main.ts b/src/main.ts index 067cda16..b7fd734d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,4 +1,4 @@ -import { enableProdMode, importProvidersFrom, inject } from '@angular/core'; +import { enableProdMode, importProvidersFrom, inject, provideZonelessChangeDetection } from '@angular/core'; import { bootstrapApplication } from '@angular/platform-browser'; import '@angular/compiler'; // Required for JIT compilation @@ -86,6 +86,7 @@ bootstrapApplication(AppComponent, { AuthService, { provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true }, { provide: LocationStrategy, useClass: PathLocationStrategy }, + provideZonelessChangeDetection(), provideHttpClient(withInterceptorsFromDi()), provideCharts(withDefaultRegisterables()), provideRouter(routes), diff --git a/tsconfig.json b/tsconfig.json index 64a80830..b461bb92 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,8 +7,8 @@ "esModuleInterop": true, "declaration": false, "experimentalDecorators": true, - "module": "es2020", - "moduleResolution": "node", + "module": "es2022", + "moduleResolution": "bundler", "importHelpers": true, "target": "ES2022", "types": ["grecaptcha"], From 11089e97676157eb22f48f66a9c909257643f65e Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Thu, 27 Nov 2025 18:32:14 -0800 Subject: [PATCH 02/27] - migrated metric module to zoneless --- .../metric-data/metric-data.component.html | 4 +- .../metric-data/metric-data.component.ts | 54 +++++++++++++------ .../metric-filter.component.html | 2 +- .../metric-filter/metric-filter.component.ts | 6 +-- .../metric/metric.component.html | 14 ++--- .../metric-module/metric/metric.component.ts | 38 +++++++------ 6 files changed, 73 insertions(+), 45 deletions(-) diff --git a/src/app/dashboard-module/domain-module/metric-module/metric-data/metric-data.component.html b/src/app/dashboard-module/domain-module/metric-module/metric-data/metric-data.component.html index db5f4131..cc98fdd0 100644 --- a/src/app/dashboard-module/domain-module/metric-module/metric-data/metric-data.component.html +++ b/src/app/dashboard-module/domain-module/metric-module/metric-data/metric-data.component.html @@ -8,7 +8,7 @@ class="mat-elevation-z8" style="width: 100%;" aria-describedby="metrics" - [dataSource]="dataSource" + [dataSource]="dataSource()" (matSortChange)="sortData($event)"> @@ -70,7 +70,7 @@
} - @if (error) { -
{{error}}
+ @if (error()) { +
{{error()}}
}
- @if (!loading) { + @if (!loading()) {
}
- @if (!loading() && dataSource) { -
@@ -73,12 +73,12 @@

After

diff --git a/src/app/dashboard-module/domain-module/changelog/changelog.component.ts b/src/app/dashboard-module/domain-module/changelog/changelog.component.ts index e1b59924..f748c312 100644 --- a/src/app/dashboard-module/domain-module/changelog/changelog.component.ts +++ b/src/app/dashboard-module/domain-module/changelog/changelog.component.ts @@ -57,12 +57,12 @@ export class ChangelogComponent implements OnInit, OnDestroy { @ViewChild(MatSort, { static: true }) sort: MatSort; @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator; - dataSource: MatTableDataSource; + dataSource = signal | null>(null); dataColumns = ['newValue', 'date', 'updatedBy']; pageLimit = 11; - pageLength = 11; - pageSkip = 0; - pageFetch = true; + pageLength = signal(11); + pageSkip = signal(0); + pageFetch = signal(true); columnsToDisplay = [ { data: 'newValue', @@ -79,11 +79,11 @@ export class ChangelogComponent implements OnInit, OnDestroy { ]; expandedElement = signal(null); - configId: string; - groupId: string; + configId = signal(''); + groupId = signal(''); classStatus = signal("mat-elevation-z8 loading"); loading = signal(true); - fetch = true; + fetch = signal(true); removable = signal(false); constructor() { @@ -93,14 +93,14 @@ export class ChangelogComponent implements OnInit, OnDestroy { }); this.activatedRoute.params.subscribe(params => { - this.groupId = params.groupid; - this.configId = params.configid; + this.groupId.set(params.groupid || ''); + this.configId.set(params.configid || ''); }); this.activatedRoute.paramMap .pipe(map(() => globalThis.history.state)) .pipe(takeUntil(this.unsubscribe)) - .subscribe(data => this.fetch = data.navigationId === 1); + .subscribe(data => this.fetch.set(data.navigationId === 1)); } ngOnInit() { @@ -127,10 +127,10 @@ export class ChangelogComponent implements OnInit, OnDestroy { } onPage(event: PageEvent) { - this.pageSkip = (event.pageSize * (event.pageIndex + 1)) - event.pageSize; - this.pageSkip = this.pageSkip + (this.pageLength - this.pageSkip); + const newPageSkip = (event.pageSize * (event.pageIndex + 1)) - event.pageSize; + this.pageSkip.set(newPageSkip + (this.pageLength() - newPageSkip)); - if (this.pageFetch) { + if (this.pageFetch()) { this.loadChangeLog(); } } @@ -155,9 +155,9 @@ export class ChangelogComponent implements OnInit, OnDestroy { if (this.strategy) { this.loadStrategyHistory(); - } else if (this.configId) { + } else if (this.configId()) { this.loadConfigHistory(); - } else if (this.groupId) { + } else if (this.groupId()) { this.loadGroupHistory(); } else { this.loadDomainHistory(); @@ -166,7 +166,7 @@ export class ChangelogComponent implements OnInit, OnDestroy { private loadDomainHistory(): void { this.loading.set(true); - this.domainService.getHistory(this.domainId, this.pageLimit, this.pageSkip) + this.domainService.getHistory(this.domainId, this.pageLimit, this.pageSkip()) .pipe(takeUntil(this.unsubscribe)) .subscribe({ next: data => this.loadSuccess(data), @@ -179,19 +179,19 @@ export class ChangelogComponent implements OnInit, OnDestroy { private loadGroupHistory(): void { this.loading.set(true); - this.groupService.getHistory(this.groupId, this.pageLimit, this.pageSkip) + this.groupService.getHistory(this.groupId(), this.pageLimit, this.pageSkip()) .pipe(takeUntil(this.unsubscribe)) .subscribe({ next: data => this.loadSuccess(data), error: error => this.loadError(error) }); - if (this.fetch) { - this.groupService.getGroupById(this.groupId) + if (this.fetch()) { + this.groupService.getGroupById(this.groupId()) .pipe(takeUntil(this.unsubscribe)) .subscribe(data => { - this.domainRouteService.updatePath(this.groupId, data.name, Types.GROUP_TYPE, - `/dashboard/domain/${this.domainName}/${this.domainId}/groups/${this.groupId}`); + this.domainRouteService.updatePath(this.groupId(), data.name, Types.GROUP_TYPE, + `/dashboard/domain/${this.domainName}/${this.domainId}/groups/${this.groupId()}`); }); } else { this.domainRouteService.refreshPath(); @@ -200,26 +200,26 @@ export class ChangelogComponent implements OnInit, OnDestroy { private loadConfigHistory(): void { this.loading.set(true); - this.configService.getHistory(this.configId, this.pageLimit, this.pageSkip) + this.configService.getHistory(this.configId(), this.pageLimit, this.pageSkip()) .pipe(takeUntil(this.unsubscribe)) .subscribe({ next: data => this.loadSuccess(data), error: error => this.loadError(error) }); - if (this.fetch) { - this.configService.getConfigById(this.configId, false) + if (this.fetch()) { + this.configService.getConfigById(this.configId(), false) .pipe(takeUntil(this.unsubscribe)) .subscribe(data => { - this.domainRouteService.updatePath(this.configId, data.key, Types.CONFIG_TYPE, - `/dashboard/domain/${this.domainName}/${this.domainId}/groups/${this.groupId}/switchers/${this.configId}`); + this.domainRouteService.updatePath(this.configId(), data.key, Types.CONFIG_TYPE, + `/dashboard/domain/${this.domainName}/${this.domainId}/groups/${this.groupId()}/switchers/${this.configId()}`); }); } } private loadStrategyHistory(): void { this.loading.set(true); - this.strategyService.getHistory(this.strategy.id, this.pageLimit, this.pageSkip) + this.strategyService.getHistory(this.strategy.id, this.pageLimit, this.pageSkip()) .pipe(takeUntil(this.unsubscribe)) .subscribe({ next: data => this.loadSuccess(data), @@ -228,17 +228,19 @@ export class ChangelogComponent implements OnInit, OnDestroy { } private loadDataSource(data: History[], refresh: boolean): void { - if (this.dataSource && refresh) { - data = this.dataSource.data.concat(data); - this.pageLength = data.length; + const currentDataSource = this.dataSource(); + if (currentDataSource && refresh) { + data = currentDataSource.data.concat(data); + this.pageLength.set(data.length); } - this.dataSource = new MatTableDataSource(data); - this.dataSource.sort = this.sort; - this.dataSource.paginator = this.paginator; - this.dataSource.filterPredicate = (dataHistory: History, filter: string) => { + const newDataSource = new MatTableDataSource(data); + newDataSource.sort = this.sort; + newDataSource.paginator = this.paginator; + newDataSource.filterPredicate = (dataHistory: History, filter: string) => { return this.customFilterPredicate(dataHistory, filter); }; + this.dataSource.set(newDataSource); } private resetDomainChangeLog(): void { @@ -251,7 +253,7 @@ export class ChangelogComponent implements OnInit, OnDestroy { } private resetGroupChangeLog(): void { - this.groupService.resetHistory(this.groupId) + this.groupService.resetHistory(this.groupId()) .pipe(takeUntil(this.unsubscribe)) .subscribe({ next: data => this.changeLogSuccess(data), @@ -260,7 +262,7 @@ export class ChangelogComponent implements OnInit, OnDestroy { } private resetConfigChangeLog(): void { - this.configService.resetHistory(this.configId) + this.configService.resetHistory(this.configId()) .pipe(takeUntil(this.unsubscribe)) .subscribe({ next: data => this.changeLogSuccess(data), @@ -279,8 +281,8 @@ export class ChangelogComponent implements OnInit, OnDestroy { private changeLogSuccess(data: any): void { if (data) { - this.dataSource = new MatTableDataSource(null); - this.pageLength = 0; + this.dataSource.set(new MatTableDataSource([])); + this.pageLength.set(0); this.toastService.showSuccess(`Change Log reseted with success`); } } @@ -294,7 +296,7 @@ export class ChangelogComponent implements OnInit, OnDestroy { if (data?.length) { this.loadDataSource(data, true); } else { - this.pageFetch = false; + this.pageFetch.set(false); } this.loading.set(false); @@ -326,7 +328,10 @@ export class ChangelogComponent implements OnInit, OnDestroy { } sortData(sort: Sort) { - const data = this.dataSource.data.slice(); + const currentDataSource = this.dataSource(); + if (!currentDataSource) return; + + const data = currentDataSource.data.slice(); if (!sort.active || sort.direction === '') { return; @@ -380,10 +385,13 @@ export class ChangelogComponent implements OnInit, OnDestroy { } applyFilter(filterValue: string) { - this.dataSource.filter = filterValue.trim().toLowerCase(); + const currentDataSource = this.dataSource(); + if (!currentDataSource) return; + + currentDataSource.filter = filterValue.trim().toLowerCase(); - if (this.dataSource.paginator) { - this.dataSource.paginator.firstPage(); + if (currentDataSource.paginator) { + currentDataSource.paginator.firstPage(); } } @@ -395,9 +403,9 @@ export class ChangelogComponent implements OnInit, OnDestroy { if (result) { if (this.strategy) { this.resetStrategyChangeLog(); - } else if (this.configId) { + } else if (this.configId()) { this.resetConfigChangeLog(); - } else if (this.groupId) { + } else if (this.groupId()) { this.resetGroupChangeLog(); } else { this.resetDomainChangeLog(); From cd2e9a080d51c43ab1b60c0c6171816bdfecae9b Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Fri, 28 Nov 2025 16:25:49 -0800 Subject: [PATCH 04/27] - fixes components editing for zoneless compatibility --- .../domain-module/components/components.component.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/app/dashboard-module/domain-module/components/components.component.ts b/src/app/dashboard-module/domain-module/components/components.component.ts index c7adfd18..d3eb11fc 100644 --- a/src/app/dashboard-module/domain-module/components/components.component.ts +++ b/src/app/dashboard-module/domain-module/components/components.component.ts @@ -211,7 +211,13 @@ export class ComponentsComponent extends BasicComponent implements OnInit, OnDes .subscribe({ next: data => { if (data) { - selectedComponent.name = componentChanged.name; + const currentComponents = this.components(); + const updatedComponents = currentComponents.map(comp => + comp.id === selectedComponent.id + ? { ...comp, name: componentChanged.name } + : comp + ); + this.components.set(updatedComponents); this.toastService.showSuccess(`Component updated with success`); } }, From dbab3686713bbb7ef98ad2a77a9e5ed647ec6580 Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Fri, 28 Nov 2025 16:36:27 -0800 Subject: [PATCH 05/27] - fixes domain snapshot for zoneless compatibility --- .../domain-snapshot.component.html | 14 ++-- .../domain-snapshot.component.ts | 78 +++++++++---------- 2 files changed, 42 insertions(+), 50 deletions(-) diff --git a/src/app/dashboard-module/domain-module/domain/domain-snapshot/domain-snapshot.component.html b/src/app/dashboard-module/domain-module/domain/domain-snapshot/domain-snapshot.component.html index 7654c8c9..3e24a023 100644 --- a/src/app/dashboard-module/domain-module/domain/domain-snapshot/domain-snapshot.component.html +++ b/src/app/dashboard-module/domain-module/domain/domain-snapshot/domain-snapshot.component.html @@ -15,7 +15,7 @@

Environment - @for (environment of environments; track environment.name) { + @for (environment of environments(); track environment.name) { {{environment.name}} @@ -25,28 +25,28 @@

Component - @for (component of components; track component.name) { + @for (component of components(); track component.name) { {{component.name}} } - Environment Status - Description + Environment Status + Description
- @if (!snapshot) { + @if (!snapshot()) { } - @if (snapshot) { - diff --git a/src/app/dashboard-module/domain-module/domain/domain-snapshot/domain-snapshot.component.ts b/src/app/dashboard-module/domain-module/domain/domain-snapshot/domain-snapshot.component.ts index 65e2b363..d9be23b8 100644 --- a/src/app/dashboard-module/domain-module/domain/domain-snapshot/domain-snapshot.component.ts +++ b/src/app/dashboard-module/domain-module/domain/domain-snapshot/domain-snapshot.component.ts @@ -1,7 +1,5 @@ -import { Component, OnInit, OnDestroy, inject } from '@angular/core'; -import { Subject } from 'rxjs'; +import { Component, OnInit, inject, signal, effect } from '@angular/core'; import { FormControl, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { takeUntil } from 'rxjs/operators'; import { ToastService } from 'src/app/_helpers/toast.service'; import { ConsoleLogger } from 'src/app/_helpers/console-logger'; import { MatDialogRef, MAT_DIALOG_DATA, MatDialogTitle, MatDialogContent, MatDialogActions } from '@angular/material/dialog'; @@ -15,7 +13,6 @@ import { BlockUIComponent } from '../../../../shared/block-ui/block-ui.component import { MatToolbar } from '@angular/material/toolbar'; import { MatIconButton, MatButton } from '@angular/material/button'; import { MatIcon } from '@angular/material/icon'; -import { CdkScrollable } from '@angular/cdk/scrolling'; import { MatFormField, MatLabel } from '@angular/material/input'; import { MatSelect } from '@angular/material/select'; import { MatOption } from '@angular/material/autocomplete'; @@ -30,70 +27,65 @@ import { CdkCopyToClipboard } from '@angular/cdk/clipboard'; '../../common/css/create.component.css', './domain-snapshot.component.css' ], - imports: [BlockUIComponent, MatDialogTitle, MatToolbar, MatIconButton, MatIcon, CdkScrollable, MatDialogContent, + imports: [BlockUIComponent, MatDialogTitle, MatToolbar, MatIconButton, MatIcon, MatDialogContent, MatFormField, MatLabel, MatSelect, FormsModule, ReactiveFormsModule, MatOption, MatCheckbox, MatDialogActions, MatButton, CdkCopyToClipboard ] }) -export class DomainSnapshotComponent extends BasicComponent implements OnInit, OnDestroy { +export class DomainSnapshotComponent extends BasicComponent implements OnInit { dialogRef = inject>(MatDialogRef); data = inject(MAT_DIALOG_DATA); private readonly environmentService = inject(EnvironmentService); private readonly componentService = inject(ComponentService); private readonly domainService = inject(DomainService); private readonly toastService = inject(ToastService); - - private readonly unsubscribe = new Subject(); componentSelection = new FormControl('-', []); environmentSelection = new FormControl('default', [ Validators.required ]); - - components: SwitcherComponent[]; - environments: Environment[]; + components = signal([]); + environments = signal([]); + includeStatus = signal(true); + includeDescription = signal(true); + snapshot = signal(null); private readonly domainId: string; - includeStatus = true; - includeDescription = true; - snapshot: string; - constructor() { super(); const data = this.data; - this.domainId = data.domainId; + + effect(() => { + const envValue = this.environmentSelection.value; + if (envValue) { + this.data.environment = envValue; + } + }); + + effect(() => { + const compValue = this.componentSelection.value; + if (compValue) { + this.data.component = compValue; + } + }); } ngOnInit() { this.environmentService.getEnvironmentsByDomainId(this.domainId) - .pipe(takeUntil(this.unsubscribe)) .subscribe(environments => { - this.environments = environments; - this.environments = this.environments.filter(environment => environment.name !== this.data.currentEnvironment); + const filteredEnvironments = environments.filter(environment => + environment.name !== this.data.currentEnvironment); + this.environments.set(filteredEnvironments); }); - + this.componentService.getComponentsByDomain(this.domainId) - .pipe(takeUntil(this.unsubscribe)) .subscribe(components => { - this.components = [{ name: '-' } as SwitcherComponent]; - this.components.push(...components); + const componentsList = [{ name: '-' } as SwitcherComponent, ...components]; + this.components.set(componentsList); }); - - this.environmentSelection.valueChanges.pipe(takeUntil(this.unsubscribe)).subscribe(value => { - this.data.environment = value; - }); - - this.componentSelection.valueChanges.pipe(takeUntil(this.unsubscribe)).subscribe(value => { - this.data.component = value; - }); - } - - ngOnDestroy() { - this.unsubscribe.next(); - this.unsubscribe.complete(); } onCancel(): void { @@ -108,15 +100,15 @@ export class DomainSnapshotComponent extends BasicComponent implements OnInit, O const environment = this.environmentSelection.value; this.setBlockUI(true, 'Downloading...'); - this.snapshot = null; + this.snapshot.set(null); this.domainService.executeSnapshotQuery( - this.domainId, environment, component, this.includeStatus, this.includeDescription) - .pipe(takeUntil(this.unsubscribe)) + this.domainId, environment, component, this.includeStatus(), this.includeDescription()) .subscribe({ - next: result => { + next: (result: any) => { if (result) { const omitTypename = (key: any, value: any) => key === "__typename" ? undefined : value; - this.snapshot = JSON.stringify(JSON.parse(JSON.stringify(result.data), omitTypename), null, 2); + const snapshotData = JSON.stringify(JSON.parse(JSON.stringify(result.data), omitTypename), null, 2); + this.snapshot.set(snapshotData); this.lockEnvSelection(); this.toastService.showSuccess(`Snapshot downloaded with success`); } @@ -131,13 +123,13 @@ export class DomainSnapshotComponent extends BasicComponent implements OnInit, O } onCopy() { - this.snapshot = null; + this.snapshot.set(null); this.lockEnvSelection(); this.toastService.showSuccess(`Snapshot copied with success`); } private lockEnvSelection(): void { - if (this.snapshot) { + if (this.snapshot()) { this.environmentSelection.disable({ onlySelf: true }); this.componentSelection.disable({ onlySelf: true }); } else { From de41fb5614ffc80eb9e1fcd36faedcfa3f080eb5 Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Fri, 28 Nov 2025 16:51:06 -0800 Subject: [PATCH 06/27] - fixes group/config list when empty --- .../domain-module/config/config-list/config-list.component.ts | 2 +- .../domain-module/group/group-list/group-list.component.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/dashboard-module/domain-module/config/config-list/config-list.component.ts b/src/app/dashboard-module/domain-module/config/config-list/config-list.component.ts index dae9a606..eb15e35e 100644 --- a/src/app/dashboard-module/domain-module/config/config-list/config-list.component.ts +++ b/src/app/dashboard-module/domain-module/config/config-list/config-list.component.ts @@ -141,7 +141,7 @@ export class ConfigListComponent extends ListComponent implements OnInit, OnDest this.error.set(this.errorHandler.doError(error)); }, complete: () => { - if (!this.configs().length) { + if (this.configs() === null) { this.error.set('Failed to connect to Switcher API'); } diff --git a/src/app/dashboard-module/domain-module/group/group-list/group-list.component.ts b/src/app/dashboard-module/domain-module/group/group-list/group-list.component.ts index 117d93e2..62c803c6 100644 --- a/src/app/dashboard-module/domain-module/group/group-list/group-list.component.ts +++ b/src/app/dashboard-module/domain-module/group/group-list/group-list.component.ts @@ -144,7 +144,7 @@ export class GroupListComponent extends ListComponent implements OnInit, OnDestr this.error.set(this.errorHandler.doError(error)); }, complete: () => { - if (!this.groups().length) { + if (this.groups() === null) { this.error.set('Failed to connect to Switcher API'); } From 2a44a2f8d177372ead11a9f5a6c879ffca221046 Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Fri, 28 Nov 2025 18:32:26 -0800 Subject: [PATCH 07/27] - fixes domain transfer for zoneless compatibility --- .../domain-transfer-dialog.html | 2 +- .../signup-domain.component.html | 13 ++-- .../signup-domain/signup-domain.component.ts | 64 ++++++++----------- .../signup-team/signup-team.component.html | 3 +- 4 files changed, 34 insertions(+), 48 deletions(-) diff --git a/src/app/dashboard-module/domain-module/domain/domain-transfer/domain-transfer-dialog.html b/src/app/dashboard-module/domain-module/domain/domain-transfer/domain-transfer-dialog.html index 494f4843..d8158640 100644 --- a/src/app/dashboard-module/domain-module/domain/domain-transfer/domain-transfer-dialog.html +++ b/src/app/dashboard-module/domain-module/domain/domain-transfer/domain-transfer-dialog.html @@ -1,5 +1,5 @@

- + Domain Transfer - } - @if (error) { -
{{ error }}
+ } @else { +
{{ error() }}
}

} @else { diff --git a/src/app/signup-domain/signup-domain.component.ts b/src/app/signup-domain/signup-domain.component.ts index b2d68b67..6eff2e24 100644 --- a/src/app/signup-domain/signup-domain.component.ts +++ b/src/app/signup-domain/signup-domain.component.ts @@ -1,7 +1,6 @@ -import { Component, OnInit, OnDestroy, inject } from '@angular/core'; -import { Subject } from 'rxjs'; +import { Component, inject, signal, computed } from '@angular/core'; +import { toSignal } from '@angular/core/rxjs-interop'; import { ActivatedRoute, Router } from '@angular/router'; -import { takeUntil } from 'rxjs/operators'; import { ToastService } from 'src/app/_helpers/toast.service'; import { ConsoleLogger } from 'src/app/_helpers/console-logger'; import { DomainService } from 'src/app/services/domain.service'; @@ -14,51 +13,40 @@ import { MatButton } from '@angular/material/button'; styleUrls: ['./signup-domain.component.css'], imports: [MatFormField, MatLabel, MatInput, MatButton] }) -export class SignupDomainComponent implements OnInit, OnDestroy { +export class SignupDomainComponent { private readonly route = inject(ActivatedRoute); private readonly router = inject(Router); private readonly domainService = inject(DomainService); private readonly toastService = inject(ToastService); - private readonly unsubscribe = new Subject(); - - loading = false; - error = ''; - request: string; - domain: string; - - ngOnInit() { - this.route.queryParams.subscribe(params => { - this.request = params['request']; - this.domain = decodeURI(params['domain']); - }); - } + private readonly queryParams = toSignal(this.route.queryParams, { initialValue: {} }); + readonly loading = signal(false); + readonly error = signal(''); + + readonly request = computed(() => this.queryParams()?.['request'] || ''); + readonly domain = computed(() => this.queryParams()?.['domain'] ? decodeURI(this.queryParams()['domain']) : ''); onAccept() { - this.loading = true; - this.domainService.acceptDomainTransfer(this.request).pipe(takeUntil(this.unsubscribe)) - .subscribe({ - next: success => { - if (success) { - this.router.navigate(['/dashboard']); - this.toastService.showSuccess(`Domain transfered with success`); - } - this.loading = false; - }, - error: error => { - ConsoleLogger.printError(error); - this.error = `Domain cannot be transfered`; - this.loading = false; + this.loading.set(true); + this.error.set(''); + + this.domainService.acceptDomainTransfer(this.request()).subscribe({ + next: success => { + if (success) { + this.router.navigate(['/dashboard']); + this.toastService.showSuccess(`Domain transfered with success`); } - }); - } - - ngOnDestroy() { - this.unsubscribe.next(); - this.unsubscribe.complete(); + this.loading.set(false); + }, + error: error => { + ConsoleLogger.printError(error); + this.error.set(`Domain cannot be transfered`); + this.loading.set(false); + } + }); } onKey(_event: any) { - this.error = ''; + this.error.set(''); } } diff --git a/src/app/signup-team/signup-team.component.html b/src/app/signup-team/signup-team.component.html index 6cb5f765..328f17c4 100644 --- a/src/app/signup-team/signup-team.component.html +++ b/src/app/signup-team/signup-team.component.html @@ -22,8 +22,7 @@

- } - @if (error) { + } @else {
{{ error }}
} From 3271f67813a18451921d75b46d1997bd9f79c238 Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Mon, 1 Dec 2025 10:47:11 -0800 Subject: [PATCH 08/27] - fixes slack-auth for zoneless compatiblity --- .../relay-detail/relay-detail.component.html | 6 +- src/app/slack-auth/slack-auth.component.html | 22 +-- src/app/slack-auth/slack-auth.component.ts | 126 ++++++++++-------- 3 files changed, 83 insertions(+), 71 deletions(-) diff --git a/src/app/dashboard-module/domain-module/config/relay-detail/relay-detail.component.html b/src/app/dashboard-module/domain-module/config/relay-detail/relay-detail.component.html index b4af7f3c..57676481 100644 --- a/src/app/dashboard-module/domain-module/config/relay-detail/relay-detail.component.html +++ b/src/app/dashboard-module/domain-module/config/relay-detail/relay-detail.component.html @@ -7,8 +7,7 @@ Relay Type @if (!editing()) { - } - @else { + } @else { VALIDATION NOTIFICATION @@ -39,8 +38,7 @@ Relay Method @if (!editing()) { - } - @else { + } @else { GET POST diff --git a/src/app/slack-auth/slack-auth.component.html b/src/app/slack-auth/slack-auth.component.html index 7c3799d0..b962b930 100644 --- a/src/app/slack-auth/slack-auth.component.html +++ b/src/app/slack-auth/slack-auth.component.html @@ -14,13 +14,13 @@

Slack Integration

The Switcher Slack app is asking for your permission to link this domain to the Slack Workspace as identified below.

- @if (!loading) { + @if (!loading()) {
Select Domain - @for (domain of domains; track domain) { + @for (domain of domains(); track domain) { {{ domain.name }} @@ -28,38 +28,38 @@

Slack Integration

- @if (!error) { + @if (!error()) {
Slack Team - +
Slack Channel - +
}
- @if (!error) { - } - @if (!error) { - }
- @if (error) { -
{{ error }}
+ @if (error()) { +
{{ error() }}
}
} @else { diff --git a/src/app/slack-auth/slack-auth.component.ts b/src/app/slack-auth/slack-auth.component.ts index d890b054..113dbb60 100644 --- a/src/app/slack-auth/slack-auth.component.ts +++ b/src/app/slack-auth/slack-auth.component.ts @@ -1,8 +1,7 @@ -import { Component, OnDestroy, OnInit, inject } from '@angular/core'; +import { Component, inject, signal, computed, DestroyRef } from '@angular/core'; import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { Domain } from '../model/domain'; import { SlackInstallation } from '../model/slack'; import { DomainService } from '../services/domain.service'; @@ -21,55 +20,72 @@ import { MatIcon } from '@angular/material/icon'; styleUrls: ['./slack-auth.component.css'], imports: [MatFormField, MatLabel, MatSelect, FormsModule, ReactiveFormsModule, MatOption, MatInput, MatButton, MatIcon] }) -export class SlackAuthComponent implements OnInit, OnDestroy { +export class SlackAuthComponent { private readonly route = inject(ActivatedRoute); private readonly router = inject(Router); private readonly domainService = inject(DomainService); private readonly slackService = inject(SlackService); private readonly toastService = inject(ToastService); + private readonly destroyRef = inject(DestroyRef); - private readonly unsubscribe = new Subject(); + private readonly enterpriseId = signal(''); + private readonly teamId = signal(''); - private enterprise_id: string; - private team_id: string; - - domainFormControl = new FormControl(undefined); + readonly domainFormControl = new FormControl(undefined); - domains: Domain[]; - selectedDomain: Domain; - installation: SlackInstallation; - loading = false; - error = ''; - - ngOnInit(): void { - this.route.queryParams.subscribe(params => { - this.enterprise_id = params['e_id'] ?? ''; - this.team_id = params['t_id'] ?? ''; - this.error = this.validate(params['error'], params['reason']); + readonly domains = signal([]); + readonly selectedDomain = signal(undefined); + readonly installation = signal(undefined); + readonly loading = signal(false); + readonly error = signal(''); + + readonly validationError = computed(() => { + const selectedDomain = this.selectedDomain(); + const enterpriseId = this.enterpriseId(); + const teamId = this.teamId(); + + if (!selectedDomain) { + return 'Please, select a Domain to proceed with the Slack installation'; + } + + if (!enterpriseId && !teamId) { + return 'Unable to load Slack Authorization from the given URL'; + } + + return ''; + }); + + constructor() { + // Initialize query params subscription + this.route.queryParams.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(params => { + this.enterpriseId.set(params['e_id'] ?? ''); + this.teamId.set(params['t_id'] ?? ''); + + const validationError = this.validate(params['error'], params['reason']); + this.error.set(validationError); this.loadDomains(); }); - this.domainFormControl.valueChanges.subscribe(value => { - this.selectedDomain = value; - this.error = this.validate(); - if (!this.error) + // Form control value changes subscription + this.domainFormControl.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(value => { + this.selectedDomain.set(value); + const validationError = this.validationError(); + this.error.set(validationError); + + if (!validationError && value) { this.loadSlackInstallation(); - }) - } - - ngOnDestroy() { - this.unsubscribe.next(); - this.unsubscribe.complete(); + } + }); } - private loadDomains() { + private loadDomains(): void { this.domainService.getDomains() - .pipe(takeUntil(this.unsubscribe)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: data => { if (data) { - this.domains = data.filter(domain => !domain.integrations.slack); + this.domains.set(data.filter(domain => !domain.integrations.slack)); } }, error: error => { @@ -80,56 +96,54 @@ export class SlackAuthComponent implements OnInit, OnDestroy { } private loadSlackInstallation(): void { - this.loading = true; - this.slackService.findSlackInstallation(this.enterprise_id, this.team_id) - .pipe(takeUntil(this.unsubscribe)) + this.loading.set(true); + this.slackService.findSlackInstallation(this.enterpriseId(), this.teamId()) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: installation => { - this.installation = installation; - this.loading = false; + this.installation.set(installation); + this.loading.set(false); }, error: error => { ConsoleLogger.printError(error); - this.error = 'Unable to load Slack Installation'; - this.loading = false; + this.error.set('Unable to load Slack Installation'); + this.loading.set(false); } }); } private validate(responseCode?: number, responseReason?: string): string { - if (responseCode == 1) { + if (responseCode === 1) { ConsoleLogger.printError(responseReason); return 'Unable to proceed with the Slack installation, try it again'; } - - if (!this.selectedDomain) - return 'Please, select a Domain to proceed with the Slack installation'; - - if (!this.enterprise_id && !this.team_id) - return 'Unable to load Slack Authorization from the given URL'; + return ''; } onAuthorize(): void { - this.loading = true; - this.slackService.authorizeInstallation(this.selectedDomain.id, this.team_id) - .pipe(takeUntil(this.unsubscribe)) + this.loading.set(true); + const selectedDomain = this.selectedDomain(); + if (!selectedDomain) return; + + this.slackService.authorizeInstallation(selectedDomain.id, this.teamId()) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: () => { - this.toastService.showSuccess(`Slack App succesfully installed for ${this.selectedDomain.name}`); + this.toastService.showSuccess(`Slack App succesfully installed for ${selectedDomain.name}`); this.router.navigate(['/dashboard']); }, error: error => { ConsoleLogger.printError(error); this.toastService.showError(`Unable to complete the Slack installation`); - this.loading = false; + this.loading.set(false); } }); } onDecline(): void { - this.loading = true; - this.slackService.declineInstallation(this.enterprise_id, this.team_id) - .pipe(takeUntil(this.unsubscribe)) + this.loading.set(true); + this.slackService.declineInstallation(this.enterpriseId(), this.teamId()) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: () => { this.router.navigate(['/dashboard']); @@ -137,7 +151,7 @@ export class SlackAuthComponent implements OnInit, OnDestroy { error: error => { ConsoleLogger.printError(error); this.toastService.showError(`Unable to decline Slack installation`); - this.loading = false; + this.loading.set(false); } }); } From 4657de3096b3acd3bd3e670a2f5b32296cb1cd79 Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Mon, 1 Dec 2025 11:26:57 -0800 Subject: [PATCH 09/27] - fixes signup-team for zoneless compatiblity --- .../signup-team/signup-team.component.html | 12 ++-- src/app/signup-team/signup-team.component.ts | 61 ++++++++----------- 2 files changed, 33 insertions(+), 40 deletions(-) diff --git a/src/app/signup-team/signup-team.component.html b/src/app/signup-team/signup-team.component.html index 328f17c4..dd3517d6 100644 --- a/src/app/signup-team/signup-team.component.html +++ b/src/app/signup-team/signup-team.component.html @@ -4,26 +4,26 @@

Switcher Management

- @if (!loading) { + @if (!loading()) {
Domain - +
Team - +
- @if (!error) { - } @else { -
{{ error }}
+
{{ error() }}
}
} @else { diff --git a/src/app/signup-team/signup-team.component.ts b/src/app/signup-team/signup-team.component.ts index 06cfb70a..e4b0faeb 100644 --- a/src/app/signup-team/signup-team.component.ts +++ b/src/app/signup-team/signup-team.component.ts @@ -1,7 +1,6 @@ -import { Component, OnInit, OnDestroy, inject } from '@angular/core'; -import { Subject } from 'rxjs'; +import { Component, inject, signal, DestroyRef } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { takeUntil } from 'rxjs/operators'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { ToastService } from '../_helpers/toast.service'; import { ConsoleLogger } from '../_helpers/console-logger'; import { TeamService } from '../services/team.service'; @@ -14,74 +13,68 @@ import { MatButton } from '@angular/material/button'; styleUrls: ['./signup-team.component.css'], imports: [MatFormField, MatLabel, MatInput, MatButton] }) -export class SignupTeamComponent implements OnInit, OnDestroy { +export class SignupTeamComponent { private readonly route = inject(ActivatedRoute); private readonly router = inject(Router); private readonly teamService = inject(TeamService); private readonly toastService = inject(ToastService); + private readonly destroyRef = inject(DestroyRef); - private readonly unsubscribe = new Subject(); + readonly loading = signal(false); + readonly error = signal(''); + readonly request = signal(''); + readonly team = signal(''); + readonly domain = signal(''); - loading = false; - error = ''; - request: string; - team: string; - domain: string; - - ngOnInit() { - this.route.queryParams.subscribe(params => { - this.request = params['request']; + constructor() { + this.route.queryParams.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(params => { + this.request.set(params['request'] || ''); - if (this.request) { + if (this.request()) { this.loadInvite(); } }); } private loadInvite(): void { - this.teamService.getInvitation(this.request).pipe(takeUntil(this.unsubscribe)) + this.teamService.getInvitation(this.request()).pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: invite => { if (invite) { - this.team = invite.team; - this.domain = invite.domain; + this.team.set(invite.team); + this.domain.set(invite.domain); } - this.loading = false; + this.loading.set(false); }, error: error => { ConsoleLogger.printError(error); - this.error = error.error; - this.loading = false; + this.error.set(error.error); + this.loading.set(false); } }); } - onAccept() { - this.loading = true; + onAccept(): void { + this.loading.set(true); - this.teamService.acceptInvitation(this.request).pipe(takeUntil(this.unsubscribe)) + this.teamService.acceptInvitation(this.request()).pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: success => { if (success) { this.router.navigate(['/dashboard']); this.toastService.showSuccess(`Joined with success`); } - this.loading = false; + this.loading.set(false); }, error: error => { ConsoleLogger.printError(error); - this.error = error.error; - this.loading = false; + this.error.set(error.error); + this.loading.set(false); } }); } - ngOnDestroy() { - this.unsubscribe.next(); - this.unsubscribe.complete(); - } - - onKey(_event: any) { - this.error = ''; + onKey(_event: any): void { + this.error.set(''); } } From 79bf7d5d8b3e9f8a875defc7e74bd7113020c773 Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Mon, 1 Dec 2025 15:46:18 -0800 Subject: [PATCH 10/27] - fixes signup for zoneless compatiblity --- src/app/signup/signup.component.html | 20 +++--- src/app/signup/signup.component.ts | 98 +++++++++++++--------------- 2 files changed, 57 insertions(+), 61 deletions(-) diff --git a/src/app/signup/signup.component.html b/src/app/signup/signup.component.html index 630011ce..3da4b7b3 100644 --- a/src/app/signup/signup.component.html +++ b/src/app/signup/signup.component.html @@ -4,7 +4,7 @@

Switcher Management

- @if (!loading) { + @if (!loading()) {
@@ -35,38 +35,38 @@

@if (hasInternalAuthEnabled()) { - } @if (hasGithubIntegration()) { } @if (hasBitbucketIntegration()) { } @if (hasSamlAuthEnabled()) {
- }
- @if (error) { -
{{error}}
+ @if (error()) { +
{{error()}}
} - @if (status) { -
{{status}}
+ @if (status()) { +
{{status()}}
}
@@ -76,7 +76,7 @@

Switcher API } - + \ No newline at end of file diff --git a/src/app/signup/signup.component.ts b/src/app/signup/signup.component.ts index 161bceb3..e5d79304 100644 --- a/src/app/signup/signup.component.ts +++ b/src/app/signup/signup.component.ts @@ -1,10 +1,9 @@ -import { Component, OnInit, OnDestroy, inject } from '@angular/core'; +import { Component, inject, signal, computed, DestroyRef } from '@angular/core'; import { Router } from '@angular/router'; import { FormBuilder, FormGroup, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { AuthService } from '../auth/services/auth.service'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; import { environment } from 'src/environments/environment'; import { ConsoleLogger } from '../_helpers/console-logger'; import { MatFormField, MatLabel, MatInput } from '@angular/material/input'; @@ -20,50 +19,51 @@ import { AppVersionComponent } from '../app-version/app-version.component'; MatButton, AppVersionComponent ] }) -export class SignupComponent implements OnInit, OnDestroy { +export class SignupComponent { private readonly formBuilder = inject(FormBuilder); private readonly router = inject(Router); private readonly authService = inject(AuthService); private readonly recaptchaV3Service = inject(ReCaptchaV3Service); + private readonly destroyRef = inject(DestroyRef); - private readonly unsubscribe = new Subject(); + readonly loginForm: FormGroup; + readonly loading = signal(false); + readonly returnUrl = '/dashboard'; + readonly apiVersion = signal(''); + readonly error = signal(''); + readonly recaptchaToken = signal(''); + readonly status = signal(''); - loginForm: FormGroup; - loading = false; - returnUrl: string; - apiVersion: string; - error = ''; - recaptcha_token: string; - status = ''; - - ngOnInit() { - if (this.authService.isLoggedIn()) { - this.router.navigate(['/dashboard']); - } + readonly f = computed(() => this.loginForm.controls); + constructor() { this.loginForm = this.formBuilder.group({ name: ['', Validators.required], email: ['', [Validators.required, Validators.email]], password: ['', Validators.required] }); - this.returnUrl = '/dashboard'; + this.checkAuthAndRedirect(); this.isAlive(); } + private checkAuthAndRedirect(): void { + if (this.authService.isLoggedIn()) { + this.router.navigate(['/dashboard']); + } + } + getRecaptchaPublicKey(): string { return environment.recaptchaPublicKey; } - get f() { return this.loginForm.controls; } - - onSubmit() { + onSubmit(): void { if (this.loginForm.invalid) { return; } - this.status = ''; - this.loading = true; + this.status.set(''); + this.loading.set(true); if (!environment.recaptchaPublicKey) { this.submitForm(); @@ -71,42 +71,37 @@ export class SignupComponent implements OnInit, OnDestroy { } this.recaptchaV3Service.execute('signup') - .pipe(takeUntil(this.unsubscribe)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: (token) => { - this.recaptcha_token = token; + this.recaptchaToken.set(token); this.submitForm(); }, error: (error) => { ConsoleLogger.printError('reCAPTCHA error:', error); - this.error = 'reCAPTCHA verification failed. Please try again.'; - this.loading = false; + this.error.set('reCAPTCHA verification failed. Please try again.'); + this.loading.set(false); } }); } - onGitHubLogin() { - this.loading = true; + onGitHubLogin(): void { + this.loading.set(true); globalThis.location.href = `https://github.com/login/oauth/authorize?client_id=${environment.githubApiClientId}`; } - onBitbucketLogin() { - this.loading = true; + onBitbucketLogin(): void { + this.loading.set(true); globalThis.location.href = `https://bitbucket.org/site/oauth2/authorize?client_id=${environment.bitbucketApiClientId}&response_type=code`; } - onSamlLogin() { - this.loading = true; + onSamlLogin(): void { + this.loading.set(true); globalThis.location.href = `${environment.apiUrl}/admin/saml/login`; } - ngOnDestroy() { - this.unsubscribe.next(); - this.unsubscribe.complete(); - } - - onKey() { - this.error = ''; + onKey(): void { + this.error.set(''); } hasGithubIntegration(): boolean { @@ -125,34 +120,35 @@ export class SignupComponent implements OnInit, OnDestroy { return environment.allowSamlAuth; } - private submitForm() { + private submitForm(): void { + const formControls = this.f(); this.authService.signup({ - name: this.f.name.value, - email: this.f.email.value, - password: this.f.password.value, - token: this.recaptcha_token || '' - }).pipe(takeUntil(this.unsubscribe)) + name: formControls.name.value, + email: formControls.email.value, + password: formControls.password.value, + token: this.recaptchaToken() || '' + }).pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: () => { this.router.navigate(['/login']); }, error: error => { ConsoleLogger.printError(error); - this.error = error; - this.loading = false; + this.error.set(error); + this.loading.set(false); } }); } private isAlive(): void { - this.authService.isAlive().pipe(takeUntil(this.unsubscribe)) + this.authService.isAlive().pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: data => { - this.apiVersion = data?.attributes.version; + this.apiVersion.set(data?.attributes.version || ''); }, error: error => { ConsoleLogger.printError(error); - this.status = 'Offline for Maintenance'; + this.status.set('Offline for Maintenance'); } }); } From 0c404eaf9cf5a866c2b2cfc2e50fc6be471994e6 Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Mon, 1 Dec 2025 16:25:52 -0800 Subject: [PATCH 11/27] - fixes app/login for zoneless compatiblity --- src/app/app.component.html | 24 +++--- src/app/app.component.ts | 78 ++++++++++--------- src/app/login/login.component.html | 20 ++--- src/app/login/login.component.ts | 117 ++++++++++++++--------------- 4 files changed, 122 insertions(+), 117 deletions(-) diff --git a/src/app/app.component.html b/src/app/app.component.html index b91a90bb..563c34db 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -21,7 +21,7 @@
  • - @if (currentToken) { + @if (currentToken()) { dashboard Dashboard @@ -35,7 +35,7 @@
  • - @if (!currentToken) { + @if (!currentToken()) { login Sign in @@ -44,7 +44,7 @@

  • - @if (!currentToken) { + @if (!currentToken()) { person_add Sign up @@ -56,31 +56,31 @@ - + `, styleUrls: ['../documentation/documentation.component.css'], imports: [MarkdownComponent] diff --git a/src/app/documentation-module/docs/components.component.ts b/src/app/documentation-module/docs/components.component.ts index 18992241..c58b7e9e 100644 --- a/src/app/documentation-module/docs/components.component.ts +++ b/src/app/documentation-module/docs/components.component.ts @@ -9,7 +9,7 @@ import { MarkdownComponent } from 'ngx-markdown';

    Components

    Switcher API - + `, styleUrls: ['../documentation/documentation.component.css'], imports: [MarkdownComponent] diff --git a/src/app/documentation-module/docs/environment.component.ts b/src/app/documentation-module/docs/environment.component.ts index ba52b9a2..8b15cbe9 100644 --- a/src/app/documentation-module/docs/environment.component.ts +++ b/src/app/documentation-module/docs/environment.component.ts @@ -9,7 +9,7 @@ import { MarkdownComponent } from 'ngx-markdown';

    Environment

    Switcher API - + `, styleUrls: ['../documentation/documentation.component.css'], imports: [MarkdownComponent] diff --git a/src/app/documentation-module/docs/gitops.component.ts b/src/app/documentation-module/docs/gitops.component.ts index 5ec52cdf..f57e87b8 100644 --- a/src/app/documentation-module/docs/gitops.component.ts +++ b/src/app/documentation-module/docs/gitops.component.ts @@ -9,7 +9,7 @@ import { MarkdownComponent } from 'ngx-markdown';

    Switcher GitOps

    Switcher API - + `, styleUrls: ['../documentation/documentation.component.css'], imports: [MarkdownComponent] diff --git a/src/app/documentation-module/docs/home.component.ts b/src/app/documentation-module/docs/home.component.ts index 6b1eeb19..a69a71e0 100644 --- a/src/app/documentation-module/docs/home.component.ts +++ b/src/app/documentation-module/docs/home.component.ts @@ -9,7 +9,7 @@ import { MarkdownComponent } from 'ngx-markdown';

    Documentation

    Switcher API - + `, styleUrls: ['../documentation/documentation.component.css'], imports: [MarkdownComponent] diff --git a/src/app/documentation-module/docs/lib-java.component.ts b/src/app/documentation-module/docs/lib-java.component.ts index 15371167..340cc4d6 100644 --- a/src/app/documentation-module/docs/lib-java.component.ts +++ b/src/app/documentation-module/docs/lib-java.component.ts @@ -9,7 +9,7 @@ import { MarkdownComponent } from 'ngx-markdown';

    Java Library

    Switcher API - + `, styleUrls: ['../documentation/documentation.component.css'], imports: [MarkdownComponent] diff --git a/src/app/documentation-module/docs/lib-javascript.component.ts b/src/app/documentation-module/docs/lib-javascript.component.ts index 94bb2242..abf2741c 100644 --- a/src/app/documentation-module/docs/lib-javascript.component.ts +++ b/src/app/documentation-module/docs/lib-javascript.component.ts @@ -9,7 +9,7 @@ import { MarkdownComponent } from 'ngx-markdown';

    JavaScript Library

    Switcher API - + `, styleUrls: ['../documentation/documentation.component.css'], imports: [MarkdownComponent] diff --git a/src/app/documentation-module/docs/markdown-injector.component.ts b/src/app/documentation-module/docs/markdown-injector.component.ts index f73cc02a..96936391 100644 --- a/src/app/documentation-module/docs/markdown-injector.component.ts +++ b/src/app/documentation-module/docs/markdown-injector.component.ts @@ -1,20 +1,22 @@ import { environment } from 'src/environments/environment'; import { MarkdownService } from 'ngx-markdown'; -import { Injectable, inject } from '@angular/core'; +import { Injectable, inject, signal } from '@angular/core'; @Injectable() export abstract class MarkdownInjector { private readonly markdownService = inject(MarkdownService); - markdown: string; + readonly markdown = signal(''); protected init(documentToRender: string): void { this.markdownService.getSource(`${environment.docsUrl}${documentToRender}`).subscribe(data => { const darkPrefix = document.documentElement.classList.contains("dark-mode") ? '_dark' : ''; - this.markdown = data ? + const processedMarkdown = data ? data.replaceAll('[$ASSETS_LOCATION]', environment.docsUrl).replaceAll('[$DARK_SUFFIX]', darkPrefix) : `${environment.docsUrl}${documentToRender} not found`; + + this.markdown.set(processedMarkdown); }); document.documentElement.addEventListener('dark-mode', () => { diff --git a/src/app/documentation-module/docs/metrics.component.ts b/src/app/documentation-module/docs/metrics.component.ts index ef16495c..8efc301b 100644 --- a/src/app/documentation-module/docs/metrics.component.ts +++ b/src/app/documentation-module/docs/metrics.component.ts @@ -9,7 +9,7 @@ import { MarkdownComponent } from 'ngx-markdown';

    Metrics

    Switcher API - + `, styleUrls: ['../documentation/documentation.component.css'], imports: [MarkdownComponent] diff --git a/src/app/documentation-module/docs/relay.component.ts b/src/app/documentation-module/docs/relay.component.ts index 4220e087..ca9a6c25 100644 --- a/src/app/documentation-module/docs/relay.component.ts +++ b/src/app/documentation-module/docs/relay.component.ts @@ -9,7 +9,7 @@ import { MarkdownComponent } from 'ngx-markdown';

    Switcher Relay

    Switcher API - + `, styleUrls: ['../documentation/documentation.component.css'], imports: [MarkdownComponent] diff --git a/src/app/documentation-module/docs/setup.component.ts b/src/app/documentation-module/docs/setup.component.ts index abbe3c6d..7643e838 100644 --- a/src/app/documentation-module/docs/setup.component.ts +++ b/src/app/documentation-module/docs/setup.component.ts @@ -9,7 +9,7 @@ import { MarkdownComponent } from 'ngx-markdown';

    Setup

    Switcher API - + `, styleUrls: ['../documentation/documentation.component.css'], imports: [MarkdownComponent] diff --git a/src/app/documentation-module/docs/shortcuts.component.ts b/src/app/documentation-module/docs/shortcuts.component.ts index 68fd0454..d1a16dcf 100644 --- a/src/app/documentation-module/docs/shortcuts.component.ts +++ b/src/app/documentation-module/docs/shortcuts.component.ts @@ -9,7 +9,7 @@ import { MarkdownComponent } from 'ngx-markdown';

    Shortcuts

    Switcher API - + `, styleUrls: ['../documentation/documentation.component.css'], imports: [MarkdownComponent] diff --git a/src/app/documentation-module/docs/slack-features.component.ts b/src/app/documentation-module/docs/slack-features.component.ts index 754e1874..80731399 100644 --- a/src/app/documentation-module/docs/slack-features.component.ts +++ b/src/app/documentation-module/docs/slack-features.component.ts @@ -9,7 +9,7 @@ import { MarkdownComponent } from 'ngx-markdown';

    Slack App Features

    Switcher API - + `, styleUrls: ['../documentation/documentation.component.css'], imports: [MarkdownComponent] diff --git a/src/app/documentation-module/docs/slack-installation.component.ts b/src/app/documentation-module/docs/slack-installation.component.ts index ca47f000..a7ee6f68 100644 --- a/src/app/documentation-module/docs/slack-installation.component.ts +++ b/src/app/documentation-module/docs/slack-installation.component.ts @@ -9,7 +9,7 @@ import { MarkdownComponent } from 'ngx-markdown';

    Slack App Installation

    Switcher API - + `, styleUrls: ['../documentation/documentation.component.css'], imports: [MarkdownComponent] diff --git a/src/app/documentation-module/docs/strategies.component.ts b/src/app/documentation-module/docs/strategies.component.ts index 3223733b..52a5dc0e 100644 --- a/src/app/documentation-module/docs/strategies.component.ts +++ b/src/app/documentation-module/docs/strategies.component.ts @@ -9,7 +9,7 @@ import { MarkdownComponent } from 'ngx-markdown';

    Strategies

    Switcher API - + `, styleUrls: ['../documentation/documentation.component.css'], imports: [MarkdownComponent] diff --git a/src/app/documentation-module/docs/team.component.ts b/src/app/documentation-module/docs/team.component.ts index bc0e12a4..998447f0 100644 --- a/src/app/documentation-module/docs/team.component.ts +++ b/src/app/documentation-module/docs/team.component.ts @@ -9,7 +9,7 @@ import { MarkdownComponent } from 'ngx-markdown';

    Teams

    Switcher API - + `, styleUrls: ['../documentation/documentation.component.css'], imports: [MarkdownComponent] diff --git a/src/app/documentation-module/documentation/documentation.component.ts b/src/app/documentation-module/documentation/documentation.component.ts index b787691b..d7b87d6b 100644 --- a/src/app/documentation-module/documentation/documentation.component.ts +++ b/src/app/documentation-module/documentation/documentation.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, OnDestroy, inject } from '@angular/core'; +import { Component, OnInit, OnDestroy, inject, signal } from '@angular/core'; import { Router, RouterLink, RouterOutlet } from '@angular/router'; import { MatIcon } from '@angular/material/icon'; @@ -11,8 +11,8 @@ import { MatIcon } from '@angular/material/icon'; export class DocumentationComponent implements OnInit, OnDestroy { private readonly router = inject(Router); - sideBarTopPos: number; - prevScrollpos = window.scrollY; + readonly sideBarTopPos = signal(0); + readonly prevScrollpos = signal(window.scrollY); ngOnInit() { this.scrollMenuHandler(); @@ -47,14 +47,17 @@ export class DocumentationComponent implements OnInit, OnDestroy { } scrollMenuHandler() { - window.onscroll = function () { + window.onscroll = () => { const currentScrollPos = window.scrollY; - if (this.prevScrollpos > currentScrollPos) { - document.getElementById("sidebarCollapse").style.top = "0px"; - } else { - document.getElementById("sidebarCollapse").style.top = "-60px"; + const sidebarCollapse = document.getElementById("sidebarCollapse"); + if (sidebarCollapse) { + if (this.prevScrollpos() > currentScrollPos) { + sidebarCollapse.style.top = "0px"; + } else { + sidebarCollapse.style.top = "-60px"; + } } - this.prevScrollpos = currentScrollPos; + this.prevScrollpos.set(currentScrollPos); } } diff --git a/src/app/documentation-module/search/search.component.html b/src/app/documentation-module/search/search.component.html index 6ac84bcb..dda21908 100644 --- a/src/app/documentation-module/search/search.component.html +++ b/src/app/documentation-module/search/search.component.html @@ -3,15 +3,15 @@

    Search

    Switcher API logo -@if (loading) { +@if (loading()) {
    Switcher API logo
    } -@if (!loading && searchDocsResponse?.results.length === 0) { +@if (!loading() && searchDocsResponse()?.results.length === 0) { } -@for (searchDocsResult of searchDocsResponse?.results; track searchDocsResult) { +@for (searchDocsResult of searchDocsResponse()?.results; track searchDocsResult) { } \ No newline at end of file diff --git a/src/app/documentation-module/search/search.component.ts b/src/app/documentation-module/search/search.component.ts index cdfc9203..1b586b7d 100644 --- a/src/app/documentation-module/search/search.component.ts +++ b/src/app/documentation-module/search/search.component.ts @@ -1,7 +1,8 @@ -import { Component, OnInit, OnDestroy, inject } from '@angular/core'; +import { Component, inject, signal, effect } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { takeUntil } from 'rxjs/operators'; -import { Subject } from 'rxjs'; +import { toSignal } from '@angular/core/rxjs-interop'; +import { switchMap } from 'rxjs/operators'; +import { of } from 'rxjs'; import { SearchDocsService } from '../services/searchdocs.service'; import { SearchDocsResponse } from '../model/searchdocs-response'; import { SearchItemComponent } from '../search-item/search-item.component'; @@ -15,32 +16,31 @@ import { SearchItemComponent } from '../search-item/search-item.component'; ], imports: [SearchItemComponent] }) -export class SearchComponent implements OnInit, OnDestroy { +export class SearchComponent { private readonly searchDocsService = inject(SearchDocsService); private readonly route = inject(ActivatedRoute); - private readonly unsubscribe = new Subject(); + readonly query = toSignal( + this.route.paramMap.pipe( + switchMap(params => of(params.get('query'))) + ), + { initialValue: null } + ); + + readonly searchDocsResponse = signal(null); + readonly loading = signal(true); - query: string; - searchDocsResponse: SearchDocsResponse; - loading = true; - - ngOnInit(): void { - this.loading = true; - this.route.paramMap.subscribe(params => { - this.query = params.get("query"); - if (this.query) { - this.searchDocsService.search(this.query).pipe(takeUntil(this.unsubscribe)).subscribe(result => { - this.searchDocsResponse = result; - this.loading = false; + constructor() { + effect(() => { + const currentQuery = this.query(); + if (currentQuery) { + this.loading.set(true); + this.searchDocsService.search(currentQuery).subscribe(result => { + this.searchDocsResponse.set(result); + this.loading.set(false); }); } }); } - ngOnDestroy() { - this.unsubscribe.next(); - this.unsubscribe.complete(); - } - } diff --git a/src/assets/documentation/libjava.md b/src/assets/documentation/libjava.md index a8ac1755..efbb5474 100644 --- a/src/assets/documentation/libjava.md +++ b/src/assets/documentation/libjava.md @@ -563,17 +563,6 @@ public class MyNativeAppFeatures extends SwitcherContextBase { } ``` ---- - -#### Additional Resources - -- 📚 [Switcher Tutorials](https://github.com/switcherapi/switcherapi-tutorials) - Complete code examples and tutorials -- 🌐 [Switcher API Documentation](https://github.com/switcherapi/switcher-api) - Backend API documentation -- 💬 [Join our Slack](https://switcher-hq.slack.com/) - Community support and discussions -- 🐛 [Report Issues](https://github.com/switcherapi/switcher-client-java/issues) - Bug reports and feature requests - ---- - * * * *Did you find an error? Please, open an issue* From c42a1ae78200ee8a89b8c33ea6a06503857a084b Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Mon, 1 Dec 2025 17:05:51 -0800 Subject: [PATCH 16/27] - fixes ext-slack for zoneless compatiblity --- .../ext-slack/ext-slack.component.html | 18 +- .../ext-slack/ext-slack.component.ts | 175 ++++++++++-------- .../slack-settings.component.html | 8 +- .../slack-settings.component.ts | 38 ++-- 4 files changed, 129 insertions(+), 110 deletions(-) diff --git a/src/app/dashboard-module/domain-module/ext-slack/ext-slack.component.html b/src/app/dashboard-module/domain-module/ext-slack/ext-slack.component.html index 793789c7..a8de45f4 100644 --- a/src/app/dashboard-module/domain-module/ext-slack/ext-slack.component.html +++ b/src/app/dashboard-module/domain-module/ext-slack/ext-slack.component.html @@ -1,4 +1,4 @@ -@if (loading) { +@if (loading()) {
    @@ -13,25 +13,25 @@

    Slack Integration

    - @if (slack) { + @if (slack(); as slackData) {
    Details
    Team Name - + Approval Channel - + Installed At - + - @if (allowUpdate) { + @if (allowUpdate()) { - fiber_new {{slack.tickets_opened}} + fiber_new {{slackData.tickets_opened}} }
    @@ -45,9 +45,9 @@
    Details
    Settings
    - @if (allowUpdate) { + @if (allowUpdate()) {
    - @if (slackUpdate) { + @if (slackUpdate()) { } - Frozen Environments - @for (env of frozenEnvironments; track env) { + @for (env of frozenEnvironments(); track env) { {{env}} @@ -31,7 +31,7 @@ } - ([]); + readonly frozenEnvironments = signal([]); + readonly settings = signal(null); + readonly updatable = signal(false); loadSettings(slack: Slack): void { - this.settings = { ...slack.settings }; - this.ignoredEnvironments = Object.assign([], slack.settings.ignored_environments); - this.frozenEnvironments = Object.assign([], slack.settings.frozen_environments); + this.settings.set({ ...slack.settings }); + this.ignoredEnvironments.set([...slack.settings.ignored_environments]); + this.frozenEnvironments.set([...slack.settings.frozen_environments]); } updateSettings(settings: Settings) { - this.settings.ignored_environments = Object.assign([], settings.ignored_environments); - this.settings.frozen_environments = Object.assign([], settings.frozen_environments); + this.settings.update(current => current ? { + ...current, + ignored_environments: [...settings.ignored_environments], + frozen_environments: [...settings.frozen_environments] + } : null); } add(event: MatChipInputEvent, list: string): void { const value = (event.value || '').trim(); if (value) { - if (list === 'ignored') - this.ignoredEnvironments.push(value); - else if (list === 'frozen') - this.frozenEnvironments.push(value); + if (list === 'ignored') { + this.ignoredEnvironments.update(envs => [...envs, value]); + } else if (list === 'frozen') { + this.frozenEnvironments.update(envs => [...envs, value]); + } } event.chipInput.clear(); @@ -46,11 +50,9 @@ export class SlackSettingsComponent { remove(env: string, list: string): void { if (list === 'ignored') { - const index = this.ignoredEnvironments.indexOf(env); - this.ignoredEnvironments.splice(index, 1); + this.ignoredEnvironments.update(envs => envs.filter(e => e !== env)); } else if (list === 'frozen') { - const index = this.frozenEnvironments.indexOf(env); - this.frozenEnvironments.splice(index, 1); + this.frozenEnvironments.update(envs => envs.filter(e => e !== env)); } } From 809f5869abe9db51e45e2aa72a8eb427b8e007c5 Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Mon, 1 Dec 2025 17:12:09 -0800 Subject: [PATCH 17/27] - bump version to v2.2.0 --- package.json | 2 +- src/environments/environment.global.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 4858d691..720f1176 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "switcher-management", - "version": "2.1.1", + "version": "2.2.0", "description": "Manage Switcher API settings, teams, integrations and more.", "author": { "name": "Roger Floriano (petruki)", diff --git a/src/environments/environment.global.ts b/src/environments/environment.global.ts index 068d3295..506c6d24 100644 --- a/src/environments/environment.global.ts +++ b/src/environments/environment.global.ts @@ -1,5 +1,5 @@ export const environment_global = { - version: 'v2.1.1', + version: 'v2.2.0', releaseTime: new Date().toUTCString(), recaptchaPublicKey: '6Lc4fMErAAAAAJSdF2ZRV6HJI_m-nhiDu8Gue18P', allowInternalAuth: true, From 2d9cc04d8059b70d510018fdef2f5231b0568e15 Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:16:20 -0800 Subject: [PATCH 18/27] - fixes domain-preview for zoneless compatiblity --- .../domain-preview.component.html | 6 ++-- .../domain-preview.component.ts | 29 +++++++++---------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/app/dashboard-module/domain-preview/domain-preview.component.html b/src/app/dashboard-module/domain-preview/domain-preview.component.html index b16c3638..3963a384 100644 --- a/src/app/dashboard-module/domain-preview/domain-preview.component.html +++ b/src/app/dashboard-module/domain-preview/domain-preview.component.html @@ -1,8 +1,8 @@ -
    -
    +
    +
    - {{domain.name}} + {{domain().name}}
    \ No newline at end of file diff --git a/src/app/dashboard-module/domain-preview/domain-preview.component.ts b/src/app/dashboard-module/domain-preview/domain-preview.component.ts index d0ce26d7..0de47c84 100644 --- a/src/app/dashboard-module/domain-preview/domain-preview.component.ts +++ b/src/app/dashboard-module/domain-preview/domain-preview.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, Input, inject } from '@angular/core'; +import { Component, inject, input, computed } from '@angular/core'; import { Router } from '@angular/router'; import { Domain } from 'src/app/model/domain'; import { NgClass } from '@angular/common'; @@ -12,26 +12,23 @@ import { NgClass } from '@angular/common'; ], imports: [NgClass] }) -export class DomainPreviewComponent implements OnInit { +export class DomainPreviewComponent { private readonly router = inject(Router); - @Input() domain: Domain; + domain = input.required(); - classStatus: string; - classBtnStatus: string; - - ngOnInit() { - this.updateStatus(); - } + classStatus = computed(() => + this.domain().activated['default'] ? 'grid-container activated' : 'grid-container deactivated' + ); + + classBtnStatus = computed(() => + this.domain().activated['default'] ? 'header-section activated' : 'header-section deactivated' + ); selectDomain() { - this.router.navigate([`/dashboard/domain/${encodeURIComponent(this.domain.name)}/${this.domain.id}`], - { state: { element: JSON.stringify(this.domain) } }); - } - - updateStatus(): void { - this.classStatus = this.domain.activated['default'] ? 'grid-container activated' : 'grid-container deactivated'; - this.classBtnStatus = this.domain.activated['default'] ? 'header-section activated' : 'header-section deactivated'; + const domainValue = this.domain(); + this.router.navigate([`/dashboard/domain/${encodeURIComponent(domainValue.name)}/${domainValue.id}`], + { state: { element: JSON.stringify(domainValue) } }); } } From 87c12bd07e788d0d90c1d88c91b8a28b6f2ab20c Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:22:16 -0800 Subject: [PATCH 19/27] - fixes group-preview for zoneless compatiblity --- .../group-preview.component.html | 12 +- .../group-preview/group-preview.component.ts | 122 +++++++++++------- 2 files changed, 82 insertions(+), 52 deletions(-) diff --git a/src/app/dashboard-module/domain-module/group/group-preview/group-preview.component.html b/src/app/dashboard-module/domain-module/group/group-preview/group-preview.component.html index 7e326314..51bf340a 100644 --- a/src/app/dashboard-module/domain-module/group/group-preview/group-preview.component.html +++ b/src/app/dashboard-module/domain-module/group/group-preview/group-preview.component.html @@ -1,16 +1,16 @@ -
    -
    +
    +
    - {{ group.name }} + {{ group().name }}
    -
    -
    +
    + diff --git a/src/app/dashboard-module/domain-module/group/group-preview/group-preview.component.ts b/src/app/dashboard-module/domain-module/group/group-preview/group-preview.component.ts index 43dc35d5..345b8d54 100644 --- a/src/app/dashboard-module/domain-module/group/group-preview/group-preview.component.ts +++ b/src/app/dashboard-module/domain-module/group/group-preview/group-preview.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, Input, OnDestroy, EventEmitter, inject } from '@angular/core'; +import { Component, OnDestroy, inject, input, computed, signal, effect, EventEmitter } from '@angular/core'; import { Router } from '@angular/router'; import { takeUntil } from 'rxjs/operators'; import { Subject } from 'rxjs'; @@ -22,7 +22,7 @@ import { NgClass } from '@angular/common'; ], imports: [BlockUIComponent, NgClass, FormsModule, ReactiveFormsModule, MatSlideToggle] }) -export class GroupPreviewComponent extends BasicComponent implements OnInit, OnDestroy { +export class GroupPreviewComponent extends BasicComponent implements OnDestroy { private readonly router = inject(Router); private readonly fb = inject(FormBuilder); private readonly groupService = inject(GroupService); @@ -30,32 +30,45 @@ export class GroupPreviewComponent extends BasicComponent implements OnInit, OnD private readonly unsubscribe = new Subject(); - @Input() domainId: string; - @Input() domainName: string; - @Input() group: Group; - @Input() environmentSelectionChange: EventEmitter; - @Input() permissions: Permissions[]; - - environmentStatusSelection: FormGroup; - selectedEnvStatus: boolean; - selectedEnv: string; - - classStatus: string; - classBtnStatus: string; + domainId = input.required(); + domainName = input.required(); + group = input.required(); + environmentSelectionChange = input.required>(); + permissions = input.required(); + + environmentStatusSelection = signal(null); + selectedEnvStatus = signal(false); + selectedEnv = signal(''); + + classStatus = computed(() => { + const status = this.group().activated[this.selectedEnv()] ?? this.group().activated['default']; + return status ? 'grid-container activated' : 'grid-container deactivated'; + }); + + classBtnStatus = computed(() => { + const status = this.group().activated[this.selectedEnv()] ?? this.group().activated['default']; + return status ? 'header-section activated' : 'header-section deactivated'; + }); - updatable = false; - removable = false; + updatable = signal(false); + removable = signal(false); - toggleSectionStyle = 'toggle-section deactivated'; + toggleSectionStyle = signal('toggle-section deactivated'); constructor() { super(); - } - - ngOnInit() { - this.readPermissionToObject(); - this.environmentSelectionChange.pipe(takeUntil(this.unsubscribe)).subscribe(envName => { - this.selectEnvironment(envName); + + // Initialize form and permissions when component is created + effect(() => { + this.readPermissionToObject(); + }, { allowSignalWrites: true }); + + // Subscribe to environment changes + effect(() => { + const envChangeEmitter = this.environmentSelectionChange(); + envChangeEmitter.pipe(takeUntil(this.unsubscribe)).subscribe(envName => { + this.selectEnvironment(envName); + }); }); } @@ -65,31 +78,39 @@ export class GroupPreviewComponent extends BasicComponent implements OnInit, OnD } selectGroup() { - this.router.navigate([`/dashboard/domain/${this.domainName}/${this.domainId}/groups/${this.group.id}`]); + const domainName = this.domainName(); + const domainId = this.domainId(); + const group = this.group(); + this.router.navigate([`/dashboard/domain/${domainName}/${domainId}/groups/${group.id}`]); } selectEnvironment(envName: string): void { - this.selectedEnv = envName; - const status = this.group.activated[envName] ?? this.group.activated['default']; - - this.classStatus = status ? 'grid-container activated' : 'grid-container deactivated'; - this.classBtnStatus = status ? 'header-section activated' : 'header-section deactivated'; + this.selectedEnv.set(envName); + const group = this.group(); + const status = group.activated[envName] ?? group.activated['default']; - this.environmentStatusSelection.get('environmentStatusSelection').setValue(status); - this.selectedEnvStatus = status; + const form = this.environmentStatusSelection(); + if (form) { + form.get('environmentStatusSelection')?.setValue(status); + } + this.selectedEnvStatus.set(status); } updateEnvironmentStatus(event: MatSlideToggleChange) { this.setBlockUI(true, 'Updating environment...'); - this.group.activated[this.selectedEnv] = event.checked; - this.selectEnvironment(this.selectedEnv); + const group = this.group(); + const selectedEnv = this.selectedEnv(); + + group.activated[selectedEnv] = event.checked; + this.selectEnvironment(selectedEnv); - this.groupService.setGroupEnvironmentStatus(this.group.id, this.selectedEnv, event.checked) + this.groupService.setGroupEnvironmentStatus(group.id, selectedEnv, event.checked) .pipe(takeUntil(this.unsubscribe)) .subscribe({ next: data => { if (data) { - this.group.activated = data.activated; + const updatedGroup = this.group(); + updatedGroup.activated = data.activated; this.setBlockUI(false); this.toastService.showSuccess(`Environment updated with success`); } @@ -97,37 +118,46 @@ export class GroupPreviewComponent extends BasicComponent implements OnInit, OnD error: error => { this.setBlockUI(false); ConsoleLogger.printError(error); - this.toastService.showError(`Unable to update the environment '${this.selectedEnv}'`); + this.toastService.showError(`Unable to update the environment '${selectedEnv}'`); } }); } private loadOperationSelectionComponent(): void { - this.environmentStatusSelection = this.fb.group({ + const formGroup = this.fb.group({ environmentStatusSelection: [null, Validators.required] }); + this.environmentStatusSelection.set(formGroup); } private readPermissionToObject(): void { this.loadOperationSelectionComponent(); - const element = this.permissions.filter(p => p.id === this.group.id)[0]; - this.updatable = element.permissions.find(p => p.action === 'UPDATE').result === 'ok'; - this.removable = element.permissions.find(p => p.action === 'DELETE').result === 'ok'; + const permissions = this.permissions(); + const group = this.group(); + const element = permissions.find(p => p.id === group.id); - if (this.isEnvStatusChangeAllowed(element)) { - this.enableEnvStatusControl(); - } else { - this.disableEnvStatusControl(); + if (element) { + this.updatable.set(element.permissions.find(p => p.action === 'UPDATE')?.result === 'ok'); + this.removable.set(element.permissions.find(p => p.action === 'DELETE')?.result === 'ok'); + + if (this.isEnvStatusChangeAllowed(element)) { + this.enableEnvStatusControl(); + } else { + this.disableEnvStatusControl(); + } } } private enableEnvStatusControl(): void { - this.toggleSectionStyle = 'toggle-section'; + this.toggleSectionStyle.set('toggle-section'); } private disableEnvStatusControl(): void { - this.environmentStatusSelection.disable({ onlySelf: true }); + const form = this.environmentStatusSelection(); + if (form) { + form.disable({ onlySelf: true }); + } } private isEnvStatusChangeAllowed(element: Permissions): boolean { From 9a778fbfa9cbea93aadf9a3029f1d940fa59f383 Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:25:38 -0800 Subject: [PATCH 20/27] - fixes config-preview for zoneless compatiblity --- .../config-preview.component.html | 12 +- .../config-preview.component.ts | 123 +++++++++++------- 2 files changed, 83 insertions(+), 52 deletions(-) diff --git a/src/app/dashboard-module/domain-module/config/config-preview/config-preview.component.html b/src/app/dashboard-module/domain-module/config/config-preview/config-preview.component.html index a5602b7b..8c5bd7a9 100644 --- a/src/app/dashboard-module/domain-module/config/config-preview/config-preview.component.html +++ b/src/app/dashboard-module/domain-module/config/config-preview/config-preview.component.html @@ -1,16 +1,16 @@ -
    -
    +
    +
    - {{config.key}} + {{config().key}}
    -
    -
    +
    + diff --git a/src/app/dashboard-module/domain-module/config/config-preview/config-preview.component.ts b/src/app/dashboard-module/domain-module/config/config-preview/config-preview.component.ts index eee26abc..bc6f35b5 100644 --- a/src/app/dashboard-module/domain-module/config/config-preview/config-preview.component.ts +++ b/src/app/dashboard-module/domain-module/config/config-preview/config-preview.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, Input, OnDestroy, EventEmitter, inject } from '@angular/core'; +import { Component, OnDestroy, inject, input, computed, signal, effect, EventEmitter } from '@angular/core'; import { Router } from '@angular/router'; import { Subject } from 'rxjs'; import { FormGroup, FormBuilder, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms'; @@ -22,7 +22,7 @@ import { NgClass } from '@angular/common'; ], imports: [BlockUIComponent, NgClass, FormsModule, ReactiveFormsModule, MatSlideToggle] }) -export class ConfigPreviewComponent extends BasicComponent implements OnInit, OnDestroy { +export class ConfigPreviewComponent extends BasicComponent implements OnDestroy { private readonly router = inject(Router); private readonly fb = inject(FormBuilder); private readonly configService = inject(ConfigService); @@ -30,34 +30,47 @@ export class ConfigPreviewComponent extends BasicComponent implements OnInit, On private readonly unsubscribe = new Subject(); - @Input() domainId: string; - @Input() domainName: string; - @Input() groupId: string; - @Input() config: Config; - @Input() environmentSelectionChange: EventEmitter; - @Input() permissions: Permissions[]; + domainId = input.required(); + domainName = input.required(); + groupId = input.required(); + config = input.required(); + environmentSelectionChange = input.required>(); + permissions = input.required(); - environmentStatusSelection: FormGroup; - selectedEnvStatus: boolean; - selectedEnv: string; + environmentStatusSelection = signal(null); + selectedEnvStatus = signal(false); + selectedEnv = signal(''); - classStatus: string; - classBtnStatus: string; + classStatus = computed(() => { + const status = this.config().activated[this.selectedEnv()] ?? this.config().activated['default']; + return status ? 'grid-container activated' : 'grid-container deactivated'; + }); + + classBtnStatus = computed(() => { + const status = this.config().activated[this.selectedEnv()] ?? this.config().activated['default']; + return status ? 'header-section activated' : 'header-section deactivated'; + }); - updatable = false; - removable = false; + updatable = signal(false); + removable = signal(false); - toggleSectionStyle = 'toggle-section deactivated'; + toggleSectionStyle = signal('toggle-section deactivated'); constructor() { super(); - } - - ngOnInit() { - this.readPermissionToObject(); - this.loadOperationSelectionComponent(); - this.environmentSelectionChange.pipe(takeUntil(this.unsubscribe)).subscribe(envName => { - this.selectEnvironment(envName); + + // Initialize form and permissions when component is created + effect(() => { + this.readPermissionToObject(); + this.loadOperationSelectionComponent(); + }, { allowSignalWrites: true }); + + // Subscribe to environment changes + effect(() => { + const envChangeEmitter = this.environmentSelectionChange(); + envChangeEmitter.pipe(takeUntil(this.unsubscribe)).subscribe(envName => { + this.selectEnvironment(envName); + }); }); } @@ -67,20 +80,28 @@ export class ConfigPreviewComponent extends BasicComponent implements OnInit, On } selectConfig() { - this.router.navigate([`/dashboard/domain/${this.domainName}/${this.domainId}/groups/${this.groupId}/switchers/${this.config.id}`]); + const domainName = this.domainName(); + const domainId = this.domainId(); + const groupId = this.groupId(); + const config = this.config(); + this.router.navigate([`/dashboard/domain/${domainName}/${domainId}/groups/${groupId}/switchers/${config.id}`]); } updateEnvironmentStatus(event: MatSlideToggleChange) { this.setBlockUI(true, 'Updating environment...'); - this.config.activated[this.selectedEnv] = event.checked; - this.selectEnvironment(this.selectedEnv); + const config = this.config(); + const selectedEnv = this.selectedEnv(); + + config.activated[selectedEnv] = event.checked; + this.selectEnvironment(selectedEnv); - this.configService.setConfigEnvironmentStatus(this.config.id, this.selectedEnv, event.checked) + this.configService.setConfigEnvironmentStatus(config.id, selectedEnv, event.checked) .pipe(takeUntil(this.unsubscribe)) .subscribe({ next: data => { if (data) { - this.config.activated = data.activated; + const updatedConfig = this.config(); + updatedConfig.activated = data.activated; this.setBlockUI(false); this.toastService.showSuccess(`Environment updated with success`); } @@ -88,48 +109,58 @@ export class ConfigPreviewComponent extends BasicComponent implements OnInit, On error: error => { this.setBlockUI(false); ConsoleLogger.printError(error); - this.toastService.showError(`Unable to update the environment '${this.selectedEnv}'`); + this.toastService.showError(`Unable to update the environment '${selectedEnv}'`); } }); } private loadOperationSelectionComponent(): void { - this.environmentStatusSelection = this.fb.group({ + const formGroup = this.fb.group({ environmentStatusSelection: [null, Validators.required] }); + this.environmentStatusSelection.set(formGroup); } private selectEnvironment(envName: string): void { - this.selectedEnv = envName; - const status = this.config.activated[envName] ?? this.config.activated['default']; - - this.classStatus = status ? 'grid-container activated' : 'grid-container deactivated'; - this.classBtnStatus = status ? 'header-section activated' : 'header-section deactivated'; + this.selectedEnv.set(envName); + const config = this.config(); + const status = config.activated[envName] ?? config.activated['default']; - this.environmentStatusSelection.get('environmentStatusSelection').setValue(status); - this.selectedEnvStatus = status; + const form = this.environmentStatusSelection(); + if (form) { + form.get('environmentStatusSelection')?.setValue(status); + } + this.selectedEnvStatus.set(status); } private readPermissionToObject(): void { this.loadOperationSelectionComponent(); - const element = this.permissions.find(p => p.id === this.config.id); - this.updatable = element.permissions.find(p => p.action === 'UPDATE').result === 'ok'; - this.removable = element.permissions.find(p => p.action === 'DELETE').result === 'ok'; + const permissions = this.permissions(); + const config = this.config(); + const element = permissions.find(p => p.id === config.id); - if (this.isEnvStatusChangeAllowed(element)) { - this.enableEnvStatusControl(); - } else { - this.disableEnvStatusControl(); + if (element) { + this.updatable.set(element.permissions.find(p => p.action === 'UPDATE')?.result === 'ok'); + this.removable.set(element.permissions.find(p => p.action === 'DELETE')?.result === 'ok'); + + if (this.isEnvStatusChangeAllowed(element)) { + this.enableEnvStatusControl(); + } else { + this.disableEnvStatusControl(); + } } } private enableEnvStatusControl(): void { - this.toggleSectionStyle = 'toggle-section'; + this.toggleSectionStyle.set('toggle-section'); } private disableEnvStatusControl(): void { - this.environmentStatusSelection.disable({ onlySelf: true }); + const form = this.environmentStatusSelection(); + if (form) { + form.disable({ onlySelf: true }); + } } private isEnvStatusChangeAllowed(element: Permissions): boolean { From 1f55a5c5494ff0027cf809980ede23aeb8d4359e Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Tue, 2 Dec 2025 12:05:43 -0800 Subject: [PATCH 21/27] - fixes ext-gitops for zoneless compatiblity --- .../ext-gitops/ext-gitops.component.html | 66 ++-- .../ext-gitops/ext-gitops.component.ts | 299 ++++++++++-------- .../gitops-env-selection.component.html | 2 +- .../gitops-env-selection.component.ts | 32 +- .../gitops-update-tokens.component.html | 6 +- .../gitops-update-tokens.component.ts | 40 ++- 6 files changed, 238 insertions(+), 207 deletions(-) diff --git a/src/app/dashboard-module/domain-module/ext-gitops/ext-gitops.component.html b/src/app/dashboard-module/domain-module/ext-gitops/ext-gitops.component.html index bc28de20..0ccf58f6 100644 --- a/src/app/dashboard-module/domain-module/ext-gitops/ext-gitops.component.html +++ b/src/app/dashboard-module/domain-module/ext-gitops/ext-gitops.component.html @@ -1,10 +1,10 @@ -@if (loading) { +@if (loading()) {
    } -@if (!featureFlag) { +@if (!featureFlag()) {
    gitops @@ -14,13 +14,12 @@

    GitOps Integration

    Oops! Switcher GitOps is unavailable at this time.

    -} -@if (featureFlag) { +} @else {
    gitops

    GitOps Integration

    - @if (allowUpdate && gitOpsAccounts.length > 0) { + @if (allowUpdate() && gitOpsAccounts().length > 0) {
    - @if (!loading && gitOpsAccounts.length === 0) { + @if (!loading() && gitOpsAccounts().length === 0) {
    - @if (allowUpdate) { + @if (allowUpdate()) {

    No GitOps accounts found. Please add a GitOps account to get started.

    } - @if (!allowUpdate) { + @if (!allowUpdate()) {

    No GitOps accounts found. Please contact your administrator to add a GitOps account.

    }
    } - @if (!loading && gitOpsAccounts.length > 0) { + @if (!loading() && gitOpsAccounts().length > 0) {
    -
    +
    Details
    Status - + Message - + Last Sync - + Last Commit - + Version - +
    - @if (allowUpdate && canRefresh()) { + @if (allowUpdate() && canRefresh()) {
    }
    - @if (reloading) { + @if (reloading()) {
    @@ -112,14 +111,14 @@
    Details
    -
    +
    Settings
    Environment - + @for (environment of getDomainEnvironments(); track environment) { {{environment}} @@ -129,62 +128,59 @@
    Settings
    Repository - +
    Branch - + Path - +
    Token - +
    Window - (s,m,h) greater than 30s - + Active + [formControl]="formGroup()?.get('active')" + [checked]="gitOpsSelected()?.settings?.active">Active Force Prune
    - @if (allowUpdate) { + @if (allowUpdate()) {
    - @if (gitOpsSelected.ID && hasChanges()) { + @if (gitOpsSelected()?.ID && hasChanges()) { } - @if (!gitOpsSelected.ID) { + @if (!gitOpsSelected()?.ID) { - } - @if (!gitOpsSelected.ID) { - } - @if (gitOpsSelected.ID) { + } @else {
    diff --git a/src/app/dashboard-module/domain-module/ext-gitops/gitops-update-tokens/gitops-update-tokens.component.ts b/src/app/dashboard-module/domain-module/ext-gitops/gitops-update-tokens/gitops-update-tokens.component.ts index 914baa4f..2fbb89fa 100644 --- a/src/app/dashboard-module/domain-module/ext-gitops/gitops-update-tokens/gitops-update-tokens.component.ts +++ b/src/app/dashboard-module/domain-module/ext-gitops/gitops-update-tokens/gitops-update-tokens.component.ts @@ -1,7 +1,6 @@ -import { Component, OnInit, OnDestroy, inject } from '@angular/core'; +import { Component, inject, signal, DestroyRef } from '@angular/core'; import { FormBuilder, FormControl, FormGroup, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatDialogRef, MAT_DIALOG_DATA, MatDialogTitle, MatDialogContent, MatDialogActions } from '@angular/material/dialog'; import { MatToolbar } from '@angular/material/toolbar'; import { MatIconButton, MatButton } from '@angular/material/button'; @@ -23,33 +22,28 @@ import { MatOption } from '@angular/material/autocomplete'; MatLabel, MatSelect, FormsModule, ReactiveFormsModule, MatOption, MatInput, MatDialogActions, MatButton ] }) -export class GitOpsUpdateTokensComponent implements OnInit, OnDestroy { +export class GitOpsUpdateTokensComponent { data = inject(MAT_DIALOG_DATA); private readonly dialogRef = inject>(MatDialogRef); private readonly fb = inject(FormBuilder); + private readonly destroyRef = inject(DestroyRef); - private readonly unsubscribe = new Subject(); - - environments: string[]; - token: string; - formGroup: FormGroup; + environments = signal([]); + token = signal(''); + formGroup = signal(null); - ngOnInit() { - this.environments = this.data.environments; + constructor() { + this.environments.set(this.data.environments); this.formInit(); } - ngOnDestroy() { - this.unsubscribe.next(); - this.unsubscribe.complete(); - } - onCancel(): void { this.dialogRef.close(); } onSave(data: any) { - const { valid } = this.formGroup; + const formGroup = this.formGroup(); + const { valid } = formGroup; if (valid) { this.dialogRef.close(data); @@ -57,17 +51,19 @@ export class GitOpsUpdateTokensComponent implements OnInit, OnDestroy { } private formInit(): void { - this.formGroup = this.fb.group({ + const formGroup = this.fb.group({ environment: new FormControl('', [Validators.required]), token: new FormControl('', [Validators.required]) }); + + this.formGroup.set(formGroup); - this.formGroup.get('environment').valueChanges - .pipe(takeUntil(this.unsubscribe)) + formGroup.get('environment').valueChanges + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(value => this.data.selection = value); - this.formGroup.get('token').valueChanges - .pipe(takeUntil(this.unsubscribe)) + formGroup.get('token').valueChanges + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(value => this.data.token = value); } From eddb6afcd4c7340e8ab97f6bb9bc49b55a05a7e5 Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Tue, 2 Dec 2025 15:38:07 -0800 Subject: [PATCH 22/27] - fixes all detail components for zoneless compatiblity --- .../domain-module/common/basic-component.ts | 13 ++-- .../domain-module/common/detail-component.ts | 40 ++++++------ .../config-detail.component.html | 20 +++--- .../config-detail/config-detail.component.ts | 40 ++++++------ .../config-preview.component.html | 2 +- .../relay-detail/relay-detail.component.html | 10 +-- .../relay-detail/relay-detail.component.ts | 64 ++++++++++--------- .../strategy-detail.component.html | 16 ++--- .../strategy-detail.component.ts | 14 ++-- .../domain-detail.component.html | 14 ++-- .../domain-detail/domain-detail.component.ts | 14 ++-- .../domain-snapshot.component.html | 2 +- .../domain/domain.component.html | 2 +- .../group-detail/group-detail.component.html | 14 ++-- .../group-detail/group-detail.component.ts | 18 +++--- .../group-preview.component.html | 2 +- .../team-detail/team-detail.component.html | 6 +- .../team-detail/team-detail.component.ts | 8 +-- .../team-permissions.component.html | 2 +- .../team-preview/team-preview.component.html | 2 +- .../settings-account.component.html | 2 +- 21 files changed, 149 insertions(+), 156 deletions(-) diff --git a/src/app/dashboard-module/domain-module/common/basic-component.ts b/src/app/dashboard-module/domain-module/common/basic-component.ts index f5232f8c..be2707eb 100644 --- a/src/app/dashboard-module/domain-module/common/basic-component.ts +++ b/src/app/dashboard-module/domain-module/common/basic-component.ts @@ -1,14 +1,11 @@ -import { ChangeDetectorRef, inject } from "@angular/core"; +import { signal } from "@angular/core"; export class BasicComponent { - private readonly cdr = inject(ChangeDetectorRef, { optional: true }); - - blockuiEnabled = false; - blockuiMessage = 'Loading...'; + blockuiEnabled = signal(false); + blockuiMessage = signal('Loading...'); protected setBlockUI(enable: boolean, message = 'Loading...'): void { - this.blockuiEnabled = enable; - this.blockuiMessage = message; - this.cdr?.detectChanges(); + this.blockuiEnabled.set(enable); + this.blockuiMessage.set(message); } } \ No newline at end of file diff --git a/src/app/dashboard-module/domain-module/common/detail-component.ts b/src/app/dashboard-module/domain-module/common/detail-component.ts index b9c50337..1ab3189c 100644 --- a/src/app/dashboard-module/domain-module/common/detail-component.ts +++ b/src/app/dashboard-module/domain-module/common/detail-component.ts @@ -1,38 +1,36 @@ import { DataUtils } from 'src/app/_helpers/data-utils'; import { EnvironmentChangeEvent } from '../environment-config/environment-config.component'; -import { EventEmitter, ChangeDetectorRef, inject, signal } from '@angular/core'; +import { EventEmitter, signal } from '@angular/core'; import { Environment } from 'src/app/model/environment'; import { ConsoleLogger } from 'src/app/_helpers/console-logger'; export class DetailComponent { - protected readonly cdr = inject(ChangeDetectorRef, { optional: true }); - childEnvironmentEmitter = new EventEmitter(); detailBodyStyle = signal('detail-body loading'); - classStatus: string; + classStatus = signal(''); editing = signal(false); - currentStatus: boolean; - currentEnvironment = 'default'; - environments: Environment[]; - loading: boolean; + currentStatus = signal(false); + currentEnvironment = signal('default'); + environments = signal([]); + loading = signal(false); - blockuiEnabled = false; - blockuiMessage: string; + blockuiEnabled = signal(false); + blockuiMessage = signal(''); - updatable = false; - removable = false; - creatable = false; + updatable = signal(false); + removable = signal(false); + creatable = signal(false); protected selectEnvironment(event: EnvironmentChangeEvent): void { - this.currentEnvironment = event.environmentName; - this.currentStatus = event.status; + this.currentEnvironment.set(event.environmentName); + this.currentStatus.set(event.status); this.childEnvironmentEmitter.emit(event); if (this.editing()) { - this.classStatus = 'header editing'; + this.classStatus.set('header editing'); } else { - this.classStatus = this.currentStatus ? 'header activated' : 'header deactivated'; + this.classStatus.set(this.currentStatus() ? 'header activated' : 'header deactivated'); } } @@ -47,9 +45,8 @@ export class DetailComponent { } protected setBlockUI(enable: boolean, message?: string): void { - this.blockuiEnabled = enable; - this.blockuiMessage = message; - this.cdr?.detectChanges(); + this.blockuiEnabled.set(enable); + this.blockuiMessage.set(message || ''); } scrollToElement($element: any): void { @@ -59,8 +56,7 @@ export class DetailComponent { } onEnvLoaded(environments: Environment[]): void { - this.environments = environments; - this.cdr?.detectChanges(); + this.environments.set(environments); } onEnvChange($event: EnvironmentChangeEvent) { diff --git a/src/app/dashboard-module/domain-module/config/config-detail/config-detail.component.html b/src/app/dashboard-module/domain-module/config/config-detail/config-detail.component.html index e3e9bc55..8f60acfd 100644 --- a/src/app/dashboard-module/domain-module/config/config-detail/config-detail.component.html +++ b/src/app/dashboard-module/domain-module/config/config-detail/config-detail.component.html @@ -1,12 +1,12 @@ - - @if (loading) { + + @if (loading()) {
    }
    -
    +
    @@ -90,21 +90,21 @@
    - @@ -112,7 +112,7 @@
    @if (!loadingStrategies()) {
    - @if (loading) { + @if (loading()) {
    @@ -141,7 +141,7 @@
    - +
    @@ -153,7 +153,7 @@
    - +
    diff --git a/src/app/dashboard-module/domain-module/config/config-detail/config-detail.component.ts b/src/app/dashboard-module/domain-module/config/config-detail/config-detail.component.ts index 290a2569..d31b92b2 100644 --- a/src/app/dashboard-module/domain-module/config/config-detail/config-detail.component.ts +++ b/src/app/dashboard-module/domain-module/config/config-detail/config-detail.component.ts @@ -108,7 +108,7 @@ export class ConfigDetailComponent extends DetailComponent implements OnInit, On return relay?.activated ? relay.activated[currentEnv] !== undefined : false; }); - override loading = true; + override loading = signal(true); loadingStrategies = signal(true); hasStrategies = signal(false); hasNewStrategy = signal(false); @@ -134,8 +134,8 @@ export class ConfigDetailComponent extends DetailComponent implements OnInit, On ngOnInit() { (document.getElementsByClassName('container')[0] as HTMLElement).style.minHeight = '1100px'; - this.loading = true; - this.currentEnvironmentSignal.set(this.currentEnvironment || 'default'); + this.loading.set(true); + this.currentEnvironmentSignal.set(this.currentEnvironment() || 'default'); this.route.parent.params.subscribe(params => { this.domainId = params.domainid; @@ -168,7 +168,7 @@ export class ConfigDetailComponent extends DetailComponent implements OnInit, On edit() { if (!this.editing()) { - this.classStatus = 'header editing'; + this.classStatus.set('header editing'); this.editing.set(true); return; } @@ -177,7 +177,7 @@ export class ConfigDetailComponent extends DetailComponent implements OnInit, On if (valid) { this.setBlockUI(true, 'Saving changes...'); - this.classStatus = this.currentStatus ? 'header activated' : 'header deactivated'; + this.classStatus.set(this.currentStatus() ? 'header activated' : 'header deactivated'); const body = { key: this.keyElement.nativeElement.value, @@ -189,7 +189,7 @@ export class ConfigDetailComponent extends DetailComponent implements OnInit, On description: this.config.description, components: String(this.config.components.map(component => component.name)), disable_metrics: this.config.disable_metrics === undefined ? - false : this.config.disable_metrics[this.currentEnvironment] + false : this.config.disable_metrics[this.currentEnvironment()] }, { key: body.key, description: body.description, @@ -248,7 +248,7 @@ export class ConfigDetailComponent extends DetailComponent implements OnInit, On result.description, result.strategy, result.operation, - this.currentEnvironment, + this.currentEnvironment(), result.values).subscribe({ next: () => { this.setBlockUI(false); @@ -274,7 +274,7 @@ export class ConfigDetailComponent extends DetailComponent implements OnInit, On } this.config.relay.activated[this.currentEnvironmentSignal()] = true; - this.currentEnvironmentSignal.set(this.currentEnvironment); + this.currentEnvironmentSignal.set(this.currentEnvironment()); this.updateData(this.config); this.classStrategySection = 'strategy-section relay'; @@ -354,7 +354,7 @@ export class ConfigDetailComponent extends DetailComponent implements OnInit, On this.config = config; this.configRelay.set(config.relay); this.disableMetrics = this.config.disable_metrics ? - this.config.disable_metrics[this.currentEnvironment] : false; + this.config.disable_metrics[this.currentEnvironment()] : false; this.loadComponents(); this.keyFormControl.setValue(config.key); @@ -379,11 +379,11 @@ export class ConfigDetailComponent extends DetailComponent implements OnInit, On } private isMetricDisabled() { - if (this.config.disable_metrics[this.currentEnvironment] === undefined) { + if (this.config.disable_metrics[this.currentEnvironment()] === undefined) { return true; } - return this.config.disable_metrics[this.currentEnvironment]; + return this.config.disable_metrics[this.currentEnvironment()]; } private loadConfig() { @@ -402,14 +402,14 @@ export class ConfigDetailComponent extends DetailComponent implements OnInit, On private readPermissionToObject(): void { this.adminService.readCollabPermission(this.domainId, ['UPDATE', 'UPDATE_RELAY', 'UPDATE_ENV_STATUS', 'DELETE'], - 'SWITCHER', 'key', this.config.key, this.currentEnvironment) + 'SWITCHER', 'key', this.config.key, this.currentEnvironment()) .pipe(takeUntil(this.unsubscribe)) .subscribe({ next: data => { if (data.length) { - this.updatable = data.find(permission => permission.action === 'UPDATE').result === 'ok'; + this.updatable.set(data.find(permission => permission.action === 'UPDATE').result === 'ok'); this.relayUpdatable.set(data.find(permission => permission.action === 'UPDATE_RELAY').result === 'ok'); - this.removable = data.find(permission => permission.action === 'DELETE').result === 'ok'; + this.removable.set(data.find(permission => permission.action === 'DELETE').result === 'ok'); this.envEnable.next( data.find(permission => permission.action === 'UPDATE_ENV_STATUS').result === 'nok' && data.find(permission => permission.action === 'UPDATE').result === 'nok' @@ -420,12 +420,12 @@ export class ConfigDetailComponent extends DetailComponent implements OnInit, On ConsoleLogger.printError(error); }, complete: () => { - this.loading = false; + this.loading.set(false); this.detailBodyStyle.set('detail-body ready'); } }); - this.adminService.readCollabPermission(this.domainId, ['CREATE'], 'STRATEGY', undefined, undefined, this.currentEnvironment) + this.adminService.readCollabPermission(this.domainId, ['CREATE'], 'STRATEGY', undefined, undefined, this.currentEnvironment()) .pipe(takeUntil(this.unsubscribe)) .subscribe({ next: data => { @@ -437,7 +437,7 @@ export class ConfigDetailComponent extends DetailComponent implements OnInit, On ConsoleLogger.printError(error); }, complete: () => { - this.loading = false; + this.loading.set(false); this.detailBodyStyle.set('detail-body ready'); } }); @@ -525,7 +525,7 @@ export class ConfigDetailComponent extends DetailComponent implements OnInit, On this.setBlockUI(false); ConsoleLogger.printError(error); this.toastService.showError(`Unable to update switcher`); - this.classStatus = 'header editing'; + this.classStatus.set('header editing'); this.editing.set(true); } }); @@ -535,7 +535,7 @@ export class ConfigDetailComponent extends DetailComponent implements OnInit, On if (!this.config.disable_metrics) this.config.disable_metrics = new Map(); - this.config.disable_metrics[this.currentEnvironment] = this.disableMetrics; + this.config.disable_metrics[this.currentEnvironment()] = this.disableMetrics; return this.config.disable_metrics; } @@ -570,7 +570,7 @@ export class ConfigDetailComponent extends DetailComponent implements OnInit, On private loadStrategies(focus?: boolean) { this.loadingStrategies.set(true); this.error.set(''); - this.strategyService.getStrategiesByConfig(this.config.id, this.currentEnvironment) + this.strategyService.getStrategiesByConfig(this.config.id, this.currentEnvironment()) .pipe(takeUntil(this.unsubscribe)) .subscribe({ next: data => { diff --git a/src/app/dashboard-module/domain-module/config/config-preview/config-preview.component.html b/src/app/dashboard-module/domain-module/config/config-preview/config-preview.component.html index 8c5bd7a9..408b777f 100644 --- a/src/app/dashboard-module/domain-module/config/config-preview/config-preview.component.html +++ b/src/app/dashboard-module/domain-module/config/config-preview/config-preview.component.html @@ -1,4 +1,4 @@ - +
    diff --git a/src/app/dashboard-module/domain-module/config/relay-detail/relay-detail.component.html b/src/app/dashboard-module/domain-module/config/relay-detail/relay-detail.component.html index 57676481..d404065d 100644 --- a/src/app/dashboard-module/domain-module/config/relay-detail/relay-detail.component.html +++ b/src/app/dashboard-module/domain-module/config/relay-detail/relay-detail.component.html @@ -1,6 +1,6 @@ - +
    -
    +
    @@ -76,17 +76,17 @@
    @if (relayVerificationEnabled() && !isVerified() && !editing()) {
    -
    } - - diff --git a/src/app/dashboard-module/domain-module/config/relay-detail/relay-detail.component.ts b/src/app/dashboard-module/domain-module/config/relay-detail/relay-detail.component.ts index 69b9cea4..4a0ec15a 100644 --- a/src/app/dashboard-module/domain-module/config/relay-detail/relay-detail.component.ts +++ b/src/app/dashboard-module/domain-module/config/relay-detail/relay-detail.component.ts @@ -50,7 +50,7 @@ export class RelayDetailComponent extends DetailComponent implements OnInit, OnD @Input() config: Config; @Input() parent: ConfigDetailComponent; - @Input() declare currentEnvironment: string; + @Input() currentEnvironmentInput: string; @ViewChild('descElement', { static: true }) descElement: ElementRef; @@ -96,7 +96,7 @@ export class RelayDetailComponent extends DetailComponent implements OnInit, OnD this.relayOld = JSON.stringify(this.config.relay); if (!this.editing()) { - this.classStatus = 'header editing'; + this.classStatus.set('header editing'); this.editing.set(true); return; } @@ -107,15 +107,15 @@ export class RelayDetailComponent extends DetailComponent implements OnInit, OnD return; } - this.classStatus = this.currentStatus ? 'header activated' : 'header deactivated'; + this.classStatus.set(this.currentStatus() ? 'header activated' : 'header deactivated'); if (super.validateEdition( { type: this.config.relay.type, method: this.config.relay.method, description: this.config.relay.description, - endpoint: this.config.relay.endpoint[this.currentEnvironment], - auth_token: this.getRelayAttribute('auth_token') ? this.config.relay.auth_token[this.currentEnvironment] : '', + endpoint: this.config.relay.endpoint[this.currentEnvironmentInput], + auth_token: this.getRelayAttribute('auth_token') ? this.config.relay.auth_token[this.currentEnvironmentInput] : '', auth_prefix: this.config.relay.auth_prefix || '' }, { @@ -160,7 +160,7 @@ export class RelayDetailComponent extends DetailComponent implements OnInit, OnD } delete() { - if (!this.config.relay.endpoint[this.currentEnvironment]) { + if (!this.config.relay.endpoint[this.currentEnvironmentInput]) { this.updateConfiguredRelay(this.config); return; } @@ -171,7 +171,7 @@ export class RelayDetailComponent extends DetailComponent implements OnInit, OnD modalConfirmation.result.then((result) => { if (result) { this.setBlockUI(true, 'Removing relay...'); - this.configService.removeConfigRelay(this.config.id, this.currentEnvironment) + this.configService.removeConfigRelay(this.config.id, this.currentEnvironmentInput) .pipe(takeUntil(this.unsubscribe)) .subscribe({ next: data => { @@ -192,7 +192,7 @@ export class RelayDetailComponent extends DetailComponent implements OnInit, OnD isVerified(): boolean { if (this.config.relay.verified) - return this.config.relay.verified[this.currentEnvironment]; + return this.config.relay.verified[this.currentEnvironmentInput]; return false; } @@ -201,13 +201,13 @@ export class RelayDetailComponent extends DetailComponent implements OnInit, OnD this.config.relay.type = this.relayTypeFormControl.value; this.config.relay.method = this.relayMethodFormControl.value; this.config.relay.description = this.descElement.nativeElement.value; - this.config.relay.endpoint[this.currentEnvironment] = this.endpointFormControl.value; + this.config.relay.endpoint[this.currentEnvironmentInput] = this.endpointFormControl.value; if (!this.config.relay.auth_token) { this.config.relay.auth_token = new Map(); } - this.config.relay.auth_token[this.currentEnvironment] = this.authTokenElement.nativeElement.value; + this.config.relay.auth_token[this.currentEnvironmentInput] = this.authTokenElement.nativeElement.value; this.config.relay.auth_prefix = this.authPrefixElement.nativeElement.value; this.setBlockUI(true, 'Updating relay...'); @@ -236,17 +236,17 @@ export class RelayDetailComponent extends DetailComponent implements OnInit, OnD } private loadRelay(): void { - this.currentStatus = this.config.relay.activated[this.currentEnvironment]; + this.currentStatus.set(this.config.relay.activated[this.currentEnvironmentInput]); this.relayTypeFormControl.setValue(this.config.relay.type); this.relayMethodFormControl.setValue(this.config.relay.method); this.endpointFormControl.setValue(this.getRelayAttribute('endpoint')); this.authTokenElement.nativeElement.value = this.getRelayAttribute('auth_token'); - if (this.config.relay.endpoint[this.currentEnvironment] == undefined) { + if (this.config.relay.endpoint[this.currentEnvironmentInput] == undefined) { this.edit(); } else { - this.classStatus = this.currentStatus ? 'header activated' : 'header deactivated'; + this.classStatus.set(this.currentStatus() ? 'header activated' : 'header deactivated'); this.editing.set(false); } @@ -255,20 +255,22 @@ export class RelayDetailComponent extends DetailComponent implements OnInit, OnD private readPermissionToObject(): void { this.adminService.readCollabPermission(this.parent.domainId, ['UPDATE', 'UPDATE_RELAY', 'UPDATE_ENV_STATUS', 'DELETE', 'DELETE_RELAY'], - 'SWITCHER', 'key', this.config.key, this.currentEnvironment) + 'SWITCHER', 'key', this.config.key, this.currentEnvironmentInput) .pipe(takeUntil(this.unsubscribe)) .subscribe({ next: data => { if (data.length) { - this.removable = - data.find(permission => permission.action === 'DELETE').result === 'ok' || - data.find(permission => permission.action === 'DELETE_RELAY').result === 'ok'; - this.updatable = - data.find(permission => permission.action === 'UPDATE').result === 'ok' || - data.find(permission => permission.action === 'UPDATE_RELAY').result === 'ok'; + this.removable.set( + data.find(permission => permission.action === 'DELETE')?.result === 'ok' || + data.find(permission => permission.action === 'DELETE_RELAY')?.result === 'ok' + ); + this.updatable.set( + data.find(permission => permission.action === 'UPDATE')?.result === 'ok' || + data.find(permission => permission.action === 'UPDATE_RELAY')?.result === 'ok' + ); this.envEnable.next( - data.find(permission => permission.action === 'UPDATE_ENV_STATUS').result === 'nok' && - data.find(permission => permission.action === 'UPDATE').result === 'nok' + data.find(permission => permission.action === 'UPDATE_ENV_STATUS')?.result === 'nok' && + data.find(permission => permission.action === 'UPDATE')?.result === 'nok' ); } }, @@ -304,7 +306,7 @@ export class RelayDetailComponent extends DetailComponent implements OnInit, OnD .subscribe({ next: data => { if (data) { - this.config.relay.activated[this.currentEnvironment] = env[this.currentEnvironment]; + this.config.relay.activated[this.currentEnvironmentInput] = env[this.currentEnvironmentInput]; this.parent.updateConfigRelay(data.relay); this.selectEnvironment(env); this.toastService.showSuccess(`Environment updated with success`); @@ -320,11 +322,11 @@ export class RelayDetailComponent extends DetailComponent implements OnInit, OnD } private updateConfiguredRelay(data: Config): void { - delete this.config.relay.activated[this.currentEnvironment]; + delete this.config.relay.activated[this.currentEnvironmentInput]; if (this.config.relay.auth_token) { - delete this.config.relay.auth_token[this.currentEnvironment]; + delete this.config.relay.auth_token[this.currentEnvironmentInput]; } - delete this.config.relay.endpoint[this.currentEnvironment]; + delete this.config.relay.endpoint[this.currentEnvironmentInput]; this.parent.updateConfigRelay(data.relay); this.parent.updateNavTab(1); } @@ -335,21 +337,21 @@ export class RelayDetailComponent extends DetailComponent implements OnInit, OnD data: { relay: this.config.relay, code: this.relayVerificationCode(), - environment: this.currentEnvironment + environment: this.currentEnvironmentInput } }); dialogRef.afterClosed().pipe(takeUntil(this.unsubscribe)).subscribe(data => { if (data) { this.setBlockUI(true, 'Verifying Relay...'); - this.configService.verifyRelay(this.config.id, this.currentEnvironment) + this.configService.verifyRelay(this.config.id, this.currentEnvironmentInput) .pipe(takeUntil(this.unsubscribe)) .subscribe({ next: response => { this.setBlockUI(false); if (response.status === 'verified') { this.toastService.showSuccess(`Relay verified with success`); - this.config.relay.verified[this.currentEnvironment] = true; + this.config.relay.verified[this.currentEnvironmentInput] = true; } else { this.toastService.showError(`Failed to verify Relay`); } @@ -366,8 +368,8 @@ export class RelayDetailComponent extends DetailComponent implements OnInit, OnD private getRelayAttribute(field: string): string { if (this.config.relay[field]) { - if (this.config.relay[field][this.currentEnvironment]) - return this.config.relay[field][this.currentEnvironment]; + if (this.config.relay[field][this.currentEnvironmentInput]) + return this.config.relay[field][this.currentEnvironmentInput]; } return ''; } diff --git a/src/app/dashboard-module/domain-module/config/strategy-detail/strategy-detail.component.html b/src/app/dashboard-module/domain-module/config/strategy-detail/strategy-detail.component.html index 5b97c82b..10c62516 100644 --- a/src/app/dashboard-module/domain-module/config/strategy-detail/strategy-detail.component.html +++ b/src/app/dashboard-module/domain-module/config/strategy-detail/strategy-detail.component.html @@ -1,6 +1,6 @@ - +
    -
    +
    @@ -64,17 +64,17 @@
    @@ -101,15 +101,15 @@ receipt - - - diff --git a/src/app/dashboard-module/domain-module/config/strategy-detail/strategy-detail.component.ts b/src/app/dashboard-module/domain-module/config/strategy-detail/strategy-detail.component.ts index e419c188..b57ae89f 100644 --- a/src/app/dashboard-module/domain-module/config/strategy-detail/strategy-detail.component.ts +++ b/src/app/dashboard-module/domain-module/config/strategy-detail/strategy-detail.component.ts @@ -105,12 +105,12 @@ export class StrategyDetailComponent extends DetailComponent implements OnInit, edit() { if (!this.editing()) { this.loadStrategyRequirements(); - this.classStatus = 'header editing'; + this.classStatus.set('header editing'); this.editing.set(true); return; } - this.classStatus = this.currentStatus ? 'header activated' : 'header deactivated'; + this.classStatus.set(this.currentStatus() ? 'header activated' : 'header deactivated'); const body = { operation: this.operationCategoryFormControl.value, @@ -323,12 +323,12 @@ export class StrategyDetailComponent extends DetailComponent implements OnInit, .subscribe({ next: data => { if (data.length) { - this.updatable = data.find(permission => permission.action === 'UPDATE').result === 'ok'; - this.removable = data.find(permission => permission.action === 'DELETE').result === 'ok'; - this.creatable = data.find(permission => permission.action === 'CREATE').result === 'ok'; + this.updatable.set(data.find(permission => permission.action === 'UPDATE')?.result === 'ok'); + this.removable.set(data.find(permission => permission.action === 'DELETE')?.result === 'ok'); + this.creatable.set(data.find(permission => permission.action === 'CREATE')?.result === 'ok'); this.envEnable.next( - data.find(permission => permission.action === 'UPDATE_ENV_STATUS').result === 'nok' && - data.find(permission => permission.action === 'UPDATE').result === 'nok' + data.find(permission => permission.action === 'UPDATE_ENV_STATUS')?.result === 'nok' && + data.find(permission => permission.action === 'UPDATE')?.result === 'nok' ); } }, diff --git a/src/app/dashboard-module/domain-module/domain-detail/domain-detail.component.html b/src/app/dashboard-module/domain-module/domain-detail/domain-detail.component.html index d4892740..2cfb34c5 100644 --- a/src/app/dashboard-module/domain-module/domain-detail/domain-detail.component.html +++ b/src/app/dashboard-module/domain-module/domain-detail/domain-detail.component.html @@ -1,12 +1,12 @@ - - @if (loading) { + + @if (loading()) {
    }
    -
    +
    @@ -60,21 +60,21 @@ }
    - -
    - @if (environments) { + @if (environments().length > 0) {

    - +
    }
    \ No newline at end of file diff --git a/src/app/dashboard-module/domain-module/domain-detail/domain-detail.component.ts b/src/app/dashboard-module/domain-module/domain-detail/domain-detail.component.ts index 20d4e09e..95665291 100644 --- a/src/app/dashboard-module/domain-module/domain-detail/domain-detail.component.ts +++ b/src/app/dashboard-module/domain-module/domain-detail/domain-detail.component.ts @@ -62,7 +62,7 @@ export class DomainDetailComponent extends DetailComponent implements OnInit, On } ngOnInit() { - this.loading = true; + this.loading.set(true); this.route.paramMap .pipe(map(() => globalThis.history.state)).pipe(takeUntil(this.unsubscribe)).subscribe(data => { if (data.element) { @@ -109,12 +109,12 @@ export class DomainDetailComponent extends DetailComponent implements OnInit, On edit() { if (!this.editing()) { - this.classStatus = 'header editing'; + this.classStatus.set('header editing'); this.editing.set(true); return; } - this.classStatus = this.currentStatus ? 'header activated' : 'header deactivated'; + this.classStatus.set(this.currentStatus() ? 'header activated' : 'header deactivated'); const newDescription = this.descElement.nativeElement.value; if (super.validateEdition( @@ -255,13 +255,13 @@ export class DomainDetailComponent extends DetailComponent implements OnInit, On private readPermissionToObject(): void { this.adminService.readCollabPermission(this.domain.id, ['UPDATE', 'UPDATE_ENV_STATUS', 'DELETE'], - 'DOMAIN', undefined, undefined, this.currentEnvironment) + 'DOMAIN', undefined, undefined, this.currentEnvironment()) .pipe(takeUntil(this.unsubscribe)) .subscribe({ next: data => { if (data.length) { - this.updatable = data.find(permission => permission.action === 'UPDATE').result === 'ok'; - this.removable = data.find(permission => permission.action === 'DELETE').result === 'ok'; + this.updatable.set(data.find(permission => permission.action === 'UPDATE').result === 'ok'); + this.removable.set(data.find(permission => permission.action === 'DELETE').result === 'ok'); this.envEnable.next( data.find(permission => permission.action === 'UPDATE_ENV_STATUS').result === 'nok' && data.find(permission => permission.action === 'UPDATE').result === 'nok' @@ -273,7 +273,7 @@ export class DomainDetailComponent extends DetailComponent implements OnInit, On }, complete: () => { this.setBlockUI(false); - this.loading = false; + this.loading.set(false); this.detailBodyStyle.set('detail-body ready'); } }); diff --git a/src/app/dashboard-module/domain-module/domain/domain-snapshot/domain-snapshot.component.html b/src/app/dashboard-module/domain-module/domain/domain-snapshot/domain-snapshot.component.html index 3e24a023..3212faf8 100644 --- a/src/app/dashboard-module/domain-module/domain/domain-snapshot/domain-snapshot.component.html +++ b/src/app/dashboard-module/domain-module/domain/domain-snapshot/domain-snapshot.component.html @@ -1,4 +1,4 @@ - +

    Domain Snapshot diff --git a/src/app/dashboard-module/domain-module/domain/domain.component.html b/src/app/dashboard-module/domain-module/domain/domain.component.html index 68cab167..8aee58fc 100644 --- a/src/app/dashboard-module/domain-module/domain/domain.component.html +++ b/src/app/dashboard-module/domain-module/domain/domain.component.html @@ -1,4 +1,4 @@ - +
    diff --git a/src/app/dashboard-module/domain-module/group/group-detail/group-detail.component.html b/src/app/dashboard-module/domain-module/group/group-detail/group-detail.component.html index 3f924c44..854175fe 100644 --- a/src/app/dashboard-module/domain-module/group/group-detail/group-detail.component.html +++ b/src/app/dashboard-module/domain-module/group/group-detail/group-detail.component.html @@ -1,12 +1,12 @@ - - @if (loading) { + + @if (loading()) {
    }
    -
    +
    @@ -64,21 +64,21 @@
    - -
    - @if (!loading && environments) { + @if (!loading() && environments().length > 0) {

    - +
    }
    \ No newline at end of file diff --git a/src/app/dashboard-module/domain-module/group/group-detail/group-detail.component.ts b/src/app/dashboard-module/domain-module/group/group-detail/group-detail.component.ts index ff9dfa64..50ca7969 100644 --- a/src/app/dashboard-module/domain-module/group/group-detail/group-detail.component.ts +++ b/src/app/dashboard-module/domain-module/group/group-detail/group-detail.component.ts @@ -66,7 +66,7 @@ export class GroupDetailComponent extends DetailComponent implements OnInit, OnD } ngOnInit() { - this.loading = true; + this.loading.set(true); this.route.parent.params.subscribe(params => { this.domainId = params.domainid; @@ -75,7 +75,7 @@ export class GroupDetailComponent extends DetailComponent implements OnInit, OnD this.route.params.subscribe(params => { this.detailBodyStyle.set('detail-body loading'); - this.loading = true; + this.loading.set(true); this.groupId = params.groupid; const groupFromState = this.router.currentNavigation()?.extras.state?.element; @@ -94,7 +94,7 @@ export class GroupDetailComponent extends DetailComponent implements OnInit, OnD edit() { if (!this.editing()) { - this.classStatus = 'header editing'; + this.classStatus.set('header editing'); this.editing.set(true); return; } @@ -103,7 +103,7 @@ export class GroupDetailComponent extends DetailComponent implements OnInit, OnD if (valid) { this.setBlockUI(true, 'Saving changes...'); - this.classStatus = this.currentStatus ? 'header activated' : 'header deactivated'; + this.classStatus.set(this.currentStatus() ? 'header activated' : 'header deactivated'); const body = { name: this.nameElement.nativeElement.value, @@ -183,13 +183,13 @@ export class GroupDetailComponent extends DetailComponent implements OnInit, OnD private readPermissionToObject(): void { this.adminService.readCollabPermission(this.domainId, ['UPDATE', 'UPDATE_ENV_STATUS', 'DELETE'], - 'GROUP', 'name', this.group.name, this.currentEnvironment) + 'GROUP', 'name', this.group.name, this.currentEnvironment()) .pipe(takeUntil(this.unsubscribe)) .subscribe({ next: data => { if (data.length) { - this.updatable = data.find(permission => permission.action === 'UPDATE').result === 'ok'; - this.removable = data.find(permission => permission.action === 'DELETE').result === 'ok'; + this.updatable.set(data.find(permission => permission.action === 'UPDATE').result === 'ok'); + this.removable.set(data.find(permission => permission.action === 'DELETE').result === 'ok'); this.envEnable.next( data.find(permission => permission.action === 'UPDATE_ENV_STATUS').result === 'nok' && data.find(permission => permission.action === 'UPDATE').result === 'nok' @@ -200,7 +200,7 @@ export class GroupDetailComponent extends DetailComponent implements OnInit, OnD ConsoleLogger.printError(error); }, complete: () => { - this.loading = false; + this.loading.set(false); this.detailBodyStyle.set('detail-body ready'); } }); @@ -226,7 +226,7 @@ export class GroupDetailComponent extends DetailComponent implements OnInit, OnD this.setBlockUI(false); ConsoleLogger.printError(error); this.toastService.showError(`Unable to update group`); - this.classStatus = 'header editing'; + this.classStatus.set('header editing'); this.editing.set(true); } }); diff --git a/src/app/dashboard-module/domain-module/group/group-preview/group-preview.component.html b/src/app/dashboard-module/domain-module/group/group-preview/group-preview.component.html index 51bf340a..ca173b56 100644 --- a/src/app/dashboard-module/domain-module/group/group-preview/group-preview.component.html +++ b/src/app/dashboard-module/domain-module/group/group-preview/group-preview.component.html @@ -1,4 +1,4 @@ - +
    diff --git a/src/app/dashboard-module/domain-module/team-module/team-detail/team-detail.component.html b/src/app/dashboard-module/domain-module/team-module/team-detail/team-detail.component.html index b1a86f21..6dc15555 100644 --- a/src/app/dashboard-module/domain-module/team-module/team-detail/team-detail.component.html +++ b/src/app/dashboard-module/domain-module/team-module/team-detail/team-detail.component.html @@ -1,7 +1,7 @@ - + @if (!teamLoading()) {
    -
    +
    @@ -80,4 +80,4 @@
    } - \ No newline at end of file + \ No newline at end of file diff --git a/src/app/dashboard-module/domain-module/team-module/team-detail/team-detail.component.ts b/src/app/dashboard-module/domain-module/team-module/team-detail/team-detail.component.ts index f27cf461..2ec9d97b 100644 --- a/src/app/dashboard-module/domain-module/team-module/team-detail/team-detail.component.ts +++ b/src/app/dashboard-module/domain-module/team-module/team-detail/team-detail.component.ts @@ -185,14 +185,12 @@ export class TeamDetailComponent extends DetailComponent implements OnInit, OnDe this.team.set(team); this.nameFormControl.setValue(team.name); this.setHeaderStyle(); + this.teamLoading.set(false); } }, error: error => { ConsoleLogger.printError(error); this.teamLoading.set(false); - }, - complete: () => { - this.teamLoading.set(false); } }); } @@ -212,9 +210,9 @@ export class TeamDetailComponent extends DetailComponent implements OnInit, OnDe private setHeaderStyle(): void { const currentTeam = this.team(); if (this.editing()) { - this.classStatus = 'header editing'; + this.classStatus.set('header editing'); } else { - this.classStatus = currentTeam?.active ? 'header activated' : 'header deactivated'; + this.classStatus.set(currentTeam?.active ? 'header activated' : 'header deactivated'); } } diff --git a/src/app/dashboard-module/domain-module/team-module/team-permissions/team-permissions.component.html b/src/app/dashboard-module/domain-module/team-module/team-permissions/team-permissions.component.html index 809ef891..3f742ee9 100644 --- a/src/app/dashboard-module/domain-module/team-module/team-permissions/team-permissions.component.html +++ b/src/app/dashboard-module/domain-module/team-module/team-permissions/team-permissions.component.html @@ -1,4 +1,4 @@ - +