update
This commit is contained in:
434
ts_web/elements/sz-demo-view-services.ts
Normal file
434
ts_web/elements/sz-demo-view-services.ts
Normal file
@@ -0,0 +1,434 @@
|
||||
import {
|
||||
DeesElement,
|
||||
customElement,
|
||||
html,
|
||||
css,
|
||||
cssManager,
|
||||
property,
|
||||
state,
|
||||
type TemplateResult,
|
||||
} from '@design.estate/dees-element';
|
||||
import type { DeesAppui } from '@design.estate/dees-catalog';
|
||||
import './index.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'sz-demo-view-services': SzDemoViewServices;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('sz-demo-view-services')
|
||||
export class SzDemoViewServices extends DeesElement {
|
||||
private appui: DeesAppui | null = null;
|
||||
|
||||
@state()
|
||||
private accessor currentView: 'list' | 'create' | 'detail' | 'backups' | 'platform-detail' = 'list';
|
||||
|
||||
@state()
|
||||
private accessor selectedService: any = null;
|
||||
|
||||
@state()
|
||||
private accessor selectedPlatformService: any = null;
|
||||
|
||||
private demoServices = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'nginx-proxy',
|
||||
image: 'nginx:latest',
|
||||
status: 'running',
|
||||
cpu: '2.5%',
|
||||
memory: '256 MB',
|
||||
ports: '80, 443',
|
||||
uptime: '5d 12h',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'api-gateway',
|
||||
image: 'api-gateway:v2.1.0',
|
||||
status: 'running',
|
||||
cpu: '8.2%',
|
||||
memory: '512 MB',
|
||||
ports: '3000',
|
||||
uptime: '3d 8h',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'worker-service',
|
||||
image: 'worker:latest',
|
||||
status: 'stopped',
|
||||
cpu: '0%',
|
||||
memory: '0 MB',
|
||||
ports: '-',
|
||||
uptime: '-',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
name: 'redis-cache',
|
||||
image: 'redis:7-alpine',
|
||||
status: 'running',
|
||||
cpu: '1.2%',
|
||||
memory: '128 MB',
|
||||
ports: '6379',
|
||||
uptime: '10d 4h',
|
||||
},
|
||||
];
|
||||
|
||||
private demoPlatformService = {
|
||||
id: '1',
|
||||
name: 'MongoDB',
|
||||
type: 'mongodb' as const,
|
||||
status: 'running' as const,
|
||||
version: '7.0.4',
|
||||
host: 'localhost',
|
||||
port: 27017,
|
||||
credentials: { username: 'admin', password: '••••••••' },
|
||||
config: { replicaSet: 'rs0', authEnabled: true, journaling: true },
|
||||
metrics: { cpu: 12, memory: 45, storage: 23, connections: 8 },
|
||||
};
|
||||
|
||||
private demoPlatformLogs = [
|
||||
{ timestamp: '2024-01-20 14:30:22', level: 'info' as const, message: 'Connection accepted from 127.0.0.1:54321' },
|
||||
{ timestamp: '2024-01-20 14:30:20', level: 'info' as const, message: 'Index build completed on collection users' },
|
||||
{ timestamp: '2024-01-20 14:30:15', level: 'warn' as const, message: 'Slow query detected: 1.2s on collection orders' },
|
||||
{ timestamp: '2024-01-20 14:30:10', level: 'info' as const, message: 'Checkpoint complete' },
|
||||
];
|
||||
|
||||
private demoBackupSchedules = [
|
||||
{ id: '1', scope: 'All Services', retention: 'D:7, W:4, M:12', schedule: '0 2 * * *', lastRun: '1/2/2026, 2:00:03 AM', nextRun: '1/3/2026, 2:00:00 AM', status: 'active' as const },
|
||||
];
|
||||
|
||||
private demoBackups = [
|
||||
{ id: '1', service: 'nginx-proxy', createdAt: '1/2/2026, 2:00:03 AM', size: '22.0 MB', includes: ['Image'] },
|
||||
{ id: '2', service: 'api-gateway', createdAt: '1/2/2026, 2:00:02 AM', size: '156.5 MB', includes: ['Image', 'Volumes'] },
|
||||
{ id: '3', service: 'redis-cache', createdAt: '1/2/2026, 2:00:00 AM', size: '48.0 MB', includes: ['Image', 'Data'] },
|
||||
];
|
||||
|
||||
public static styles = [
|
||||
cssManager.defaultStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
padding: 24px;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.header-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: ${cssManager.bdTheme('#18181b', '#fafafa')};
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.page-subtitle {
|
||||
font-size: 14px;
|
||||
color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 8px 14px;
|
||||
background: ${cssManager.bdTheme('#18181b', '#fafafa')};
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: ${cssManager.bdTheme('#fafafa', '#18181b')};
|
||||
cursor: pointer;
|
||||
transition: all 200ms ease;
|
||||
}
|
||||
|
||||
.action-button:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.action-button.secondary {
|
||||
background: ${cssManager.bdTheme('#ffffff', '#09090b')};
|
||||
border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')};
|
||||
color: ${cssManager.bdTheme('#18181b', '#fafafa')};
|
||||
}
|
||||
|
||||
.action-button.secondary:hover {
|
||||
background: ${cssManager.bdTheme('#f4f4f5', '#18181b')};
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
margin-bottom: 24px;
|
||||
border-bottom: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')};
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.tab {
|
||||
padding: 10px 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
|
||||
background: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
transition: color 200ms ease;
|
||||
}
|
||||
|
||||
.tab:hover {
|
||||
color: ${cssManager.bdTheme('#18181b', '#fafafa')};
|
||||
}
|
||||
|
||||
.tab.active {
|
||||
color: ${cssManager.bdTheme('#18181b', '#fafafa')};
|
||||
}
|
||||
|
||||
.tab.active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -1px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: ${cssManager.bdTheme('#18181b', '#fafafa')};
|
||||
border-radius: 1px 1px 0 0;
|
||||
}
|
||||
|
||||
.back-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 12px;
|
||||
background: transparent;
|
||||
border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')};
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
|
||||
cursor: pointer;
|
||||
margin-bottom: 16px;
|
||||
transition: all 200ms ease;
|
||||
}
|
||||
|
||||
.back-button:hover {
|
||||
background: ${cssManager.bdTheme('#f4f4f5', '#18181b')};
|
||||
color: ${cssManager.bdTheme('#18181b', '#fafafa')};
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
public render(): TemplateResult {
|
||||
return html`
|
||||
${this.currentView === 'list' ? this.renderListView() : ''}
|
||||
${this.currentView === 'create' ? this.renderCreateView() : ''}
|
||||
${this.currentView === 'detail' ? this.renderDetailView() : ''}
|
||||
${this.currentView === 'backups' ? this.renderBackupsView() : ''}
|
||||
${this.currentView === 'platform-detail' ? this.renderPlatformDetailView() : ''}
|
||||
`;
|
||||
}
|
||||
|
||||
private renderListView(): TemplateResult {
|
||||
return html`
|
||||
<div class="page-header">
|
||||
<div class="header-info">
|
||||
<h1 class="page-title">Services</h1>
|
||||
<p class="page-subtitle">Manage your Docker containers and platform services</p>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<button class="action-button secondary" @click=${() => this.currentView = 'backups'}>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
|
||||
<polyline points="17 8 12 3 7 8"/>
|
||||
<line x1="12" y1="3" x2="12" y2="15"/>
|
||||
</svg>
|
||||
Backups
|
||||
</button>
|
||||
<button class="action-button" @click=${() => this.currentView = 'create'}>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<line x1="12" y1="5" x2="12" y2="19"/>
|
||||
<line x1="5" y1="12" x2="19" y2="12"/>
|
||||
</svg>
|
||||
Deploy Service
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tabs">
|
||||
<button class="tab active">Docker Services</button>
|
||||
<button class="tab" @click=${() => { this.selectedPlatformService = this.demoPlatformService; this.currentView = 'platform-detail'; }}>Platform Services</button>
|
||||
</div>
|
||||
|
||||
<sz-services-list-view
|
||||
.services=${this.demoServices}
|
||||
@view-service=${(e: CustomEvent) => { this.selectedService = e.detail; this.currentView = 'detail'; }}
|
||||
@start-service=${(e: CustomEvent) => console.log('Start service:', e.detail)}
|
||||
@stop-service=${(e: CustomEvent) => console.log('Stop service:', e.detail)}
|
||||
@restart-service=${(e: CustomEvent) => console.log('Restart service:', e.detail)}
|
||||
@delete-service=${(e: CustomEvent) => console.log('Delete service:', e.detail)}
|
||||
></sz-services-list-view>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderCreateView(): TemplateResult {
|
||||
return html`
|
||||
<button class="back-button" @click=${() => this.currentView = 'list'}>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
Back to Services
|
||||
</button>
|
||||
|
||||
<sz-service-create-view
|
||||
.registries=${[
|
||||
{ id: '1', name: 'Onebox Registry', url: 'registry.onebox.local' },
|
||||
{ id: '2', name: 'Docker Hub', url: 'docker.io' },
|
||||
]}
|
||||
@create-service=${(e: CustomEvent) => { console.log('Create service:', e.detail); this.currentView = 'list'; }}
|
||||
@cancel=${() => this.currentView = 'list'}
|
||||
></sz-service-create-view>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderDetailView(): TemplateResult {
|
||||
return html`
|
||||
<button class="back-button" @click=${() => this.currentView = 'list'}>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
Back to Services
|
||||
</button>
|
||||
|
||||
<sz-service-detail-view
|
||||
.service=${{
|
||||
id: this.selectedService?.id || '1',
|
||||
name: this.selectedService?.name || 'nginx-proxy',
|
||||
image: this.selectedService?.image || 'nginx:latest',
|
||||
status: this.selectedService?.status || 'running',
|
||||
ports: [{ host: '80', container: '80' }, { host: '443', container: '443' }],
|
||||
envVars: [
|
||||
{ key: 'NGINX_HOST', value: 'localhost' },
|
||||
{ key: 'NGINX_PORT', value: '80' },
|
||||
],
|
||||
volumes: [
|
||||
{ host: '/data/nginx/conf', container: '/etc/nginx/conf.d' },
|
||||
],
|
||||
createdAt: '2024-01-15 10:30:00',
|
||||
restartPolicy: 'always',
|
||||
}}
|
||||
.logs=${[
|
||||
{ timestamp: '2024-01-20 14:30:22', level: 'info', message: '127.0.0.1 - - [20/Jan/2024:14:30:22 +0000] "GET / HTTP/1.1" 200 612' },
|
||||
{ timestamp: '2024-01-20 14:30:21', level: 'info', message: '127.0.0.1 - - [20/Jan/2024:14:30:21 +0000] "GET /api/health HTTP/1.1" 200 15' },
|
||||
{ timestamp: '2024-01-20 14:30:20', level: 'warn', message: 'upstream timed out (110: Connection timed out)' },
|
||||
{ timestamp: '2024-01-20 14:30:19', level: 'info', message: '127.0.0.1 - - [20/Jan/2024:14:30:19 +0000] "POST /api/data HTTP/1.1" 201 89' },
|
||||
]}
|
||||
@start=${() => console.log('Start')}
|
||||
@stop=${() => console.log('Stop')}
|
||||
@restart=${() => console.log('Restart')}
|
||||
></sz-service-detail-view>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderBackupsView(): TemplateResult {
|
||||
return html`
|
||||
<button class="back-button" @click=${() => this.currentView = 'list'}>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
Back to Services
|
||||
</button>
|
||||
|
||||
<div class="page-header">
|
||||
<div class="header-info">
|
||||
<h1 class="page-title">Backups</h1>
|
||||
<p class="page-subtitle">Manage backup schedules and restore points</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<sz-services-backups-view
|
||||
.schedules=${this.demoBackupSchedules}
|
||||
.backups=${this.demoBackups}
|
||||
@create-schedule=${() => console.log('Create schedule')}
|
||||
@run-now=${(e: CustomEvent) => console.log('Run now:', e.detail)}
|
||||
@download=${(e: CustomEvent) => console.log('Download:', e.detail)}
|
||||
></sz-services-backups-view>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderPlatformDetailView(): TemplateResult {
|
||||
return html`
|
||||
<button class="back-button" @click=${() => this.currentView = 'list'}>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
Back to Services
|
||||
</button>
|
||||
|
||||
<sz-platform-service-detail-view
|
||||
.service=${this.demoPlatformService}
|
||||
.logs=${this.demoPlatformLogs}
|
||||
@start=${() => console.log('Start')}
|
||||
@stop=${() => console.log('Stop')}
|
||||
@restart=${() => console.log('Restart')}
|
||||
></sz-platform-service-detail-view>
|
||||
`;
|
||||
}
|
||||
|
||||
async onActivate(context: { appui: DeesAppui; viewId: string }) {
|
||||
this.appui = context.appui;
|
||||
|
||||
// Set up content tabs
|
||||
this.appui.setContentTabs([
|
||||
{ key: 'Docker Services', action: () => { this.currentView = 'list'; this.updateSecondaryMenu(); } },
|
||||
{ key: 'Platform Services', action: () => { this.currentView = 'platform-detail'; this.updateSecondaryMenu(); } },
|
||||
{ key: 'Backups', action: () => { this.currentView = 'backups'; this.updateSecondaryMenu(); } },
|
||||
]);
|
||||
|
||||
this.updateSecondaryMenu();
|
||||
}
|
||||
|
||||
private updateSecondaryMenu() {
|
||||
if (!this.appui) return;
|
||||
|
||||
this.appui.setSecondaryMenu({
|
||||
heading: 'Services',
|
||||
groups: [
|
||||
{
|
||||
name: 'Actions',
|
||||
items: [
|
||||
{ type: 'action', key: 'Deploy Service', iconName: 'lucide:Plus', action: () => { this.currentView = 'create'; } },
|
||||
{ type: 'action', key: 'Refresh', iconName: 'lucide:RefreshCw', action: () => { console.log('Refresh'); } },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Quick Filters',
|
||||
items: [
|
||||
{ key: 'Running', iconName: 'lucide:Play', badge: '3', badgeVariant: 'success', action: () => { console.log('Filter running'); } },
|
||||
{ key: 'Stopped', iconName: 'lucide:Square', badge: '1', action: () => { console.log('Filter stopped'); } },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
onDeactivate() {
|
||||
// Cleanup if needed
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user