Improve editor sync status line
This commit is contained in:
parent
47f4ddfc63
commit
376008de54
7 changed files with 209 additions and 148 deletions
|
|
@ -1,10 +1,10 @@
|
||||||
import type {
|
import type {
|
||||||
|
MarkdownView,
|
||||||
Editor,
|
Editor,
|
||||||
MarkdownFileInfo,
|
MarkdownFileInfo,
|
||||||
TAbstractFile,
|
TAbstractFile,
|
||||||
WorkspaceLeaf
|
WorkspaceLeaf
|
||||||
} from "obsidian";
|
} from "obsidian";
|
||||||
import type { MarkdownView } from "obsidian";
|
|
||||||
import { Platform, Plugin, TFile } from "obsidian";
|
import { Platform, Plugin, TFile } from "obsidian";
|
||||||
import "../manifest.json";
|
import "../manifest.json";
|
||||||
import { HistoryView } from "./views/history/history-view";
|
import { HistoryView } from "./views/history/history-view";
|
||||||
|
|
@ -15,7 +15,7 @@ import { SyncClient, rateLimit, DEFAULT_SETTINGS, Logger } from "sync-client";
|
||||||
import { ObsidianFileSystemOperations } from "./obsidian-file-system";
|
import { ObsidianFileSystemOperations } from "./obsidian-file-system";
|
||||||
import { SyncSettingsTab } from "./views/settings/settings-tab";
|
import { SyncSettingsTab } from "./views/settings/settings-tab";
|
||||||
import { logToConsole } from "./utils/log-to-console";
|
import { logToConsole } from "./utils/log-to-console";
|
||||||
import { updateEditorStatusDisplay } from "./views/editor-sync-line/editor-sync-line";
|
import { EditorStatusDisplayManager } from "./views/editor-status-display-manager/editor-status-display-manager";
|
||||||
import { remoteCursorsTheme } from "./views/cursors/remote-cursor-theme";
|
import { remoteCursorsTheme } from "./views/cursors/remote-cursor-theme";
|
||||||
import {
|
import {
|
||||||
remoteCursorsPlugin,
|
remoteCursorsPlugin,
|
||||||
|
|
@ -124,17 +124,23 @@ export default class VaultLinkPlugin extends Plugin {
|
||||||
this.registerEditorEvents();
|
this.registerEditorEvents();
|
||||||
await this.client.start();
|
await this.client.start();
|
||||||
|
|
||||||
const interval = setInterval(() => {
|
const editorStatusDisplayManager = new EditorStatusDisplayManager(
|
||||||
updateEditorStatusDisplay(this.app.workspace, this.client);
|
this,
|
||||||
}, 200);
|
this.app.workspace,
|
||||||
|
this.client
|
||||||
|
);
|
||||||
this.disposables.push(() => {
|
this.disposables.push(() => {
|
||||||
clearInterval(interval);
|
editorStatusDisplayManager.stop();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public onunload(): void {
|
public onunload(): void {
|
||||||
this.client.stop();
|
this.client.waitAndStop().catch((err: unknown) => {
|
||||||
|
this.client.logger.error(
|
||||||
|
`Error while stopping the sync client: ${err}`
|
||||||
|
);
|
||||||
|
});
|
||||||
this.disposables.forEach((disposable) => {
|
this.disposables.forEach((disposable) => {
|
||||||
disposable();
|
disposable();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
import type { Workspace } from "obsidian";
|
||||||
|
import { FileView, setIcon } from "obsidian";
|
||||||
|
import type { SyncClient } from "sync-client";
|
||||||
|
import { DocumentSyncStatus } from "sync-client";
|
||||||
|
import "./editor-status-display-manager.scss";
|
||||||
|
import type VaultLinkPlugin from "src/vault-link-plugin";
|
||||||
|
import { HistoryView } from "../history/history-view";
|
||||||
|
|
||||||
|
export class EditorStatusDisplayManager {
|
||||||
|
private static readonly UPDATE_INTERVAL_IN_MS = 100;
|
||||||
|
|
||||||
|
private readonly intervalId: NodeJS.Timeout;
|
||||||
|
private readonly lastStatuses = new Map<string, DocumentSyncStatus>();
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
private readonly plugin: VaultLinkPlugin,
|
||||||
|
private readonly workspace: Workspace,
|
||||||
|
private readonly client: SyncClient
|
||||||
|
) {
|
||||||
|
this.intervalId = setInterval(() => {
|
||||||
|
this.updateEditorStatusDisplay();
|
||||||
|
}, EditorStatusDisplayManager.UPDATE_INTERVAL_IN_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public stop(): void {
|
||||||
|
clearInterval(this.intervalId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateEditorStatusDisplay(): void {
|
||||||
|
this.workspace.iterateAllLeaves((leaf) => {
|
||||||
|
if (leaf.view instanceof FileView) {
|
||||||
|
const filePath = leaf.view.file?.path;
|
||||||
|
if (filePath == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const element = this.getElementFromLeaf(leaf.view);
|
||||||
|
if (element == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const previousStatus = this.lastStatuses.get(filePath);
|
||||||
|
const currentStatus =
|
||||||
|
this.client.getDocumentSyncingStatus(filePath);
|
||||||
|
if (previousStatus === currentStatus) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.lastStatuses.set(filePath, currentStatus);
|
||||||
|
|
||||||
|
if (currentStatus == DocumentSyncStatus.SYNCING_IS_DISABLED) {
|
||||||
|
element.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentStatus == DocumentSyncStatus.SYNCING) {
|
||||||
|
element.classList.add("loading");
|
||||||
|
} else {
|
||||||
|
element.classList.remove("loading");
|
||||||
|
}
|
||||||
|
|
||||||
|
const iconContainer = element.querySelector(".icon");
|
||||||
|
if (iconContainer != null) {
|
||||||
|
setIcon(
|
||||||
|
iconContainer as HTMLElement, // eslint-disable-line @typescript-eslint/no-unsafe-type-assertion
|
||||||
|
currentStatus == DocumentSyncStatus.SYNCING
|
||||||
|
? "loader"
|
||||||
|
: "circle-check"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private getElementFromLeaf(fileView: FileView): Element | undefined {
|
||||||
|
const parent = fileView.contentEl.querySelector(".cm-editor");
|
||||||
|
if (parent == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
parent.querySelector(".vault-link-sync-status") ??
|
||||||
|
parent.createDiv(
|
||||||
|
{
|
||||||
|
cls: "vault-link-sync-status"
|
||||||
|
},
|
||||||
|
(el) => {
|
||||||
|
el.createSpan({ text: "VaultLink sync state" });
|
||||||
|
el.createDiv({
|
||||||
|
cls: "icon"
|
||||||
|
});
|
||||||
|
el.onclick = async (): Promise<void> =>
|
||||||
|
this.plugin.activateView(HistoryView.TYPE);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
import type { Workspace } from "obsidian";
|
|
||||||
import { FileView, setIcon } from "obsidian";
|
|
||||||
import type { SyncClient } from "sync-client";
|
|
||||||
import { DocumentSyncStatus } from "sync-client";
|
|
||||||
import "./editor-sync-line.scss";
|
|
||||||
|
|
||||||
export function updateEditorStatusDisplay(
|
|
||||||
workspace: Workspace,
|
|
||||||
client: SyncClient
|
|
||||||
): void {
|
|
||||||
workspace.iterateAllLeaves((leaf) => {
|
|
||||||
if (leaf.view instanceof FileView) {
|
|
||||||
const filePath = leaf.view.file?.path;
|
|
||||||
if (filePath == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const parent = leaf.view.contentEl.querySelector(".cm-editor");
|
|
||||||
if (parent == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const element =
|
|
||||||
parent.querySelector(".vault-link-sync-status") ??
|
|
||||||
parent.createDiv(
|
|
||||||
{
|
|
||||||
cls: "vault-link-sync-status"
|
|
||||||
},
|
|
||||||
(el) => {
|
|
||||||
el.createSpan({ text: "VaultLink sync state" });
|
|
||||||
el.createDiv({
|
|
||||||
cls: "icon"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const isLoading =
|
|
||||||
client.getDocumentSyncingStatus(filePath) ==
|
|
||||||
DocumentSyncStatus.SYNCING;
|
|
||||||
|
|
||||||
if (isLoading) {
|
|
||||||
element.classList.add("loading");
|
|
||||||
} else {
|
|
||||||
element.classList.remove("loading");
|
|
||||||
}
|
|
||||||
|
|
||||||
const iconContainer = element.querySelector(".icon");
|
|
||||||
if (iconContainer != null) {
|
|
||||||
setIcon(
|
|
||||||
iconContainer as HTMLElement, // eslint-disable-line @typescript-eslint/no-unsafe-type-assertion
|
|
||||||
isLoading ? "loader" : "circle-check"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
@ -13,10 +13,11 @@ export class WebSocketManager {
|
||||||
cursors: ClientCursors[]
|
cursors: ClientCursors[]
|
||||||
) => unknown)[] = [];
|
) => unknown)[] = [];
|
||||||
|
|
||||||
private refreshWebSocketInterval: NodeJS.Timeout | undefined;
|
|
||||||
|
|
||||||
private webSocket: WebSocket | undefined;
|
private webSocket: WebSocket | undefined;
|
||||||
|
|
||||||
|
private isStopped = true;
|
||||||
|
private _isFirstSyncCompleted = false;
|
||||||
|
|
||||||
private readonly webSocketFactoryImplementation: typeof globalThis.WebSocket;
|
private readonly webSocketFactoryImplementation: typeof globalThis.WebSocket;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
|
|
@ -41,20 +42,15 @@ export class WebSocketManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateWebSocket(settings.getSettings());
|
|
||||||
|
|
||||||
settings.addOnSettingsChangeListener((newSettings, oldSettings) => {
|
settings.addOnSettingsChangeListener((newSettings, oldSettings) => {
|
||||||
if (
|
if (
|
||||||
newSettings.remoteUri !== oldSettings.remoteUri ||
|
newSettings.remoteUri !== oldSettings.remoteUri ||
|
||||||
newSettings.vaultName !== oldSettings.vaultName ||
|
newSettings.vaultName !== oldSettings.vaultName ||
|
||||||
newSettings.token !== oldSettings.token ||
|
newSettings.token !== oldSettings.token
|
||||||
newSettings.isSyncEnabled !== oldSettings.isSyncEnabled
|
|
||||||
) {
|
) {
|
||||||
this.updateWebSocket(newSettings);
|
this.initializeWebSocket(newSettings);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setWebSocketRefreshInterval();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public get isWebSocketConnected(): boolean {
|
public get isWebSocketConnected(): boolean {
|
||||||
|
|
@ -64,6 +60,10 @@ export class WebSocketManager {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get isFirstSyncCompleted(): boolean {
|
||||||
|
return this._isFirstSyncCompleted;
|
||||||
|
}
|
||||||
|
|
||||||
public addWebSocketStatusChangeListener(listener: () => unknown): void {
|
public addWebSocketStatusChangeListener(listener: () => unknown): void {
|
||||||
this.webSocketStatusChangeListeners.push(listener);
|
this.webSocketStatusChangeListeners.push(listener);
|
||||||
}
|
}
|
||||||
|
|
@ -74,19 +74,15 @@ export class WebSocketManager {
|
||||||
this.remoteCursorsUpdateListeners.push(listener);
|
this.remoteCursorsUpdateListeners.push(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async reset(): Promise<void> {
|
public start(): void {
|
||||||
this.setWebSocketRefreshInterval();
|
this.isStopped = false;
|
||||||
this.updateWebSocket(this.settings.getSettings());
|
this._isFirstSyncCompleted = false;
|
||||||
|
this.initializeWebSocket(this.settings.getSettings());
|
||||||
}
|
}
|
||||||
|
|
||||||
public stop(): void {
|
public stop(): void {
|
||||||
clearInterval(this.refreshWebSocketInterval);
|
this.isStopped = true;
|
||||||
|
this.webSocket?.close(1000, "WebSocketManager has been stopped");
|
||||||
try {
|
|
||||||
this.webSocket?.close();
|
|
||||||
} catch (e) {
|
|
||||||
this.logger.warn(`Failed to close WebSocket: ${e}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateLocalCursors(cursorPositions: CursorPositionFromClient): void {
|
public updateLocalCursors(cursorPositions: CursorPositionFromClient): void {
|
||||||
|
|
@ -101,23 +97,22 @@ export class WebSocketManager {
|
||||||
...cursorPositions
|
...cursorPositions
|
||||||
};
|
};
|
||||||
this.webSocket?.send(JSON.stringify(message));
|
this.webSocket?.send(JSON.stringify(message));
|
||||||
this.logger.info(
|
this.logger.debug(
|
||||||
`Sent cursor positions: ${JSON.stringify(cursorPositions)}`
|
`Sent cursor positions: ${JSON.stringify(cursorPositions)}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateWebSocket(settings: SyncSettings): void {
|
private initializeWebSocket(settings: SyncSettings): void {
|
||||||
|
if (this.isStopped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.webSocket?.close();
|
this.webSocket?.close();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.warn(`Failed to close WebSocket: ${e}`);
|
this.logger.warn(`Failed to close WebSocket: ${e}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!settings.isSyncEnabled) {
|
|
||||||
this.webSocket = undefined;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const wsUri = new URL(settings.remoteUri);
|
const wsUri = new URL(settings.remoteUri);
|
||||||
wsUri.protocol = wsUri.protocol === "https" ? "wss" : "ws";
|
wsUri.protocol = wsUri.protocol === "https" ? "wss" : "ws";
|
||||||
wsUri.pathname = `/vaults/${settings.vaultName}/ws`;
|
wsUri.pathname = `/vaults/${settings.vaultName}/ws`;
|
||||||
|
|
@ -126,55 +121,10 @@ export class WebSocketManager {
|
||||||
|
|
||||||
this.webSocket = new this.webSocketFactoryImplementation(wsUri);
|
this.webSocket = new this.webSocketFactoryImplementation(wsUri);
|
||||||
|
|
||||||
this.webSocket.onmessage = async (event): Promise<void> => {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
||||||
const message = JSON.parse(event.data) as WebSocketServerMessage;
|
|
||||||
|
|
||||||
if (message.type === "vaultUpdate") {
|
|
||||||
try {
|
|
||||||
await Promise.all(
|
|
||||||
message.documents.map(async (document) =>
|
|
||||||
this.syncer.syncRemotelyUpdatedFile(document)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (message.isInitialSync && message.documents.length > 0) {
|
|
||||||
this.database.setLastSeenUpdateId(
|
|
||||||
message.documents
|
|
||||||
.map((document) => document.vaultUpdateId)
|
|
||||||
.reduce((a, b) => Math.max(a, b))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
this.logger.error(
|
|
||||||
`Failed to sync remotely updated file: ${e}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
||||||
} else if (message.type === "cursorPositions") {
|
|
||||||
this.logger.debug(
|
|
||||||
`Received cursor positions for ${JSON.stringify(message.clients)}`
|
|
||||||
);
|
|
||||||
this.remoteCursorsUpdateListeners.forEach((listener) => {
|
|
||||||
listener(
|
|
||||||
message.clients.filter(
|
|
||||||
(client) => client.deviceId !== this.deviceId
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.logger.warn(
|
|
||||||
`Received unknown message type: ${JSON.stringify(message)}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// The JS WebSocket API doesn't support setting headers, so we have to send the token as a message
|
// The JS WebSocket API doesn't support setting headers, so we have to send the token as a message
|
||||||
this.webSocket.onopen = (): void => {
|
this.webSocket.onopen = (): void => {
|
||||||
this.logger.info("WebSocket connection opened");
|
this.logger.info("WebSocket connection opened");
|
||||||
this.webSocketStatusChangeListeners.forEach((listener) => {
|
this.webSocketStatusChangeListeners.forEach((l) => l());
|
||||||
listener();
|
|
||||||
});
|
|
||||||
|
|
||||||
const message: WebSocketClientMessage = {
|
const message: WebSocketClientMessage = {
|
||||||
type: "handshake",
|
type: "handshake",
|
||||||
|
|
@ -185,25 +135,65 @@ export class WebSocketManager {
|
||||||
this.webSocket?.send(JSON.stringify(message));
|
this.webSocket?.send(JSON.stringify(message));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.webSocket.onmessage = async (event): Promise<void> => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||||
|
const message = JSON.parse(event.data) as WebSocketServerMessage;
|
||||||
|
return this.handleWebSocketMessage(message);
|
||||||
|
};
|
||||||
|
|
||||||
this.webSocket.onclose = (event): void => {
|
this.webSocket.onclose = (event): void => {
|
||||||
this.logger.warn(
|
this.logger.warn(
|
||||||
`WebSocket closed with code ${event.code} (${event.reason == "" ? "unknown reason" : event.reason})`
|
`WebSocket closed with code ${event.code} (${event.reason == "" ? "unknown reason" : event.reason})`
|
||||||
);
|
);
|
||||||
this.webSocketStatusChangeListeners.forEach((listener) => {
|
this.webSocketStatusChangeListeners.forEach((l) => l());
|
||||||
listener();
|
|
||||||
});
|
if (!this.isStopped) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.initializeWebSocket(this.settings.getSettings());
|
||||||
|
}, this.settings.getSettings().webSocketRetryIntervalMs);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private setWebSocketRefreshInterval(): void {
|
private async handleWebSocketMessage(
|
||||||
this.refreshWebSocketInterval = setInterval(() => {
|
message: WebSocketServerMessage
|
||||||
if (
|
): Promise<void> {
|
||||||
this.webSocket?.readyState ===
|
if (message.type === "vaultUpdate") {
|
||||||
this.webSocketFactoryImplementation.CLOSED
|
try {
|
||||||
) {
|
await Promise.all(
|
||||||
this.logger.info("WebSocket is closed, reconnecting...");
|
message.documents.map(async (document) =>
|
||||||
this.updateWebSocket(this.settings.getSettings());
|
this.syncer.syncRemotelyUpdatedFile(document)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (message.isInitialSync && message.documents.length > 0) {
|
||||||
|
this.database.setLastSeenUpdateId(
|
||||||
|
message.documents
|
||||||
|
.map((document) => document.vaultUpdateId)
|
||||||
|
.reduce((a, b) => Math.max(a, b))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._isFirstSyncCompleted = true;
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(`Failed to sync remotely updated file: ${e}`);
|
||||||
}
|
}
|
||||||
}, this.settings.getSettings().webSocketRetryIntervalMs);
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
|
} else if (message.type === "cursorPositions") {
|
||||||
|
this.logger.debug(
|
||||||
|
`Received cursor positions for ${JSON.stringify(message.clients)}`
|
||||||
|
);
|
||||||
|
this.remoteCursorsUpdateListeners.forEach((listener) => {
|
||||||
|
listener(
|
||||||
|
message.clients.filter(
|
||||||
|
(client) => client.deviceId !== this.deviceId
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.logger.warn(
|
||||||
|
`Received unknown message type: ${JSON.stringify(message)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import { FileChangeNotifier } from "./sync-operations/file-change-notifier";
|
||||||
|
|
||||||
export class SyncClient {
|
export class SyncClient {
|
||||||
private static readonly MINIMUM_SAVE_INTERVAL_MS = 1000;
|
private static readonly MINIMUM_SAVE_INTERVAL_MS = 1000;
|
||||||
|
private hasFinishedOfflineSync = false;
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/max-params
|
// eslint-disable-next-line @typescript-eslint/max-params
|
||||||
private constructor(
|
private constructor(
|
||||||
|
|
@ -43,6 +44,14 @@ export class SyncClient {
|
||||||
if (newSettings.vaultName !== oldSettings.vaultName) {
|
if (newSettings.vaultName !== oldSettings.vaultName) {
|
||||||
await this.reset();
|
await this.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newSettings.isSyncEnabled !== oldSettings.isSyncEnabled) {
|
||||||
|
if (newSettings.isSyncEnabled) {
|
||||||
|
await this.start();
|
||||||
|
} else {
|
||||||
|
this.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -198,9 +207,12 @@ export class SyncClient {
|
||||||
|
|
||||||
public async start(): Promise<void> {
|
public async start(): Promise<void> {
|
||||||
await this.syncer.scheduleSyncForOfflineChanges();
|
await this.syncer.scheduleSyncForOfflineChanges();
|
||||||
|
this.hasFinishedOfflineSync = true;
|
||||||
|
this.webSocketManager.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public stop(): void {
|
public stop(): void {
|
||||||
|
this.hasFinishedOfflineSync = false;
|
||||||
this.webSocketManager.stop();
|
this.webSocketManager.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -216,7 +228,6 @@ export class SyncClient {
|
||||||
this.stop();
|
this.stop();
|
||||||
this.connectionStatus.startReset();
|
this.connectionStatus.startReset();
|
||||||
await this.syncer.reset();
|
await this.syncer.reset();
|
||||||
await this.webSocketManager.reset();
|
|
||||||
this.history.reset();
|
this.history.reset();
|
||||||
this.database.reset();
|
this.database.reset();
|
||||||
this._logger.reset();
|
this._logger.reset();
|
||||||
|
|
@ -286,6 +297,17 @@ export class SyncClient {
|
||||||
public getDocumentSyncingStatus(
|
public getDocumentSyncingStatus(
|
||||||
relativePath: RelativePath
|
relativePath: RelativePath
|
||||||
): DocumentSyncStatus {
|
): DocumentSyncStatus {
|
||||||
|
if (!this.settings.getSettings().isSyncEnabled) {
|
||||||
|
return DocumentSyncStatus.SYNCING_IS_DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!this.webSocketManager.isFirstSyncCompleted ||
|
||||||
|
!this.hasFinishedOfflineSync
|
||||||
|
) {
|
||||||
|
return DocumentSyncStatus.SYNCING;
|
||||||
|
}
|
||||||
|
|
||||||
const document =
|
const document =
|
||||||
this.database.getLatestDocumentByRelativePath(relativePath);
|
this.database.getLatestDocumentByRelativePath(relativePath);
|
||||||
if (document === undefined) {
|
if (document === undefined) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
export enum DocumentSyncStatus {
|
export enum DocumentSyncStatus {
|
||||||
UP_TO_DATE = "UP_TO_DATE",
|
UP_TO_DATE = "UP_TO_DATE",
|
||||||
SYNCING = "SYNCING"
|
SYNCING = "SYNCING",
|
||||||
|
SYNCING_IS_DISABLED = "SYNCING_IS_DISABLED"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue