From ec87a65e82b653695cce840c5c200db1c103b0ee Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Thu, 19 Dec 2024 21:44:57 +0000 Subject: [PATCH] Add status bar --- .github/workflows/docker-publish.yml | 2 +- plugin/src/events/sync-event-handler.ts | 2 +- plugin/src/plugin.ts | 5 +- .../{sync_service.ts => sync-service.ts} | 46 ++++++++++++++++++- .../apply-local-changes-remotely.ts | 2 +- .../apply-remote-changes-locally.ts | 4 +- .../sync-locally-created-file.ts | 2 +- .../sync-locally-deleted-file.ts | 2 +- .../sync-locally-updated-file.ts | 2 +- .../sync-remotely-updated-file.ts | 2 +- plugin/src/views/settings-tab.ts | 2 +- plugin/src/views/status-bar.ts | 21 +++++++++ 12 files changed, 80 insertions(+), 12 deletions(-) rename plugin/src/services/{sync_service.ts => sync-service.ts} (84%) create mode 100644 plugin/src/views/status-bar.ts diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 84e3e01..bfad786 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -77,7 +77,7 @@ jobs: # Sign the resulting Docker image digest except on PRs. # This will only write to the public Rekor transparency log when the Docker - # repository is public to avoid leaking data. If you would like to publish + # repository is public to avoid leaking data. If you would like to publish # transparency data even for private images, pass --force to cosign below. # https://github.com/sigstore/cosign - name: Sign the published Docker image diff --git a/plugin/src/events/sync-event-handler.ts b/plugin/src/events/sync-event-handler.ts index 8fb258c..d75a089 100644 --- a/plugin/src/events/sync-event-handler.ts +++ b/plugin/src/events/sync-event-handler.ts @@ -1,7 +1,7 @@ import { TAbstractFile, TFile } from "obsidian"; import { FileEventHandler } from "./file-event-handler"; import { Logger } from "src/logger"; -import { SyncService } from "src/services/sync_service"; +import { SyncService } from "src/services/sync-service"; import { Database } from "src/database/database"; import { syncLocallyDeletedFile } from "src/sync-operations/sync-locally-deleted-file"; import { syncLocallyUpdatedFile } from "src/sync-operations/sync-locally-updated-file"; diff --git a/plugin/src/plugin.ts b/plugin/src/plugin.ts index 62b2b3e..820dc80 100644 --- a/plugin/src/plugin.ts +++ b/plugin/src/plugin.ts @@ -9,11 +9,12 @@ import { SyncView } from "./views/sync-view"; import { Logger } from "./logger"; import { SyncEventHandler } from "./events/sync-event-handler"; -import { SyncService } from "./services/sync_service"; +import { SyncService } from "./services/sync-service"; import { Database } from "./database/database"; import { applyRemoteChangesLocally } from "./sync-operations/apply-remote-changes-locally"; import { ObsidianFileOperations } from "./file-operations/obsidian-file-operations"; import { applyLocalChangesRemotely } from "./sync-operations/apply-local-changes-remotely"; +import { StatusBar } from "./views/status-bar"; export default class SyncPlugin extends Plugin { private remoteListenerIntervalId: number | null = null; @@ -44,6 +45,8 @@ export default class SyncPlugin extends Plugin { const syncServer = new SyncService(database); + new StatusBar(this, syncServer); + this.addSettingTab( new SyncSettingsTab(this.app, this, database, syncServer) ); diff --git a/plugin/src/services/sync_service.ts b/plugin/src/services/sync-service.ts similarity index 84% rename from plugin/src/services/sync_service.ts rename to plugin/src/services/sync-service.ts index cbdd63a..472c29b 100644 --- a/plugin/src/services/sync_service.ts +++ b/plugin/src/services/sync-service.ts @@ -1,7 +1,7 @@ import * as lib from "../../../backend/sync_lib/pkg/sync_lib.js"; import createClient, { Client } from "openapi-fetch"; -import type { components, paths } from "./types"; // generated by openapi-typescript +import type { components, paths } from "./types.js"; // generated by openapi-typescript import { Logger } from "src/logger"; import { Database } from "src/database/database"; import { SyncSettings } from "src/database/sync-settings"; @@ -12,10 +12,24 @@ import { } from "src/database/document-metadata"; import PQueue from "p-queue"; +export interface RequestCountStatus { + waiting: number; + success: number; + failure: number; +} + export class SyncService { - private promiseQueue: PQueue; private client: Client; + private promiseQueue: PQueue; + private requestCountListeners: Array<(status: RequestCountStatus) => void> = + []; + private status: RequestCountStatus = { + waiting: 0, + success: 0, + failure: 0, + }; + public constructor(private database: Database) { this.createClient(database.getSettings()); this.promiseQueue = new PQueue({ @@ -26,6 +40,34 @@ export class SyncService { this.createClient(s); this.promiseQueue.concurrency = s.uploadConcurrency; }); + + this.promiseQueue.on("active", () => { + this.status.waiting = this.promiseQueue.pending; + this.emitRequestCountChange(); + }); + + this.promiseQueue.on("completed", () => { + this.status.success++; + this.emitRequestCountChange(); + }); + + this.promiseQueue.on("error", () => { + this.status.failure++; + this.emitRequestCountChange(); + }); + } + + public addRequestCountChangeListener( + listener: (status: RequestCountStatus) => void + ): void { + this.requestCountListeners.push(listener); + listener({ ...this.status }); + } + + private emitRequestCountChange(): void { + this.requestCountListeners.forEach((listener) => + listener({ ...this.status }) + ); } private createClient(settings: SyncSettings) { diff --git a/plugin/src/sync-operations/apply-local-changes-remotely.ts b/plugin/src/sync-operations/apply-local-changes-remotely.ts index 982d1f6..22b3286 100644 --- a/plugin/src/sync-operations/apply-local-changes-remotely.ts +++ b/plugin/src/sync-operations/apply-local-changes-remotely.ts @@ -1,5 +1,5 @@ import { Database } from "../database/database"; -import { SyncService } from "../services/sync_service"; +import { SyncService } from "../services/sync-service"; import { Logger } from "../logger"; import { FileOperations } from "../file-operations/file-operations"; import { syncLocallyCreatedFile } from "./sync-locally-created-file"; diff --git a/plugin/src/sync-operations/apply-remote-changes-locally.ts b/plugin/src/sync-operations/apply-remote-changes-locally.ts index e20e0f7..462e4fa 100644 --- a/plugin/src/sync-operations/apply-remote-changes-locally.ts +++ b/plugin/src/sync-operations/apply-remote-changes-locally.ts @@ -1,7 +1,7 @@ import { Database } from "src/database/database"; import { FileOperations } from "src/file-operations/file-operations"; import { Logger } from "src/logger"; -import { SyncService } from "src/services/sync_service"; +import { SyncService } from "src/services/sync-service"; import { syncRemotelyUpdatedFile } from "./sync-remotely-updated-file"; let isRunning = false; @@ -14,6 +14,8 @@ export async function applyRemoteChangesLocally( if (isRunning) { Logger.getInstance().info("Pull sync already in progress, skipping"); return; + } else { + Logger.getInstance().info("Starting pull sync"); } isRunning = true; diff --git a/plugin/src/sync-operations/sync-locally-created-file.ts b/plugin/src/sync-operations/sync-locally-created-file.ts index cbb828d..9828776 100644 --- a/plugin/src/sync-operations/sync-locally-created-file.ts +++ b/plugin/src/sync-operations/sync-locally-created-file.ts @@ -1,7 +1,7 @@ import * as lib from "../../../backend/sync_lib/pkg/sync_lib.js"; import { Database } from "src/database/database"; import { Logger } from "src/logger"; -import { SyncService } from "src/services/sync_service"; +import { SyncService } from "src/services/sync-service"; import { hash } from "src/utils/hash"; import { unlockDocument, waitForDocumentLock } from "./locks"; import { FileOperations } from "src/file-operations/file-operations"; diff --git a/plugin/src/sync-operations/sync-locally-deleted-file.ts b/plugin/src/sync-operations/sync-locally-deleted-file.ts index 2382c7a..f5d94b5 100644 --- a/plugin/src/sync-operations/sync-locally-deleted-file.ts +++ b/plugin/src/sync-operations/sync-locally-deleted-file.ts @@ -1,7 +1,7 @@ import { Database } from "src/database/database"; import { RelativePath } from "src/database/document-metadata"; import { Logger } from "src/logger"; -import { SyncService } from "src/services/sync_service"; +import { SyncService } from "src/services/sync-service"; import { unlockDocument, waitForDocumentLock } from "./locks"; export async function syncLocallyDeletedFile({ diff --git a/plugin/src/sync-operations/sync-locally-updated-file.ts b/plugin/src/sync-operations/sync-locally-updated-file.ts index 01c1b35..9a61b98 100644 --- a/plugin/src/sync-operations/sync-locally-updated-file.ts +++ b/plugin/src/sync-operations/sync-locally-updated-file.ts @@ -1,7 +1,7 @@ import * as lib from "../../../backend/sync_lib/pkg/sync_lib.js"; import { Database } from "src/database/database"; import { Logger } from "src/logger"; -import { SyncService } from "src/services/sync_service"; +import { SyncService } from "src/services/sync-service"; import { hash } from "src/utils/hash"; import { unlockDocument, waitForDocumentLock } from "./locks"; import { FileOperations } from "src/file-operations/file-operations"; diff --git a/plugin/src/sync-operations/sync-remotely-updated-file.ts b/plugin/src/sync-operations/sync-remotely-updated-file.ts index 8e10a28..b97aea8 100644 --- a/plugin/src/sync-operations/sync-remotely-updated-file.ts +++ b/plugin/src/sync-operations/sync-remotely-updated-file.ts @@ -1,6 +1,6 @@ import { Database } from "src/database/database"; import { unlockDocument, waitForDocumentLock } from "./locks"; -import { SyncService } from "src/services/sync_service"; +import { SyncService } from "src/services/sync-service"; import * as lib from "../../../backend/sync_lib/pkg/sync_lib.js"; import { hash } from "src/utils/hash"; import { Logger } from "src/logger"; diff --git a/plugin/src/views/settings-tab.ts b/plugin/src/views/settings-tab.ts index f3e10ac..a8c8640 100644 --- a/plugin/src/views/settings-tab.ts +++ b/plugin/src/views/settings-tab.ts @@ -2,7 +2,7 @@ import { App, Notice, PluginSettingTab, Setting } from "obsidian"; import SyncPlugin from "src/plugin"; import { Database } from "src/database/database"; -import { SyncService } from "src/services/sync_service"; +import { SyncService } from "src/services/sync-service"; export class SyncSettingsTab extends PluginSettingTab { private editedVaultName: string; diff --git a/plugin/src/views/status-bar.ts b/plugin/src/views/status-bar.ts new file mode 100644 index 0000000..ec83f75 --- /dev/null +++ b/plugin/src/views/status-bar.ts @@ -0,0 +1,21 @@ +import { Plugin } from "obsidian"; +import { RequestCountStatus, SyncService } from "src/services/sync-service"; + +export class StatusBar { + private statusBarItem: HTMLElement; + + public constructor(plugin: Plugin, service: SyncService) { + this.statusBarItem = plugin.addStatusBarItem(); + service.addRequestCountChangeListener((status) => + this.updateStatus(status) + ); + } + + private updateStatus({ + waiting, + success, + failure, + }: RequestCountStatus): void { + this.statusBarItem.setText(`${waiting} 🔄 ${success} ✅ ${failure} ❌`); + } +}