import type { Database } from "src/database/database"; import type { CheckConnectionResult, SyncService } from "src/services/sync-service"; import type { Syncer } from "src/sync-operations/syncer"; import type { HistoryStats, SyncHistory } from "src/tracing/sync-history"; export class StatusDescription { private lastHistoryStats: HistoryStats | undefined; private lastRemaining: number | undefined; private lastConnectionState: CheckConnectionResult | undefined; private statusChangeListeners: (() => void)[] = []; public constructor( private readonly database: Database, private readonly syncService: SyncService, history: SyncHistory, syncer: Syncer ) { void this.updateConnectionState(); history.addSyncHistoryUpdateListener((status) => { this.lastHistoryStats = status; this.updateDescription(); }); syncer.addRemainingOperationsListener((remainingOperations) => { this.lastRemaining = remainingOperations; this.updateDescription(); }); database.addOnSettingsChangeHandlers(() => { void this.updateConnectionState(); }); } public async updateConnectionState(): Promise { this.lastConnectionState = await this.syncService.checkConnection(); this.updateDescription(); } public addStatusChangeListener(listener: () => void): void { this.statusChangeListeners.push(listener); } public removeStatusChangeListener(listener: () => void): void { this.statusChangeListeners = this.statusChangeListeners.filter( (l) => l !== listener ); } public renderStatusDescription(container: HTMLElement): void { container.empty(); container.addClass("status-description"); if (this.lastConnectionState == undefined) { container.createSpan({ text: "VaultLink is starting up…", cls: "warning" }); return; } if (!this.lastConnectionState.isSuccessful) { container.createSpan({ text: `VaultLink failed to connect to the remote server with the error "${this.lastConnectionState.message}"`, cls: "error" }); return; } container.createSpan({ text: "VaultLink is connected to the server " }); container.createEl("a", { text: this.database.getSettings().remoteUri, href: this.database.getSettings().remoteUri }); container.createSpan({ text: ` and has indexed approximately ` }); container.createSpan({ text: `${this.database.getDocuments().size}`, cls: "number" }); container.createSpan({ text: ` documents. ` }); if ( (this.lastRemaining ?? 0) === 0 && (this.lastHistoryStats?.success ?? 0) === 0 && (this.lastHistoryStats?.error ?? 0) === 0 ) { if (this.database.getSettings().isSyncEnabled) { container.createSpan({ text: "Syncing is enabled but VaultLink hasn't found anything to sync yet." }); } else { container.createSpan({ text: "However, syncing is disabled right now.", cls: "warning" }); } return; } container.createSpan({ text: "The plugin has " }); container.createSpan({ text: `${this.lastRemaining ?? 0}`, cls: "number" }); container.createSpan({ text: " outstanding operations while having succeeded " }); container.createSpan({ text: `${this.lastHistoryStats?.success ?? 0}`, cls: ["number", "good"] }); container.createSpan({ text: " times and failed " }); container.createSpan({ text: `${this.lastHistoryStats?.error ?? 0}`, cls: ["number", "bad"] }); container.createSpan({ text: " times." }); } private updateDescription(): void { this.statusChangeListeners.forEach((listener) => { listener(); }); } }