Simple Managment webapp [LLM]

This commit is contained in:
2025-12-03 17:20:50 +01:00
parent b521f74951
commit e7f613b5dc
76 changed files with 20009 additions and 1 deletions

View File

@@ -0,0 +1,68 @@
<div class="page-content">
<div class="page-header">
<h2>Clients</h2>
<button nz-button (click)="loadClients()">
<span nz-icon nzType="reload"></span>
Refresh
</button>
</div>
<nz-card>
<nz-table
#clientTable
[nzData]="clients()"
[nzLoading]="loading()"
[nzShowPagination]="false"
nzSize="middle"
>
<thead>
<tr>
<th nzWidth="5%"></th>
<th nzWidth="20%">Name</th>
<th nzWidth="15%">Type</th>
<th nzWidth="25%">Agent</th>
<th nzWidth="20%">Created</th>
<th nzWidth="15%">Client ID</th>
</tr>
</thead>
<tbody>
@for (client of clients(); track client.client_id) {
<tr>
<td>
<span
nz-icon
[nzType]="getClientIcon(client.type)"
nzTheme="outline"
class="client-icon"
></span>
</td>
<td>{{ client.name || '-' }}</td>
<td>
<nz-tag>{{ getClientTypeLabel(client.type) }}</nz-tag>
</td>
<td>
<div class="agent-info">
<span>{{ client.agent_model }}</span>
<span class="agent-version">v{{ client.agent_version }}</span>
</div>
</td>
<td>
<span nz-tooltip [nzTooltipTitle]="client.timestamp_created">
{{ client.timestamp_created | relativeTime }}
</span>
</td>
<td>
<span class="mono client-id">{{ client.client_id }}</span>
</td>
</tr>
} @empty {
<tr>
<td colspan="6">
<nz-empty nzNotFoundContent="No clients registered"></nz-empty>
</td>
</tr>
}
</tbody>
</nz-table>
</nz-card>
</div>

View File

@@ -0,0 +1,30 @@
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
h2 {
margin: 0;
}
}
.client-icon {
font-size: 18px;
color: #666;
}
.agent-info {
display: flex;
flex-direction: column;
.agent-version {
font-size: 12px;
color: #999;
}
}
.client-id {
font-size: 11px;
color: #999;
}

View File

@@ -0,0 +1,73 @@
import { Component, inject, signal, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { NzTableModule } from 'ng-zorro-antd/table';
import { NzButtonModule } from 'ng-zorro-antd/button';
import { NzIconModule } from 'ng-zorro-antd/icon';
import { NzTagModule } from 'ng-zorro-antd/tag';
import { NzEmptyModule } from 'ng-zorro-antd/empty';
import { NzCardModule } from 'ng-zorro-antd/card';
import { NzToolTipModule } from 'ng-zorro-antd/tooltip';
import { ApiService } from '../../../core/services/api.service';
import { AuthService } from '../../../core/services/auth.service';
import { Client, ClientType, getClientTypeIcon } from '../../../core/models';
import { RelativeTimePipe } from '../../../shared/pipes/relative-time.pipe';
@Component({
selector: 'app-client-list',
standalone: true,
imports: [
CommonModule,
NzTableModule,
NzButtonModule,
NzIconModule,
NzTagModule,
NzEmptyModule,
NzCardModule,
NzToolTipModule,
RelativeTimePipe,
],
templateUrl: './client-list.component.html',
styleUrl: './client-list.component.scss'
})
export class ClientListComponent implements OnInit {
private apiService = inject(ApiService);
private authService = inject(AuthService);
clients = signal<Client[]>([]);
loading = signal(false);
ngOnInit(): void {
this.loadClients();
}
loadClients(): void {
const userId = this.authService.getUserId();
if (!userId) return;
this.loading.set(true);
this.apiService.getClients(userId).subscribe({
next: (response) => {
this.clients.set(response.clients);
this.loading.set(false);
},
error: () => {
this.loading.set(false);
}
});
}
getClientIcon(type: ClientType): string {
return getClientTypeIcon(type);
}
getClientTypeLabel(type: ClientType): string {
switch (type) {
case 'ANDROID': return 'Android';
case 'IOS': return 'iOS';
case 'MACOS': return 'macOS';
case 'WINDOWS': return 'Windows';
case 'LINUX': return 'Linux';
default: return type;
}
}
}