diff --git a/src/meshcore_hub/web/static/js/spa/components.js b/src/meshcore_hub/web/static/js/spa/components.js
index aa18d3c..eb3af35 100644
--- a/src/meshcore_hub/web/static/js/spa/components.js
+++ b/src/meshcore_hub/web/static/js/spa/components.js
@@ -8,6 +8,7 @@ import { html, nothing } from 'lit-html';
import { render } from 'lit-html';
import { unsafeHTML } from 'lit-html/directives/unsafe-html.js';
import { t } from './i18n.js';
+import { iconAlert } from './icons.js';
// Re-export lit-html utilities for page modules
export { html, nothing, unsafeHTML };
@@ -381,6 +382,17 @@ export function successAlert(message) {
`;
}
+/**
+ * Render a warning badge with tooltip for transient API errors.
+ * @param {string} message - Error message to display as tooltip
+ * @returns {TemplateResult}
+ */
+export function warningBadge(message) {
+ return html`
+ ${iconAlert('h-4 w-4')}
+ `;
+}
+
/**
* Render pagination controls.
* @param {number} page - Current page (1-based)
diff --git a/src/meshcore_hub/web/static/js/spa/pages/advertisements.js b/src/meshcore_hub/web/static/js/spa/pages/advertisements.js
index 0c18aee..c62e800 100644
--- a/src/meshcore_hub/web/static/js/spa/pages/advertisements.js
+++ b/src/meshcore_hub/web/static/js/spa/pages/advertisements.js
@@ -2,7 +2,7 @@ import { apiGet } from '../api.js';
import {
html, litRender, nothing, t,
getConfig, formatDateTime, formatDateTimeShort, formatRelativeTime,
- truncateKey, errorAlert,
+ truncateKey, warningBadge,
pagination, createFilterHandler, autoSubmit, submitOnEnter, copyToClipboard, renderNodeDisplay,
observerIcons, observerDetailRow, toggleObserverDetail, toggleCardObserverDetail
} from '../components.js';
@@ -24,17 +24,29 @@ export async function render(container, params, router) {
const tzBadge = tz && tz !== 'UTC' ? html`${tz}` : nothing;
const navigate = (url) => router.navigate(url);
- function renderPage(content, { total = null } = {}) {
+ let lastContent = nothing;
+ let lastTotal = null;
+
+ function renderPage(content, { total = null, error = null } = {}) {
+ if (!error) {
+ lastContent = content;
+ lastTotal = total;
+ }
+ const displayContent = error ? lastContent : content;
+ const displayTotal = error ? lastTotal : total;
litRender(html`
-
+
${t('entities.advertisements')}
-
-
- ${tzBadge}
- ${total !== null ? html`${t('common.total', { count: total })}` : nothing}
-
+ ${tzBadge}
-${content}`, container);
+
+ ${displayTotal !== null
+ ? html`${t('common.total', { count: displayTotal })}`
+ : nothing}
+
+ ${error ? warningBadge(error) : nothing}
+
+${displayContent}`, container);
}
// Render page header immediately (old content stays visible until data loads)
@@ -223,7 +235,7 @@ ${content}`, container);
${paginationBlock}`, { total });
} catch (e) {
- renderPage(errorAlert(e.message));
+ renderPage(nothing, { error: e.message });
}
}
diff --git a/src/meshcore_hub/web/static/js/spa/pages/messages.js b/src/meshcore_hub/web/static/js/spa/pages/messages.js
index fed6bc6..9b0a41b 100644
--- a/src/meshcore_hub/web/static/js/spa/pages/messages.js
+++ b/src/meshcore_hub/web/static/js/spa/pages/messages.js
@@ -3,7 +3,7 @@ import {
html, litRender, nothing, t,
getConfig, formatDateTime, formatDateTimeShort, formatRelativeTime,
getChannelLabelsMap, resolveChannelLabel,
- truncateKey, errorAlert,
+ truncateKey, warningBadge,
pagination, timezoneIndicator,
createFilterHandler, autoSubmit, submitOnEnter,
observerIcons, observerDetailRow, toggleObserverDetail, toggleCardObserverDetail
@@ -169,17 +169,29 @@ export async function render(container, params, router) {
return deduped;
}
- function renderPage(content, { total = null } = {}) {
+ let lastContent = nothing;
+ let lastTotal = null;
+
+ function renderPage(content, { total = null, error = null } = {}) {
+ if (!error) {
+ lastContent = content;
+ lastTotal = total;
+ }
+ const displayContent = error ? lastContent : content;
+ const displayTotal = error ? lastTotal : total;
litRender(html`
-
+
${t('entities.messages')}
-
-
- ${tzBadge}
- ${total !== null ? html`${t('common.total', { count: total })}` : nothing}
-
+ ${tzBadge}
-${content}`, container);
+
+ ${displayTotal !== null
+ ? html`${t('common.total', { count: displayTotal })}`
+ : nothing}
+
+ ${error ? warningBadge(error) : nothing}
+
+${displayContent}`, container);
}
// Render page header immediately (old content stays visible until data loads)
@@ -348,7 +360,7 @@ ${content}`, container);
${paginationBlock}`, { total });
} catch (e) {
- renderPage(errorAlert(e.message));
+ renderPage(nothing, { error: e.message });
}
}
diff --git a/src/meshcore_hub/web/static/js/spa/pages/nodes.js b/src/meshcore_hub/web/static/js/spa/pages/nodes.js
index e6a072c..0c0f529 100644
--- a/src/meshcore_hub/web/static/js/spa/pages/nodes.js
+++ b/src/meshcore_hub/web/static/js/spa/pages/nodes.js
@@ -2,7 +2,7 @@ import { apiGet } from '../api.js';
import {
html, litRender, nothing,
getConfig, formatDateTime, formatDateTimeShort,
- truncateKey, errorAlert,
+ truncateKey, warningBadge,
pagination, timezoneIndicator,
createFilterHandler, autoSubmit, submitOnEnter, copyToClipboard, renderNodeDisplay, t
} from '../components.js';
@@ -24,17 +24,29 @@ export async function render(container, params, router) {
const tzBadge = tz && tz !== 'UTC' ? html`
${tz}` : nothing;
const navigate = (url) => router.navigate(url);
- function renderPage(content, { total = null } = {}) {
+ let lastContent = nothing;
+ let lastTotal = null;
+
+ function renderPage(content, { total = null, error = null } = {}) {
+ if (!error) {
+ lastContent = content;
+ lastTotal = total;
+ }
+ const displayContent = error ? lastContent : content;
+ const displayTotal = error ? lastTotal : total;
litRender(html`
-
+
${t('entities.nodes')}
-
-
- ${tzBadge}
- ${total !== null ? html`${t('common.total', { count: total })}` : nothing}
-
+ ${tzBadge}
-${content}`, container);
+
+ ${displayTotal !== null
+ ? html`${t('common.total', { count: displayTotal })}`
+ : nothing}
+
+ ${error ? warningBadge(error) : nothing}
+
+${displayContent}`, container);
}
// Render page header immediately (old content stays visible until data loads)
@@ -195,7 +207,7 @@ ${content}`, container);
${paginationBlock}`, { total });
} catch (e) {
- renderPage(errorAlert(e.message));
+ renderPage(nothing, { error: e.message });
}
}