Skip to content

Commit 71f4fc8

Browse files
committed
fix: for dashboard document, handle data fetching error
1 parent b903070 commit 71f4fc8

1 file changed

Lines changed: 23 additions & 10 deletions

File tree

DOCS/CDSE_Migration/CLMS_CDSE_Migration_Dashboard.qmd

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,18 @@ author: "Copernicus Land Monitoring Service"
55
date: 2026-07-16
66
category: non-browsable
77
type: dashboard
8-
execute:
9-
echo: false
10-
format:
11-
html:
12-
code-fold: false
138
---
149

1510

1611

1712
```{ojs}
1813
// ── Load data from the canonical data repo ──
1914
data = await fetch("https://raw.githubusercontent.com/copernicus-land/clms-cdse-migration-data/main/migration_data.json")
20-
.then(r => { if (!r.ok) throw new Error(String(r.status)); return r.json() })
21-
.catch(e => { console.error("Failed to load data", e); return {groups:[], portfolio:{}, cdse:{}, summary:{}} })
15+
.then(r => { if (!r.ok) throw new Error("HTTP " + r.status); return r.json() })
16+
// On failure, return a COMPLETE empty shape (every field the cells below read)
17+
// plus `_loadError`, so nothing downstream throws and the dynamic blocks can
18+
// show an error section instead of crashing the OJS runtime.
19+
.catch(e => { console.error("Failed to load data", e); return {_loadError: String(e && e.message || e), groups:[], portfolio:{}, cdse:{}, summary:{}, scraped_at:"", odata_tracking:{history:[]}, previous:{groups:[]}} })
2220
groups = data.groups
2321
summary = data.summary
2422
portfolio = data.portfolio
@@ -102,6 +100,14 @@ check = (on) => on
102100
? htl.html`<span style="color:#00aa00;font-weight:bold">✓</span>`
103101
: htl.html`<span style="color:#ccc">✗</span>`
104102
103+
// ── Error banner shown in place of the dynamic blocks when the live data
104+
// load failed. A FUNCTION (not a plain cell) so Quarto doesn't auto-display it;
105+
// it's only rendered when a gated block calls errorSection(). ──
106+
errorSection = () => htl.html`<div style="border:1px solid #e0b4b4;background:#fff6f6;border-radius:6px;padding:16px;margin:12px 0;color:#912d2b">
107+
<strong>Dashboard data could not be loaded.</strong>
108+
<div style="margin-top:6px">The live data source did not respond${data._loadError ? htl.html` (${data._loadError})` : ""}. Please refresh the page or try again later.</div>
109+
</div>`
110+
105111
// ── Deltas vs previous run, computed client-side from the embedded snapshot ──
106112
prevByName = Object.fromEntries((data.previous?.groups || []).map(g => [g.name, g]))
107113
changes = (data.previous?.groups?.length ? groups : []).map(g => {
@@ -251,7 +257,9 @@ onboardingPlot = {
251257
## Migration Statistics
252258

253259
```{ojs}
254-
html`
260+
{
261+
if (data._loadError) return errorSection();
262+
return html`
255263
${newGroups.length > 0 ? htl.html `
256264
<div style="background:#e8f5e9;border:1px solid #a5d6a7;border-radius:6px;padding:12px;margin:12px 0">
257265
<strong>🆕 Products ${lastWeek}</strong>
@@ -272,7 +280,8 @@ ${(odataWeeklyDelta || odataDailyDelta || odataHist.length > 0) ? htl.html `
272280
${odataDailyAvg ? htl.html `<div style="margin:4px 0;color:#888;font-size:0.85em">Daily average: ${odataDailyAvg.toLocaleString()} new files/day</div>` : ""}
273281
${onboardingPlot}
274282
</div>` : ""}
275-
`
283+
`;
284+
}
276285
```
277286

278287
## CLMS Product on CDSE
@@ -283,6 +292,7 @@ This table shows the full, currently active CLMS portfolio and each product's mi
283292
// (multi-select, all enabled by default). Replaces the old single-select
284293
// dropdown, which only let one component be viewed at a time.
285294
viewof activeComponents = {
295+
if (data._loadError) { const el = document.createElement("span"); el.value = new Set(); return el; }
286296
const allComponents = [...new Set(groups.map(d => componentOf(d)).filter(Boolean))].sort()
287297
const active = new Set(allComponents)
288298
@@ -312,14 +322,17 @@ viewof activeComponents = {
312322
return container;
313323
}
314324
315-
viewof searchTerm = Inputs.text({label: "Search", placeholder: "Product group…", width: 250})
325+
viewof searchTerm = data._loadError
326+
? Object.assign(document.createElement("span"), { value: "" })
327+
: Inputs.text({label: "Search", placeholder: "Product group…", width: 250})
316328
```
317329

318330
```{ojs}
319331
// ── Build the table via plain DOM APIs ──
320332
// so that column widths defined on <colgroup> are guaranteed to apply to
321333
// every row, including rows toggled between hidden/visible.
322334
productGroupsTable = {
335+
if (data._loadError) return htl.html``;
323336
// Category takes the remaining width (~46%) now that Progress is gone
324337
const colWidths = ["auto", "9%", "9%", "9%", "9%", "9%", "9%"];
325338

0 commit comments

Comments
 (0)