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
460 lines
15 KiB
JavaScript
460 lines
15 KiB
JavaScript
/**
|
||
* Team-Specific Dashboard Templates
|
||
*
|
||
* Each team (UI, UX, QA) gets a tailored dashboard with relevant metrics and actions
|
||
*/
|
||
|
||
export const UITeamDashboard = (health, stats, discovery, activity, projectName = 'Default Project', dashboardData = {}, projectId = null, app = null) => {
|
||
const uiData = dashboardData.ui || { token_drift: { total: 0, by_severity: {} }, code_metrics: {} };
|
||
const tokenDrift = uiData.token_drift || { total: 0, by_severity: {} };
|
||
|
||
return `
|
||
<div class="page-header">
|
||
<h1>UI Team Dashboard</h1>
|
||
<p class="text-muted">Component library & Figma sync tools · <strong class="text-primary">${projectName}</strong></p>
|
||
</div>
|
||
|
||
<!-- Key Metrics -->
|
||
<div class="grid grid-cols-4 gap-4 mt-6">
|
||
<ds-card>
|
||
<ds-card-content>
|
||
<div class="stat">
|
||
<div class="stat__label">Components</div>
|
||
<div class="stat__value">${stats.components?.total || discovery.files?.components || 0}</div>
|
||
</div>
|
||
</ds-card-content>
|
||
</ds-card>
|
||
|
||
<ds-card>
|
||
<ds-card-content>
|
||
<div class="stat">
|
||
<div class="stat__label">Token Drift Issues</div>
|
||
<div class="stat__value">${tokenDrift.total || 0}</div>
|
||
</div>
|
||
</ds-card-content>
|
||
</ds-card>
|
||
|
||
<ds-card>
|
||
<ds-card-content>
|
||
<div class="stat">
|
||
<div class="stat__label">Critical Issues</div>
|
||
<div class="stat__value">${tokenDrift.by_severity?.critical || 0}</div>
|
||
</div>
|
||
</ds-card-content>
|
||
</ds-card>
|
||
|
||
<ds-card>
|
||
<ds-card-content>
|
||
<div class="stat">
|
||
<div class="stat__label">Warnings</div>
|
||
<div class="stat__value">${tokenDrift.by_severity?.warning || 0}</div>
|
||
</div>
|
||
</ds-card-content>
|
||
</ds-card>
|
||
</div>
|
||
|
||
<!-- Quick Actions -->
|
||
<div class="grid grid-cols-2 gap-6 mt-6">
|
||
<ds-card>
|
||
<ds-card-header>
|
||
<ds-card-title>Figma Tools</ds-card-title>
|
||
<ds-card-description>Extract and sync from Figma</ds-card-description>
|
||
</ds-card-header>
|
||
<ds-card-content>
|
||
<div class="flex flex-col gap-3">
|
||
<ds-button variant="primary" data-action="extractTokens">
|
||
🎨 Extract Tokens from Figma
|
||
</ds-button>
|
||
<ds-button variant="outline" data-action="extractComponents">
|
||
📦 Extract Components
|
||
</ds-button>
|
||
<ds-button variant="outline" data-action="syncTokens">
|
||
🔄 Sync Tokens to File
|
||
</ds-button>
|
||
</div>
|
||
</ds-card-content>
|
||
</ds-card>
|
||
|
||
<ds-card>
|
||
<ds-card-header>
|
||
<ds-card-title>Component Generation</ds-card-title>
|
||
<ds-card-description>Generate code from designs</ds-card-description>
|
||
</ds-card-header>
|
||
<ds-card-content>
|
||
<div class="flex flex-col gap-3">
|
||
<ds-button variant="primary">
|
||
⚡ Generate Component Code
|
||
</ds-button>
|
||
<ds-button variant="outline">
|
||
📚 Generate Storybook Stories
|
||
</ds-button>
|
||
<ds-button variant="outline">
|
||
🎨 Generate Storybook Theme
|
||
</ds-button>
|
||
</div>
|
||
</ds-card-content>
|
||
</ds-card>
|
||
</div>
|
||
|
||
<!-- Recent Activity -->
|
||
<div class="mt-6">
|
||
<ds-card>
|
||
<ds-card-header>
|
||
<ds-card-title>Recent Syncs</ds-card-title>
|
||
</ds-card-header>
|
||
<ds-card-content>
|
||
${activity.length > 0 ? `
|
||
<div class="flex flex-col gap-3">
|
||
${activity.slice(0, 5).map(item => `
|
||
<div class="flex items-center gap-3 text-sm">
|
||
<span class="status-dot ${item.status === 'success' ? 'status-dot--success' : 'status-dot--error'}"></span>
|
||
<span class="flex-1">${item.message}</span>
|
||
<span class="text-muted text-xs">${new Date(item.timestamp).toLocaleTimeString()}</span>
|
||
</div>
|
||
`).join('')}
|
||
</div>
|
||
` : '<p class="text-muted text-sm">No recent activity</p>'}
|
||
</ds-card-content>
|
||
</ds-card>
|
||
</div>
|
||
`;
|
||
};
|
||
|
||
export const UXTeamDashboard = (health, stats, discovery, activity, projectName = 'Default Project', dashboardData = {}, projectId = null, app = null) => {
|
||
const uxData = dashboardData.ux || { figma_files_count: 0, figma_files: [] };
|
||
const figmaFiles = uxData.figma_files || [];
|
||
|
||
return `
|
||
<div class="page-header">
|
||
<h1>UX Team Dashboard</h1>
|
||
<p class="text-muted">Design consistency & token validation · <strong class="text-primary">${projectName}</strong></p>
|
||
</div>
|
||
|
||
<!-- Key Metrics -->
|
||
<div class="grid grid-cols-4 gap-4 mt-6">
|
||
<ds-card>
|
||
<ds-card-content>
|
||
<div class="stat">
|
||
<div class="stat__label">Figma Files</div>
|
||
<div class="stat__value">${uxData.figma_files_count || 0}</div>
|
||
</div>
|
||
</ds-card-content>
|
||
</ds-card>
|
||
|
||
<ds-card>
|
||
<ds-card-content>
|
||
<div class="stat">
|
||
<div class="stat__label">Synced Files</div>
|
||
<div class="stat__value">${figmaFiles.filter(f => f.sync_status === 'success').length}</div>
|
||
</div>
|
||
</ds-card-content>
|
||
</ds-card>
|
||
|
||
<ds-card>
|
||
<ds-card-content>
|
||
<div class="stat">
|
||
<div class="stat__label">Pending Sync</div>
|
||
<div class="stat__value">${figmaFiles.filter(f => f.sync_status === 'pending').length}</div>
|
||
</div>
|
||
</ds-card-content>
|
||
</ds-card>
|
||
|
||
<ds-card>
|
||
<ds-card-content>
|
||
<div class="stat">
|
||
<div class="stat__label">Design Tokens</div>
|
||
<div class="stat__value">${stats.tokens?.total || 0}</div>
|
||
</div>
|
||
</ds-card-content>
|
||
</ds-card>
|
||
</div>
|
||
|
||
<!-- Add New Figma File Form -->
|
||
<div class="mt-6">
|
||
<ds-card>
|
||
<ds-card-header>
|
||
<ds-card-title>➕ Add Figma File</ds-card-title>
|
||
<ds-card-description>Configure Figma files for this project</ds-card-description>
|
||
</ds-card-header>
|
||
<ds-card-content>
|
||
<form id="add-figma-file-form" class="flex flex-col gap-3">
|
||
<div>
|
||
<label class="text-sm font-medium">File Name</label>
|
||
<input
|
||
type="text"
|
||
name="file_name"
|
||
placeholder="Design System Components"
|
||
required
|
||
class="w-full p-2 border rounded mt-1"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label class="text-sm font-medium">Figma URL</label>
|
||
<input
|
||
type="url"
|
||
name="figma_url"
|
||
placeholder="https://figma.com/file/..."
|
||
required
|
||
class="w-full p-2 border rounded mt-1"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label class="text-sm font-medium">File Key</label>
|
||
<input
|
||
type="text"
|
||
name="file_key"
|
||
placeholder="abc123xyz"
|
||
required
|
||
class="w-full p-2 border rounded mt-1"
|
||
/>
|
||
<p class="text-xs text-muted mt-1">Extract from Figma URL: figma.com/file/<strong>FILE_KEY</strong>/...</p>
|
||
</div>
|
||
<ds-button type="submit" variant="primary" class="w-full">
|
||
Add Figma File
|
||
</ds-button>
|
||
</form>
|
||
</ds-card-content>
|
||
</ds-card>
|
||
</div>
|
||
|
||
<!-- Figma Files List -->
|
||
<div class="mt-6">
|
||
<ds-card>
|
||
<ds-card-header>
|
||
<ds-card-title>Figma Files (${figmaFiles.length})</ds-card-title>
|
||
<ds-card-description>Manage Figma files for this project</ds-card-description>
|
||
</ds-card-header>
|
||
<ds-card-content>
|
||
${figmaFiles.length === 0 ? `
|
||
<p class="text-muted text-sm text-center py-8">
|
||
No Figma files configured yet. Add your first file above! 👆
|
||
</p>
|
||
` : `
|
||
<div class="flex flex-col gap-3">
|
||
${figmaFiles.map(file => {
|
||
const statusColors = {
|
||
pending: 'text-muted',
|
||
syncing: 'text-warning',
|
||
success: 'text-success',
|
||
error: 'text-destructive'
|
||
};
|
||
const statusIcons = {
|
||
pending: '⏳',
|
||
syncing: '🔄',
|
||
success: '✓',
|
||
error: '❌'
|
||
};
|
||
return `
|
||
<div class="flex items-center gap-3 p-3 rounded border">
|
||
<span class="text-2xl">${statusIcons[file.sync_status] || '📄'}</span>
|
||
<div class="flex-1">
|
||
<div class="font-medium">${file.file_name}</div>
|
||
<div class="text-xs text-muted">Key: ${file.file_key}</div>
|
||
<div class="text-xs ${statusColors[file.sync_status] || 'text-muted'}">
|
||
Status: ${file.sync_status || 'pending'}
|
||
${file.last_synced ? `· Last synced: ${new Date(file.last_synced).toLocaleString()}` : ''}
|
||
</div>
|
||
</div>
|
||
<div class="flex gap-2">
|
||
<ds-button
|
||
variant="outline"
|
||
size="sm"
|
||
data-action="sync-figma-file"
|
||
data-file-id="${file.id}"
|
||
>
|
||
🔄 Sync
|
||
</ds-button>
|
||
<ds-button
|
||
variant="ghost"
|
||
size="sm"
|
||
data-action="delete-figma-file"
|
||
data-file-id="${file.id}"
|
||
>
|
||
🗑️
|
||
</ds-button>
|
||
</div>
|
||
</div>
|
||
`;
|
||
}).join('')}
|
||
</div>
|
||
`}
|
||
</ds-card-content>
|
||
</ds-card>
|
||
</div>
|
||
`;
|
||
};
|
||
|
||
export const QATeamDashboard = (health, stats, discovery, activity, projectName = 'Default Project', dashboardData = {}, projectId = null, app = null) => {
|
||
const healthScore = discovery.health?.score || 0;
|
||
const healthGrade = discovery.health?.grade || '-';
|
||
const qaData = dashboardData.qa || { esre_count: 0, test_summary: {} };
|
||
|
||
return `
|
||
<div class="page-header">
|
||
<h1>QA Team Dashboard</h1>
|
||
<p class="text-muted">Testing, validation & quality metrics · <strong class="text-primary">${projectName}</strong></p>
|
||
</div>
|
||
|
||
<!-- Key Metrics -->
|
||
<div class="grid grid-cols-4 gap-4 mt-6">
|
||
<ds-card>
|
||
<ds-card-content>
|
||
<div class="stat">
|
||
<div class="stat__label">Health Score</div>
|
||
<div class="stat__value flex items-center gap-2">
|
||
<span class="status-dot ${healthScore >= 80 ? 'status-dot--success' : healthScore >= 60 ? 'status-dot--warning' : 'status-dot--error'}"></span>
|
||
${healthScore}% (${healthGrade})
|
||
</div>
|
||
</div>
|
||
</ds-card-content>
|
||
</ds-card>
|
||
|
||
<ds-card>
|
||
<ds-card-content>
|
||
<div class="stat">
|
||
<div class="stat__label">ESRE Definitions</div>
|
||
<div class="stat__value">${qaData.esre_count || 0}</div>
|
||
</div>
|
||
</ds-card-content>
|
||
</ds-card>
|
||
|
||
<ds-card>
|
||
<ds-card-content>
|
||
<div class="stat">
|
||
<div class="stat__label">Tests Run</div>
|
||
<div class="stat__value">${qaData.test_summary?.total_tests || 0}</div>
|
||
</div>
|
||
</ds-card-content>
|
||
</ds-card>
|
||
|
||
<ds-card>
|
||
<ds-card-content>
|
||
<div class="stat">
|
||
<div class="stat__label">Tests Passed</div>
|
||
<div class="stat__value">${qaData.test_summary?.passed_tests || 0}</div>
|
||
</div>
|
||
</ds-card-content>
|
||
</ds-card>
|
||
</div>
|
||
|
||
<!-- Quick Actions -->
|
||
<div class="grid grid-cols-2 gap-6 mt-6">
|
||
<ds-card>
|
||
<ds-card-header>
|
||
<ds-card-title>Quality Analysis</ds-card-title>
|
||
<ds-card-description>Find issues and improvements</ds-card-description>
|
||
</ds-card-header>
|
||
<ds-card-content>
|
||
<div class="flex flex-col gap-3">
|
||
<ds-button variant="primary" data-action="navigate-quick-wins">
|
||
⚡ Get Quick Wins
|
||
</ds-button>
|
||
<ds-button variant="outline">
|
||
🔍 Find Unused Styles
|
||
</ds-button>
|
||
<ds-button variant="outline">
|
||
📍 Find Inline Styles
|
||
</ds-button>
|
||
</div>
|
||
</ds-card-content>
|
||
</ds-card>
|
||
|
||
<ds-card>
|
||
<ds-card-header>
|
||
<ds-card-title>Validation</ds-card-title>
|
||
<ds-card-description>Check compliance and quality</ds-card-description>
|
||
</ds-card-header>
|
||
<ds-card-content>
|
||
<div class="flex flex-col gap-3">
|
||
<ds-button variant="primary" data-action="validateComponents">
|
||
✅ Validate Components
|
||
</ds-button>
|
||
<ds-button variant="outline">
|
||
📊 Analyze React Components
|
||
</ds-button>
|
||
<ds-button variant="outline">
|
||
🎯 Check Story Coverage
|
||
</ds-button>
|
||
</div>
|
||
</ds-card-content>
|
||
</ds-card>
|
||
</div>
|
||
|
||
<!-- Add New ESRE Definition Form -->
|
||
<div class="mt-6">
|
||
<ds-card>
|
||
<ds-card-header>
|
||
<ds-card-title>➕ Add ESRE Definition</ds-card-title>
|
||
<ds-card-description>Define Expected State Requirements for components</ds-card-description>
|
||
</ds-card-header>
|
||
<ds-card-content>
|
||
<form id="add-esre-form" class="flex flex-col gap-3">
|
||
<div>
|
||
<label class="text-sm font-medium">Name</label>
|
||
<input
|
||
type="text"
|
||
name="name"
|
||
placeholder="Button Color Test"
|
||
required
|
||
class="w-full p-2 border rounded mt-1"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label class="text-sm font-medium">Component Name (Optional)</label>
|
||
<input
|
||
type="text"
|
||
name="component_name"
|
||
placeholder="Button"
|
||
class="w-full p-2 border rounded mt-1"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label class="text-sm font-medium">Definition (Natural Language)</label>
|
||
<textarea
|
||
name="definition_text"
|
||
placeholder="Primary button background should use the primary-500 token"
|
||
required
|
||
rows="3"
|
||
class="w-full p-2 border rounded mt-1"
|
||
></textarea>
|
||
</div>
|
||
<div>
|
||
<label class="text-sm font-medium">Expected Value (Optional)</label>
|
||
<input
|
||
type="text"
|
||
name="expected_value"
|
||
placeholder="var(--primary-500)"
|
||
class="w-full p-2 border rounded mt-1"
|
||
/>
|
||
</div>
|
||
<ds-button type="submit" variant="primary" class="w-full">
|
||
Add ESRE Definition
|
||
</ds-button>
|
||
</form>
|
||
</ds-card-content>
|
||
</ds-card>
|
||
</div>
|
||
|
||
<!-- ESRE Definitions List -->
|
||
<div class="mt-6">
|
||
<ds-card>
|
||
<ds-card-header>
|
||
<ds-card-title>ESRE Definitions (${qaData.esre_count || 0})</ds-card-title>
|
||
<ds-card-description>Expected State Requirements for testing</ds-card-description>
|
||
</ds-card-header>
|
||
<ds-card-content>
|
||
${qaData.esre_count === 0 ? `
|
||
<p class="text-muted text-sm text-center py-8">
|
||
No ESRE definitions yet. Add your first definition above! 👆
|
||
</p>
|
||
` : `
|
||
<p class="text-muted text-sm text-center py-4">
|
||
Use the API to list ESRE definitions for this project.
|
||
</p>
|
||
`}
|
||
</ds-card-content>
|
||
</ds-card>
|
||
</div>
|
||
`;
|
||
};
|