/** * ds-component-list.js * List view of all design system components * UX Team Tool #4 */ import { createListView, setupListHandlers } from '../../utils/tool-templates.js'; import { ComponentHelpers } from '../../utils/component-helpers.js'; import contextStore from '../../stores/context-store.js'; import toolBridge from '../../services/tool-bridge.js'; class DSComponentList extends HTMLElement { constructor() { super(); this.components = []; this.filteredComponents = []; this.isLoading = false; } async connectedCallback() { this.render(); await this.loadComponents(); } async loadComponents() { this.isLoading = true; const container = this.querySelector('#component-list-container'); if (container) { container.innerHTML = ComponentHelpers.renderLoading('Loading components...'); } try { const context = contextStore.getMCPContext(); if (!context.project_id) { throw new Error('No project selected'); } // Call component audit to get component list const result = await toolBridge.executeTool('dss_audit_components', { path: `/projects/${context.project_id}` }); this.components = result.components || []; this.filteredComponents = [...this.components]; this.renderComponentList(); } catch (error) { console.error('[DSComponentList] Failed to load components:', error); if (container) { container.innerHTML = ComponentHelpers.renderError('Failed to load components', error); } } finally { this.isLoading = false; } } renderComponentList() { const container = this.querySelector('#component-list-container'); if (!container) return; const config = { title: 'Design System Components', items: this.filteredComponents, columns: [ { key: 'name', label: 'Component', render: (comp) => `${ComponentHelpers.escapeHtml(comp.name)}` }, { key: 'path', label: 'File Path', render: (comp) => `${ComponentHelpers.escapeHtml(comp.path)}` }, { key: 'type', label: 'Type', render: (comp) => ComponentHelpers.createBadge(comp.type || 'react', 'info') }, { key: 'dsAdoption', label: 'DS Adoption', render: (comp) => { const percentage = comp.dsAdoption || 0; let color = '#f48771'; if (percentage >= 80) color = '#89d185'; else if (percentage >= 50) color = '#ffbf00'; return `
${percentage}%
`; } } ], actions: [ { label: 'Refresh', icon: '🔄', onClick: () => this.loadComponents() }, { label: 'Export Report', icon: '📥', onClick: () => this.exportReport() } ], onSearch: (query) => this.handleSearch(query), onFilter: (filterValue) => this.handleFilter(filterValue) }; container.innerHTML = createListView(config); setupListHandlers(container, config); // Update filter dropdown const filterSelect = container.querySelector('#filter-select'); if (filterSelect) { const types = [...new Set(this.components.map(c => c.type || 'react'))]; filterSelect.innerHTML = ` ${types.map(type => ``).join('')} `; } } handleSearch(query) { const lowerQuery = query.toLowerCase(); this.filteredComponents = this.components.filter(comp => comp.name.toLowerCase().includes(lowerQuery) || comp.path.toLowerCase().includes(lowerQuery) ); this.renderComponentList(); } handleFilter(filterValue) { if (!filterValue) { this.filteredComponents = [...this.components]; } else { this.filteredComponents = this.components.filter(comp => (comp.type || 'react') === filterValue); } this.renderComponentList(); } exportReport() { const data = JSON.stringify(this.components, null, 2); const blob = new Blob([data], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'component-audit.json'; a.click(); URL.revokeObjectURL(url); ComponentHelpers.showToast?.('Report exported', 'success'); } render() { this.innerHTML = `
${ComponentHelpers.renderLoading('Loading components...')}
`; } } customElements.define('ds-component-list', DSComponentList); export default DSComponentList;