import { DeesElement, customElement, html, css, cssManager, property, type TemplateResult, } from '@design.estate/dees-element'; declare global { interface HTMLElementTagNameMap { 'sz-services-backups-view': SzServicesBackupsView; } } export interface IBackupSchedule { id: string; scope: string; retention: string; schedule: string; lastRun?: string; nextRun?: string; status: 'active' | 'failed' | 'disabled'; error?: string; } export interface IBackup { id: string; service: string; createdAt: string; size: string; includes: string[]; } @customElement('sz-services-backups-view') export class SzServicesBackupsView extends DeesElement { public static demo = () => html`
`; public static demoGroups = ['Services']; @property({ type: Array }) public accessor schedules: IBackupSchedule[] = []; @property({ type: Array }) public accessor backups: IBackup[] = []; public static styles = [ cssManager.defaultStyles, css` :host { display: block; } dees-tile { display: block; margin-bottom: 24px; } .section-header { height: 36px; display: flex; align-items: center; padding: 0 16px; width: 100%; box-sizing: border-box; } .section-heading { flex: 1; display: flex; align-items: baseline; gap: 8px; min-width: 0; } .section-title { font-weight: 500; font-size: 13px; letter-spacing: -0.01em; color: var(--dees-color-text-secondary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .section-subtitle { font-size: 12px; color: var(--dees-color-text-muted); letter-spacing: -0.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .section-footer { display: flex; flex-direction: row; justify-content: flex-end; align-items: center; gap: 0; height: 36px; width: 100%; box-sizing: border-box; } .tile-button { padding: 0 16px; height: 100%; text-align: center; font-size: 12px; font-weight: 500; cursor: pointer; user-select: none; transition: all 0.15s ease; background: transparent; border: none; border-left: 1px solid var(--dees-color-border-subtle); color: var(--dees-color-text-muted); white-space: nowrap; display: flex; align-items: center; gap: 6px; } .tile-button:first-child { border-left: none; } .tile-button:hover { background: var(--dees-color-hover); color: var(--dees-color-text-primary); } .tile-button.primary { color: ${cssManager.bdTheme('hsl(217.2 91.2% 59.8%)', 'hsl(213.1 93.9% 67.8%)')}; font-weight: 600; } .tile-button.primary:hover { background: ${cssManager.bdTheme('hsl(217.2 91.2% 59.8% / 0.08)', 'hsl(213.1 93.9% 67.8% / 0.08)')}; color: ${cssManager.bdTheme('hsl(217.2 91.2% 50%)', 'hsl(213.1 93.9% 75%)')}; } .table-header { display: grid; gap: 16px; padding: 12px 16px; background: ${cssManager.bdTheme('#f4f4f5', '#18181b')}; border-bottom: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')}; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; } .schedules-header { grid-template-columns: 1fr 1fr 1fr 1.5fr 1.5fr 80px 120px; } .backups-header { grid-template-columns: 1.5fr 1.5fr 100px 1fr 120px; } .table-row { display: grid; gap: 16px; padding: 12px 16px; border-bottom: 1px solid ${cssManager.bdTheme('#f4f4f5', '#27272a')}; font-size: 14px; color: ${cssManager.bdTheme('#18181b', '#fafafa')}; align-items: center; } .schedules-row { grid-template-columns: 1fr 1fr 1fr 1.5fr 1.5fr 80px 120px; } .backups-row { grid-template-columns: 1.5fr 1.5fr 100px 1fr 120px; } .table-row:last-child { border-bottom: none; } .table-row:hover { background: ${cssManager.bdTheme('#f4f4f5', '#18181b')}; } .status-badge { display: inline-flex; align-items: center; padding: 2px 8px; border-radius: 9999px; font-size: 12px; font-weight: 500; } .status-badge.active { background: ${cssManager.bdTheme('#dcfce7', 'rgba(34, 197, 94, 0.2)')}; color: ${cssManager.bdTheme('#16a34a', '#22c55e')}; } .status-badge.failed { background: ${cssManager.bdTheme('#fee2e2', 'rgba(239, 68, 68, 0.2)')}; color: ${cssManager.bdTheme('#dc2626', '#ef4444')}; } .status-badge.disabled { background: ${cssManager.bdTheme('#f4f4f5', '#27272a')}; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; } .meta-text { font-size: 13px; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; } .includes-list { display: flex; flex-wrap: wrap; gap: 4px; } .include-badge { padding: 2px 8px; background: ${cssManager.bdTheme('#dbeafe', 'rgba(59, 130, 246, 0.2)')}; color: ${cssManager.bdTheme('#2563eb', '#60a5fa')}; border-radius: 4px; font-size: 11px; font-weight: 500; } .row-actions { display: flex; gap: 4px; } .icon-button { padding: 6px; background: transparent; border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')}; border-radius: 4px; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; cursor: pointer; transition: all 200ms ease; } .icon-button:hover { background: ${cssManager.bdTheme('#f4f4f5', '#18181b')}; color: ${cssManager.bdTheme('#18181b', '#fafafa')}; } .icon-button.danger:hover { background: ${cssManager.bdTheme('#fee2e2', 'rgba(239, 68, 68, 0.2)')}; color: ${cssManager.bdTheme('#dc2626', '#ef4444')}; border-color: ${cssManager.bdTheme('#fee2e2', 'rgba(239, 68, 68, 0.3)')}; } `, ]; public render(): TemplateResult { return html`
Backup Schedules Configure automated backup schedules for your services
Scope Retention Schedule Last Run Next Run Status Actions
${this.schedules.map(schedule => html`
${schedule.scope} ${schedule.retention} ${schedule.schedule} ${schedule.lastRun || '-'} ${schedule.nextRun || '-'} ${schedule.status === 'active' ? 'Active' : schedule.status === 'failed' ? 'Failed' : 'Disabled'}
`)}
All Backups Browse and manage all backups across services
Service Created Size Includes Actions
${this.backups.map(backup => html`
${backup.service} ${backup.createdAt} ${backup.size} ${backup.includes.map(inc => html`${inc}`)}
`)}
`; } private handleImport() { this.dispatchEvent(new CustomEvent('import', { bubbles: true, composed: true })); } private handleCreateSchedule() { this.dispatchEvent(new CustomEvent('create-schedule', { bubbles: true, composed: true })); } private handleRunNow(schedule: IBackupSchedule) { this.dispatchEvent(new CustomEvent('run-now', { detail: schedule, bubbles: true, composed: true })); } private handleToggle(schedule: IBackupSchedule) { this.dispatchEvent(new CustomEvent('toggle-schedule', { detail: schedule, bubbles: true, composed: true })); } private handleDeleteSchedule(schedule: IBackupSchedule) { this.dispatchEvent(new CustomEvent('delete-schedule', { detail: schedule, bubbles: true, composed: true })); } private handleDownload(backup: IBackup) { this.dispatchEvent(new CustomEvent('download', { detail: backup, bubbles: true, composed: true })); } private handleDeleteBackup(backup: IBackup) { this.dispatchEvent(new CustomEvent('delete-backup', { detail: backup, bubbles: true, composed: true })); } }