updated: app/data-service.js, app/styles.css, app/ui-settings.js, index.html

This commit is contained in:
2026-05-28 23:52:29 -07:00
parent 1433ec1495
commit ed1107a0c0
4 changed files with 174 additions and 2 deletions
+108
View File
@@ -24,6 +24,8 @@
onRenderWeek: null
};
let lastConnectionProbeResult = null;
let lastNonSettingsSection = "home";
function getElements() {
@@ -42,6 +44,11 @@
stellariumBackgroundHintEl: document.getElementById("stellarium-background-hint"),
apiBaseUrlEl: document.getElementById("api-base-url"),
apiKeyEl: document.getElementById("api-key"),
apiConnectionSummaryEl: document.getElementById("api-connection-summary"),
apiConnectionSummaryStateEl: document.getElementById("api-connection-summary-state"),
apiConnectionSummaryClientEl: document.getElementById("api-connection-summary-client"),
apiConnectionSummaryAccessEl: document.getElementById("api-connection-summary-access"),
apiConnectionSummaryPermissionsEl: document.getElementById("api-connection-summary-permissions"),
settingsPageStatusEl: document.getElementById("settings-page-status"),
settingsPageStatusTextEl: document.getElementById("settings-page-status-text"),
settingsPageStatusTimeEl: document.getElementById("settings-page-status-time"),
@@ -192,6 +199,98 @@
|| String(previous?.apiKey || "").trim() !== String(next?.apiKey || "").trim();
}
function normalizeConnectionValues(values) {
return Array.isArray(values)
? values.map((entry) => String(entry || "").trim()).filter(Boolean)
: [];
}
function hasAdminCapability(auth) {
const roles = normalizeConnectionValues(auth?.roles);
const scopes = normalizeConnectionValues(auth?.scopes);
return roles.includes("admin") || scopes.includes("api:admin");
}
function formatConnectionValues(values, fallback = "none") {
const normalized = normalizeConnectionValues(values);
return normalized.length ? normalized.join(", ") : fallback;
}
function setConnectionSummary(result = null) {
const {
apiConnectionSummaryEl,
apiConnectionSummaryStateEl,
apiConnectionSummaryClientEl,
apiConnectionSummaryAccessEl,
apiConnectionSummaryPermissionsEl
} = getElements();
if (!apiConnectionSummaryEl) {
return;
}
if (!result) {
apiConnectionSummaryEl.dataset.tone = "neutral";
if (apiConnectionSummaryStateEl) {
apiConnectionSummaryStateEl.textContent = "Not checked yet.";
}
if (apiConnectionSummaryClientEl) {
apiConnectionSummaryClientEl.textContent = "No authenticated API identity.";
}
if (apiConnectionSummaryAccessEl) {
apiConnectionSummaryAccessEl.textContent = "Unknown";
}
if (apiConnectionSummaryPermissionsEl) {
apiConnectionSummaryPermissionsEl.textContent = "Save settings to validate this API key.";
}
return;
}
const tone = result.ok ? "success" : (result.reason === "auth-required" ? "warning" : "error");
const auth = result.auth || result.health?.auth || {};
const roles = normalizeConnectionValues(auth.roles);
const scopes = normalizeConnectionValues(auth.scopes);
const authenticated = auth.authenticated === true;
const accessValue = authenticated
? `${String(auth.accessLevel || "premium").trim() || "premium"}${hasAdminCapability(auth) ? " - admin capable" : ""}`
: (result.health?.apiKeyRequired ? "API key required" : "public");
const permissionsValue = authenticated
? `roles: ${formatConnectionValues(roles)} | scopes: ${formatConnectionValues(scopes)}`
: (result.message || "Unable to validate the API connection.");
apiConnectionSummaryEl.dataset.tone = tone;
if (apiConnectionSummaryStateEl) {
apiConnectionSummaryStateEl.textContent = result.ok
? `Connected${Number.isInteger(result.deckCount) ? `${result.deckCount} deck${result.deckCount === 1 ? "" : "s"}` : ""}`
: String(result.message || "Unable to validate the API connection.");
}
if (apiConnectionSummaryClientEl) {
apiConnectionSummaryClientEl.textContent = authenticated
? [String(auth.clientId || "").trim(), String(auth.accountId || "").trim()].filter(Boolean).join(" / ") || "Authenticated client"
: (result.health?.apiKeyRequired ? "No valid API identity returned." : "Public access");
}
if (apiConnectionSummaryAccessEl) {
apiConnectionSummaryAccessEl.textContent = accessValue;
}
if (apiConnectionSummaryPermissionsEl) {
apiConnectionSummaryPermissionsEl.textContent = permissionsValue;
}
}
async function refreshConnectionSummary(connectionSettings = getConnectionSettings(), { probeResult = null } = {}) {
const apiBaseUrl = String(connectionSettings?.apiBaseUrl || "").trim();
if (!apiBaseUrl) {
lastConnectionProbeResult = null;
setConnectionSummary(null);
return null;
}
const result = probeResult || await window.TarotDataService?.probeConnection?.(connectionSettings) || null;
lastConnectionProbeResult = result;
setConnectionSummary(result);
return result;
}
function setStatus(text) {
if (typeof config.onStatus === "function") {
@@ -571,6 +670,9 @@
}
applySettingsToInputs(loadSavedSettings());
syncSavedSettingsStatus();
void refreshConnectionSummary(getConnectionSettings(), {
probeResult: lastConnectionProbeResult
});
config.setActiveSection?.("settings");
}
@@ -595,8 +697,12 @@
const probeResult = await window.TarotDataService?.probeConnection?.(connectionSettings);
if (!probeResult?.ok) {
setConnectionSummary(probeResult);
throw new Error(probeResult?.message || "Unable to validate the API connection.");
}
lastConnectionProbeResult = probeResult;
setConnectionSummary(probeResult);
}
const connectionResult = window.TarotAppConfig?.updateConnectionSettings?.(connectionSettings) || { didPersist: true };
@@ -738,6 +844,7 @@
syncConnectionInputs();
syncTarotDeckInputOptions();
syncDeckCacheStatus(window.TarotCardImages?.getDeckPreloadStatus?.());
void refreshConnectionSummary(getConnectionSettings());
});
document.addEventListener("tarot:deck-cache-status", (event) => {
@@ -756,6 +863,7 @@
};
syncSavedSettingsStatus();
setConnectionSummary(lastConnectionProbeResult);
bindInteractions();
}