import { DeesElement, customElement, html, css, cssManager, property, type TemplateResult, } from '@design.estate/dees-element'; declare global { interface HTMLElementTagNameMap { 'sz-platform-service-detail-view': SzPlatformServiceDetailView; } } export interface IPlatformServiceDetail { id: string; name: string; type: 'mongodb' | 'minio' | 'clickhouse' | 'redis'; status: 'running' | 'stopped' | 'error'; version: string; host: string; port: number; credentials?: { username?: string; password?: string; accessKey?: string; secretKey?: string; }; config: Record; metrics?: { cpu: number; memory: number; storage: number; connections?: number; }; } export interface IPlatformLogEntry { timestamp: string; level: 'info' | 'warn' | 'error' | 'debug'; message: string; } @customElement('sz-platform-service-detail-view') export class SzPlatformServiceDetailView extends DeesElement { public static demo = () => html`
`; public static demoGroups = ['Platform']; @property({ type: Object }) public accessor service: IPlatformServiceDetail | null = null; @property({ type: Array }) public accessor logs: IPlatformLogEntry[] = []; @property({ type: Boolean }) public accessor actionLoading: boolean = false; public static styles = [ cssManager.defaultStyles, css` :host { display: block; } .header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 24px; } .header-info { display: flex; align-items: center; gap: 16px; } .service-icon { width: 56px; height: 56px; background: ${cssManager.bdTheme('#f4f4f5', '#27272a')}; border-radius: 12px; display: flex; align-items: center; justify-content: center; } .service-icon svg { width: 28px; height: 28px; color: ${cssManager.bdTheme('#18181b', '#fafafa')}; } .service-details { display: flex; flex-direction: column; gap: 4px; } .service-name { font-size: 22px; font-weight: 600; color: ${cssManager.bdTheme('#18181b', '#fafafa')}; } .service-meta { display: flex; align-items: center; gap: 12px; font-size: 14px; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; } .status-badge { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border-radius: 9999px; font-size: 13px; font-weight: 500; } .status-badge.running { background: ${cssManager.bdTheme('#dcfce7', 'rgba(34, 197, 94, 0.2)')}; color: ${cssManager.bdTheme('#16a34a', '#22c55e')}; } .status-badge.stopped { background: ${cssManager.bdTheme('#f4f4f5', '#27272a')}; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; } .status-badge.error { background: ${cssManager.bdTheme('#fee2e2', 'rgba(239, 68, 68, 0.2)')}; color: ${cssManager.bdTheme('#dc2626', '#ef4444')}; } .status-dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; } .header-actions { display: flex; gap: 8px; } .action-button { display: inline-flex; align-items: center; gap: 6px; padding: 8px 14px; background: ${cssManager.bdTheme('#ffffff', '#09090b')}; border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')}; border-radius: 6px; font-size: 13px; font-weight: 500; color: ${cssManager.bdTheme('#18181b', '#fafafa')}; cursor: pointer; transition: all 200ms ease; } .action-button:hover:not(:disabled) { background: ${cssManager.bdTheme('#f4f4f5', '#18181b')}; } .action-button:disabled { opacity: 0.6; cursor: not-allowed; } .action-button svg { width: 14px; height: 14px; } .action-button.danger { color: ${cssManager.bdTheme('#dc2626', '#ef4444')}; border-color: ${cssManager.bdTheme('#fee2e2', 'rgba(239, 68, 68, 0.3)')}; } .action-button.danger:hover:not(:disabled) { background: ${cssManager.bdTheme('#fee2e2', 'rgba(239, 68, 68, 0.2)')}; } .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px; } @media (max-width: 768px) { .grid { grid-template-columns: 1fr; } } .section { background: ${cssManager.bdTheme('#ffffff', '#09090b')}; border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')}; border-radius: 8px; overflow: hidden; } .section.full-width { grid-column: 1 / -1; } .section-header { display: flex; justify-content: space-between; align-items: center; padding: 14px 16px; border-bottom: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')}; background: ${cssManager.bdTheme('#f4f4f5', '#18181b')}; } .section-title { font-size: 14px; font-weight: 600; color: ${cssManager.bdTheme('#18181b', '#fafafa')}; display: flex; align-items: center; gap: 8px; } .section-title svg { width: 16px; height: 16px; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; } .section-content { padding: 16px; } .info-row { display: flex; justify-content: space-between; align-items: center; padding: 10px 0; border-bottom: 1px solid ${cssManager.bdTheme('#f4f4f5', '#27272a')}; } .info-row:last-child { border-bottom: none; } .info-label { font-size: 13px; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; } .info-value { font-size: 13px; font-weight: 500; color: ${cssManager.bdTheme('#18181b', '#fafafa')}; font-family: monospace; display: flex; align-items: center; gap: 8px; } .copy-button { padding: 4px; background: transparent; border: none; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; cursor: pointer; border-radius: 4px; transition: all 200ms ease; } .copy-button:hover { background: ${cssManager.bdTheme('#f4f4f5', '#27272a')}; color: ${cssManager.bdTheme('#18181b', '#fafafa')}; } .metrics-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; } @media (max-width: 600px) { .metrics-grid { grid-template-columns: repeat(2, 1fr); } } .metric-card { text-align: center; padding: 12px; background: ${cssManager.bdTheme('#f4f4f5', '#18181b')}; border-radius: 6px; } .metric-value { font-size: 20px; font-weight: 600; color: ${cssManager.bdTheme('#18181b', '#fafafa')}; } .metric-label { font-size: 12px; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; margin-top: 2px; } .progress-bar { height: 4px; background: ${cssManager.bdTheme('#e4e4e7', '#27272a')}; border-radius: 2px; margin-top: 8px; overflow: hidden; } .progress-fill { height: 100%; border-radius: 2px; transition: width 300ms ease; } .progress-fill.low { background: ${cssManager.bdTheme('#22c55e', '#22c55e')}; } .progress-fill.medium { background: ${cssManager.bdTheme('#eab308', '#eab308')}; } .progress-fill.high { background: ${cssManager.bdTheme('#ef4444', '#ef4444')}; } .log-container { background: ${cssManager.bdTheme('#18181b', '#09090b')}; border-radius: 6px; padding: 12px; max-height: 300px; overflow-y: auto; font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace; font-size: 12px; line-height: 1.6; } .log-entry { display: flex; gap: 12px; padding: 4px 0; } .log-timestamp { color: #71717a; flex-shrink: 0; } .log-level { flex-shrink: 0; width: 50px; text-transform: uppercase; font-weight: 500; } .log-level.info { color: #60a5fa; } .log-level.warn { color: #fbbf24; } .log-level.error { color: #f87171; } .log-level.debug { color: #a1a1aa; } .log-message { color: #fafafa; word-break: break-word; } .config-item { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid ${cssManager.bdTheme('#f4f4f5', '#27272a')}; } .config-item:last-child { border-bottom: none; } .config-key { font-size: 13px; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; } .config-value { font-size: 13px; font-weight: 500; color: ${cssManager.bdTheme('#18181b', '#fafafa')}; } .config-value.true { color: ${cssManager.bdTheme('#16a34a', '#22c55e')}; } .config-value.false { color: ${cssManager.bdTheme('#dc2626', '#ef4444')}; } .empty-state { text-align: center; padding: 40px 20px; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; } `, ]; public render(): TemplateResult { if (!this.service) { return html`
No service selected
`; } return html`
${this.renderServiceIcon()}
${this.service.name}
${this.service.status.charAt(0).toUpperCase() + this.service.status.slice(1)} Version ${this.service.version}
${this.service.status === 'running' ? html` ` : html` `}
Connection
Host ${this.service.host}
Port ${this.service.port}
${this.service.credentials?.username ? html`
Username ${this.service.credentials.username}
Password ••••••••
` : ''} ${this.service.credentials?.accessKey ? html`
Access Key ${this.service.credentials.accessKey}
Secret Key ••••••••
` : ''}
Configuration
${Object.entries(this.service.config).map(([key, value]) => html`
${this.formatConfigKey(key)} ${this.formatConfigValue(value)}
`)}
${this.service.metrics ? html`
Resource Usage
${this.service.metrics.cpu}%
CPU
${this.service.metrics.memory}%
Memory
${this.service.metrics.storage}%
Storage
${this.service.metrics.connections !== undefined ? html`
${this.service.metrics.connections}
Connections
` : ''}
` : ''}
Logs
${this.logs.length > 0 ? this.logs.map(log => html`
${log.timestamp} ${log.level} ${log.message}
`) : html`
No logs available
`}
`; } private renderServiceIcon(): TemplateResult { const type = this.service?.type; switch (type) { case 'mongodb': return html``; case 'minio': return html``; case 'clickhouse': return html``; case 'redis': return html``; default: return html``; } } private getProgressClass(value: number): string { if (value < 50) return 'low'; if (value < 80) return 'medium'; return 'high'; } private formatConfigKey(key: string): string { return key.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase()); } private formatConfigValue(value: any): string { if (typeof value === 'boolean') return value ? 'Enabled' : 'Disabled'; return String(value); } private copyToClipboard(text: string) { navigator.clipboard.writeText(text); this.dispatchEvent(new CustomEvent('copy', { detail: text, bubbles: true, composed: true })); } private handleStart() { this.dispatchEvent(new CustomEvent('start', { detail: this.service, bubbles: true, composed: true })); } private handleStop() { this.dispatchEvent(new CustomEvent('stop', { detail: this.service, bubbles: true, composed: true })); } private handleRestart() { this.dispatchEvent(new CustomEvent('restart', { detail: this.service, bubbles: true, composed: true })); } }