diff --git a/surfsense_obsidian/src/settings.ts b/surfsense_obsidian/src/settings.ts index 1191e5b7a..4dc6a732f 100644 --- a/surfsense_obsidian/src/settings.ts +++ b/surfsense_obsidian/src/settings.ts @@ -4,6 +4,7 @@ import { Platform, PluginSettingTab, Setting, + setIcon, } from "obsidian"; import { AuthError } from "./api-client"; import { normalizeFolder, parseExcludePatterns } from "./excludes"; @@ -29,7 +30,7 @@ export class SurfSenseSettingTab extends PluginSettingTab { const settings = this.plugin.settings; - new Setting(containerEl).setName("Connection").setHeading(); + this.renderConnectionHeading(containerEl); new Setting(containerEl) .setName("Server URL") @@ -262,6 +263,53 @@ export class SurfSenseSettingTab extends PluginSettingTab { ); } + private renderConnectionHeading(containerEl: HTMLElement): void { + const heading = new Setting(containerEl).setName("Connection").setHeading(); + const indicator = heading.nameEl.createSpan({ + cls: "surfsense-connection-indicator", + }); + const visual = this.getConnectionVisual(); + indicator.addClass(`surfsense-connection-indicator--${visual.tone}`); + setIcon(indicator, visual.icon); + indicator.setAttr("aria-label", visual.label); + indicator.setAttr("title", visual.label); + } + + private getConnectionVisual(): { + icon: string; + label: string; + tone: "ok" | "syncing" | "warn" | "err" | "muted"; + } { + const settings = this.plugin.settings; + const kind = this.plugin.lastStatus.kind; + + if (kind === "auth-error") { + return { icon: "lock", label: "Token invalid or expired", tone: "err" }; + } + if (kind === "error") { + return { icon: "alert-circle", label: "Connection error", tone: "err" }; + } + if (kind === "offline") { + return { icon: "wifi-off", label: "Server unreachable", tone: "warn" }; + } + + if (!settings.apiToken) { + return { icon: "circle", label: "Missing API token", tone: "muted" }; + } + if (!settings.searchSpaceId) { + return { icon: "circle", label: "Pick a search space", tone: "muted" }; + } + if (!settings.connectorId) { + return { icon: "circle", label: "Not connected yet", tone: "muted" }; + } + + if (kind === "syncing" || kind === "queued") { + return { icon: "refresh-ccw", label: "Connected and syncing", tone: "syncing" }; + } + + return { icon: "check-circle", label: "Connected", tone: "ok" }; + } + private async refreshSearchSpaces(): Promise { this.loadingSpaces = true; try { diff --git a/surfsense_obsidian/styles.css b/surfsense_obsidian/styles.css index 81b2203f3..586ddffa6 100644 --- a/surfsense_obsidian/styles.css +++ b/surfsense_obsidian/styles.css @@ -37,3 +37,36 @@ .surfsense-status--err .surfsense-status__icon { color: var(--color-red); } + +.surfsense-connection-indicator { + display: inline-flex; + margin-left: 8px; + vertical-align: middle; + width: 14px; + height: 14px; +} + +.surfsense-connection-indicator svg { + width: 14px; + height: 14px; +} + +.surfsense-connection-indicator--ok { + color: var(--color-green); +} + +.surfsense-connection-indicator--syncing { + color: var(--color-blue); +} + +.surfsense-connection-indicator--warn { + color: var(--color-yellow); +} + +.surfsense-connection-indicator--err { + color: var(--color-red); +} + +.surfsense-connection-indicator--muted { + color: var(--text-muted); +}