'
+ `${escapeHtml(collapseSummary)}
`
+ ''
@@ -363,6 +364,8 @@ export function wireDecisionCockpitHandlers() {
}));
} catch (_) {}
}
+ const details = root.querySelector('.decision-cockpit-details');
+ if (details && !details.open) details.open = true;
const target = document.querySelector(targetSelector);
if (target) {
event.preventDefault();
diff --git a/public/Delivera-CurrentSprint-Export-Dashboard.js b/public/Delivera-CurrentSprint-Export-Dashboard.js
index 72e615e..7eb964c 100644
--- a/public/Delivera-CurrentSprint-Export-Dashboard.js
+++ b/public/Delivera-CurrentSprint-Export-Dashboard.js
@@ -734,7 +734,7 @@ async function exportDashboardAsPng(data, btn) {
a.click();
setButtonStatus(btn, 'Downloaded!', originalText);
} catch (error) {
- console.error('PNG snapshot export error:', error);
+ console.warn('PNG snapshot export error:', error); // eslint-disable-line no-console
const errorEl = document.getElementById('current-sprint-error');
if (errorEl) {
setActionErrorOnEl(errorEl, {
@@ -759,7 +759,7 @@ async function copyDashboardAsText(data, btn) {
setButtonStatus(btn, 'Copied!', originalText);
setLastExportStatus('Copy detail', 'Detailed sprint text copied');
} catch (error) {
- console.error('Copy text error:', error);
+ console.warn('Copy text error:', error); // eslint-disable-line no-console
setButtonStatus(btn, 'Copy failed', originalText);
}
}
@@ -789,7 +789,7 @@ async function copyDashboardSummary(data, btn) {
setButtonStatus(btn, 'Copied!', originalText);
setLastExportStatus('Copy summary', 'Sprint summary copied for stand-up, review, and leadership updates');
} catch (error) {
- console.error('Copy summary error:', error);
+ console.warn('Copy summary error:', error); // eslint-disable-line no-console
setButtonStatus(btn, 'Copy failed', originalText);
}
}
@@ -831,7 +831,7 @@ async function copyDashboardAsStandup(data, btn) {
setButtonStatus(btn, 'Copied!', originalText);
setLastExportStatus('Stand-up script', text);
} catch (error) {
- console.error('Copy stand-up script error:', error);
+ console.warn('Copy stand-up script error:', error); // eslint-disable-line no-console
setButtonStatus(btn, 'Copy failed', originalText);
}
}
@@ -851,7 +851,7 @@ async function exportDashboardAsMarkdown(data, btn) {
setButtonStatus(btn, 'Exported!', originalText);
setLastExportStatus('Markdown', `File sprint-${model.meta.sprintName || 'export'}.md`);
} catch (error) {
- console.error('Markdown export error:', error);
+ console.warn('Markdown export error:', error); // eslint-disable-line no-console
setButtonStatus(btn, 'Export failed', originalText);
}
}
@@ -872,7 +872,7 @@ async function copyDashboardLink(data, btn) {
setButtonStatus(btn, 'Link copied!', originalText);
setLastExportStatus('Copy link', url);
} catch (error) {
- console.error('Copy link error:', error);
+ console.warn('Copy link error:', error); // eslint-disable-line no-console
setButtonStatus(btn, 'Copy failed', originalText);
setLastExportStatus('Copy link failed', 'Try Copy summary instead.');
}
@@ -898,7 +898,7 @@ async function emailDashboard(data, btn) {
setLastExportStatus('Email failed', 'Use Copy summary or Markdown export instead.');
}
} catch (error) {
- console.error('Email error:', error);
+ console.warn('Email error:', error); // eslint-disable-line no-console
setButtonStatus(btn, 'Email unavailable', originalText);
setLastExportStatus('Email unavailable', 'Share via Copy summary or Markdown.');
}
diff --git a/public/Delivera-CurrentSprint-Header-Bar.js b/public/Delivera-CurrentSprint-Header-Bar.js
index f5cf43d..68016d4 100644
--- a/public/Delivera-CurrentSprint-Header-Bar.js
+++ b/public/Delivera-CurrentSprint-Header-Bar.js
@@ -82,9 +82,13 @@ function renderHeaderActiveFilterLabel() {
});
}
-function getHeaderStatusSummary({ statusBadge, freshnessLabel, exportReadiness }) {
- const freshnessText = freshnessLabel || (statusBadge === SPRINT_COPY.statusLive ? SPRINT_COPY.liveDataShort : SPRINT_COPY.statusSnapshot);
- return `${freshnessText} | ${exportReadiness}`;
+function getHeaderStatusSummary({ statusBadge, freshnessLabel, exportReadiness, isHistoricalSprint = false, closedDateLabel = '' }) {
+ if (isHistoricalSprint) {
+ const closed = closedDateLabel ? ` · closed ${closedDateLabel}` : '';
+ return `Snapshot${closed} · ${exportReadiness}`;
+ }
+ const freshnessText = freshnessLabel || SPRINT_COPY.liveDataShort;
+ return `Live · ${freshnessText} · ${exportReadiness}`;
}
function getVerdictPresentation({ verdictInfo, remainingChipLabel, remainingDays, donePercentage }) {
@@ -152,7 +156,8 @@ function renderHeaderIdentityMetricsRow({ donePct, issuesCount, logH, estH, delt
? ('' + escapeHtml(delta.short) + '')
: '';
const doneInner = escapeHtml(String(donePct)) + '%' + (delta ? ' ' + deltaHtml : '');
- return '';
}
- if (issuesCount > 0 && !viewportLean) {
+ const showIntelligenceStrip = issuesCount > 0 && !viewportLean && (edgeStateAttr !== 'none' || stuckCount > 0);
+ if (showIntelligenceStrip) {
html += '
@@ -312,6 +328,64 @@ function gradeFromSignals(onTimePct, predictabilityPct, sprintCount = 0) {
return deriveDeliveryGrade(onTimePct, predictability, sprintCount);
}
+function renderSquadActivationStatus(squads) {
+ if (!Array.isArray(squads) || squads.length === 0) return '';
+
+ function classifyBadge(squad) {
+ if (squad.sprintState === 'unavailable') return { cls: 'squad-badge--unknown', label: 'Unavailable' };
+ if (squad.hasActiveSprintFallback) {
+ return squad.nextSprintStartOverdue
+ ? { cls: 'squad-badge--stalled', label: 'Overdue start' }
+ : (squad.suggestStartSprint ? { cls: 'squad-badge--pending', label: 'Not started' } : { cls: 'squad-badge--stalled', label: 'No sprint' });
+ }
+ if (squad.sprintState === 'active') return { cls: 'squad-badge--active', label: 'Active sprint' };
+ if (squad.sprintState === 'future') return { cls: 'squad-badge--pending', label: 'Upcoming' };
+ return { cls: 'squad-badge--unknown', label: squad.sprintState || 'Unknown' };
+ }
+
+ const rows = squads.map((squad) => {
+ const badge = classifyBadge(squad);
+ let detail = squad.sprintName ? escapeHtml(squad.sprintName) : '';
+ if (squad.sprintStartDate) {
+ detail += detail ? ' · started ' : 'Started ';
+ detail += escapeHtml(squad.sprintStartDate.slice(0, 10));
+ }
+ if (squad.hasActiveSprintFallback && squad.nextSprintCandidate) {
+ detail = escapeHtml(squad.nextSprintCandidate.name || '') + ' planned' + (squad.nextSprintStartOverdue ? ' — start overdue' : ' — click Start Sprint in Jira');
+ }
+ if (squad.hasActiveSprintFallback && !squad.nextSprintCandidate) {
+ detail = 'No future sprint planned';
+ }
+ if (squad.error) detail = escapeHtml(squad.error);
+ const progress = squad.totalStories > 0
+ ? `${squad.doneStories}/${squad.totalStories} done` : '';
+ return `
+
+ ${escapeHtml(badge.label)}
+ ${escapeHtml(squad.boardName)}
+ ${detail ? `${detail}` : ''}
+ ${progress}
+
+ `;
+ }).join('');
+
+ const stalledCount = squads.filter((s) => s.hasActiveSprintFallback).length;
+ const alertHtml = stalledCount > 0
+ ? `⚠ ${stalledCount} squad${stalledCount > 1 ? 's' : ''} without an active sprint — risk of invisible scrambling.
`
+ : '';
+
+ return `
+
+
+ ${alertHtml}
+ ${rows}
+
+ `;
+}
+
export function renderLeadershipPage(data) {
const boards = data.boards || [];
const meta = data.meta || {};
@@ -395,6 +469,10 @@ export function renderLeadershipPage(data) {
html += renderLeadershipKpiStrip(data);
html += renderLeadershipEvidenceFold(data);
+ if (Array.isArray(data.squads) && data.squads.length > 0) {
+ html += renderSquadActivationStatus(data.squads);
+ }
+
html += '';
html += '';
diff --git a/public/Delivera-Report-Page-Filters-Summary-Helpers.js b/public/Delivera-Report-Page-Filters-Summary-Helpers.js
index 6069379..ac2d66a 100644
--- a/public/Delivera-Report-Page-Filters-Summary-Helpers.js
+++ b/public/Delivera-Report-Page-Filters-Summary-Helpers.js
@@ -153,11 +153,12 @@ export function updateAppliedFiltersSummary() {
const chips = buildUnifiedReportContextChips(
typeof outcomesCount === 'number' ? { outcomesCount } : {},
);
- const secondary = reportState.previewData
- ? (document.body?.classList.contains('preview-active')
- ? 'Preview is open — chips match your current filter picks.'
- : 'Results reflect the last preview for this scope.')
- : 'Run preview once to load numbers for the scope in the chips.';
+ const previewActive = document.body?.classList.contains('preview-active');
+ const secondary = previewActive
+ ? ''
+ : (reportState.previewData
+ ? 'Results reflect the last preview for this scope.'
+ : 'Run preview once to load numbers for the scope in the chips.');
filterStripSummaryEl.innerHTML = renderContextBar({
title: REPORT_CONTEXT_BAR_TITLE,
chips,
diff --git a/public/Delivera-Report-Page-Init-Controller.js b/public/Delivera-Report-Page-Init-Controller.js
index 883a0c2..107501e 100644
--- a/public/Delivera-Report-Page-Init-Controller.js
+++ b/public/Delivera-Report-Page-Init-Controller.js
@@ -27,7 +27,7 @@ import { initExportMenu as initReportExportMenu } from './Delivera-Report-Page-E
import { getCurrentSelectionComplexity, shouldAutoPreviewOnInit, refreshPreviewButtonLabel, updateAppliedFiltersSummary, hydrateFromLastQuery } from './Delivera-Report-Page-Filters-Summary-Helpers.js';
import { initSharedPageIdentityObserver, initSharedTableScrollIndicators } from './Delivera-Shared-Page-Identity-Scroll-Helpers.js';
import { initReportFiltersPanelState } from './Delivera-Report-Page-Init-Filters-Panel-State-Helpers.js';
-import { initGlobalOutcomeModal } from './Delivera-Shared-Outcome-Modal.js';
+import { initWorkDraftDrawer as initGlobalOutcomeModal } from './Delivera-Work-Draft-Canvas.js';
import { renderReportNamedViewsBar, wireReportNamedViews } from './Delivera-Report-Page-Named-Views.js';
import { initOverlayManager } from './Delivera-Shared-Overlay-Manager.js';
import { wireLeadershipContentInteractions } from './Delivera-Leadership-Shared-Actions.js';
@@ -230,6 +230,19 @@ function initReportPage() {
}
return false;
}
+ if (normalized === 'open-current-sprint') {
+ window.location.href = '/current-sprint';
+ return true;
+ }
+ if (normalized === 'open-sprints' || normalized === 'open-sprints-tab') {
+ const sprintsTab = document.getElementById('tab-btn-sprints');
+ if (sprintsTab) {
+ sprintsTab.click();
+ sprintsTab.focus();
+ return true;
+ }
+ return false;
+ }
if (normalized === 'reset-filters') {
try {
localStorage.removeItem(SHARED_DATE_RANGE_KEY);
@@ -374,14 +387,14 @@ function initReportPage() {
syncHeaderLoadLatestVisibility(true);
}
updateAppliedFiltersSummary();
- if (shouldAutoPreviewOnInit()) {
- const previewBtn = document.getElementById('preview-btn');
- if (previewBtn && !previewBtn.disabled) scheduleAutoPreview(1000);
- }
initReportExportMenu();
initPreviewFlow();
wirePreviewContextActions();
- restoreLastPreviewFromStorage();
+ const cacheRestored = restoreLastPreviewFromStorage();
+ if (!cacheRestored && shouldAutoPreviewOnInit()) {
+ const previewBtn = document.getElementById('preview-btn');
+ if (previewBtn && !previewBtn.disabled) scheduleAutoPreview(1000);
+ }
initFilters();
initSearchClearButtons();
renderNotificationDock({ pageContext: 'report', collapsedByDefault: true });
@@ -418,18 +431,17 @@ function initReportPage() {
if (query) currentSprintHref += '?' + query;
} catch (_) {}
wrap.innerHTML = ''
- + ''
+ + ''
+ ''
+ '
'
+ ''
- + ''
- + '
';
- wrap.innerHTML += ''
+ + '
'
+ + '
'
+ ''
+ + 'Sprint'
+ '