import { DeesElement, customElement, html, css, property, state, cssManager } from '@design.estate/dees-element'; import type { TaskManager, ITaskMetadata, IScheduledTaskInfo } from '../ts/index.js'; /** * A web component that displays TaskManager tasks with progress visualization */ @customElement('taskbuffer-dashboard') export class TaskbufferDashboard extends DeesElement { // Properties @property({ type: Object }) public taskManager: TaskManager | null = null; @property({ type: Number }) public refreshInterval: number = 1000; // milliseconds // Internal state @state() private tasks: ITaskMetadata[] = []; @state() private scheduledTasks: IScheduledTaskInfo[] = []; @state() private isRunning: boolean = false; private refreshTimer: any; // Styles static styles = [ cssManager.defaultStyles, css` :host { display: block; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } .dashboard-container { padding: 24px; background: ${cssManager.bdTheme('#ffffff', '#0a0a0a')}; min-height: 100vh; } .dashboard-header { margin-bottom: 32px; } .dashboard-title { font-size: 28px; font-weight: 700; color: ${cssManager.bdTheme('#09090b', '#fafafa')}; margin-bottom: 8px; display: flex; align-items: center; gap: 12px; } .status-indicator { width: 12px; height: 12px; border-radius: 50%; background: ${cssManager.bdTheme('#22c55e', '#22c55e')}; animation: pulse 2s infinite; } .status-indicator.inactive { background: ${cssManager.bdTheme('#94a3b8', '#475569')}; animation: none; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } .dashboard-subtitle { font-size: 14px; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; } .tasks-section { margin-bottom: 48px; } .section-title { font-size: 20px; font-weight: 600; color: ${cssManager.bdTheme('#18181b', '#e4e4e7')}; margin-bottom: 16px; } .tasks-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(350px, 1fr)); gap: 16px; } .task-card { background: ${cssManager.bdTheme('#f8fafc', '#18181b')}; border: 1px solid ${cssManager.bdTheme('#e2e8f0', '#27272a')}; border-radius: 12px; padding: 20px; transition: all 0.2s ease; } .task-card:hover { transform: translateY(-2px); box-shadow: 0 4px 12px ${cssManager.bdTheme('rgba(0,0,0,0.1)', 'rgba(0,0,0,0.3)')}; } .task-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 12px; } .task-name { font-size: 16px; font-weight: 600; color: ${cssManager.bdTheme('#0f172a', '#f1f5f9')}; } .task-status { display: inline-block; padding: 4px 8px; border-radius: 6px; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; } .task-status.idle { background: ${cssManager.bdTheme('#f1f5f9', '#27272a')}; color: ${cssManager.bdTheme('#64748b', '#94a3b8')}; } .task-status.running { background: ${cssManager.bdTheme('#dbeafe', '#1e3a8a')}; color: ${cssManager.bdTheme('#1e40af', '#93c5fd')}; } .task-status.completed { background: ${cssManager.bdTheme('#dcfce7', '#14532d')}; color: ${cssManager.bdTheme('#15803d', '#86efac')}; } .task-status.failed { background: ${cssManager.bdTheme('#fee2e2', '#7f1d1d')}; color: ${cssManager.bdTheme('#dc2626', '#fca5a5')}; } .task-info { display: flex; gap: 16px; margin-bottom: 16px; font-size: 13px; color: ${cssManager.bdTheme('#64748b', '#94a3b8')}; } .task-info-item { display: flex; align-items: center; gap: 4px; } .task-info-icon { width: 14px; height: 14px; opacity: 0.7; } .progress-container { margin-bottom: 16px; } .progress-label { display: flex; justify-content: space-between; margin-bottom: 8px; font-size: 13px; color: ${cssManager.bdTheme('#475569', '#cbd5e1')}; } .progress-bar { height: 8px; background: ${cssManager.bdTheme('#e2e8f0', '#27272a')}; border-radius: 4px; overflow: hidden; position: relative; } .progress-fill { height: 100%; background: linear-gradient(90deg, #3b82f6, #6366f1); border-radius: 4px; transition: width 0.3s ease; position: relative; overflow: hidden; } .progress-fill::after { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: linear-gradient( 90deg, transparent, rgba(255, 255, 255, 0.3), transparent ); animation: shimmer 2s infinite; } @keyframes shimmer { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } } .steps-container { border-top: 1px solid ${cssManager.bdTheme('#e2e8f0', '#27272a')}; padding-top: 12px; } .steps-title { font-size: 12px; font-weight: 600; color: ${cssManager.bdTheme('#64748b', '#94a3b8')}; margin-bottom: 8px; text-transform: uppercase; letter-spacing: 0.5px; } .step-item { display: flex; align-items: center; gap: 8px; padding: 6px 0; font-size: 13px; } .step-indicator { width: 20px; height: 20px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 600; flex-shrink: 0; } .step-indicator.pending { background: ${cssManager.bdTheme('#f1f5f9', '#27272a')}; color: ${cssManager.bdTheme('#94a3b8', '#64748b')}; border: 2px solid ${cssManager.bdTheme('#cbd5e1', '#3f3f46')}; } .step-indicator.active { background: linear-gradient(135deg, #3b82f6, #6366f1); color: white; animation: pulse 1.5s infinite; } .step-indicator.completed { background: ${cssManager.bdTheme('#22c55e', '#22c55e')}; color: white; } .step-details { flex: 1; } .step-name { font-weight: 500; color: ${cssManager.bdTheme('#1e293b', '#e2e8f0')}; } .step-description { font-size: 11px; color: ${cssManager.bdTheme('#64748b', '#94a3b8')}; margin-top: 2px; } .step-percentage { font-size: 11px; font-weight: 600; color: ${cssManager.bdTheme('#94a3b8', '#64748b')}; } .empty-state { text-align: center; padding: 48px; color: ${cssManager.bdTheme('#94a3b8', '#64748b')}; } .empty-state-icon { width: 64px; height: 64px; margin: 0 auto 16px; opacity: 0.3; } .empty-state-text { font-size: 16px; margin-bottom: 8px; } .empty-state-subtext { font-size: 14px; color: ${cssManager.bdTheme('#cbd5e1', '#475569')}; } .scheduled-section { margin-top: 32px; } .schedule-info { display: flex; align-items: center; gap: 8px; margin-top: 8px; font-size: 12px; color: ${cssManager.bdTheme('#64748b', '#94a3b8')}; } .schedule-icon { width: 14px; height: 14px; } `, ]; // Lifecycle async connectedCallback() { await super.connectedCallback(); this.startRefreshing(); } async disconnectedCallback() { await super.disconnectedCallback(); this.stopRefreshing(); } // Methods private startRefreshing() { if (this.refreshTimer) { clearInterval(this.refreshTimer); } this.updateData(); this.refreshTimer = setInterval(() => { this.updateData(); }, this.refreshInterval); this.isRunning = true; } private stopRefreshing() { if (this.refreshTimer) { clearInterval(this.refreshTimer); this.refreshTimer = null; } this.isRunning = false; } private updateData() { if (!this.taskManager) { this.tasks = []; this.scheduledTasks = []; return; } this.tasks = this.taskManager.getAllTasksMetadata(); this.scheduledTasks = this.taskManager.getScheduledTasks(); } private formatNextRun(date: Date): string { const now = new Date(); const diff = date.getTime() - now.getTime(); if (diff < 0) return 'Past due'; if (diff < 60000) return 'Less than a minute'; if (diff < 3600000) return `${Math.floor(diff / 60000)} minutes`; if (diff < 86400000) return `${Math.floor(diff / 3600000)} hours`; return `${Math.floor(diff / 86400000)} days`; } private formatDuration(ms?: number): string { if (!ms) return '-'; if (ms < 1000) return `${ms}ms`; if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`; return `${(ms / 60000).toFixed(1)}m`; } // Render render() { return html`