diff --git a/.gitea/workflows/build-push.yaml b/.gitea/workflows/build-push.yaml new file mode 100644 index 0000000..7f7b39a --- /dev/null +++ b/.gitea/workflows/build-push.yaml @@ -0,0 +1,29 @@ +name: Build and Push Docker Image + +on: + push: + branches: [master] + +jobs: + build-and-push: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Harbor + uses: docker/login-action@v3 + with: + registry: harbor.galpodlipnik.com + username: ${{ secrets.HARBOR_USERNAME }} + password: ${{ secrets.HARBOR_PASSWORD }} + + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: harbor.galpodlipnik.com/project/docker-inspector:latest diff --git a/.gitea/workflows/test.yaml b/.gitea/workflows/test.yaml deleted file mode 100644 index c537cc6..0000000 --- a/.gitea/workflows/test.yaml +++ /dev/null @@ -1,19 +0,0 @@ -name: Gitea Actions Demo -run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀 -on: [push] - -jobs: - Explore-Gitea-Actions: - runs-on: ubuntu-latest - steps: - - run: echo "🎉 The job was automatically triggered by a ${{ gitea.event_name }} event." - - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by Gitea!" - - run: echo "🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}." - - name: Check out repository code - uses: actions/checkout@v4 - - run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner." - - run: echo "🖥️ The workflow is now ready to test your code on the runner." - - name: List files in the repository - run: | - ls ${{ gitea.workspace }} - - run: echo "🍏 This job's status is ${{ job.status }}." diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8b32cee --- /dev/null +++ b/Dockerfile @@ -0,0 +1,55 @@ +# Build frontend +FROM node:20-alpine AS frontend-builder +WORKDIR /app/frontend +COPY frontend/package*.json ./ +RUN npm ci --legacy-peer-deps +COPY frontend/ ./ +RUN npm run build + +# Build backend +FROM node:20-alpine AS backend-builder +WORKDIR /app/backend +COPY backend/package*.json ./ +RUN npm ci +COPY backend/ ./ +RUN npm run build + +# Final image +FROM node:20-alpine +RUN apk add --no-cache tini +WORKDIR /app + +# Create a non-root user +RUN addgroup -S appgroup && adduser -S appuser -G appgroup + +# Copy built backend +COPY --from=backend-builder /app/backend/dist ./dist +COPY --from=backend-builder /app/backend/package*.json ./ + +# Copy built frontend +COPY --from=frontend-builder /app/frontend/dist/frontend ./public + +# Install production dependencies only +RUN npm ci --omit=dev + +# Create a startup script to serve both frontend and backend +COPY --chmod=755 < /app/public/env.js +echo "window.env = {" >> /app/public/env.js +env | grep DOCKER_ | sed 's/\(.*\)=\(.*\)/ \1: "\2",/' >> /app/public/env.js +echo "};" >> /app/public/env.js + +# Start the server +node dist/index.js +EOF + +# Set ownership +RUN chown -R appuser:appgroup /app + +USER appuser +EXPOSE 3000 +ENTRYPOINT ["/sbin/tini", "--"] +CMD ["/app/start.sh"] \ No newline at end of file diff --git a/frontend/libs/shared/environment/src/lib/env.service.ts b/frontend/libs/shared/environment/src/lib/env.service.ts new file mode 100644 index 0000000..d87adc8 --- /dev/null +++ b/frontend/libs/shared/environment/src/lib/env.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@angular/core'; + +declare global { + interface Window { + env: Record; + } +} + +@Injectable({ + providedIn: 'root', +}) +export class EnvService { + getEnv(key: string): string | undefined { + return window.env?.[key]; + } +} + diff --git a/frontend/libs/shared/navbar/src/lib/navbar.component.ts b/frontend/libs/shared/navbar/src/lib/navbar.component.ts index a1dc6d0..de91642 100644 --- a/frontend/libs/shared/navbar/src/lib/navbar.component.ts +++ b/frontend/libs/shared/navbar/src/lib/navbar.component.ts @@ -2,15 +2,18 @@ import { Component, inject } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatIcon } from '@angular/material/icon'; import { MatToolbarModule } from '@angular/material/toolbar'; +import { Router } from '@angular/router'; import { ThemeToggleService } from '@frontend/shared/theme-toggle'; @Component({ selector: 'frontend-navbar', imports: [MatToolbarModule, MatIcon, MatButtonModule], template: ` - - view_carousel - Docker Containers + +
+ view_carousel + Docker Containers +
+ + + `, + styles: [ + ` + .container-card { + border-radius: 8px; + transition: transform 0.2s; + overflow: hidden; + cursor: pointer; + } + .container-card:hover { + transform: translateY(-2px); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1); + } + + .avatar-container { + display: flex; + align-items: center; + justify-content: center; + background-color: rgba(0, 0, 0, 0.04); + border-radius: 50%; + } + .status-icon { + font-size: 24px; + height: 24px; + width: 24px; + } + + .card-content { + padding: 16px 16px 8px; + } + .info-row { + display: flex; + margin-bottom: 12px; + align-items: center; + } + .label { + font-weight: 500; + color: var(--mat-text-secondary-color); + width: 70px; + } + .value { + font-size: 14px; + } + .monospace { + font-family: 'Roboto Mono', monospace; + } + + .state-running { + color: var(--mat-green-500); + } + .state-exited, + .state-stopped { + color: var(--mat-red-500); + } + .state-created, + .state-paused { + color: var(--mat-amber-500); + } + + .status-chip-running { + background-color: var(--mat-green-50) !important; + color: var(--mat-green-700) !important; + } + .status-chip-exited, + .status-chip-stopped { + background-color: var(--mat-red-50) !important; + color: var(--mat-red-700) !important; + } + .status-chip-created, + .status-chip-paused { + background-color: var(--mat-amber-50) !important; + color: var(--mat-amber-700) !important; + } + + mat-card-actions { + padding: 16px; + display: flex; + justify-content: flex-end; + gap: 8px; + } + .action-button { + min-width: 100px; + } + + @media (max-width: 599px) { + mat-card-actions { + flex-direction: column; + align-items: stretch; + } + .action-button { + width: 100%; + margin: 0 !important; + } + } + `, + ], +}) +export class ContainerCardComponent { + @Input() container: any; + @Output() containerClick = new EventEmitter(); + @Output() actionClick = new EventEmitter<{ id: string; state: string }>(); + + getStateIcon(state: string): string { + switch (state) { + case 'running': + return 'play_circle'; + case 'exited': + return 'stop_circle'; + case 'created': + return 'fiber_new'; + case 'paused': + return 'pause_circle'; + default: + return 'help_circle'; + } + } + + getStateClass(state: string): string { + return `state-${state.toLowerCase()}`; + } + + getStatusClass(status: string): string { + if (status.includes('Up')) return 'status-chip-running'; + if (status.includes('Exited')) return 'status-chip-exited'; + if (status.includes('Created')) return 'status-chip-created'; + if (status.includes('Paused')) return 'status-chip-paused'; + return ''; + } + + onActionClick(event: Event, id: string, state: string) { + event.stopPropagation(); + this.actionClick.emit({ id, state }); + } +} + diff --git a/frontend/libs/web/containers/src/lib/containers-shell.component.ts b/frontend/libs/web/containers/src/lib/containers-shell.component.ts index f253342..d4361eb 100644 --- a/frontend/libs/web/containers/src/lib/containers-shell.component.ts +++ b/frontend/libs/web/containers/src/lib/containers-shell.component.ts @@ -8,7 +8,6 @@ import { ContainersComponent } from './containers.component'; imports: [ContainersComponent, MatToolbarModule, MatIconModule], template: `
-

View and manage your Docker containers here.

`, @@ -27,4 +26,3 @@ import { ContainersComponent } from './containers.component'; ], }) export class ContainersComponentShell {} - diff --git a/frontend/libs/web/containers/src/lib/containers.component.ts b/frontend/libs/web/containers/src/lib/containers.component.ts index af00381..585bdfe 100644 --- a/frontend/libs/web/containers/src/lib/containers.component.ts +++ b/frontend/libs/web/containers/src/lib/containers.component.ts @@ -1,62 +1,20 @@ -import { NgClass } from '@angular/common'; import { Component, inject, OnInit } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatCardModule } from '@angular/material/card'; -import { MatChipsModule } from '@angular/material/chips'; -import { MatIconModule } from '@angular/material/icon'; -import { StatsWsService } from '@frontend/shared/stats-ws'; +import { Router } from '@angular/router'; +import { WsService } from '@frontend/shared/ws'; +import { ContainerCardComponent } from './container-card.component'; @Component({ selector: 'frontend-containers', - imports: [ - MatCardModule, - MatIconModule, - MatChipsModule, - MatButtonModule, - NgClass, - ], + standalone: true, + imports: [ContainerCardComponent], template: `
@for (container of containers(); track container.id) { - - - - {{ getStateIcon(container.state) }} - - {{ container.name }} - {{ container.image }} - - -
- ID: - {{ container.id.substring(0, 12) }} -
-
- Status: - - {{ container.status }} - -
-
- - - - -
+ }
`, @@ -64,111 +22,38 @@ import { StatsWsService } from '@frontend/shared/stats-ws'; ` .content-container { display: grid; - grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); - gap: 16px; - margin-top: 16px; + grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); + gap: 24px; + padding: 24px; } - .container-card { - transition: - transform 0.2s, - box-shadow 0.2s; - } - - .container-card:hover { - transform: translateY(-4px); - box-shadow: 0 6px 10px rgba(0, 0, 0, 0.1); - } - - .info-row { - display: flex; - margin-bottom: 8px; - align-items: center; - } - - .label { - font-weight: 500; - color: var(--sys-on-surface-variant); - width: 70px; - } - - .value { - font-family: monospace; - font-size: 14px; - } - - .state-running { - color: #4caf50; - } - - .state-exited, - .state-stopped { - color: #f44336; - } - - .state-created, - .state-paused { - color: #ff9800; - } - - .status-chip-running { - background-color: rgba(76, 175, 80, 0.15) !important; - color: #4caf50 !important; - } - - .status-chip-exited, - .status-chip-stopped { - background-color: rgba(244, 67, 54, 0.15) !important; - color: #f44336 !important; - } - - .status-chip-created, - .status-chip-paused { - background-color: rgba(255, 152, 0, 0.15) !important; - color: #ff9800 !important; - } - - mat-card-actions { - padding: 8px 16px 16px; - display: flex; - justify-content: flex-end; + @media (max-width: 599px) { + .content-container { + padding: 16px; + gap: 16px; + } } `, ], }) export class ContainersComponent implements OnInit { - private readonly service = inject(StatsWsService); + private readonly service = inject(WsService); + private readonly router = inject(Router); protected containers = this.service.containers; ngOnInit() { this.service.initContainers(); } - getStateIcon(state: string): string { - switch (state) { - case 'running': - return 'play_circle'; - case 'exited': - return 'stop_circle'; - case 'created': - return 'fiber_new'; - case 'paused': - return 'pause_circle'; - default: - return 'help_circle'; - } + onContainerClick(id: string): void { + this.router.navigate(['/container'], { + queryParams: { id }, + }); } - getStateClass(state: string): string { - return `state-${state.toLowerCase()}`; - } - - getStatusClass(status: string): string { - if (status.includes('Up')) return 'status-chip-running'; - if (status.includes('Exited')) return 'status-chip-exited'; - if (status.includes('Created')) return 'status-chip-created'; - if (status.includes('Paused')) return 'status-chip-paused'; - return ''; + onContainerAction(action: { id: string; state: string }): void { + console.log( + `Container action clicked: ${action.id}, State: ${action.state}` + ); } } - diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 7c7dae3..10a6d66 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,28 +9,29 @@ "version": "0.0.0", "license": "MIT", "dependencies": { - "@angular/cdk": "^20.0.1", - "@angular/common": "20.0.0", - "@angular/compiler": "20.0.0", - "@angular/core": "20.0.0", - "@angular/forms": "20.0.0", - "@angular/material": "^20.0.1", - "@angular/platform-browser": "20.0.0", - "@angular/platform-browser-dynamic": "20.0.0", - "@angular/router": "20.0.0", - "@mmstack/form-material": "^19.2.0", - "@mmstack/primitives": "^19.2.3", - "@mmstack/resource": "^19.2.0", + "@angular/cdk": "20.0.2", + "@angular/common": "20.0.2", + "@angular/compiler": "20.0.2", + "@angular/core": "20.0.2", + "@angular/forms": "20.0.2", + "@angular/material": "20.0.2", + "@angular/platform-browser": "20.0.2", + "@angular/platform-browser-dynamic": "20.0.2", + "@angular/router": "20.0.2", + "@mmstack/form-material": "19.2.2", + "@mmstack/primitives": "19.2.3", + "@mmstack/resource": "19.2.0", + "@mmstack/router-core": "^19.3.0", "rxjs": "7.8.2", "zone.js": "0.15.1" }, "devDependencies": { - "@angular-devkit/build-angular": "20.0.0", - "@angular-devkit/core": "20.0.0", - "@angular-devkit/schematics": "20.0.0", - "@angular/cli": "20.0.0", - "@angular/compiler-cli": "20.0.0", - "@angular/language-service": "20.0.0", + "@angular-devkit/build-angular": "20.0.1", + "@angular-devkit/core": "20.0.1", + "@angular-devkit/schematics": "20.0.1", + "@angular/cli": "20.0.1", + "@angular/compiler-cli": "20.0.2", + "@angular/language-service": "20.0.2", "@eslint/js": "9.28.0", "@nx/angular": "21.1.3", "@nx/eslint": "21.1.3", @@ -39,14 +40,14 @@ "@nx/js": "21.1.3", "@nx/web": "21.1.3", "@nx/workspace": "21.1.3", - "@schematics/angular": "20.0.0", + "@schematics/angular": "20.0.1", "@swc-node/register": "1.10.10", - "@swc/core": "1.11.29", + "@swc/core": "1.11.31", "@swc/helpers": "0.5.17", "@types/jest": "29.5.14", - "@types/node": "22.15.29", + "@types/node": "22.15.30", "@typescript-eslint/utils": "8.33.1", - "angular-eslint": "19.7.0", + "angular-eslint": "20.0.0", "eslint": "9.28.0", "eslint-config-prettier": "10.1.5", "jest": "29.7.0", @@ -83,13 +84,13 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.2000.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2000.0.tgz", - "integrity": "sha512-6accOuvf1BY6hTO5LzYcxp2Dpl0bThgYF3KdwVWqrYF5+6PWfQLdy+rKxBiCIv0+0OngZVI79RuAtUKFowFM/A==", + "version": "0.2000.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2000.1.tgz", + "integrity": "sha512-EcOGU1xEhARYpDF391VaeUg/+YRym9OxzJMcc0rSHl3YLK8/m+24ap2YAQY5N7n9+mmEqHVu/q31ldFpOoMCTw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "20.0.0", + "@angular-devkit/core": "20.0.1", "rxjs": "7.8.2" }, "engines": { @@ -99,17 +100,17 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-20.0.0.tgz", - "integrity": "sha512-6JAVLjGLSTy69FAXTPzi9t4SswT4b3mOiz8GPleNTO0VmxgQA8C+zUqG81fH1ZDdSZBfUZcbgim+Y47G3cORcg==", + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-20.0.1.tgz", + "integrity": "sha512-rUrGwdqUNOy6AlisBjOaQncZOanwqgHIa6HDw9a0nrbQxDpLzwJAiNLGcmIivfvAXxSq60+YFHHM48VV42oxyg==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2000.0", - "@angular-devkit/build-webpack": "0.2000.0", - "@angular-devkit/core": "20.0.0", - "@angular/build": "20.0.0", + "@angular-devkit/architect": "0.2000.1", + "@angular-devkit/build-webpack": "0.2000.1", + "@angular-devkit/core": "20.0.1", + "@angular/build": "20.0.1", "@babel/core": "7.27.1", "@babel/generator": "7.27.1", "@babel/helper-annotate-as-pure": "7.27.1", @@ -120,7 +121,7 @@ "@babel/preset-env": "7.27.2", "@babel/runtime": "7.27.1", "@discoveryjs/json-ext": "0.6.3", - "@ngtools/webpack": "20.0.0", + "@ngtools/webpack": "20.0.1", "@vitejs/plugin-basic-ssl": "2.0.0", "ansi-colors": "4.1.3", "autoprefixer": "10.4.21", @@ -176,7 +177,7 @@ "@angular/platform-browser": "^20.0.0", "@angular/platform-server": "^20.0.0", "@angular/service-worker": "^20.0.0", - "@angular/ssr": "^20.0.0", + "@angular/ssr": "^20.0.1", "@web/test-runner": "^0.20.0", "browser-sync": "^3.0.2", "jest": "^29.5.0", @@ -1440,13 +1441,13 @@ } }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.2000.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.2000.0.tgz", - "integrity": "sha512-bIbz6uFQLTBvmadWJo/KEF1GruqIC23HF8YcUfy/1AuSd07EjoWL8wZrpl6eY+RE8hjua3AC1XSrzWD2e+xd8w==", + "version": "0.2000.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.2000.1.tgz", + "integrity": "sha512-v+A08zOUC3wrP9msN2+qrAaKnDEKi9H1o5bYOe/yH9S8ZXZ56R/r5EsY58Vcf6yQSywRDip2HJnPDtIGkQYnew==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.2000.0", + "@angular-devkit/architect": "0.2000.1", "rxjs": "7.8.2" }, "engines": { @@ -1460,9 +1461,9 @@ } }, "node_modules/@angular-devkit/core": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-20.0.0.tgz", - "integrity": "sha512-cnB/I1QQC3WoIcb+f/7hknOOkgIFjAuxd7nW1RnS+pn0qQTWyjnXjq2jocx2TBMwZRikycc7f3mlA1DgWzJUuQ==", + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-20.0.1.tgz", + "integrity": "sha512-Ilafyj8JVwq3NZsaiGw5UDkP4EAkGKiEvZ4TC3WVidZbM4EpKt9/Jd7ZpsTRGDLG429U+fGhay+ZQeCFGqy5rA==", "dev": true, "license": "MIT", "dependencies": { @@ -1488,13 +1489,13 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-20.0.0.tgz", - "integrity": "sha512-35WbWP8ARnaqVjOzy7IOyWsY/jeyUqfVj4KgHG2O4fHAhIhaBqhP8dDDP+SwM+bToIqklg0fzHUUhFTRxzzyoQ==", + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-20.0.1.tgz", + "integrity": "sha512-bSr/5YIdjtwKYqylkYrlOVP+tuFz+tfOldmLfWHAsDGnJUznb5t4ckx6yyROp+iDQfu2Aez09p+l4KfUBq+H9A==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "20.0.0", + "@angular-devkit/core": "20.0.1", "jsonc-parser": "3.3.1", "magic-string": "0.30.17", "ora": "8.2.0", @@ -1729,90 +1730,36 @@ } }, "node_modules/@angular-eslint/builder": { - "version": "19.7.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-19.7.0.tgz", - "integrity": "sha512-tnanOOwUKzeS0FwhjJd/dNeb8gVzcF0+cI4/ZgohOjZxm8fZqtzXcKfGS1C7KsR/CPHBdY9cbF1OVPJEarrnsQ==", + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-20.0.0.tgz", + "integrity": "sha512-9jS3VvY+K+EHw9pofsdwKxDirKuTuRBnjMZdaKoUfLoYy5eS1XGJBXoMdaQiM+mSlTv113+L0SK4U565xiBLHQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": ">= 0.1900.0 < 0.2000.0", - "@angular-devkit/core": ">= 19.0.0 < 20.0.0" + "@angular-devkit/architect": ">= 0.2000.0 < 0.2100.0", + "@angular-devkit/core": ">= 20.0.0 < 21.0.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, - "node_modules/@angular-eslint/builder/node_modules/@angular-devkit/architect": { - "version": "0.1902.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1902.14.tgz", - "integrity": "sha512-rgMkqOrxedzqLZ8w59T/0YrpWt7LDmGwt+ZhNHE7cn27jZ876yGC2Bhcn58YZh2+R03WEJ9q0ePblaBYz03SMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "19.2.14", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular-eslint/builder/node_modules/@angular-devkit/core": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.14.tgz", - "integrity": "sha512-aaPEnRNIBoYT4XrrYcZlHadX8vFDTUR+4wUgcmr0cNDLeWzWtoPFeVq8TQD6kFDeqovSx/UVEblGgg/28WvHyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.17.1", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.2", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^4.0.0" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@angular-eslint/builder/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "19.7.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-19.7.0.tgz", - "integrity": "sha512-95Z30MhQ93s1G1mEnsVuG45te82I+6dp8Y0MamRgyh4OZvOajmEXpvCwT+hkr/9WAroLZ7p5nlMbzAA+OXZ+YQ==", + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-20.0.0.tgz", + "integrity": "sha512-mDXMQd08s11q9fC6Ps3ffZmvXop9eLuAAXexofHhA7uuoQAoUWS2zoOSNTWtDR6oxMcqEeMnALCjjFeJVBSVmg==", "dev": true, "license": "MIT" }, "node_modules/@angular-eslint/eslint-plugin": { - "version": "19.7.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-19.7.0.tgz", - "integrity": "sha512-M8OqDgiFSSxMinW/Gkdrvy2O2Oeo8bGk1DQc0s3aEKB44PYAjXC49jMSihvdozqtu1qjPBcTN5kvUwzwN5oWxA==", + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-20.0.0.tgz", + "integrity": "sha512-xzaLj2yEn43DH0bE9Gw3GrmC+jivIS5/Hbh3bDj3ctw3mUUrD8hrS7kBo1neZ0gnoVLoo/mwIldG+xs5NDY66A==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "19.7.0", - "@angular-eslint/utils": "19.7.0" + "@angular-eslint/bundled-angular-compiler": "20.0.0", + "@angular-eslint/utils": "20.0.0" }, "peerDependencies": { "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", @@ -1821,19 +1768,19 @@ } }, "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "19.7.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-19.7.0.tgz", - "integrity": "sha512-gR+RH7ZDFctupUsCcxWWloD0I7m9pE8HiDX9TrwrSQbNgzvp/P7+Mgv709rR1Jju9GSVavPh7EG3VgiCyR2m5w==", + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-20.0.0.tgz", + "integrity": "sha512-QoGgrawU5JFcaj0TjXHKC6fiZkxBeGVRj/TWJtTo/x+c5TVoV5k9pI7Uxdmo9kr4SkPXmt80ZklvExSA510gyw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "19.7.0", - "@angular-eslint/utils": "19.7.0", + "@angular-eslint/bundled-angular-compiler": "20.0.0", + "@angular-eslint/utils": "20.0.0", "aria-query": "5.3.2", "axobject-query": "4.1.0" }, "peerDependencies": { - "@angular-eslint/template-parser": "19.7.0", + "@angular-eslint/template-parser": "20.0.0", "@typescript-eslint/types": "^7.11.0 || ^8.0.0", "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", "eslint": "^8.57.0 || ^9.0.0", @@ -1841,68 +1788,21 @@ } }, "node_modules/@angular-eslint/schematics": { - "version": "19.7.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-19.7.0.tgz", - "integrity": "sha512-07j/qXfSLvLsUq8a7WJlGYgcgfVEJ1ODuwJ2R4686dh2lqZ5GRV75fpdOtOBdC38MILLwd5el+8LfdaIG19Yog==", + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-20.0.0.tgz", + "integrity": "sha512-VL3Sb6Df+iiUSPaQG8NxMPLx0dFRtRGSzsfe6CWYW7FUFP5dYEjpB63gKSAiIBLjPgnG6PMAzrRtfN4nDaTM+g==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": ">= 19.0.0 < 20.0.0", - "@angular-devkit/schematics": ">= 19.0.0 < 20.0.0", - "@angular-eslint/eslint-plugin": "19.7.0", - "@angular-eslint/eslint-plugin-template": "19.7.0", + "@angular-devkit/core": ">= 20.0.0 < 21.0.0", + "@angular-devkit/schematics": ">= 20.0.0 < 21.0.0", + "@angular-eslint/eslint-plugin": "20.0.0", + "@angular-eslint/eslint-plugin-template": "20.0.0", "ignore": "7.0.5", "semver": "7.7.2", "strip-json-comments": "3.1.1" } }, - "node_modules/@angular-eslint/schematics/node_modules/@angular-devkit/core": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.14.tgz", - "integrity": "sha512-aaPEnRNIBoYT4XrrYcZlHadX8vFDTUR+4wUgcmr0cNDLeWzWtoPFeVq8TQD6kFDeqovSx/UVEblGgg/28WvHyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.17.1", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.2", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^4.0.0" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@angular-eslint/schematics/node_modules/@angular-devkit/schematics": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-19.2.14.tgz", - "integrity": "sha512-s89/MWXHy8+GP/cRfFbSECIG3FQQQwNVv44OOmghPVgKQgQ+EoE/zygL2hqKYTUPoPaS/IhNXdXjSE5pS9yLeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "19.2.14", - "jsonc-parser": "3.3.1", - "magic-string": "0.30.17", - "ora": "5.4.1", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, "node_modules/@angular-eslint/schematics/node_modules/ignore": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", @@ -1913,48 +1813,14 @@ "node": ">= 4" } }, - "node_modules/@angular-eslint/schematics/node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@angular-eslint/schematics/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/@angular-eslint/template-parser": { - "version": "19.7.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-19.7.0.tgz", - "integrity": "sha512-XLPt6gk8VMOrUO9NWRpXN8zgwJuCDV+9y3KbVnd4WyakO0sOz9SVzktuI4AeY9jWS9/tqU6P8Uj0WZsMVz7F8w==", + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-20.0.0.tgz", + "integrity": "sha512-5y9hxH/z+9rIOJp1FwRBSgJ6xt8/pgRfBF+eEIPyIHKl5mV0cVzlQiD7j1LMYTcxJZLHAoryomvSBDpmbtAlWg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "19.7.0", + "@angular-eslint/bundled-angular-compiler": "20.0.0", "eslint-scope": "^8.0.2" }, "peerDependencies": { @@ -1980,13 +1846,13 @@ } }, "node_modules/@angular-eslint/utils": { - "version": "19.7.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-19.7.0.tgz", - "integrity": "sha512-F4JcZtc2/Wl0AwRaeUywupPHdaOtldpwfrGYewT1dYDikFafyDk5T6E9JYv/HgLXROPNMDVPFquwikNvAPlfAg==", + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-20.0.0.tgz", + "integrity": "sha512-3wsx0iX5f/IQgcTwXIzQq2VPHSjYXJasKNSfgMyKXn4MJGljaSNj+A0ao/5zjnwWVpL0vK5PQsk7EIuMcgAdrg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "19.7.0" + "@angular-eslint/bundled-angular-compiler": "20.0.0" }, "peerDependencies": { "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", @@ -1995,14 +1861,14 @@ } }, "node_modules/@angular/build": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-20.0.0.tgz", - "integrity": "sha512-b/FAvvUbsMEgr+UlvTtDz4NCv+BFi+55swtKRmaritvZ2rDfhF1x9tUmSkT6GebGXkI/Gg0kl5rJoD5iv5lY3A==", + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-20.0.1.tgz", + "integrity": "sha512-m/0jtXIeOaoU/WXtMLRuvq7UaGRxNHpoRKVVoJrifvZuNBYGM4e2lzxlIlo8kiQhPpZQc0zcAMoosbmzKKdkUQ==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2000.0", + "@angular-devkit/architect": "0.2000.1", "@babel/core": "7.27.1", "@babel/helper-annotate-as-pure": "7.27.1", "@babel/helper-split-export-declaration": "7.24.7", @@ -2044,7 +1910,7 @@ "@angular/platform-browser": "^20.0.0", "@angular/platform-server": "^20.0.0", "@angular/service-worker": "^20.0.0", - "@angular/ssr": "^20.0.0", + "@angular/ssr": "^20.0.1", "karma": "^6.4.0", "less": "^4.2.0", "ng-packagr": "^20.0.0", @@ -2649,9 +2515,9 @@ } }, "node_modules/@angular/cdk": { - "version": "20.0.1", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-20.0.1.tgz", - "integrity": "sha512-llJIyKdF9D0hJ9/PNy9A5vmayNgHr7MtQrtjpeLyPuK8qkUnxQd9Hzv5olqixRrbxxDs/Lt0l1T2ViHGy7WYhg==", + "version": "20.0.2", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-20.0.2.tgz", + "integrity": "sha512-gRQcpTNhnwBxXSmpnrljODUHQmB2Hnxc6L2Ad6mSMV+c3opd9KIFxL5eG2WOOPHGAaPrV4gNFw+t1i01U4grTg==", "license": "MIT", "dependencies": { "parse5": "^7.1.2", @@ -2688,18 +2554,18 @@ } }, "node_modules/@angular/cli": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-20.0.0.tgz", - "integrity": "sha512-k9EDaaLYTMWkBbayUh6Tf0PJ+E0e6jRPrjOSPsOJHRh+S5BsNdLIsKJmThGXkq2wnD35+2CKPy9UQyvfaIA5KQ==", + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-20.0.1.tgz", + "integrity": "sha512-OU91byvG/WsDDUVmXIJr3/sU89U6g8G8IXrqgVRVPgjXKEQMnUNBlmygD2rMUR5C02g2lGc6s2j0hnOJ/dDNOw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.2000.0", - "@angular-devkit/core": "20.0.0", - "@angular-devkit/schematics": "20.0.0", + "@angular-devkit/architect": "0.2000.1", + "@angular-devkit/core": "20.0.1", + "@angular-devkit/schematics": "20.0.1", "@inquirer/prompts": "7.5.1", "@listr2/prompt-adapter-inquirer": "2.0.22", - "@schematics/angular": "20.0.0", + "@schematics/angular": "20.0.1", "@yarnpkg/lockfile": "1.1.0", "ini": "5.0.0", "jsonc-parser": "3.3.1", @@ -2808,9 +2674,9 @@ } }, "node_modules/@angular/common": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-20.0.0.tgz", - "integrity": "sha512-tZTvxDjx+wH74/hIpip63u4tlaXNVXkq1iVf4gk7RPQGCAYLNPDWma8X+RpXMXWikn4/mA5NS1VBBtStTbS+gg==", + "version": "20.0.2", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-20.0.2.tgz", + "integrity": "sha512-dqzKFL2MgPpQiaY9ZyDhGZYWEXblsqofW6czH/+HkmlNgSmDCBaY/UhNQShxNQ0KQbR1o08OWuQr29zxkY1CMA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -2819,14 +2685,14 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "20.0.0", + "@angular/core": "20.0.2", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-20.0.0.tgz", - "integrity": "sha512-RzS7MFNy/f8Tft0u6Q1zszzFTeki4408zsBALwmS91a8O8x/jaEvfwA7swC7RiqiX9KKmAyuBJ0qiv42v1T5dA==", + "version": "20.0.2", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-20.0.2.tgz", + "integrity": "sha512-BJYXGUZaY9awYvgt0w9TDq73A1+m8W5eMRn/krWeQcfWakwTgs27BSxmhfJhD45KrMrky5yxAvGgqSfMKrLeng==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -2836,20 +2702,20 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-20.0.0.tgz", - "integrity": "sha512-dPFp/YyRJkiyppnoI85mZz0CJv0ulc5MpJV16Lx0qdrRyoKmBrGmdaGEP0DOhhBLVAmJ5J2wvShvWfE2pjMMWw==", + "version": "20.0.2", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-20.0.2.tgz", + "integrity": "sha512-kVKHS5ZRadTR+rRuBl3Dsccsv/jiHXdJJYlDQwQW87afd4RtAu75P3RsSd8jaUj+7P9O4Ve4vwCZVtgOh0yxbw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "7.27.1", + "@babel/core": "7.27.4", "@jridgewell/sourcemap-codec": "^1.4.14", "chokidar": "^4.0.0", "convert-source-map": "^1.5.1", "reflect-metadata": "^0.2.0", "semver": "^7.0.0", "tslib": "^2.3.0", - "yargs": "^17.2.1" + "yargs": "^18.0.0" }, "bin": { "ng-xi18n": "bundles/src/bin/ng_xi18n.js", @@ -2859,7 +2725,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "20.0.0", + "@angular/compiler": "20.0.2", "typescript": ">=5.8 <5.9" }, "peerDependenciesMeta": { @@ -2868,52 +2734,45 @@ } } }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.1.tgz", - "integrity": "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==", + "node_modules/@angular/compiler-cli/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.1", - "@babel/helper-compilation-targets": "^7.27.1", - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helpers": "^7.27.1", - "@babel/parser": "^7.27.1", - "@babel/template": "^7.27.1", - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, "engines": { - "node": ">=6.9.0" + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "node_modules/@angular/compiler-cli/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/@angular/compiler-cli/node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", "dev": true, "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" } }, "node_modules/@angular/compiler-cli/node_modules/convert-source-map": { @@ -2923,10 +2782,97 @@ "dev": true, "license": "MIT" }, + "node_modules/@angular/compiler-cli/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular/compiler-cli/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular/compiler-cli/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@angular/compiler-cli/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@angular/compiler-cli/node_modules/yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/@angular/compiler-cli/node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, "node_modules/@angular/core": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-20.0.0.tgz", - "integrity": "sha512-2UjKbTtYSY8omY+LE4G6hQ1/R4PkE6NY7/2u99TxLH/oOnc9broCH1g9ITU+n0eJURcOFeK0/w6RdSrK+di3pg==", + "version": "20.0.2", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-20.0.2.tgz", + "integrity": "sha512-z9L8WPrHTkfupHtpO6aW4KqcqigIhxcQwCaEMgXWc5WJkoiMJSfo/dk+cyiGjCfTkc5Y6DO6f6ERi0IWYWWbPA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -2935,7 +2881,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "20.0.0", + "@angular/compiler": "20.0.2", "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0" }, @@ -2949,9 +2895,9 @@ } }, "node_modules/@angular/forms": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-20.0.0.tgz", - "integrity": "sha512-6yeb99IrNyeyj7o0bbd+n3JTZrXX2dJfdYLJH3tlXVlO9wg63bq+YR1AeM+RDCYMs+YDJis0lQpF6s+OICJv4g==", + "version": "20.0.2", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-20.0.2.tgz", + "integrity": "sha512-RrQKwzFZsEDXsvesNXS4XxndEKZHC+VexIdRr1vlxx7isfvpl4htOxceW0D+Gvku1mnaS99eB/AWS50HxW3B3Q==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -2960,16 +2906,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "20.0.0", - "@angular/core": "20.0.0", - "@angular/platform-browser": "20.0.0", + "@angular/common": "20.0.2", + "@angular/core": "20.0.2", + "@angular/platform-browser": "20.0.2", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/language-service": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-20.0.0.tgz", - "integrity": "sha512-lprUUz56dk3ORWGD6Z7Hmzo2MqxezW5qXaxpJHOow3+8/Jx6q+PPWCZrFSEyTtaKr/oRGzHLVCEzB+tmB980Fw==", + "version": "20.0.2", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-20.0.2.tgz", + "integrity": "sha512-CUkKyuMUvRqJR5BeSDQ4gGX8z5vxRkQ0mqIq4uMXrFs/rMn7cYqfzr3rjxp0S69wsOKF4G/6pgN5xpUhnqhdgw==", "dev": true, "license": "MIT", "engines": { @@ -2977,15 +2923,15 @@ } }, "node_modules/@angular/material": { - "version": "20.0.1", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-20.0.1.tgz", - "integrity": "sha512-ip1hLYSVi2+UtMsONnRFocof0bk+0mCXErrdfH3MLg1j5ZtJ8XEOUY9TeGqWFCkVf8J37mIAI5g2TZW1YuJLUg==", + "version": "20.0.2", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-20.0.2.tgz", + "integrity": "sha512-yIXvF+LjFdHjJWyvn1SxbWB9LdNxYnqEKbKzminW4WPXlPJMOAeyhEDFeQv9W92Zv+/ibS4tI3/SD759ejb45g==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/cdk": "20.0.1", + "@angular/cdk": "20.0.2", "@angular/common": "^20.0.0 || ^21.0.0", "@angular/core": "^20.0.0 || ^21.0.0", "@angular/forms": "^20.0.0 || ^21.0.0", @@ -2994,9 +2940,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.0.0.tgz", - "integrity": "sha512-FP9YjT2beF0tov0wub6+eUQqJd2MwyYqEQQ6+Qx67ukd04plIryhrcImORehrsN24DbnHkyTqhCvUyNAZs2uwA==", + "version": "20.0.2", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.0.2.tgz", + "integrity": "sha512-4adMQSVlwxjY9z/LEk3Q5hr4/qbM9UD9FcqbyZOt3+BL+F2GwGdKzwg6Dj4Dv0Tv8/dudNSVgHc8lIdQ4C7K1w==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -3005,9 +2951,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/animations": "20.0.0", - "@angular/common": "20.0.0", - "@angular/core": "20.0.0" + "@angular/animations": "20.0.2", + "@angular/common": "20.0.2", + "@angular/core": "20.0.2" }, "peerDependenciesMeta": { "@angular/animations": { @@ -3016,9 +2962,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-20.0.0.tgz", - "integrity": "sha512-AACq3Ijuq59SdLDmfxWU8hYlo8O4Br9OHWNAga2W0X6p/7HlpeZZVdTlb/KGVYRKJvGpgSB10QYlRPfm215q9Q==", + "version": "20.0.2", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-20.0.2.tgz", + "integrity": "sha512-8MDGsgcxUxSldcX6HRGB5dj+xOCQ8qmx8Vog9unEBNkuPH0vqvOepqn3prdV6dM31jYfJ9JAEKeEfNZFjuWSkA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -3027,16 +2973,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "20.0.0", - "@angular/compiler": "20.0.0", - "@angular/core": "20.0.0", - "@angular/platform-browser": "20.0.0" + "@angular/common": "20.0.2", + "@angular/compiler": "20.0.2", + "@angular/core": "20.0.2", + "@angular/platform-browser": "20.0.2" } }, "node_modules/@angular/router": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-20.0.0.tgz", - "integrity": "sha512-RQ7rU4NaZDSvvOfMZQmB50q7de+jrHYb+f0ExLKBvr80B1MK3oc9VvI2BzBkGfM4aGx71MMa0UizjOiT/31kqw==", + "version": "20.0.2", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-20.0.2.tgz", + "integrity": "sha512-UyuTeoXkkZw1eFFNwrTfb1JXow6HKVdLNb3n9MhqDz+3ekdiqDH8EBaKhxYZxlcpNoa6cNbECZJYtaHy1lw38g==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -3045,9 +2991,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "20.0.0", - "@angular/core": "20.0.0", - "@angular/platform-browser": "20.0.0", + "@angular/common": "20.0.2", + "@angular/core": "20.0.2", + "@angular/platform-browser": "20.0.2", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -6951,13 +6897,13 @@ ] }, "node_modules/@mmstack/form-adapters": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/@mmstack/form-adapters/-/form-adapters-19.2.0.tgz", - "integrity": "sha512-+lArKFF+ywyaMra5kEFzsRPgqhtYCtx/ek8NCRzleIUREghskG5W3O9CUtBjYWcbYlM/QZna/a6s9OP6YlM+yQ==", + "version": "19.2.1", + "resolved": "https://registry.npmjs.org/@mmstack/form-adapters/-/form-adapters-19.2.1.tgz", + "integrity": "sha512-hct01pyN+vs2r6azav3z+PiJOprXGVyitSSvc928lHnNcaFXWI5qSTpjE4F4oBOSbQT85U4rJQQK38ujsogcnA==", "license": "MIT", "dependencies": { "@mmstack/form-core": "^19.2.0", - "@mmstack/form-validation": "^19.2.0", + "@mmstack/form-validation": "^19.2.1", "@mmstack/primitives": "^19.2.1", "tslib": "^2.3.0" }, @@ -6996,14 +6942,14 @@ } }, "node_modules/@mmstack/form-material": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/@mmstack/form-material/-/form-material-19.2.0.tgz", - "integrity": "sha512-PRciRr+MPM36WzCm7jAdE2QC5x6padIG/F/DFsZUa0XVJZrBt7TzhEFB6/mSmRTu879uR7rMzM56WJ5cRd/T/w==", + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@mmstack/form-material/-/form-material-19.2.2.tgz", + "integrity": "sha512-1cIKldknQ0TzcCkrGavWeFoTQsoUyNtilgtzSVtp35SQGp/4mHaRjM/XkehmMSlYS5lN+HOY+iQAWSwrx6wI2A==", "license": "MIT", "dependencies": { - "@mmstack/form-adapters": "^19.2.0", + "@mmstack/form-adapters": "^19.2.1", "@mmstack/form-core": "^19.2.0", - "@mmstack/form-validation": "^19.2.0", + "@mmstack/form-validation": "^19.2.1", "@mmstack/primitives": "^19.2.1", "@mmstack/resource": "^19.2.0", "tslib": "^2.3.0" @@ -7017,9 +6963,9 @@ } }, "node_modules/@mmstack/form-validation": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/@mmstack/form-validation/-/form-validation-19.2.0.tgz", - "integrity": "sha512-Z6IyN0U62rGy9SAID39d4BI9mhMw9FOEL7hyGVSKwoTdSJwpf9hhdB3cTC9500d02xRmJmYiBESb/jVDsP+6Gw==", + "version": "19.2.1", + "resolved": "https://registry.npmjs.org/@mmstack/form-validation/-/form-validation-19.2.1.tgz", + "integrity": "sha512-4oHj5s3njp2uK792aC/gqUo5bibOtb80zA+2Wk2wTO9j3sggudAdR3LA003S0VS3PqvES968nASd3NbFPKcQBg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -7082,6 +7028,21 @@ "uuid": "dist/esm/bin/uuid" } }, + "node_modules/@mmstack/router-core": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@mmstack/router-core/-/router-core-19.3.0.tgz", + "integrity": "sha512-zpNDbA1DrGvDMXGbhm5ZD1w4iQrm6DrOGRCv9tnfdn4gi9c97mJIMKzFusMYaJKS61v5zM4cyYdCNlHiGgz95w==", + "license": "MIT", + "dependencies": { + "@mmstack/primitives": "^19.2.3", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/core": "^19.2.3", + "@angular/router": "^19.2.3", + "rxjs": "~7.8.2" + } + }, "node_modules/@modern-js/node-bundle-require": { "version": "2.67.6", "resolved": "https://registry.npmjs.org/@modern-js/node-bundle-require/-/node-bundle-require-2.67.6.tgz", @@ -8364,9 +8325,9 @@ } }, "node_modules/@ngtools/webpack": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-20.0.0.tgz", - "integrity": "sha512-3kT8PlLDvThhZxNbJWdG2qrZrUOg0tAjd7mnsOsg65/2tsBZ2HaR3fSzkHOG+Ly6SlWiS4owKWqPRGlgFuq1bw==", + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-20.0.1.tgz", + "integrity": "sha512-uTLeN/k+CWHMbgc7XLp0Kfs9ozNoFdsgMi+no9ygegrakGgt/CzCU1JL0VbdnFQwqPc/mDYe7S/+aDWsce8TuA==", "dev": true, "license": "MIT", "engines": { @@ -10599,14 +10560,14 @@ } }, "node_modules/@schematics/angular": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-20.0.0.tgz", - "integrity": "sha512-lK5TvxEoeaoPnxM31qeNWhHUJ3kKMnRHknYhOfOmS8xfme78nS01FdU7TODLkg2p4GNEVVtXoxhj3FmrG3srKw==", + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-20.0.1.tgz", + "integrity": "sha512-29T9vUAjZnbXM+vImIQcdqG/ibdcfj5+pybo5cbiMSwVPVyerXgnD0HKC4dyZ34V2RFZa8cmyCLe/5bYoPQ+0g==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "20.0.0", - "@angular-devkit/schematics": "20.0.0", + "@angular-devkit/core": "20.0.1", + "@angular-devkit/schematics": "20.0.1", "jsonc-parser": "3.3.1" }, "engines": { @@ -10807,9 +10768,9 @@ } }, "node_modules/@swc/core": { - "version": "1.11.29", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.11.29.tgz", - "integrity": "sha512-g4mThMIpWbNhV8G2rWp5a5/Igv8/2UFRJx2yImrLGMgrDDYZIopqZ/z0jZxDgqNA1QDx93rpwNF7jGsxVWcMlA==", + "version": "1.11.31", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.11.31.tgz", + "integrity": "sha512-mAby9aUnKRjMEA7v8cVZS9Ah4duoRBnX7X6r5qrhTxErx+68MoY1TPrVwj/66/SWN3Bl+jijqAqoB8Qx0QE34A==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -10825,16 +10786,16 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.11.29", - "@swc/core-darwin-x64": "1.11.29", - "@swc/core-linux-arm-gnueabihf": "1.11.29", - "@swc/core-linux-arm64-gnu": "1.11.29", - "@swc/core-linux-arm64-musl": "1.11.29", - "@swc/core-linux-x64-gnu": "1.11.29", - "@swc/core-linux-x64-musl": "1.11.29", - "@swc/core-win32-arm64-msvc": "1.11.29", - "@swc/core-win32-ia32-msvc": "1.11.29", - "@swc/core-win32-x64-msvc": "1.11.29" + "@swc/core-darwin-arm64": "1.11.31", + "@swc/core-darwin-x64": "1.11.31", + "@swc/core-linux-arm-gnueabihf": "1.11.31", + "@swc/core-linux-arm64-gnu": "1.11.31", + "@swc/core-linux-arm64-musl": "1.11.31", + "@swc/core-linux-x64-gnu": "1.11.31", + "@swc/core-linux-x64-musl": "1.11.31", + "@swc/core-win32-arm64-msvc": "1.11.31", + "@swc/core-win32-ia32-msvc": "1.11.31", + "@swc/core-win32-x64-msvc": "1.11.31" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" @@ -10846,9 +10807,9 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.11.29", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.11.29.tgz", - "integrity": "sha512-whsCX7URzbuS5aET58c75Dloby3Gtj/ITk2vc4WW6pSDQKSPDuONsIcZ7B2ng8oz0K6ttbi4p3H/PNPQLJ4maQ==", + "version": "1.11.31", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.11.31.tgz", + "integrity": "sha512-NTEaYOts0OGSbJZc0O74xsji+64JrF1stmBii6D5EevWEtrY4wlZhm8SiP/qPrOB+HqtAihxWIukWkP2aSdGSQ==", "cpu": [ "arm64" ], @@ -10863,9 +10824,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.11.29", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.11.29.tgz", - "integrity": "sha512-S3eTo/KYFk+76cWJRgX30hylN5XkSmjYtCBnM4jPLYn7L6zWYEPajsFLmruQEiTEDUg0gBEWLMNyUeghtswouw==", + "version": "1.11.31", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.11.31.tgz", + "integrity": "sha512-THSGaSwT96JwXDwuXQ6yFBbn+xDMdyw7OmBpnweAWsh5DhZmQkALEm1DgdQO3+rrE99MkmzwAfclc0UmYro/OA==", "cpu": [ "x64" ], @@ -10880,9 +10841,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.11.29", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.11.29.tgz", - "integrity": "sha512-o9gdshbzkUMG6azldHdmKklcfrcMx+a23d/2qHQHPDLUPAN+Trd+sDQUYArK5Fcm7TlpG4sczz95ghN0DMkM7g==", + "version": "1.11.31", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.11.31.tgz", + "integrity": "sha512-laKtQFnW7KHgE57Hx32os2SNAogcuIDxYE+3DYIOmDMqD7/1DCfJe6Rln2N9WcOw6HuDbDpyQavIwZNfSAa8vQ==", "cpu": [ "arm" ], @@ -10897,9 +10858,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.11.29", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.11.29.tgz", - "integrity": "sha512-sLoaciOgUKQF1KX9T6hPGzvhOQaJn+3DHy4LOHeXhQqvBgr+7QcZ+hl4uixPKTzxk6hy6Hb0QOvQEdBAAR1gXw==", + "version": "1.11.31", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.11.31.tgz", + "integrity": "sha512-T+vGw9aPE1YVyRxRr1n7NAdkbgzBzrXCCJ95xAZc/0+WUwmL77Z+js0J5v1KKTRxw4FvrslNCOXzMWrSLdwPSA==", "cpu": [ "arm64" ], @@ -10914,9 +10875,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.11.29", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.11.29.tgz", - "integrity": "sha512-PwjB10BC0N+Ce7RU/L23eYch6lXFHz7r3NFavIcwDNa/AAqywfxyxh13OeRy+P0cg7NDpWEETWspXeI4Ek8otw==", + "version": "1.11.31", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.11.31.tgz", + "integrity": "sha512-Mztp5NZkyd5MrOAG+kl+QSn0lL4Uawd4CK4J7wm97Hs44N9DHGIG5nOz7Qve1KZo407Y25lTxi/PqzPKHo61zQ==", "cpu": [ "arm64" ], @@ -10931,9 +10892,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.11.29", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.11.29.tgz", - "integrity": "sha512-i62vBVoPaVe9A3mc6gJG07n0/e7FVeAvdD9uzZTtGLiuIfVfIBta8EMquzvf+POLycSk79Z6lRhGPZPJPYiQaA==", + "version": "1.11.31", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.11.31.tgz", + "integrity": "sha512-DDVE0LZcXOWwOqFU1Xi7gdtiUg3FHA0vbGb3trjWCuI1ZtDZHEQYL4M3/2FjqKZtIwASrDvO96w91okZbXhvMg==", "cpu": [ "x64" ], @@ -10948,9 +10909,9 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.11.29", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.11.29.tgz", - "integrity": "sha512-YER0XU1xqFdK0hKkfSVX1YIyCvMDI7K07GIpefPvcfyNGs38AXKhb2byySDjbVxkdl4dycaxxhRyhQ2gKSlsFQ==", + "version": "1.11.31", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.11.31.tgz", + "integrity": "sha512-mJA1MzPPRIfaBUHZi0xJQ4vwL09MNWDeFtxXb0r4Yzpf0v5Lue9ymumcBPmw/h6TKWms+Non4+TDquAsweuKSw==", "cpu": [ "x64" ], @@ -10965,9 +10926,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.11.29", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.11.29.tgz", - "integrity": "sha512-po+WHw+k9g6FAg5IJ+sMwtA/fIUL3zPQ4m/uJgONBATCVnDDkyW6dBA49uHNVtSEvjvhuD8DVWdFP847YTcITw==", + "version": "1.11.31", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.11.31.tgz", + "integrity": "sha512-RdtakUkNVAb/FFIMw3LnfNdlH1/ep6KgiPDRlmyUfd0WdIQ3OACmeBegEFNFTzi7gEuzy2Yxg4LWf4IUVk8/bg==", "cpu": [ "arm64" ], @@ -10982,9 +10943,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.11.29", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.11.29.tgz", - "integrity": "sha512-h+NjOrbqdRBYr5ItmStmQt6x3tnhqgwbj9YxdGPepbTDamFv7vFnhZR0YfB3jz3UKJ8H3uGJ65Zw1VsC+xpFkg==", + "version": "1.11.31", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.11.31.tgz", + "integrity": "sha512-hErXdCGsg7swWdG1fossuL8542I59xV+all751mYlBoZ8kOghLSKObGQTkBbuNvc0sUKWfWg1X0iBuIhAYar+w==", "cpu": [ "ia32" ], @@ -10999,9 +10960,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.11.29", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.11.29.tgz", - "integrity": "sha512-Q8cs2BDV9wqDvqobkXOYdC+pLUSEpX/KvI0Dgfun1F+LzuLotRFuDhrvkU9ETJA6OnD2+Fn/ieHgloiKA/Mn/g==", + "version": "1.11.31", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.11.31.tgz", + "integrity": "sha512-5t7SGjUBMMhF9b5j17ml/f/498kiBJNf4vZFNM421UGUEETdtjPN9jZIuQrowBkoFGJTCVL/ECM4YRtTH30u/A==", "cpu": [ "x64" ], @@ -11400,9 +11361,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.15.29", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.29.tgz", - "integrity": "sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ==", + "version": "22.15.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.30.tgz", + "integrity": "sha512-6Q7lr06bEHdlfplU6YRbgG1SFBdlsfNC4/lX+SkhiTs0cpJkOElmWls8PxDFv4yY/xKb8Y6SO0OmSX4wgqTZbA==", "dev": true, "license": "MIT", "dependencies": { @@ -12192,19 +12153,19 @@ } }, "node_modules/angular-eslint": { - "version": "19.7.0", - "resolved": "https://registry.npmjs.org/angular-eslint/-/angular-eslint-19.7.0.tgz", - "integrity": "sha512-ujlc8CR40RYEWUctpVEg41ZCtmKnWeJH0mzORhzf0NVZb6FLhoNhmDPr1byw4Bcxzl0DAoNgKBhJymt6FNL6Rw==", + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/angular-eslint/-/angular-eslint-20.0.0.tgz", + "integrity": "sha512-9wCkzR+oxMKDXktFItI10dFaX4qCuz9SgClXdh/ZHmCANHK/RtPnXnD+gROPvhNN1M6BAJKialjIrs88orz97A==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": ">= 19.0.0 < 20.0.0", - "@angular-devkit/schematics": ">= 19.0.0 < 20.0.0", - "@angular-eslint/builder": "19.7.0", - "@angular-eslint/eslint-plugin": "19.7.0", - "@angular-eslint/eslint-plugin-template": "19.7.0", - "@angular-eslint/schematics": "19.7.0", - "@angular-eslint/template-parser": "19.7.0", + "@angular-devkit/core": ">= 20.0.0 < 21.0.0", + "@angular-devkit/schematics": ">= 20.0.0 < 21.0.0", + "@angular-eslint/builder": "20.0.0", + "@angular-eslint/eslint-plugin": "20.0.0", + "@angular-eslint/eslint-plugin-template": "20.0.0", + "@angular-eslint/schematics": "20.0.0", + "@angular-eslint/template-parser": "20.0.0", "@typescript-eslint/types": "^8.0.0", "@typescript-eslint/utils": "^8.0.0" }, @@ -12214,87 +12175,6 @@ "typescript-eslint": "^8.0.0" } }, - "node_modules/angular-eslint/node_modules/@angular-devkit/core": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.14.tgz", - "integrity": "sha512-aaPEnRNIBoYT4XrrYcZlHadX8vFDTUR+4wUgcmr0cNDLeWzWtoPFeVq8TQD6kFDeqovSx/UVEblGgg/28WvHyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.17.1", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.2", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^4.0.0" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/angular-eslint/node_modules/@angular-devkit/schematics": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-19.2.14.tgz", - "integrity": "sha512-s89/MWXHy8+GP/cRfFbSECIG3FQQQwNVv44OOmghPVgKQgQ+EoE/zygL2hqKYTUPoPaS/IhNXdXjSE5pS9yLeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "19.2.14", - "jsonc-parser": "3.3.1", - "magic-string": "0.30.17", - "ora": "5.4.1", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/angular-eslint/node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/angular-eslint/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -16771,9 +16651,9 @@ } }, "node_modules/htmlparser2/node_modules/entities": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.0.tgz", - "integrity": "sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -21440,9 +21320,9 @@ } }, "node_modules/parse5-html-rewriting-stream/node_modules/entities": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.0.tgz", - "integrity": "sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -21479,9 +21359,9 @@ } }, "node_modules/parse5-sax-parser/node_modules/entities": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.0.tgz", - "integrity": "sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", "dev": true, "license": "BSD-2-Clause", "engines": { diff --git a/frontend/package.json b/frontend/package.json index 1439ca1..847e32f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,28 +9,29 @@ }, "private": true, "dependencies": { - "@angular/cdk": "^20.0.1", - "@angular/common": "20.0.0", - "@angular/compiler": "20.0.0", - "@angular/core": "20.0.0", - "@angular/forms": "20.0.0", - "@angular/material": "^20.0.1", - "@angular/platform-browser": "20.0.0", - "@angular/platform-browser-dynamic": "20.0.0", - "@angular/router": "20.0.0", - "@mmstack/form-material": "^19.2.0", - "@mmstack/primitives": "^19.2.3", - "@mmstack/resource": "^19.2.0", + "@angular/cdk": "20.0.2", + "@angular/common": "20.0.2", + "@angular/compiler": "20.0.2", + "@angular/core": "20.0.2", + "@angular/forms": "20.0.2", + "@angular/material": "20.0.2", + "@angular/platform-browser": "20.0.2", + "@angular/platform-browser-dynamic": "20.0.2", + "@angular/router": "20.0.2", + "@mmstack/form-material": "19.2.2", + "@mmstack/primitives": "19.2.3", + "@mmstack/resource": "19.2.0", + "@mmstack/router-core": "^19.3.0", "rxjs": "7.8.2", "zone.js": "0.15.1" }, "devDependencies": { - "@angular-devkit/build-angular": "20.0.0", - "@angular-devkit/core": "20.0.0", - "@angular-devkit/schematics": "20.0.0", - "@angular/cli": "20.0.0", - "@angular/compiler-cli": "20.0.0", - "@angular/language-service": "20.0.0", + "@angular-devkit/build-angular": "20.0.1", + "@angular-devkit/core": "20.0.1", + "@angular-devkit/schematics": "20.0.1", + "@angular/cli": "20.0.1", + "@angular/compiler-cli": "20.0.2", + "@angular/language-service": "20.0.2", "@eslint/js": "9.28.0", "@nx/angular": "21.1.3", "@nx/eslint": "21.1.3", @@ -39,14 +40,14 @@ "@nx/js": "21.1.3", "@nx/web": "21.1.3", "@nx/workspace": "21.1.3", - "@schematics/angular": "20.0.0", + "@schematics/angular": "20.0.1", "@swc-node/register": "1.10.10", - "@swc/core": "1.11.29", + "@swc/core": "1.11.31", "@swc/helpers": "0.5.17", "@types/jest": "29.5.14", - "@types/node": "22.15.29", + "@types/node": "22.15.30", "@typescript-eslint/utils": "8.33.1", - "angular-eslint": "19.7.0", + "angular-eslint": "20.0.0", "eslint": "9.28.0", "eslint-config-prettier": "10.1.5", "jest": "29.7.0", diff --git a/frontend/src/app/app.config.ts b/frontend/src/app/app.config.ts index 585e9db..8fee80a 100644 --- a/frontend/src/app/app.config.ts +++ b/frontend/src/app/app.config.ts @@ -1,15 +1,16 @@ -import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; -import { provideRouter } from '@angular/router'; -import { appRoutes } from './app.routes'; import { provideHttpClient } from '@angular/common/http'; +import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; +import { provideRouter, withPreloading } from '@angular/router'; import { ENVIRONMENT } from '@frontend/shared/environment'; +import { PreloadStrategy } from '@mmstack/router-core'; import { environment } from '../environments/environment'; +import { appRoutes } from './app.routes'; export const appConfig: ApplicationConfig = { - providers: [ - provideZoneChangeDetection({ eventCoalescing: true }), - provideHttpClient(), - provideRouter(appRoutes), - { provide: ENVIRONMENT, useValue: environment } - ], + providers: [ + provideZoneChangeDetection({ eventCoalescing: true }), + provideHttpClient(), + provideRouter(appRoutes, withPreloading(PreloadStrategy)), + { provide: ENVIRONMENT, useValue: environment }, + ], }; diff --git a/frontend/src/app/app.routes.ts b/frontend/src/app/app.routes.ts index a9f8b45..17b4f87 100644 --- a/frontend/src/app/app.routes.ts +++ b/frontend/src/app/app.routes.ts @@ -4,7 +4,16 @@ export const appRoutes: Route[] = [ { path: 'containers', loadComponent: () => - import('@frontend/web/container').then((m) => m.ContainersComponentShell), + import('@frontend/web/containers').then( + (m) => m.ContainersComponentShell + ), + }, + { + path: 'container', + loadComponent: () => + import('@frontend/web/container').then( + (m) => m.ContainerDetailsComponent + ), }, { path: '**', diff --git a/frontend/src/environments/environment.prod.ts b/frontend/src/environments/environment.prod.ts deleted file mode 100644 index 89f87d5..0000000 --- a/frontend/src/environments/environment.prod.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Environment } from '@frontend/shared/environment'; - -export const environment: Environment = { - // Change this to your production WebSocket server URL - wsBaseUrl: 'wss://your-production-server.com', - production: true, - apis: { - containers: '/ws/containers', - container: '/ws/container', - stats: '/ws/stats', - combined: '/ws/combined' - } -}; diff --git a/frontend/src/index.html b/frontend/src/index.html index 641681f..f8f1280 100644 --- a/frontend/src/index.html +++ b/frontend/src/index.html @@ -1,13 +1,14 @@ - + - - - frontend - - - - - - - + + + frontend + + + + + + + + diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index ddfe114..8bb9088 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -7,7 +7,6 @@ body { } body { margin: 0; - font-family: Roboto, 'Helvetica Neue', sans-serif; background-color: #fafafa; color: rgba(0, 0, 0, 0.87); transition: @@ -20,7 +19,6 @@ body.dark-theme { color: rgba(255, 255, 255, 0.87); } -// Add this for the mat-card styling .container { margin-bottom: 16px; transition: @@ -28,7 +26,6 @@ body.dark-theme { color 0.3s ease; } -// Ensure mat-card content changes color appropriately body.dark-theme .mat-mdc-card { --mdc-elevated-card-container-color: #424242; color: rgba(255, 255, 255, 0.87); diff --git a/frontend/tsconfig.base.json b/frontend/tsconfig.base.json index 0e43e1c..530e19d 100644 --- a/frontend/tsconfig.base.json +++ b/frontend/tsconfig.base.json @@ -17,11 +17,12 @@ "paths": { "@frontend/shared/environment": ["libs/shared/environment/src/index.ts"], "@frontend/shared/navbar": ["libs/shared/navbar/src/index.ts"], - "@frontend/shared/stats-ws": ["libs/shared/stats-ws/src/index.ts"], "@frontend/shared/theme-toggle": [ "libs/shared/theme-toggle/src/index.ts" ], - "@frontend/web/container": ["libs/web/containers/src/index.ts"] + "@frontend/shared/ws": ["libs/shared/ws/src/index.ts"], + "@frontend/web/container": ["libs/web/container/src/index.ts"], + "@frontend/web/containers": ["libs/web/containers/src/index.ts"] } }, "exclude": ["node_modules", "tmp"]