From 7e5fe1d67608403c2dabb3ffc5a1275d4d8b22e0 Mon Sep 17 00:00:00 2001 From: tiddlygit-test Date: Sun, 18 Dec 2022 21:26:21 +0800 Subject: [PATCH] fix: sync on start not reloading wiki fixes https://github.com/tiddly-gittly/TidGi-Desktop/issues/298 --- src/services/git/index.ts | 30 +++++++++++---- src/services/git/interface.ts | 11 +++++- src/services/git/stepWithChanges.ts | 4 ++ src/services/wiki/index.ts | 30 ++++++++------- .../workspaces/getWorkspaceMenuTemplate.ts | 8 ++-- src/services/workspacesView/index.ts | 38 ++++++++++--------- 6 files changed, 77 insertions(+), 44 deletions(-) create mode 100644 src/services/git/stepWithChanges.ts diff --git a/src/services/git/index.ts b/src/services/git/index.ts index e374906a..894d6ca1 100644 --- a/src/services/git/index.ts +++ b/src/services/git/index.ts @@ -37,6 +37,7 @@ import { WindowNames } from '@services/windows/WindowProperties'; import { lazyInject } from '@services/container'; import { githubDesktopUrl } from '@/constants/urls'; import { IWorkspace } from '@services/workspaces/interface'; +import { stepWithChanges } from './stepWithChanges'; @injectable() export class Git implements IGitService { @@ -223,7 +224,7 @@ export class Git implements IGitService { } } - private readonly getWorkerObserver = (resolve: () => void, reject: (error: Error) => void): Observer => ({ + private readonly getWorkerMessageObserver = (resolve: () => void, reject: (error: Error) => void): Observer => ({ next: (messageObject) => { const { message, meta, level } = messageObject; if (typeof meta === 'object' && meta !== null && 'step' in meta) { @@ -269,20 +270,35 @@ export class Git implements IGitService { // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions const syncImmediately = !!isSyncedWiki && !!isMainWiki; return await new Promise((resolve, reject) => { - this.gitWorker?.initWikiGit(wikiFolderPath, syncImmediately && net.isOnline(), remoteUrl, userInfo).subscribe(this.getWorkerObserver(resolve, reject)); + this.gitWorker + ?.initWikiGit(wikiFolderPath, syncImmediately && net.isOnline(), remoteUrl, userInfo) + .subscribe(this.getWorkerMessageObserver(resolve, reject)); }); } - public async commitAndSync(workspace: IWorkspace, config: ICommitAndSyncConfigs): Promise { + public async commitAndSync(workspace: IWorkspace, config: ICommitAndSyncConfigs): Promise { if (!net.isOnline()) { - return; + return false; } try { - return await new Promise((resolve, reject) => { - this.gitWorker?.commitAndSyncWiki(workspace, config).subscribe(this.getWorkerObserver(resolve, reject)); + return await new Promise((resolve, reject) => { + const observable = this.gitWorker?.commitAndSyncWiki(workspace, config); + observable?.subscribe(this.getWorkerMessageObserver(() => {}, reject)); + let hasChanges = false; + observable?.subscribe({ + next: (messageObject) => { + const { meta } = messageObject; + if (typeof meta === 'object' && meta !== null && 'step' in meta && stepWithChanges.includes((meta as { step: GitStep }).step)) { + hasChanges = true; + } + }, + complete: () => resolve(hasChanges), + }); + return true; }); } catch (error) { this.createFailedDialog((error as Error).message, workspace.wikiFolderLocation); + return true; } } @@ -291,7 +307,7 @@ export class Git implements IGitService { return; } return await new Promise((resolve, reject) => { - this.gitWorker?.cloneWiki(repoFolderPath, remoteUrl, userInfo).subscribe(this.getWorkerObserver(resolve, reject)); + this.gitWorker?.cloneWiki(repoFolderPath, remoteUrl, userInfo).subscribe(this.getWorkerMessageObserver(resolve, reject)); }); } } diff --git a/src/services/git/interface.ts b/src/services/git/interface.ts index 09af9760..14139980 100644 --- a/src/services/git/interface.ts +++ b/src/services/git/interface.ts @@ -22,7 +22,11 @@ export interface IGitLogMessage { meta: unknown; } -export interface ICommitAndSyncConfigs { commitOnly?: boolean; remoteUrl?: string; userInfo?: IGitUserInfos } +export interface ICommitAndSyncConfigs { + commitOnly?: boolean; + remoteUrl?: string; + userInfo?: IGitUserInfos; +} /** * System Preferences are not stored in storage but stored in macOS Preferences. @@ -30,7 +34,10 @@ export interface ICommitAndSyncConfigs { commitOnly?: boolean; remoteUrl?: strin */ export interface IGitService { clone(remoteUrl: string, repoFolderPath: string, userInfo: IGitUserInfos): Promise; - commitAndSync(workspace: IWorkspace, config: ICommitAndSyncConfigs): Promise; + /** + * Return true if this function's execution causes local changes. Return false if is only push or nothing changed. + */ + commitAndSync(workspace: IWorkspace, config: ICommitAndSyncConfigs): Promise; getModifiedFileList(wikiFolderPath: string): Promise; /** Inspect git's remote url from folder's .git config, return undefined if there is no initialized git */ getWorkspacesRemote(wikiFolderPath?: string): Promise; diff --git a/src/services/git/stepWithChanges.ts b/src/services/git/stepWithChanges.ts new file mode 100644 index 00000000..a27f28da --- /dev/null +++ b/src/services/git/stepWithChanges.ts @@ -0,0 +1,4 @@ +import { GitStep } from 'git-sync-js'; + +// TODO: move this to git-sync-js +export const stepWithChanges = [GitStep.GitMerge, GitStep.LocalStateDivergeRebase, GitStep.LocalStateBehindSync]; diff --git a/src/services/wiki/index.ts b/src/services/wiki/index.ts index 340132df..96b2b986 100644 --- a/src/services/wiki/index.ts +++ b/src/services/wiki/index.ts @@ -508,9 +508,11 @@ export class Wiki implements IWikiService { userInfo !== undefined && (await checkCanSyncDueToNoDraft(workspace)) ) { - await this.gitService.commitAndSync(workspace, { remoteUrl: githubRepoUrl, userInfo }); - await this.workspaceViewService.restartWorkspaceViewService(id); - await this.viewService.reloadViewsWebContents(id); + const hasChanges = await this.gitService.commitAndSync(workspace, { remoteUrl: githubRepoUrl, userInfo }); + if (hasChanges) { + await this.workspaceViewService.restartWorkspaceViewService(id); + await this.viewService.reloadViewsWebContents(id); + } } else if (backupOnInterval && (await checkCanSyncDueToNoDraft(workspace))) { await this.gitService.commitAndSync(workspace, { commitOnly: true }); } @@ -563,7 +565,17 @@ export class Wiki implements IWikiService { const userName = (workspace.userName || (await this.authService.get('userName'))) ?? ''; // if is main wiki - if (!isSubWiki) { + if (isSubWiki) { + // if is private repo wiki + // if we are creating a sub-wiki just now, restart the main wiki to load content from private wiki + if (typeof mainWikiToLink === 'string' && !this.checkWikiStartLock(mainWikiToLink)) { + const mainWorkspace = await this.workspaceService.getByWikiFolderLocation(mainWikiToLink); + if (mainWorkspace === undefined) { + throw new Error(`mainWorkspace is undefined in wikiStartup() for mainWikiPath ${mainWikiToLink}`); + } + await this.restartWiki(mainWorkspace); + } + } else { try { logger.debug('startWiki() calling startWiki'); await this.startWiki(wikiFolderLocation, port, userName); @@ -585,16 +597,6 @@ export class Wiki implements IWikiService { throw error; } } - } else { - // if is private repo wiki - // if we are creating a sub-wiki just now, restart the main wiki to load content from private wiki - if (typeof mainWikiToLink === 'string' && !this.checkWikiStartLock(mainWikiToLink)) { - const mainWorkspace = await this.workspaceService.getByWikiFolderLocation(mainWikiToLink); - if (mainWorkspace === undefined) { - throw new Error(`mainWorkspace is undefined in wikiStartup() for mainWikiPath ${mainWikiToLink}`); - } - await this.restartWiki(mainWorkspace); - } } await this.startIntervalSyncIfNeeded(workspace); } diff --git a/src/services/workspaces/getWorkspaceMenuTemplate.ts b/src/services/workspaces/getWorkspaceMenuTemplate.ts index 934ae668..e7ed8696 100644 --- a/src/services/workspaces/getWorkspaceMenuTemplate.ts +++ b/src/services/workspaces/getWorkspaceMenuTemplate.ts @@ -111,9 +111,11 @@ export async function getWorkspaceMenuTemplate( label: t('ContextMenu.SyncNow') + (isOnline ? '' : `(${t('ContextMenu.NoNetworkConnection')})`), enabled: isOnline, click: async () => { - await service.git.commitAndSync(workspace, { remoteUrl: gitUrl, userInfo }); - await service.workspaceView.restartWorkspaceViewService(id); - await service.view.reloadViewsWebContents(id); + const hasChanges = await service.git.commitAndSync(workspace, { remoteUrl: gitUrl, userInfo }); + if (hasChanges) { + await service.workspaceView.restartWorkspaceViewService(id); + await service.view.reloadViewsWebContents(id); + } }, }); } diff --git a/src/services/workspacesView/index.ts b/src/services/workspacesView/index.ts index e022abf4..7fca786c 100644 --- a/src/services/workspacesView/index.ts +++ b/src/services/workspacesView/index.ts @@ -114,9 +114,11 @@ export class WorkspaceView implements IWorkspaceViewService { throw new TypeError(`userInfo is undefined in initializeAllWorkspaceView when init ${wikiFolderLocation}`); } // sync in non-blocking way - void this.gitService.commitAndSync(workspace, { remoteUrl: githubRepoUrl, userInfo }).then(async () => { - await this.workspaceViewService.restartWorkspaceViewService(workspace.id); - await this.viewService.reloadViewsWebContents(workspace.id); + void this.gitService.commitAndSync(workspace, { remoteUrl: githubRepoUrl, userInfo }).then(async (hasChanges) => { + if (hasChanges) { + await this.workspaceViewService.restartWorkspaceViewService(workspace.id); + await this.viewService.reloadViewsWebContents(workspace.id); + } }); } } catch (error) { @@ -161,14 +163,14 @@ export class WorkspaceView implements IWorkspaceViewService { // if is newly created wiki, we set the language as user preference const currentLanguage = await this.preferenceService.get('language'); const tiddlywikiLanguageName = tiddlywikiLanguagesMap[currentLanguage]; - if (tiddlywikiLanguageName !== undefined) { - logger.debug(`Setting wiki language to ${currentLanguage} (${tiddlywikiLanguageName}) on init`); - await this.wikiService.setWikiLanguage(view, workspace.id, tiddlywikiLanguageName); - } else { + if (tiddlywikiLanguageName === undefined) { const errorMessage = `When creating new wiki, and switch to language "${currentLanguage}", there is no corresponding tiddlywiki language registered`; logger.error(errorMessage, { tiddlywikiLanguagesMap, }); + } else { + logger.debug(`Setting wiki language to ${currentLanguage} (${tiddlywikiLanguageName}) on init`); + await this.wikiService.setWikiLanguage(view, workspace.id, tiddlywikiLanguageName); } } } @@ -178,14 +180,14 @@ export class WorkspaceView implements IWorkspaceViewService { workspaceID: string, view: Electron.CrossProcessExports.BrowserView | undefined = this.viewService.getView(workspaceID, WindowNames.main), ): Promise { - if (view !== undefined) { + if (view === undefined) { + logger.warn(`Can't update lastUrl for workspace ${workspaceID}, view is not found`); + } else { const currentUrl = view.webContents.getURL(); logger.debug(`Updating lastUrl for workspace ${workspaceID} to ${currentUrl}`); await this.workspaceService.update(workspaceID, { lastUrl: currentUrl, }); - } else { - logger.warn(`Can't update lastUrl for workspace ${workspaceID}, view is not found`); } } @@ -351,8 +353,10 @@ export class WorkspaceView implements IWorkspaceViewService { } public async restartWorkspaceViewService(id?: string): Promise { - const workspaceToRestart = id !== undefined ? await this.workspaceService.get(id) : await this.workspaceService.getActiveWorkspace(); - if (workspaceToRestart !== undefined) { + const workspaceToRestart = id === undefined ? await this.workspaceService.getActiveWorkspace() : await this.workspaceService.get(id); + if (workspaceToRestart === undefined) { + logger.warn(`restartWorkspaceViewService: no workspace ${id ?? 'id undefined'} to restart`); + } else { logger.info(`Restarting workspace ${workspaceToRestart.id}`); await this.updateLastUrl(workspaceToRestart.id); await this.workspaceService.updateMetaData(workspaceToRestart.id, { didFailLoadErrorMessage: null, isLoading: false }); @@ -364,8 +368,6 @@ export class WorkspaceView implements IWorkspaceViewService { } await this.viewService.reloadViewsWebContents(workspaceToRestart.id); this.wikiService.wikiOperation(WikiChannel.generalNotification, workspaceToRestart.id, i18n.t('ContextMenu.RestartServiceComplete')); - } else { - logger.warn(`restartWorkspaceViewService: no workspace ${id ?? 'id undefined'} to restart`); } } @@ -443,7 +445,7 @@ export class WorkspaceView implements IWorkspaceViewService { } private async realignActiveWorkspaceView(id?: string): Promise { - const workspaceToRealign = id !== undefined ? await this.workspaceService.get(id) : await this.workspaceService.getActiveWorkspace(); + const workspaceToRealign = id === undefined ? await this.workspaceService.getActiveWorkspace() : await this.workspaceService.get(id); logger.debug(`realignActiveWorkspaceView() activeWorkspace.id: ${workspaceToRealign?.id ?? 'undefined'}`); const mainWindow = this.windowService.get(WindowNames.main); const menuBarWindow = this.windowService.get(WindowNames.menuBar); @@ -455,14 +457,14 @@ export class WorkspaceView implements IWorkspaceViewService { !!menuBarBrowserViewWebContent, )}`, ); - if (workspaceToRealign !== undefined) { + if (workspaceToRealign === undefined) { + logger.warn('realignActiveWorkspaceView: no active workspace'); + } else { if (mainWindow === undefined && menuBarWindow === undefined) { logger.warn('realignActiveWorkspaceView: no active window'); } mainBrowserViewWebContent && void this.viewService.realignActiveView(mainWindow, workspaceToRealign.id); menuBarBrowserViewWebContent && void this.viewService.realignActiveView(menuBarWindow, workspaceToRealign.id); - } else { - logger.warn('realignActiveWorkspaceView: no active workspace'); } /* eslint-enable @typescript-eslint/strict-boolean-expressions */ }