Migrated from design-system-swarm with fresh git history.
Old project history preserved in /home/overbits/apps/design-system-swarm
Core components:
- MCP Server (Python FastAPI with mcp 1.23.1)
- Claude Plugin (agents, commands, skills, strategies, hooks, core)
- DSS Backend (dss-mvp1 - token translation, Figma sync)
- Admin UI (Node.js/React)
- Server (Node.js/Express)
- Storybook integration (dss-mvp1/.storybook)
Self-contained configuration:
- All paths relative or use DSS_BASE_PATH=/home/overbits/dss
- PYTHONPATH configured for dss-mvp1 and dss-claude-plugin
- .env file with all configuration
- Claude plugin uses ${CLAUDE_PLUGIN_ROOT} for portability
Migration completed: $(date)
🤖 Clean migration with full functionality preserved
171 lines
5.3 KiB
JavaScript
171 lines
5.3 KiB
JavaScript
/**
|
|
* 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) => `<span style="font-family: monospace; font-size: 11px; font-weight: 600;">${ComponentHelpers.escapeHtml(comp.name)}</span>`
|
|
},
|
|
{
|
|
key: 'path',
|
|
label: 'File Path',
|
|
render: (comp) => `<span style="font-family: monospace; font-size: 10px; color: var(--vscode-text-dim);">${ComponentHelpers.escapeHtml(comp.path)}</span>`
|
|
},
|
|
{
|
|
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 `
|
|
<div style="display: flex; align-items: center; gap: 8px;">
|
|
<div style="flex: 1; height: 6px; background: var(--vscode-bg); border-radius: 3px; overflow: hidden;">
|
|
<div style="height: 100%; width: ${percentage}%; background: ${color};"></div>
|
|
</div>
|
|
<span style="font-size: 10px; font-weight: 600; min-width: 35px;">${percentage}%</span>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
],
|
|
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 = `
|
|
<option value="">All Types</option>
|
|
${types.map(type => `<option value="${type}">${type}</option>`).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 = `
|
|
<div id="component-list-container" style="height: 100%; overflow: hidden;">
|
|
${ComponentHelpers.renderLoading('Loading components...')}
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
|
|
customElements.define('ds-component-list', DSComponentList);
|
|
|
|
export default DSComponentList;
|