Initial commit: Clean DSS implementation
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
This commit is contained in:
459
admin-ui/js/core/team-dashboards.js
Normal file
459
admin-ui/js/core/team-dashboards.js
Normal file
@@ -0,0 +1,459 @@
|
||||
/**
|
||||
* 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>
|
||||
`;
|
||||
};
|
||||
Reference in New Issue
Block a user