mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-11 02:33:51 +08:00
feat(dashboard): add context sections for assets, dependencies, test context, and conflict detection
This commit is contained in:
@@ -1328,10 +1328,40 @@ code {
|
|||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.context-section {
|
||||||
|
padding: 1rem;
|
||||||
|
background: hsl(var(--muted) / 0.3);
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-section-title {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
border-bottom: 1px solid hsl(var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
.context-field {
|
.context-field {
|
||||||
padding: 0.75rem;
|
display: flex;
|
||||||
background: hsl(var(--muted));
|
flex-direction: column;
|
||||||
border-radius: 0.375rem;
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-label {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: hsl(var(--muted-foreground));
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.025em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-value {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: hsl(var(--foreground));
|
||||||
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.context-field label {
|
.context-field label {
|
||||||
@@ -1712,6 +1742,21 @@ code {
|
|||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Summary Item Direct (No collapse) */
|
||||||
|
.summary-item-direct {
|
||||||
|
border: 1px solid hsl(var(--border));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
padding: 1rem;
|
||||||
|
background: hsl(var(--card));
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-item-direct .summary-content-pre {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
padding: 0.75rem;
|
||||||
|
background: hsl(var(--muted));
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
.markdown-content {
|
.markdown-content {
|
||||||
background: hsl(var(--muted));
|
background: hsl(var(--muted));
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
|
|||||||
@@ -943,11 +943,15 @@ function renderContextContent(context) {
|
|||||||
const techStack = projectContext.tech_stack || metadata.tech_stack || {};
|
const techStack = projectContext.tech_stack || metadata.tech_stack || {};
|
||||||
const codingConventions = projectContext.coding_conventions || {};
|
const codingConventions = projectContext.coding_conventions || {};
|
||||||
const architecturePatterns = projectContext.architecture_patterns || [];
|
const architecturePatterns = projectContext.architecture_patterns || [];
|
||||||
|
const assets = context.assets || {};
|
||||||
|
const dependencies = context.dependencies || {};
|
||||||
|
const testContext = context.test_context || {};
|
||||||
|
const conflictDetection = context.conflict_detection || {};
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="context-tab-content space-y-6">
|
<div class="context-tab-content space-y-6">
|
||||||
<!-- Header with View JSON button -->
|
<!-- Header with View JSON button -->
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center mb-4">
|
||||||
<h3 class="text-lg font-semibold text-foreground">Context Package</h3>
|
<h3 class="text-lg font-semibold text-foreground">Context Package</h3>
|
||||||
<button class="px-4 py-2 bg-primary text-primary-foreground rounded hover:bg-primary/90 transition-colors" onclick="openMarkdownModal('context-package.json', window._currentContextJson, 'json')">
|
<button class="px-4 py-2 bg-primary text-primary-foreground rounded hover:bg-primary/90 transition-colors" onclick="openMarkdownModal('context-package.json', window._currentContextJson, 'json')">
|
||||||
👁️ View JSON
|
👁️ View JSON
|
||||||
@@ -1024,6 +1028,46 @@ function renderContextContent(context) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
` : ''}
|
` : ''}
|
||||||
|
|
||||||
|
<!-- Assets Section -->
|
||||||
|
${Object.keys(assets).length > 0 ? `
|
||||||
|
<div class="context-section">
|
||||||
|
<h4 class="context-section-title">📚 Assets & Resources</h4>
|
||||||
|
<div class="space-y-4">
|
||||||
|
${renderAssetsSection(assets)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
|
||||||
|
<!-- Dependencies Section -->
|
||||||
|
${(dependencies.internal && dependencies.internal.length > 0) || (dependencies.external && dependencies.external.length > 0) ? `
|
||||||
|
<div class="context-section">
|
||||||
|
<h4 class="context-section-title">🔗 Dependencies</h4>
|
||||||
|
<div class="space-y-4">
|
||||||
|
${renderDependenciesSection(dependencies)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
|
||||||
|
<!-- Test Context Section -->
|
||||||
|
${Object.keys(testContext).length > 0 ? `
|
||||||
|
<div class="context-section">
|
||||||
|
<h4 class="context-section-title">🧪 Test Context</h4>
|
||||||
|
<div class="space-y-4">
|
||||||
|
${renderTestContextSection(testContext)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
|
||||||
|
<!-- Conflict Detection Section -->
|
||||||
|
${Object.keys(conflictDetection).length > 0 ? `
|
||||||
|
<div class="context-section">
|
||||||
|
<h4 class="context-section-title">⚠️ Conflict Detection & Risk Analysis</h4>
|
||||||
|
<div class="space-y-4">
|
||||||
|
${renderConflictDetectionSection(conflictDetection)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -1148,6 +1192,339 @@ function renderCodingConventions(conventions) {
|
|||||||
return sections.join('');
|
return sections.join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderAssetsSection(assets) {
|
||||||
|
const sections = [];
|
||||||
|
|
||||||
|
// Documentation
|
||||||
|
if (assets.documentation && assets.documentation.length > 0) {
|
||||||
|
sections.push(`
|
||||||
|
<div class="asset-category">
|
||||||
|
<h5 class="asset-category-title">📄 Documentation</h5>
|
||||||
|
<div class="asset-grid">
|
||||||
|
${assets.documentation.map(doc => `
|
||||||
|
<div class="asset-card">
|
||||||
|
<div class="asset-card-header">
|
||||||
|
<span class="asset-path">${escapeHtml(doc.path)}</span>
|
||||||
|
<span class="relevance-score" style="background: ${getRelevanceColor(doc.relevance_score)}">${(doc.relevance_score * 100).toFixed(0)}%</span>
|
||||||
|
</div>
|
||||||
|
<div class="asset-card-body">
|
||||||
|
<div class="asset-scope">${escapeHtml(doc.scope || '')}</div>
|
||||||
|
${doc.contains && doc.contains.length > 0 ? `
|
||||||
|
<div class="asset-tags">
|
||||||
|
${doc.contains.map(tag => `<span class="asset-tag">${escapeHtml(tag)}</span>`).join('')}
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Source Code
|
||||||
|
if (assets.source_code && assets.source_code.length > 0) {
|
||||||
|
sections.push(`
|
||||||
|
<div class="asset-category">
|
||||||
|
<h5 class="asset-category-title">💻 Source Code</h5>
|
||||||
|
<div class="asset-grid">
|
||||||
|
${assets.source_code.map(src => `
|
||||||
|
<div class="asset-card">
|
||||||
|
<div class="asset-card-header">
|
||||||
|
<span class="asset-path">${escapeHtml(src.path)}</span>
|
||||||
|
<span class="relevance-score" style="background: ${getRelevanceColor(src.relevance_score)}">${(src.relevance_score * 100).toFixed(0)}%</span>
|
||||||
|
</div>
|
||||||
|
<div class="asset-card-body">
|
||||||
|
<div class="asset-role-badge badge-${getRoleBadgeClass(src.role)}">${escapeHtml(src.role || '')}</div>
|
||||||
|
${src.exports && src.exports.length > 0 ? `
|
||||||
|
<div class="asset-meta"><strong>Exports:</strong> ${src.exports.map(e => `<code class="inline-code">${escapeHtml(e)}</code>`).join(', ')}</div>
|
||||||
|
` : ''}
|
||||||
|
${src.features && src.features.length > 0 ? `
|
||||||
|
<div class="asset-features">${src.features.map(f => `<span class="feature-tag">${escapeHtml(f)}</span>`).join('')}</div>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests
|
||||||
|
if (assets.tests && assets.tests.length > 0) {
|
||||||
|
sections.push(`
|
||||||
|
<div class="asset-category">
|
||||||
|
<h5 class="asset-category-title">🧪 Tests</h5>
|
||||||
|
<div class="asset-grid">
|
||||||
|
${assets.tests.map(test => `
|
||||||
|
<div class="asset-card">
|
||||||
|
<div class="asset-card-header">
|
||||||
|
<span class="asset-path">${escapeHtml(test.path)}</span>
|
||||||
|
${test.test_count ? `<span class="test-count-badge">${test.test_count} tests</span>` : ''}
|
||||||
|
</div>
|
||||||
|
<div class="asset-card-body">
|
||||||
|
<div class="asset-type">${escapeHtml(test.type || '')}</div>
|
||||||
|
${test.test_classes ? `<div class="asset-meta"><strong>Classes:</strong> ${escapeHtml(test.test_classes.join(', '))}</div>` : ''}
|
||||||
|
${test.coverage ? `<div class="asset-meta"><strong>Coverage:</strong> ${escapeHtml(test.coverage)}</div>` : ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sections.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderDependenciesSection(dependencies) {
|
||||||
|
const sections = [];
|
||||||
|
|
||||||
|
// Internal Dependencies
|
||||||
|
if (dependencies.internal && dependencies.internal.length > 0) {
|
||||||
|
sections.push(`
|
||||||
|
<div class="dep-category">
|
||||||
|
<h5 class="dep-category-title">🔄 Internal Dependencies</h5>
|
||||||
|
<div class="dep-graph">
|
||||||
|
${dependencies.internal.slice(0, 10).map(dep => `
|
||||||
|
<div class="dep-item">
|
||||||
|
<div class="dep-from">${escapeHtml(dep.from)}</div>
|
||||||
|
<div class="dep-arrow">
|
||||||
|
<span class="dep-type-badge badge-${dep.type}">${escapeHtml(dep.type)}</span>
|
||||||
|
→
|
||||||
|
</div>
|
||||||
|
<div class="dep-to">${escapeHtml(dep.to)}</div>
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
${dependencies.internal.length > 10 ? `<div class="dep-more">... and ${dependencies.internal.length - 10} more</div>` : ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// External Dependencies
|
||||||
|
if (dependencies.external && dependencies.external.length > 0) {
|
||||||
|
sections.push(`
|
||||||
|
<div class="dep-category">
|
||||||
|
<h5 class="dep-category-title">📦 External Dependencies</h5>
|
||||||
|
<div class="dep-grid">
|
||||||
|
${dependencies.external.map(dep => `
|
||||||
|
<div class="dep-external-card">
|
||||||
|
<div class="dep-package-name">${escapeHtml(dep.package)}</div>
|
||||||
|
<div class="dep-version">${escapeHtml(dep.version || '')}</div>
|
||||||
|
<div class="dep-usage">${escapeHtml(dep.usage || '')}</div>
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sections.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTestContextSection(testContext) {
|
||||||
|
const sections = [];
|
||||||
|
|
||||||
|
// Test Frameworks
|
||||||
|
if (testContext.frameworks) {
|
||||||
|
const frameworks = testContext.frameworks;
|
||||||
|
sections.push(`
|
||||||
|
<div class="test-category">
|
||||||
|
<h5 class="test-category-title">🛠️ Test Frameworks</h5>
|
||||||
|
<div class="test-frameworks-grid">
|
||||||
|
${frameworks.backend ? `
|
||||||
|
<div class="framework-card framework-installed">
|
||||||
|
<div class="framework-header">
|
||||||
|
<span class="framework-label">Backend</span>
|
||||||
|
<span class="framework-name">${escapeHtml(frameworks.backend.name || 'N/A')}</span>
|
||||||
|
</div>
|
||||||
|
${frameworks.backend.plugins ? `
|
||||||
|
<div class="framework-plugins">${frameworks.backend.plugins.map(p => `<span class="plugin-tag">${escapeHtml(p)}</span>`).join('')}</div>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
${frameworks.frontend ? `
|
||||||
|
<div class="framework-card ${frameworks.frontend.name && frameworks.frontend.name.includes('NONE') ? 'framework-missing' : 'framework-installed'}">
|
||||||
|
<div class="framework-header">
|
||||||
|
<span class="framework-label">Frontend</span>
|
||||||
|
<span class="framework-name">${escapeHtml(frameworks.frontend.name || 'N/A')}</span>
|
||||||
|
</div>
|
||||||
|
${frameworks.frontend.recommended ? `<div class="framework-recommended">Recommended: ${escapeHtml(frameworks.frontend.recommended)}</div>` : ''}
|
||||||
|
${frameworks.frontend.gap ? `<div class="framework-gap">⚠️ ${escapeHtml(frameworks.frontend.gap)}</div>` : ''}
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Existing Tests Statistics
|
||||||
|
if (testContext.existing_tests) {
|
||||||
|
const tests = testContext.existing_tests;
|
||||||
|
let totalTests = 0;
|
||||||
|
let totalClasses = 0;
|
||||||
|
|
||||||
|
if (tests.backend) {
|
||||||
|
if (tests.backend.integration) {
|
||||||
|
totalTests += tests.backend.integration.tests || 0;
|
||||||
|
totalClasses += tests.backend.integration.classes || 0;
|
||||||
|
}
|
||||||
|
if (tests.backend.api_endpoints) {
|
||||||
|
totalTests += tests.backend.api_endpoints.tests || 0;
|
||||||
|
totalClasses += tests.backend.api_endpoints.classes || 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sections.push(`
|
||||||
|
<div class="test-category">
|
||||||
|
<h5 class="test-category-title">📊 Test Statistics</h5>
|
||||||
|
<div class="test-stats-grid">
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-value">${totalTests}</div>
|
||||||
|
<div class="stat-label">Total Tests</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-value">${totalClasses}</div>
|
||||||
|
<div class="stat-label">Test Classes</div>
|
||||||
|
</div>
|
||||||
|
${testContext.coverage_config && testContext.coverage_config.target ? `
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-value">${escapeHtml(testContext.coverage_config.target)}</div>
|
||||||
|
<div class="stat-label">Coverage Target</div>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test Markers
|
||||||
|
if (testContext.test_markers) {
|
||||||
|
sections.push(`
|
||||||
|
<div class="test-category">
|
||||||
|
<h5 class="test-category-title">🏷️ Test Markers</h5>
|
||||||
|
<div class="test-markers-grid">
|
||||||
|
${Object.entries(testContext.test_markers).map(([marker, desc]) => `
|
||||||
|
<div class="marker-card">
|
||||||
|
<span class="marker-name">@${escapeHtml(marker)}</span>
|
||||||
|
<span class="marker-desc">${escapeHtml(desc)}</span>
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sections.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderConflictDetectionSection(conflictDetection) {
|
||||||
|
const sections = [];
|
||||||
|
|
||||||
|
// Risk Level Indicator
|
||||||
|
if (conflictDetection.risk_level) {
|
||||||
|
const riskLevel = conflictDetection.risk_level;
|
||||||
|
const riskColor = riskLevel === 'high' ? '#ef4444' : riskLevel === 'medium' ? '#f59e0b' : '#10b981';
|
||||||
|
sections.push(`
|
||||||
|
<div class="risk-indicator" style="border-color: ${riskColor}">
|
||||||
|
<div class="risk-level" style="background: ${riskColor}">
|
||||||
|
${escapeHtml(riskLevel.toUpperCase())} RISK
|
||||||
|
</div>
|
||||||
|
${conflictDetection.mitigation_strategy ? `
|
||||||
|
<div class="risk-mitigation">
|
||||||
|
<strong>Mitigation Strategy:</strong> ${escapeHtml(conflictDetection.mitigation_strategy)}
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Risk Factors
|
||||||
|
if (conflictDetection.risk_factors) {
|
||||||
|
const factors = conflictDetection.risk_factors;
|
||||||
|
sections.push(`
|
||||||
|
<div class="conflict-category">
|
||||||
|
<h5 class="conflict-category-title">⚠️ Risk Factors</h5>
|
||||||
|
<div class="risk-factors-list">
|
||||||
|
${factors.test_gaps && factors.test_gaps.length > 0 ? `
|
||||||
|
<div class="risk-factor">
|
||||||
|
<strong class="risk-factor-title">Test Gaps:</strong>
|
||||||
|
<ul class="risk-factor-items">
|
||||||
|
${factors.test_gaps.map(gap => `<li>${escapeHtml(gap)}</li>`).join('')}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
${factors.existing_implementations && factors.existing_implementations.length > 0 ? `
|
||||||
|
<div class="risk-factor">
|
||||||
|
<strong class="risk-factor-title">Existing Implementations:</strong>
|
||||||
|
<ul class="risk-factor-items">
|
||||||
|
${factors.existing_implementations.map(impl => `<li>${escapeHtml(impl)}</li>`).join('')}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Affected Modules
|
||||||
|
if (conflictDetection.affected_modules && conflictDetection.affected_modules.length > 0) {
|
||||||
|
sections.push(`
|
||||||
|
<div class="conflict-category">
|
||||||
|
<h5 class="conflict-category-title">📦 Affected Modules</h5>
|
||||||
|
<div class="affected-modules-grid">
|
||||||
|
${conflictDetection.affected_modules.map(mod => `
|
||||||
|
<span class="affected-module-tag">${escapeHtml(mod)}</span>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Historical Conflicts
|
||||||
|
if (conflictDetection.historical_conflicts && conflictDetection.historical_conflicts.length > 0) {
|
||||||
|
sections.push(`
|
||||||
|
<div class="conflict-category">
|
||||||
|
<h5 class="conflict-category-title">📜 Historical Lessons</h5>
|
||||||
|
<div class="historical-conflicts-list">
|
||||||
|
${conflictDetection.historical_conflicts.map(conflict => `
|
||||||
|
<div class="historical-conflict-card">
|
||||||
|
<div class="conflict-source">Source: ${escapeHtml(conflict.source || 'Unknown')}</div>
|
||||||
|
${conflict.lesson ? `<div class="conflict-lesson"><strong>Lesson:</strong> ${escapeHtml(conflict.lesson)}</div>` : ''}
|
||||||
|
${conflict.recommendation ? `<div class="conflict-recommendation"><strong>Recommendation:</strong> ${escapeHtml(conflict.recommendation)}</div>` : ''}
|
||||||
|
${conflict.challenge ? `<div class="conflict-challenge"><strong>Challenge:</strong> ${escapeHtml(conflict.challenge)}</div>` : ''}
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sections.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper functions
|
||||||
|
function getRelevanceColor(score) {
|
||||||
|
if (score >= 0.95) return '#10b981';
|
||||||
|
if (score >= 0.90) return '#3b82f6';
|
||||||
|
if (score >= 0.80) return '#f59e0b';
|
||||||
|
return '#6b7280';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRoleBadgeClass(role) {
|
||||||
|
const roleMap = {
|
||||||
|
'core-hook': 'primary',
|
||||||
|
'api-client': 'success',
|
||||||
|
'api-router': 'info',
|
||||||
|
'service-layer': 'warning',
|
||||||
|
'pydantic-schemas': 'secondary',
|
||||||
|
'orm-model': 'secondary',
|
||||||
|
'typescript-types': 'info'
|
||||||
|
};
|
||||||
|
return roleMap[role] || 'secondary';
|
||||||
|
}
|
||||||
|
|
||||||
async function loadAndRenderSummaryTab(session, contentArea) {
|
async function loadAndRenderSummaryTab(session, contentArea) {
|
||||||
contentArea.innerHTML = '<div class="tab-loading">Loading summaries...</div>';
|
contentArea.innerHTML = '<div class="tab-loading">Loading summaries...</div>';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user