Choose a system or branch to narrow every dashboard measure to that scope. Patron values use current-account eligibility; small groups remain privacy-suppressed.
Choose a system or branch to narrow every dashboard measure to that scope.${mode === 'patrons' ? ' Small patron groups remain privacy-suppressed.' : ''}
+ ${systems.length ? `
System totals
${breakdownTable(systems, { mode, level: 'system' })}` : ''}
+ All ${formatNumber(branches.length)} branch totals${breakdownTable(branches, { mode, level: 'branch' })}`;
}
@@ -232,11 +246,13 @@ function renderOverview(data) {
? ' · item type does not apply'
: '';
return `${dashboardIntro(data, 'What is being used—and where to act', 'A combined view of circulation demand, collection performance, and community reach. Every number keeps its source and time basis visible.')}
-
+
${metricCard('Checkouts', hasCirculation ? formatNumber(circ.checkouts) : '—', hasCirculation ? periodComparisonDetail(circ, 'checkouts', data.scope?.comparison_mode) : 'Period transaction feed not available', hasCirculation ? 'success' : '', data.metricDefinitions.checkouts)}
${metricCard('Renewals', hasCirculation ? formatNumber(circ.renewals) : '—', hasCirculation ? periodComparisonDetail(circ, 'renewals', data.scope?.comparison_mode) : 'Period transaction feed not available', '', data.metricDefinitions.renewals)}
+ ${metricCard('Total circulation', hasCirculation ? formatNumber(Number(circ.activity || 0) || Number(circ.checkouts || 0) + Number(circ.renewals || 0)) : '—', hasCirculation ? `${circ.period_label || 'Selected period'} · checkouts plus renewals` : 'Period transaction feed not available', '', data.metricDefinitions.turnover)}
${metricCard('Current items', hasCollection ? formatNumber(collection.items) : '—', hasCollection ? (collection.titles ? `${formatNumber(collection.titles)} titles represented` : 'Actual current item records') : 'Current item snapshot not available', '', data.metricDefinitions.items)}
${metricCard('Used recently', hasCollection ? formatPercent(collection.recent_use_rate) : '—', hasCollection ? `${activityWindow} · ${formatNumber(collection.used_recently)} items with recorded use` : 'Current item snapshot not available', hasCollection ? 'success' : '', data.metricDefinitions.used_recently)}
+ ${metricCard('Current patrons', hasPatrons ? formatNumber(patrons.total) : '—', hasPatrons ? (patrons.eligibility_label || 'Unexpired or non-expiring accounts') : 'Patron aggregate not available', '', data.metricDefinitions.current_patrons)}
${metricCard('Active patrons', hasPatrons ? formatNumber(patrons.active) : '—', hasPatrons ? `${activityWindow} · ${formatPercent(patrons.active_rate)} of current patrons${patronScopeNote}` : 'Patron aggregate not available', '', data.metricDefinitions.active_patrons)}
${metricCard('New patrons', hasPatrons ? formatNumber(patrons.new) : '—', hasPatrons ? `${patrons.new_period_label || 'Created in the selected period'}${patronScopeNote}` : 'Patron aggregate not available', '', data.metricDefinitions.new_patrons)}
@@ -246,7 +262,7 @@ function renderOverview(data) {
Demand by item type
Select a format to see every applicable KPI for that item type.
Actionable groups that can open as an exact Query report.
${opportunityTable(data.opportunities)}${serviceCoverageSection(data)}${sourceNotes(data)}`;
}
@@ -272,8 +288,18 @@ function renderCollection(data) {
Collection age
Current items by creation-date band.
${rankedBars(data.ageBands, 'items')}
Hold pressure
Demand indicators for copies and titles currently in scope.
${metricCard('Open holds', formatNumber(circ.holds), `${Number(circ.holds_per_100_items || 0).toFixed(1)} per 100 items`)}
Recently used
Items with a recorded last-use date in the ${activityWindow.toLowerCase()}.
${metricCard('Recent-use rate', formatPercent(collection.recent_use_rate), `${activityWindow} · ${formatNumber(collection.used_recently)} of ${formatNumber(collection.items)} items`)}
+
Inventory and availability health
Current operational risks and inventory coverage for the selected collection.
+
+ ${metricCard('Inventory coverage', formatPercent(collection.inventory_coverage), `${formatNumber(collection.inventoried)} of ${formatNumber(collection.items)} items have an inventory date`, '', data.metricDefinitions.inventory_coverage)}
+ ${metricCard('Inventoried recently', formatNumber(collection.inventoried_last_365_days), 'Inventory date recorded in the last 12 months')}
+ ${metricCard('Unavailable', formatNumber(collection.unavailable_items), `${formatPercent(collection.unavailable_rate)} of current items`, collection.unavailable_rate > 0.2 ? 'active' : '')}
+ ${metricCard('Missing or lost', formatNumber(collection.missing_lost_items), `${percentage(collection.missing_lost_items, collection.items)} of current items`, collection.missing_lost_items > 0 ? 'active' : '')}
+ ${metricCard('In transit', formatNumber(collection.in_transit_items), 'Items currently assigned an in-transit location')}
+ ${metricCard('Price coverage', formatPercent(collection.price_coverage), `${formatMoney(collection.total_value)} recorded collection value`)}
+
+
Collection-development queue
Open the underlying records to review, sort, or export them.