containers page wip
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
This commit is contained in:
parent
50056356f3
commit
4a2a9eba30
7
frontend/libs/shared/navbar/README.md
Normal file
7
frontend/libs/shared/navbar/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# navbar
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `nx test navbar` to execute the unit tests.
|
||||
34
frontend/libs/shared/navbar/eslint.config.mjs
Normal file
34
frontend/libs/shared/navbar/eslint.config.mjs
Normal file
@ -0,0 +1,34 @@
|
||||
import nx from '@nx/eslint-plugin';
|
||||
import baseConfig from '../../../eslint.base.config.mjs';
|
||||
|
||||
export default [
|
||||
...baseConfig,
|
||||
...nx.configs['flat/angular'],
|
||||
...nx.configs['flat/angular-template'],
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
rules: {
|
||||
'@angular-eslint/directive-selector': [
|
||||
'error',
|
||||
{
|
||||
type: 'attribute',
|
||||
prefix: 'lib',
|
||||
style: 'camelCase',
|
||||
},
|
||||
],
|
||||
'@angular-eslint/component-selector': [
|
||||
'error',
|
||||
{
|
||||
type: 'element',
|
||||
prefix: 'lib',
|
||||
style: 'kebab-case',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.html'],
|
||||
// Override or add rules here
|
||||
rules: {},
|
||||
},
|
||||
];
|
||||
21
frontend/libs/shared/navbar/jest.config.ts
Normal file
21
frontend/libs/shared/navbar/jest.config.ts
Normal file
@ -0,0 +1,21 @@
|
||||
export default {
|
||||
displayName: 'navbar',
|
||||
preset: '../../../jest.preset.js',
|
||||
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
|
||||
coverageDirectory: '../../../coverage/libs/shared/navbar',
|
||||
transform: {
|
||||
'^.+\\.(ts|mjs|js|html)$': [
|
||||
'jest-preset-angular',
|
||||
{
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
stringifyContentPathRegex: '\\.(html|svg)$',
|
||||
},
|
||||
],
|
||||
},
|
||||
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
|
||||
snapshotSerializers: [
|
||||
'jest-preset-angular/build/serializers/no-ng-attributes',
|
||||
'jest-preset-angular/build/serializers/ng-snapshot',
|
||||
'jest-preset-angular/build/serializers/html-comment',
|
||||
],
|
||||
};
|
||||
20
frontend/libs/shared/navbar/project.json
Normal file
20
frontend/libs/shared/navbar/project.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "navbar",
|
||||
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "libs/shared/navbar/src",
|
||||
"prefix": "lib",
|
||||
"projectType": "library",
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"test": {
|
||||
"executor": "@nx/jest:jest",
|
||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
||||
"options": {
|
||||
"jestConfig": "libs/shared/navbar/jest.config.ts"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint"
|
||||
}
|
||||
}
|
||||
}
|
||||
2
frontend/libs/shared/navbar/src/index.ts
Normal file
2
frontend/libs/shared/navbar/src/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './lib/navbar-shell.component';
|
||||
export * from './lib/navbar.component';
|
||||
@ -0,0 +1,13 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { NavbarComponent } from './navbar.component';
|
||||
|
||||
@Component({
|
||||
selector: 'frontend-navbar-shell',
|
||||
imports: [NavbarComponent],
|
||||
template: `
|
||||
<frontend-navbar />
|
||||
<ng-content />
|
||||
`,
|
||||
})
|
||||
export class NavbarShellComponent {}
|
||||
|
||||
37
frontend/libs/shared/navbar/src/lib/navbar.component.ts
Normal file
37
frontend/libs/shared/navbar/src/lib/navbar.component.ts
Normal file
@ -0,0 +1,37 @@
|
||||
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 { ThemeToggleService } from '@frontend/shared/theme-toggle';
|
||||
|
||||
@Component({
|
||||
selector: 'frontend-navbar',
|
||||
imports: [MatToolbarModule, MatIcon, MatButtonModule],
|
||||
template: `
|
||||
<mat-toolbar>
|
||||
<mat-icon>view_carousel</mat-icon>
|
||||
<span>Docker Containers</span>
|
||||
<span class="spacer"></span>
|
||||
<button mat-icon-button (click)="switchTheme()">
|
||||
<mat-icon>{{ isDarkTheme() ? 'light_mode' : 'dark_mode' }}</mat-icon>
|
||||
</button>
|
||||
</mat-toolbar>
|
||||
`,
|
||||
styles: [
|
||||
`
|
||||
.spacer {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
`,
|
||||
],
|
||||
})
|
||||
export class NavbarComponent {
|
||||
private readonly themeToggleService = inject(ThemeToggleService);
|
||||
|
||||
protected isDarkTheme = this.themeToggleService.isDark;
|
||||
|
||||
switchTheme() {
|
||||
this.themeToggleService.toggleTheme();
|
||||
}
|
||||
}
|
||||
|
||||
6
frontend/libs/shared/navbar/src/test-setup.ts
Normal file
6
frontend/libs/shared/navbar/src/test-setup.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
|
||||
|
||||
setupZoneTestEnv({
|
||||
errorOnUnknownElements: true,
|
||||
errorOnUnknownProperties: true,
|
||||
});
|
||||
28
frontend/libs/shared/navbar/tsconfig.json
Normal file
28
frontend/libs/shared/navbar/tsconfig.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2022",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
],
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"strictTemplates": true
|
||||
}
|
||||
}
|
||||
17
frontend/libs/shared/navbar/tsconfig.lib.json
Normal file
17
frontend/libs/shared/navbar/tsconfig.lib.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../dist/out-tsc",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"src/**/*.spec.ts",
|
||||
"src/test-setup.ts",
|
||||
"jest.config.ts",
|
||||
"src/**/*.test.ts"
|
||||
],
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
16
frontend/libs/shared/navbar/tsconfig.spec.json
Normal file
16
frontend/libs/shared/navbar/tsconfig.spec.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"target": "es2016",
|
||||
"types": ["jest", "node"]
|
||||
},
|
||||
"files": ["src/test-setup.ts"],
|
||||
"include": [
|
||||
"jest.config.ts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
@ -1,2 +1,2 @@
|
||||
export * from './lib/containers';
|
||||
export * from './lib/types';
|
||||
export * from './lib/ws.service';
|
||||
|
||||
7
frontend/libs/web/containers/README.md
Normal file
7
frontend/libs/web/containers/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# containers
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `nx test containers` to execute the unit tests.
|
||||
34
frontend/libs/web/containers/eslint.config.mjs
Normal file
34
frontend/libs/web/containers/eslint.config.mjs
Normal file
@ -0,0 +1,34 @@
|
||||
import nx from '@nx/eslint-plugin';
|
||||
import baseConfig from '../../../eslint.base.config.mjs';
|
||||
|
||||
export default [
|
||||
...baseConfig,
|
||||
...nx.configs['flat/angular'],
|
||||
...nx.configs['flat/angular-template'],
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
rules: {
|
||||
'@angular-eslint/directive-selector': [
|
||||
'error',
|
||||
{
|
||||
type: 'attribute',
|
||||
prefix: 'lib',
|
||||
style: 'camelCase',
|
||||
},
|
||||
],
|
||||
'@angular-eslint/component-selector': [
|
||||
'error',
|
||||
{
|
||||
type: 'element',
|
||||
prefix: 'lib',
|
||||
style: 'kebab-case',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.html'],
|
||||
// Override or add rules here
|
||||
rules: {},
|
||||
},
|
||||
];
|
||||
21
frontend/libs/web/containers/jest.config.ts
Normal file
21
frontend/libs/web/containers/jest.config.ts
Normal file
@ -0,0 +1,21 @@
|
||||
export default {
|
||||
displayName: 'containers',
|
||||
preset: '../../../jest.preset.js',
|
||||
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
|
||||
coverageDirectory: '../../../coverage/libs/web/containers',
|
||||
transform: {
|
||||
'^.+\\.(ts|mjs|js|html)$': [
|
||||
'jest-preset-angular',
|
||||
{
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
stringifyContentPathRegex: '\\.(html|svg)$',
|
||||
},
|
||||
],
|
||||
},
|
||||
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
|
||||
snapshotSerializers: [
|
||||
'jest-preset-angular/build/serializers/no-ng-attributes',
|
||||
'jest-preset-angular/build/serializers/ng-snapshot',
|
||||
'jest-preset-angular/build/serializers/html-comment',
|
||||
],
|
||||
};
|
||||
20
frontend/libs/web/containers/project.json
Normal file
20
frontend/libs/web/containers/project.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "containers",
|
||||
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "libs/web/containers/src",
|
||||
"prefix": "lib",
|
||||
"projectType": "library",
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"test": {
|
||||
"executor": "@nx/jest:jest",
|
||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
||||
"options": {
|
||||
"jestConfig": "libs/web/containers/jest.config.ts"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint"
|
||||
}
|
||||
}
|
||||
}
|
||||
1
frontend/libs/web/containers/src/index.ts
Normal file
1
frontend/libs/web/containers/src/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './lib/containers-shell.component';
|
||||
@ -0,0 +1,30 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { ContainersComponent } from './containers.component';
|
||||
|
||||
@Component({
|
||||
selector: 'frontend-containers-shell',
|
||||
imports: [ContainersComponent, MatToolbarModule, MatIconModule],
|
||||
template: `
|
||||
<div class="content">
|
||||
<p class="description">View and manage your Docker containers here.</p>
|
||||
<frontend-containers />
|
||||
</div>
|
||||
`,
|
||||
styles: [
|
||||
`
|
||||
.content {
|
||||
padding: 24px;
|
||||
flex: 1;
|
||||
}
|
||||
.description {
|
||||
color: var(--sys-on-surface-variant);
|
||||
margin-bottom: 24px;
|
||||
font-size: 16px;
|
||||
}
|
||||
`,
|
||||
],
|
||||
})
|
||||
export class ContainersComponentShell {}
|
||||
|
||||
174
frontend/libs/web/containers/src/lib/containers.component.ts
Normal file
174
frontend/libs/web/containers/src/lib/containers.component.ts
Normal file
@ -0,0 +1,174 @@
|
||||
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';
|
||||
|
||||
@Component({
|
||||
selector: 'frontend-containers',
|
||||
imports: [
|
||||
MatCardModule,
|
||||
MatIconModule,
|
||||
MatChipsModule,
|
||||
MatButtonModule,
|
||||
NgClass,
|
||||
],
|
||||
template: `
|
||||
<div class="content-container">
|
||||
@for (container of containers(); track container.id) {
|
||||
<mat-card class="container-card">
|
||||
<mat-card-header>
|
||||
<mat-icon
|
||||
mat-card-avatar
|
||||
[ngClass]="getStateClass(container.state)"
|
||||
>
|
||||
{{ getStateIcon(container.state) }}
|
||||
</mat-icon>
|
||||
<mat-card-title>{{ container.name }}</mat-card-title>
|
||||
<mat-card-subtitle>{{ container.image }}</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<div class="info-row">
|
||||
<span class="label">ID:</span>
|
||||
<span class="value">{{ container.id.substring(0, 12) }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">Status:</span>
|
||||
<mat-chip [ngClass]="getStatusClass(container.status)">
|
||||
{{ container.status }}
|
||||
</mat-chip>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button mat-button color="primary">
|
||||
<mat-icon>info</mat-icon> DETAILS
|
||||
</button>
|
||||
<button
|
||||
mat-button
|
||||
[disabled]="true"
|
||||
[color]="container.state === 'running' ? 'warn' : 'primary'"
|
||||
>
|
||||
<mat-icon>{{
|
||||
container.state === 'running' ? 'stop' : 'play_arrow'
|
||||
}}</mat-icon>
|
||||
{{ container.state === 'running' ? 'STOP' : 'START' }}
|
||||
</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
}
|
||||
</div>
|
||||
`,
|
||||
styles: [
|
||||
`
|
||||
.content-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 16px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
`,
|
||||
],
|
||||
})
|
||||
export class ContainersComponent implements OnInit {
|
||||
private readonly service = inject(StatsWsService);
|
||||
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';
|
||||
}
|
||||
}
|
||||
|
||||
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 '';
|
||||
}
|
||||
}
|
||||
|
||||
6
frontend/libs/web/containers/src/test-setup.ts
Normal file
6
frontend/libs/web/containers/src/test-setup.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
|
||||
|
||||
setupZoneTestEnv({
|
||||
errorOnUnknownElements: true,
|
||||
errorOnUnknownProperties: true,
|
||||
});
|
||||
28
frontend/libs/web/containers/tsconfig.json
Normal file
28
frontend/libs/web/containers/tsconfig.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2022",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
],
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"strictTemplates": true
|
||||
}
|
||||
}
|
||||
17
frontend/libs/web/containers/tsconfig.lib.json
Normal file
17
frontend/libs/web/containers/tsconfig.lib.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../dist/out-tsc",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"src/**/*.spec.ts",
|
||||
"src/test-setup.ts",
|
||||
"jest.config.ts",
|
||||
"src/**/*.test.ts"
|
||||
],
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
16
frontend/libs/web/containers/tsconfig.spec.json
Normal file
16
frontend/libs/web/containers/tsconfig.spec.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"target": "es2016",
|
||||
"types": ["jest", "node"]
|
||||
},
|
||||
"files": ["src/test-setup.ts"],
|
||||
"include": [
|
||||
"jest.config.ts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
609
frontend/package-lock.json
generated
609
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -32,13 +32,13 @@
|
||||
"@angular/compiler-cli": "20.0.0",
|
||||
"@angular/language-service": "20.0.0",
|
||||
"@eslint/js": "9.28.0",
|
||||
"@nx/angular": "21.1.2",
|
||||
"@nx/eslint": "21.1.2",
|
||||
"@nx/eslint-plugin": "21.1.2",
|
||||
"@nx/jest": "21.1.2",
|
||||
"@nx/js": "21.1.2",
|
||||
"@nx/web": "21.1.2",
|
||||
"@nx/workspace": "21.1.2",
|
||||
"@nx/angular": "21.1.3",
|
||||
"@nx/eslint": "21.1.3",
|
||||
"@nx/eslint-plugin": "21.1.3",
|
||||
"@nx/jest": "21.1.3",
|
||||
"@nx/js": "21.1.3",
|
||||
"@nx/web": "21.1.3",
|
||||
"@nx/workspace": "21.1.3",
|
||||
"@schematics/angular": "20.0.0",
|
||||
"@swc-node/register": "1.10.10",
|
||||
"@swc/core": "1.11.29",
|
||||
@ -52,7 +52,7 @@
|
||||
"jest": "29.7.0",
|
||||
"jest-environment-jsdom": "29.7.0",
|
||||
"jest-preset-angular": "14.6.0",
|
||||
"nx": "21.1.2",
|
||||
"nx": "21.1.3",
|
||||
"prettier": "3.5.3",
|
||||
"ts-jest": "29.3.4",
|
||||
"ts-node": "10.9.2",
|
||||
|
||||
@ -1,74 +1,15 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, OnInit, inject } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { StatsWsService } from '@frontend/shared/stats-ws';
|
||||
import { ThemeToggleService } from '@frontend/shared/theme-toggle';
|
||||
import { Component } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import { NavbarShellComponent } from '@frontend/shared/navbar';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
imports: [
|
||||
RouterModule,
|
||||
MatButtonModule,
|
||||
MatCardModule,
|
||||
MatIconModule,
|
||||
MatToolbarModule,
|
||||
CommonModule,
|
||||
],
|
||||
imports: [NavbarShellComponent, RouterOutlet],
|
||||
selector: 'app-root',
|
||||
template: `
|
||||
<mat-toolbar>
|
||||
<span>Docker Containers</span>
|
||||
<span class="spacer"></span>
|
||||
<button mat-icon-button (click)="switchTheme()">
|
||||
<mat-icon>{{ isDarkTheme() ? 'light_mode' : 'dark_mode' }}</mat-icon>
|
||||
</button>
|
||||
</mat-toolbar>
|
||||
|
||||
<div class="content-container">
|
||||
@for (container of containers(); track container.id) {
|
||||
<mat-card class="container">
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{ container.name }}</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<p>ID: {{ container.id }}</p>
|
||||
<p>Image: {{ container.image }}</p>
|
||||
<p>Status: {{ container.status }}</p>
|
||||
<p>State: {{ container.state }}</p>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
}
|
||||
</div>
|
||||
<router-outlet></router-outlet>
|
||||
<frontend-navbar-shell>
|
||||
<router-outlet />
|
||||
</frontend-navbar-shell>
|
||||
`,
|
||||
styles: [
|
||||
`
|
||||
.spacer {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.content-container {
|
||||
padding: 16px;
|
||||
}
|
||||
`,
|
||||
],
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
private readonly service = inject(StatsWsService);
|
||||
private readonly themeToggleService = inject(ThemeToggleService);
|
||||
protected containers = this.service.containers;
|
||||
|
||||
// Add this to check current theme for the template
|
||||
protected isDarkTheme = () => this.themeToggleService.isDark();
|
||||
|
||||
switchTheme() {
|
||||
this.themeToggleService.toggleTheme();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.service.initContainers();
|
||||
}
|
||||
}
|
||||
export class AppComponent {}
|
||||
|
||||
@ -1,3 +1,13 @@
|
||||
import { Route } from '@angular/router';
|
||||
|
||||
export const appRoutes: Route[] = [];
|
||||
export const appRoutes: Route[] = [
|
||||
{
|
||||
path: 'containers',
|
||||
loadComponent: () =>
|
||||
import('@frontend/web/container').then((m) => m.ContainersComponentShell),
|
||||
},
|
||||
{
|
||||
path: '**',
|
||||
redirectTo: 'containers',
|
||||
},
|
||||
];
|
||||
|
||||
@ -1,16 +1,35 @@
|
||||
@import url('https://fonts.googleapis.com/icon?family=Material+Icons');
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
max-width: 100vw;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Roboto, 'Helvetica Neue', sans-serif;
|
||||
background-color: #fafafa;
|
||||
transition: background-color 0.3s ease;
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
transition:
|
||||
background-color 0.3s ease,
|
||||
color 0.3s ease;
|
||||
}
|
||||
|
||||
body.dark-theme {
|
||||
background-color: #303030;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
}
|
||||
|
||||
// Add this for the mat-card styling
|
||||
.container {
|
||||
margin-bottom: 16px;
|
||||
transition:
|
||||
background-color 0.3s ease,
|
||||
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);
|
||||
}
|
||||
|
||||
@ -16,8 +16,12 @@
|
||||
"baseUrl": ".",
|
||||
"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/shared/theme-toggle": [
|
||||
"libs/shared/theme-toggle/src/index.ts"
|
||||
],
|
||||
"@frontend/web/container": ["libs/web/containers/src/index.ts"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "tmp"]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user