mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2025-12-06 02:30:47 -08:00
refactor: move sync logic to sync service
This commit is contained in:
parent
8bf3fcdc1d
commit
5f41b77da9
15 changed files with 240 additions and 143 deletions
|
|
@ -5,8 +5,8 @@
|
||||||
See [this 6aedff4b commit](https://github.com/tiddly-gittly/TidGi-Desktop/commit/6aedff4bb2441e692c95aedc57a586953a641615) for example, you need to modify these files:
|
See [this 6aedff4b commit](https://github.com/tiddly-gittly/TidGi-Desktop/commit/6aedff4bb2441e692c95aedc57a586953a641615) for example, you need to modify these files:
|
||||||
|
|
||||||
- [src/preload/common/services.ts](../../src/preload/common/services.ts) to expose it to renderer side for in-wiki plugin access
|
- [src/preload/common/services.ts](../../src/preload/common/services.ts) to expose it to renderer side for in-wiki plugin access
|
||||||
- [src/services/libs/bindServiceAndProxy.ts](../../src/services/libs/bindServiceAndProxy.ts) for dependency injection in inversifyjs
|
|
||||||
- [src/services/serviceIdentifier.ts](../../src/services/serviceIdentifier.ts) for IoC id
|
- [src/services/serviceIdentifier.ts](../../src/services/serviceIdentifier.ts) for IoC id
|
||||||
|
- [src/services/libs/bindServiceAndProxy.ts](../../src/services/libs/bindServiceAndProxy.ts) for dependency injection in inversifyjs
|
||||||
|
|
||||||
## Sync service
|
## Sync service
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,10 @@ export enum MetaDataChannel {
|
||||||
pushViewMetaData = 'pushViewMetaData',
|
pushViewMetaData = 'pushViewMetaData',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum SyncChannel {
|
||||||
|
name = 'SyncChannel',
|
||||||
|
}
|
||||||
|
|
||||||
export type Channels =
|
export type Channels =
|
||||||
| MainChannel
|
| MainChannel
|
||||||
| AuthenticationChannel
|
| AuthenticationChannel
|
||||||
|
|
@ -167,4 +171,5 @@ export type Channels =
|
||||||
| WindowChannel
|
| WindowChannel
|
||||||
| ThemeChannel
|
| ThemeChannel
|
||||||
| I18NChannels
|
| I18NChannels
|
||||||
| MetaDataChannel;
|
| MetaDataChannel
|
||||||
|
| SyncChannel;
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import { INativeService, NativeServiceIPCDescriptor } from '@services/native/int
|
||||||
import { INotificationService, NotificationServiceIPCDescriptor } from '@services/notifications/interface';
|
import { INotificationService, NotificationServiceIPCDescriptor } from '@services/notifications/interface';
|
||||||
import { IPagesService, PagesServiceIPCDescriptor } from '@services/pages/interface';
|
import { IPagesService, PagesServiceIPCDescriptor } from '@services/pages/interface';
|
||||||
import { IPreferenceService, PreferenceServiceIPCDescriptor } from '@services/preferences/interface';
|
import { IPreferenceService, PreferenceServiceIPCDescriptor } from '@services/preferences/interface';
|
||||||
|
import { ISyncService, SyncServiceIPCDescriptor } from '@services/sync/interface';
|
||||||
import { ISystemPreferenceService, SystemPreferenceServiceIPCDescriptor } from '@services/systemPreferences/interface';
|
import { ISystemPreferenceService, SystemPreferenceServiceIPCDescriptor } from '@services/systemPreferences/interface';
|
||||||
import { IThemeService, ThemeServiceIPCDescriptor } from '@services/theme/interface';
|
import { IThemeService, ThemeServiceIPCDescriptor } from '@services/theme/interface';
|
||||||
import { IUpdaterService, UpdaterServiceIPCDescriptor } from '@services/updater/interface';
|
import { IUpdaterService, UpdaterServiceIPCDescriptor } from '@services/updater/interface';
|
||||||
|
|
@ -35,6 +36,7 @@ export const native = createProxy<INativeService>(NativeServiceIPCDescriptor);
|
||||||
export const notification = createProxy<INotificationService>(NotificationServiceIPCDescriptor);
|
export const notification = createProxy<INotificationService>(NotificationServiceIPCDescriptor);
|
||||||
export const pages = createProxy<IPagesService>(PagesServiceIPCDescriptor);
|
export const pages = createProxy<IPagesService>(PagesServiceIPCDescriptor);
|
||||||
export const preference = createProxy<IPreferenceService>(PreferenceServiceIPCDescriptor);
|
export const preference = createProxy<IPreferenceService>(PreferenceServiceIPCDescriptor);
|
||||||
|
export const sync = createProxy<ISyncService>(SyncServiceIPCDescriptor);
|
||||||
export const systemPreference = createProxy<ISystemPreferenceService>(SystemPreferenceServiceIPCDescriptor);
|
export const systemPreference = createProxy<ISystemPreferenceService>(SystemPreferenceServiceIPCDescriptor);
|
||||||
export const theme = createProxy<IThemeService>(ThemeServiceIPCDescriptor);
|
export const theme = createProxy<IThemeService>(ThemeServiceIPCDescriptor);
|
||||||
export const updater = createProxy<IUpdaterService>(UpdaterServiceIPCDescriptor);
|
export const updater = createProxy<IUpdaterService>(UpdaterServiceIPCDescriptor);
|
||||||
|
|
@ -55,6 +57,7 @@ export const descriptors = {
|
||||||
notification: NotificationServiceIPCDescriptor,
|
notification: NotificationServiceIPCDescriptor,
|
||||||
pages: PagesServiceIPCDescriptor,
|
pages: PagesServiceIPCDescriptor,
|
||||||
preference: PreferenceServiceIPCDescriptor,
|
preference: PreferenceServiceIPCDescriptor,
|
||||||
|
sync: SyncServiceIPCDescriptor,
|
||||||
systemPreference: SystemPreferenceServiceIPCDescriptor,
|
systemPreference: SystemPreferenceServiceIPCDescriptor,
|
||||||
theme: ThemeServiceIPCDescriptor,
|
theme: ThemeServiceIPCDescriptor,
|
||||||
updater: UpdaterServiceIPCDescriptor,
|
updater: UpdaterServiceIPCDescriptor,
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import { NativeService } from '@services/native';
|
||||||
import { NotificationService } from '@services/notifications';
|
import { NotificationService } from '@services/notifications';
|
||||||
import { Pages } from '@services/pages';
|
import { Pages } from '@services/pages';
|
||||||
import { Preference } from '@services/preferences';
|
import { Preference } from '@services/preferences';
|
||||||
|
import { Sync } from '@services/sync';
|
||||||
import { SystemPreference } from '@services/systemPreferences';
|
import { SystemPreference } from '@services/systemPreferences';
|
||||||
import { ThemeService } from '@services/theme';
|
import { ThemeService } from '@services/theme';
|
||||||
import { Updater } from '@services/updater';
|
import { Updater } from '@services/updater';
|
||||||
|
|
@ -46,6 +47,8 @@ import type { IPagesService } from '@services/pages/interface';
|
||||||
import { PagesServiceIPCDescriptor } from '@services/pages/interface';
|
import { PagesServiceIPCDescriptor } from '@services/pages/interface';
|
||||||
import type { IPreferenceService } from '@services/preferences/interface';
|
import type { IPreferenceService } from '@services/preferences/interface';
|
||||||
import { PreferenceServiceIPCDescriptor } from '@services/preferences/interface';
|
import { PreferenceServiceIPCDescriptor } from '@services/preferences/interface';
|
||||||
|
import type { ISyncService } from '@services/sync/interface';
|
||||||
|
import { SyncServiceIPCDescriptor } from '@services/sync/interface';
|
||||||
import type { ISystemPreferenceService } from '@services/systemPreferences/interface';
|
import type { ISystemPreferenceService } from '@services/systemPreferences/interface';
|
||||||
import { SystemPreferenceServiceIPCDescriptor } from '@services/systemPreferences/interface';
|
import { SystemPreferenceServiceIPCDescriptor } from '@services/systemPreferences/interface';
|
||||||
import type { IThemeService } from '@services/theme/interface';
|
import type { IThemeService } from '@services/theme/interface';
|
||||||
|
|
@ -80,6 +83,7 @@ export function bindServiceAndProxy(): void {
|
||||||
container.bind<IThemeService>(serviceIdentifier.ThemeService).to(ThemeService).inSingletonScope();
|
container.bind<IThemeService>(serviceIdentifier.ThemeService).to(ThemeService).inSingletonScope();
|
||||||
container.bind<IUpdaterService>(serviceIdentifier.Updater).to(Updater).inSingletonScope();
|
container.bind<IUpdaterService>(serviceIdentifier.Updater).to(Updater).inSingletonScope();
|
||||||
container.bind<IViewService>(serviceIdentifier.View).to(View).inSingletonScope();
|
container.bind<IViewService>(serviceIdentifier.View).to(View).inSingletonScope();
|
||||||
|
container.bind<ISyncService>(serviceIdentifier.Sync).to(Sync).inSingletonScope();
|
||||||
container.bind<IWikiGitWorkspaceService>(serviceIdentifier.WikiGitWorkspace).to(WikiGitWorkspace).inSingletonScope();
|
container.bind<IWikiGitWorkspaceService>(serviceIdentifier.WikiGitWorkspace).to(WikiGitWorkspace).inSingletonScope();
|
||||||
container.bind<IWikiService>(serviceIdentifier.Wiki).to(Wiki).inSingletonScope();
|
container.bind<IWikiService>(serviceIdentifier.Wiki).to(Wiki).inSingletonScope();
|
||||||
container.bind<IWindowService>(serviceIdentifier.Window).to(Window).inSingletonScope();
|
container.bind<IWindowService>(serviceIdentifier.Window).to(Window).inSingletonScope();
|
||||||
|
|
@ -99,6 +103,7 @@ export function bindServiceAndProxy(): void {
|
||||||
const systemPreferenceService = container.get<ISystemPreferenceService>(serviceIdentifier.SystemPreference);
|
const systemPreferenceService = container.get<ISystemPreferenceService>(serviceIdentifier.SystemPreference);
|
||||||
const themeService = container.get<IThemeService>(serviceIdentifier.ThemeService);
|
const themeService = container.get<IThemeService>(serviceIdentifier.ThemeService);
|
||||||
const updaterService = container.get<IUpdaterService>(serviceIdentifier.Updater);
|
const updaterService = container.get<IUpdaterService>(serviceIdentifier.Updater);
|
||||||
|
const syncService = container.get<ISyncService>(serviceIdentifier.Sync);
|
||||||
const viewService = container.get<IViewService>(serviceIdentifier.View);
|
const viewService = container.get<IViewService>(serviceIdentifier.View);
|
||||||
const wikiGitWorkspaceService = container.get<IWikiGitWorkspaceService>(serviceIdentifier.WikiGitWorkspace);
|
const wikiGitWorkspaceService = container.get<IWikiGitWorkspaceService>(serviceIdentifier.WikiGitWorkspace);
|
||||||
const wikiService = container.get<IWikiService>(serviceIdentifier.Wiki);
|
const wikiService = container.get<IWikiService>(serviceIdentifier.Wiki);
|
||||||
|
|
@ -115,6 +120,7 @@ export function bindServiceAndProxy(): void {
|
||||||
registerProxy(nativeService, NativeServiceIPCDescriptor);
|
registerProxy(nativeService, NativeServiceIPCDescriptor);
|
||||||
registerProxy(notificationService, NotificationServiceIPCDescriptor);
|
registerProxy(notificationService, NotificationServiceIPCDescriptor);
|
||||||
registerProxy(pagesService, PagesServiceIPCDescriptor);
|
registerProxy(pagesService, PagesServiceIPCDescriptor);
|
||||||
|
registerProxy(syncService, SyncServiceIPCDescriptor);
|
||||||
registerProxy(preferenceService, PreferenceServiceIPCDescriptor);
|
registerProxy(preferenceService, PreferenceServiceIPCDescriptor);
|
||||||
registerProxy(systemPreferenceService, SystemPreferenceServiceIPCDescriptor);
|
registerProxy(systemPreferenceService, SystemPreferenceServiceIPCDescriptor);
|
||||||
registerProxy(themeService, ThemeServiceIPCDescriptor);
|
registerProxy(themeService, ThemeServiceIPCDescriptor);
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import type { INativeService } from '@services/native/interface';
|
||||||
import type { IPagesService } from '@services/pages/interface';
|
import type { IPagesService } from '@services/pages/interface';
|
||||||
import type { IPreferenceService } from '@services/preferences/interface';
|
import type { IPreferenceService } from '@services/preferences/interface';
|
||||||
import serviceIdentifier from '@services/serviceIdentifier';
|
import serviceIdentifier from '@services/serviceIdentifier';
|
||||||
|
import { ISyncService } from '@services/sync/interface';
|
||||||
import type { IUpdaterService } from '@services/updater/interface';
|
import type { IUpdaterService } from '@services/updater/interface';
|
||||||
import type { IViewService } from '@services/view/interface';
|
import type { IViewService } from '@services/view/interface';
|
||||||
import type { IWikiService } from '@services/wiki/interface';
|
import type { IWikiService } from '@services/wiki/interface';
|
||||||
|
|
@ -70,6 +71,9 @@ export class MenuService implements IMenuService {
|
||||||
@lazyInject(serviceIdentifier.WorkspaceView)
|
@lazyInject(serviceIdentifier.WorkspaceView)
|
||||||
private readonly workspaceViewService!: IWorkspaceViewService;
|
private readonly workspaceViewService!: IWorkspaceViewService;
|
||||||
|
|
||||||
|
@lazyInject(serviceIdentifier.Sync)
|
||||||
|
private readonly syncService!: ISyncService;
|
||||||
|
|
||||||
#menuTemplate?: DeferredMenuItemConstructorOptions[];
|
#menuTemplate?: DeferredMenuItemConstructorOptions[];
|
||||||
private get menuTemplate(): DeferredMenuItemConstructorOptions[] {
|
private get menuTemplate(): DeferredMenuItemConstructorOptions[] {
|
||||||
if (this.#menuTemplate === undefined) {
|
if (this.#menuTemplate === undefined) {
|
||||||
|
|
@ -302,6 +306,7 @@ export class MenuService implements IMenuService {
|
||||||
window: this.windowService,
|
window: this.windowService,
|
||||||
workspace: this.workspaceService,
|
workspace: this.workspaceService,
|
||||||
workspaceView: this.workspaceViewService,
|
workspaceView: this.workspaceViewService,
|
||||||
|
sync: this.syncService,
|
||||||
};
|
};
|
||||||
// workspace menus
|
// workspace menus
|
||||||
menu.append(new MenuItem({ type: 'separator' }));
|
menu.append(new MenuItem({ type: 'separator' }));
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ export default {
|
||||||
NotificationService: Symbol.for('NotificationService'),
|
NotificationService: Symbol.for('NotificationService'),
|
||||||
Pages: Symbol.for('Pages'),
|
Pages: Symbol.for('Pages'),
|
||||||
Preference: Symbol.for('Preference'),
|
Preference: Symbol.for('Preference'),
|
||||||
|
Sync: Symbol.for('Sync'),
|
||||||
SystemPreference: Symbol.for('SystemPreference'),
|
SystemPreference: Symbol.for('SystemPreference'),
|
||||||
ThemeService: Symbol.for('ThemeService'),
|
ThemeService: Symbol.for('ThemeService'),
|
||||||
Updater: Symbol.for('Updater'),
|
Updater: Symbol.for('Updater'),
|
||||||
|
|
|
||||||
137
src/services/sync/index.ts
Normal file
137
src/services/sync/index.ts
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
import { injectable } from 'inversify';
|
||||||
|
|
||||||
|
import { WikiChannel } from '@/constants/channels';
|
||||||
|
import type { IAuthenticationService } from '@services/auth/interface';
|
||||||
|
import { lazyInject } from '@services/container';
|
||||||
|
import { ICommitAndSyncConfigs, IGitService } from '@services/git/interface';
|
||||||
|
import { logger } from '@services/libs/log';
|
||||||
|
import type { IPreferenceService } from '@services/preferences/interface';
|
||||||
|
import serviceIdentifier from '@services/serviceIdentifier';
|
||||||
|
import { SupportedStorageServices } from '@services/types';
|
||||||
|
import type { IViewService } from '@services/view/interface';
|
||||||
|
import type { IWikiService } from '@services/wiki/interface';
|
||||||
|
import { IWorkspace, IWorkspaceService } from '@services/workspaces/interface';
|
||||||
|
import { IWorkspaceViewService } from '@services/workspacesView/interface';
|
||||||
|
import { ISyncService } from './interface';
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
export class Sync implements ISyncService {
|
||||||
|
@lazyInject(serviceIdentifier.Authentication)
|
||||||
|
private readonly authService!: IAuthenticationService;
|
||||||
|
|
||||||
|
@lazyInject(serviceIdentifier.Preference)
|
||||||
|
private readonly preferenceService!: IPreferenceService;
|
||||||
|
|
||||||
|
@lazyInject(serviceIdentifier.Wiki)
|
||||||
|
private readonly wikiService!: IWikiService;
|
||||||
|
|
||||||
|
@lazyInject(serviceIdentifier.View)
|
||||||
|
private readonly viewService!: IViewService;
|
||||||
|
|
||||||
|
@lazyInject(serviceIdentifier.Git)
|
||||||
|
private readonly gitService!: IGitService;
|
||||||
|
|
||||||
|
@lazyInject(serviceIdentifier.WorkspaceView)
|
||||||
|
private readonly workspaceViewService!: IWorkspaceViewService;
|
||||||
|
|
||||||
|
@lazyInject(serviceIdentifier.Workspace)
|
||||||
|
private readonly workspaceService!: IWorkspaceService;
|
||||||
|
|
||||||
|
public async syncWikiIfNeeded(workspace: IWorkspace): Promise<void> {
|
||||||
|
const { gitUrl, storageService, backupOnInterval, id, isSubWiki } = workspace;
|
||||||
|
const userInfo = await this.authService.getStorageServiceUserInfo(storageService);
|
||||||
|
|
||||||
|
if (
|
||||||
|
storageService !== SupportedStorageServices.local &&
|
||||||
|
typeof gitUrl === 'string' &&
|
||||||
|
userInfo !== undefined &&
|
||||||
|
(await this.checkCanSyncDueToNoDraft(id))
|
||||||
|
) {
|
||||||
|
const syncOrForcePullConfigs = { remoteUrl: gitUrl, userInfo } satisfies ICommitAndSyncConfigs;
|
||||||
|
// sync current workspace first
|
||||||
|
const hasChanges = await this.gitService.syncOrForcePull(workspace, syncOrForcePullConfigs);
|
||||||
|
if (isSubWiki) {
|
||||||
|
// after sync this sub wiki, reload its main workspace
|
||||||
|
const mainWorkspace = this.workspaceService.getMainWorkspace(workspace);
|
||||||
|
if (hasChanges && mainWorkspace !== undefined) {
|
||||||
|
await this.workspaceViewService.restartWorkspaceViewService(mainWorkspace.id);
|
||||||
|
await this.viewService.reloadViewsWebContents(mainWorkspace.id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// sync all sub workspace
|
||||||
|
const subWorkspaces = await this.workspaceService.getSubWorkspacesAsList(id);
|
||||||
|
const subHasChangesPromise = subWorkspaces.map(async (subWorkspace) => {
|
||||||
|
const { gitUrl: subGitUrl, storageService: subStorageService } = subWorkspace;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||||
|
if (!subGitUrl) return false;
|
||||||
|
const subUserInfo = await this.authService.getStorageServiceUserInfo(subStorageService);
|
||||||
|
const hasChanges = await this.gitService.syncOrForcePull(subWorkspace, { remoteUrl: subGitUrl, userInfo: subUserInfo });
|
||||||
|
return hasChanges;
|
||||||
|
});
|
||||||
|
const subHasChange = (await Promise.all(subHasChangesPromise)).some(Boolean);
|
||||||
|
// any of main or sub has changes, reload main workspace
|
||||||
|
if (hasChanges || subHasChange) {
|
||||||
|
await this.workspaceViewService.restartWorkspaceViewService(id);
|
||||||
|
await this.viewService.reloadViewsWebContents(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (backupOnInterval && (await this.checkCanSyncDueToNoDraft(id))) {
|
||||||
|
// for local workspace, commitOnly, no sync and no force pull.
|
||||||
|
await this.gitService.commitAndSync(workspace, { commitOnly: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async checkCanSyncDueToNoDraft(workspaceID: string): Promise<boolean> {
|
||||||
|
const syncOnlyWhenNoDraft = await this.preferenceService.get('syncOnlyWhenNoDraft');
|
||||||
|
if (!syncOnlyWhenNoDraft) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// TODO: check this, seems not working.
|
||||||
|
const draftTitles = await this.wikiService.wikiOperationInServer(WikiChannel.runFilter, workspaceID, ['[is[draft]]']);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||||
|
if (Array.isArray(draftTitles) && draftTitles.length > 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(
|
||||||
|
`${(error as Error).message} when checking draft titles. ${
|
||||||
|
(error as Error).stack ?? ''
|
||||||
|
}\n This might because it just will throw error when on Windows and App is at background (BrowserView will disappear and not accessible.)`,
|
||||||
|
);
|
||||||
|
// when app is on background, might have no draft, because user won't edit it. So just return true
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record<workspaceID, returnValue<setInterval>>
|
||||||
|
* Set this in wikiStartup, and clear it when wiki is down.
|
||||||
|
*/
|
||||||
|
private wikiSyncIntervals: Record<string, ReturnType<typeof setInterval>> = {};
|
||||||
|
/**
|
||||||
|
* Trigger git sync interval if needed in config
|
||||||
|
*/
|
||||||
|
public async startIntervalSyncIfNeeded(workspace: IWorkspace): Promise<void> {
|
||||||
|
const { syncOnInterval, backupOnInterval, id } = workspace;
|
||||||
|
if (syncOnInterval || backupOnInterval) {
|
||||||
|
const syncDebounceInterval = await this.preferenceService.get('syncDebounceInterval');
|
||||||
|
this.wikiSyncIntervals[id] = setInterval(async () => {
|
||||||
|
await this.syncWikiIfNeeded(workspace);
|
||||||
|
}, syncDebounceInterval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public stopIntervalSync(workspaceID: string): void {
|
||||||
|
if (typeof this.wikiSyncIntervals[workspaceID] === 'number') {
|
||||||
|
clearInterval(this.wikiSyncIntervals[workspaceID]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public clearAllSyncIntervals(): void {
|
||||||
|
Object.values(this.wikiSyncIntervals).forEach((interval) => {
|
||||||
|
clearInterval(interval);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/services/sync/interface.ts
Normal file
33
src/services/sync/interface.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { SyncChannel } from '@/constants/channels';
|
||||||
|
import { IWorkspace } from '@services/workspaces/interface';
|
||||||
|
|
||||||
|
import { ProxyPropertyType } from 'electron-ipc-cat/common';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manage sync process and interval sync.
|
||||||
|
*/
|
||||||
|
export interface ISyncService {
|
||||||
|
/**
|
||||||
|
* Check if there is any draft in current workspace that block us syncing.
|
||||||
|
* @returns true if can sync, false if cannot sync due to there is a draft in current workspace.
|
||||||
|
*/
|
||||||
|
checkCanSyncDueToNoDraft(workspaceID: string): Promise<boolean>;
|
||||||
|
clearAllSyncIntervals(): void;
|
||||||
|
startIntervalSyncIfNeeded(workspace: IWorkspace): Promise<void>;
|
||||||
|
stopIntervalSync(workspaceID: string): void;
|
||||||
|
/**
|
||||||
|
* Trigger git sync for a wiki workspace.
|
||||||
|
* Simply do some check before calling `gitService.syncOrForcePull`, and after that, restart workspaceViewService if needed.
|
||||||
|
*/
|
||||||
|
syncWikiIfNeeded(workspace: IWorkspace): Promise<void>;
|
||||||
|
}
|
||||||
|
export const SyncServiceIPCDescriptor = {
|
||||||
|
channel: SyncChannel.name,
|
||||||
|
properties: {
|
||||||
|
clearAllSyncIntervals: ProxyPropertyType.Function,
|
||||||
|
checkCanSyncDueToNoDraft: ProxyPropertyType.Function,
|
||||||
|
startIntervalSyncIfNeeded: ProxyPropertyType.Function,
|
||||||
|
stopIntervalSync: ProxyPropertyType.Function,
|
||||||
|
syncWikiIfNeeded: ProxyPropertyType.Function,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -18,7 +18,6 @@ import type { IGitService, IGitUserInfos } from '@services/git/interface';
|
||||||
import { i18n } from '@services/libs/i18n';
|
import { i18n } from '@services/libs/i18n';
|
||||||
import { getWikiErrorLogFileName, logger, startWikiLogger } from '@services/libs/log';
|
import { getWikiErrorLogFileName, logger, startWikiLogger } from '@services/libs/log';
|
||||||
import serviceIdentifier from '@services/serviceIdentifier';
|
import serviceIdentifier from '@services/serviceIdentifier';
|
||||||
import { SupportedStorageServices } from '@services/types';
|
|
||||||
import type { IViewService } from '@services/view/interface';
|
import type { IViewService } from '@services/view/interface';
|
||||||
import type { IWindowService } from '@services/windows/interface';
|
import type { IWindowService } from '@services/windows/interface';
|
||||||
import { WindowNames } from '@services/windows/WindowProperties';
|
import { WindowNames } from '@services/windows/WindowProperties';
|
||||||
|
|
@ -42,6 +41,7 @@ import { isHtmlWiki } from '@/constants/fileNames';
|
||||||
import { defaultServerIP } from '@/constants/urls';
|
import { defaultServerIP } from '@/constants/urls';
|
||||||
import { IDatabaseService } from '@services/database/interface';
|
import { IDatabaseService } from '@services/database/interface';
|
||||||
import { IPreferenceService } from '@services/preferences/interface';
|
import { IPreferenceService } from '@services/preferences/interface';
|
||||||
|
import { ISyncService } from '@services/sync/interface';
|
||||||
import { mapValues } from 'lodash';
|
import { mapValues } from 'lodash';
|
||||||
import { wikiWorkerStartedEventName } from './constants';
|
import { wikiWorkerStartedEventName } from './constants';
|
||||||
import { IWorkerWikiOperations } from './wikiOperations/executor/wikiOperationInServer';
|
import { IWorkerWikiOperations } from './wikiOperations/executor/wikiOperationInServer';
|
||||||
|
|
@ -73,6 +73,9 @@ export class Wiki implements IWikiService {
|
||||||
@lazyInject(serviceIdentifier.WorkspaceView)
|
@lazyInject(serviceIdentifier.WorkspaceView)
|
||||||
private readonly workspaceViewService!: IWorkspaceViewService;
|
private readonly workspaceViewService!: IWorkspaceViewService;
|
||||||
|
|
||||||
|
@lazyInject(serviceIdentifier.Sync)
|
||||||
|
private readonly syncService!: ISyncService;
|
||||||
|
|
||||||
public async getSubWikiPluginContent(mainWikiPath: string): Promise<ISubWikiPluginContent[]> {
|
public async getSubWikiPluginContent(mainWikiPath: string): Promise<ISubWikiPluginContent[]> {
|
||||||
return await getSubWikiPluginContent(mainWikiPath);
|
return await getSubWikiPluginContent(mainWikiPath);
|
||||||
}
|
}
|
||||||
|
|
@ -329,7 +332,7 @@ export class Wiki implements IWikiService {
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
clearInterval(this.wikiSyncIntervals[id]);
|
this.syncService.stopIntervalSync(id);
|
||||||
try {
|
try {
|
||||||
logger.debug(`worker.beforeExit for ${id}`);
|
logger.debug(`worker.beforeExit for ${id}`);
|
||||||
await worker.beforeExit();
|
await worker.beforeExit();
|
||||||
|
|
@ -597,84 +600,6 @@ export class Wiki implements IWikiService {
|
||||||
return textResult;
|
return textResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Trigger git sync
|
|
||||||
* Simply do some check before calling `gitService.syncOrForcePull`
|
|
||||||
*/
|
|
||||||
private async syncWikiIfNeeded(workspace: IWorkspace): Promise<void> {
|
|
||||||
const { gitUrl: githubRepoUrl, storageService, backupOnInterval, id } = workspace;
|
|
||||||
const checkCanSyncDueToNoDraft = async (): Promise<boolean> => {
|
|
||||||
const syncOnlyWhenNoDraft = await this.preferenceService.get('syncOnlyWhenNoDraft');
|
|
||||||
if (!syncOnlyWhenNoDraft) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const draftTitles = await this.wikiOperationInServer(WikiChannel.runFilter, id, ['[is[draft]]']);
|
|
||||||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
||||||
if (Array.isArray(draftTitles) && draftTitles.length > 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
logger.error(
|
|
||||||
`${(error as Error).message} when checking draft titles. ${
|
|
||||||
(error as Error).stack ?? ''
|
|
||||||
}\n This might because it just will throw error when on Windows and App is at background (BrowserView will disappear and not accessible.)`,
|
|
||||||
);
|
|
||||||
// when app is on background, might have no draft, because user won't edit it. So just return true
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const userInfo = await this.authService.getStorageServiceUserInfo(storageService);
|
|
||||||
|
|
||||||
if (
|
|
||||||
storageService !== SupportedStorageServices.local &&
|
|
||||||
typeof githubRepoUrl === 'string' &&
|
|
||||||
userInfo !== undefined &&
|
|
||||||
(await checkCanSyncDueToNoDraft())
|
|
||||||
) {
|
|
||||||
const hasChanges = await this.gitService.syncOrForcePull(workspace, { remoteUrl: githubRepoUrl, userInfo });
|
|
||||||
if (hasChanges) {
|
|
||||||
await this.workspaceViewService.restartWorkspaceViewService(id);
|
|
||||||
await this.viewService.reloadViewsWebContents(id);
|
|
||||||
}
|
|
||||||
} else if (backupOnInterval && (await checkCanSyncDueToNoDraft())) {
|
|
||||||
// for local workspace, commitOnly, no sync and no force pull.
|
|
||||||
await this.gitService.commitAndSync(workspace, { commitOnly: true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Record<workspaceID, returnValue<setInterval>>
|
|
||||||
* Set this in wikiStartup, and clear it when wiki is down.
|
|
||||||
*/
|
|
||||||
private wikiSyncIntervals: Record<string, ReturnType<typeof setInterval>> = {};
|
|
||||||
/**
|
|
||||||
* Trigger git sync interval if needed in config
|
|
||||||
*/
|
|
||||||
private async startIntervalSyncIfNeeded(workspace: IWorkspace): Promise<void> {
|
|
||||||
const { syncOnInterval, backupOnInterval, id } = workspace;
|
|
||||||
if (syncOnInterval || backupOnInterval) {
|
|
||||||
const syncDebounceInterval = await this.preferenceService.get('syncDebounceInterval');
|
|
||||||
this.wikiSyncIntervals[id] = setInterval(async () => {
|
|
||||||
await this.syncWikiIfNeeded(workspace);
|
|
||||||
}, syncDebounceInterval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private stopIntervalSync(workspace: IWorkspace): void {
|
|
||||||
const { id } = workspace;
|
|
||||||
if (typeof this.wikiSyncIntervals[id] === 'number') {
|
|
||||||
clearInterval(this.wikiSyncIntervals[id]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public clearAllSyncIntervals(): void {
|
|
||||||
Object.values(this.wikiSyncIntervals).forEach((interval) => {
|
|
||||||
clearInterval(interval);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public async wikiStartup(workspace: IWorkspace): Promise<void> {
|
public async wikiStartup(workspace: IWorkspace): Promise<void> {
|
||||||
const { id, isSubWiki, name, mainWikiID, wikiFolderLocation } = workspace;
|
const { id, isSubWiki, name, mainWikiID, wikiFolderLocation } = workspace;
|
||||||
|
|
||||||
|
|
@ -722,7 +647,7 @@ export class Wiki implements IWikiService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await this.startIntervalSyncIfNeeded(workspace);
|
await this.syncService.startIntervalSyncIfNeeded(workspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async restartWiki(workspace: IWorkspace): Promise<void> {
|
public async restartWiki(workspace: IWorkspace): Promise<void> {
|
||||||
|
|
@ -731,12 +656,12 @@ export class Wiki implements IWikiService {
|
||||||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||||
const userName = await this.authService.getUserName(workspace);
|
const userName = await this.authService.getUserName(workspace);
|
||||||
|
|
||||||
this.stopIntervalSync(workspace);
|
this.syncService.stopIntervalSync(id);
|
||||||
if (!isSubWiki) {
|
if (!isSubWiki) {
|
||||||
await this.stopWiki(id);
|
await this.stopWiki(id);
|
||||||
await this.startWiki(id, userName);
|
await this.startWiki(id, userName);
|
||||||
}
|
}
|
||||||
await this.startIntervalSyncIfNeeded(workspace);
|
await this.syncService.startIntervalSyncIfNeeded(workspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateSubWikiPluginContent(mainWikiPath: string, newConfig?: IWorkspace, oldConfig?: IWorkspace): Promise<void> {
|
public async updateSubWikiPluginContent(mainWikiPath: string, newConfig?: IWorkspace, oldConfig?: IWorkspace): Promise<void> {
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ export interface IWikiService {
|
||||||
/** return true if wiki does existed and folder is a valid tiddlywiki folder, return error message (a string) if there is an error checking wiki existence */
|
/** return true if wiki does existed and folder is a valid tiddlywiki folder, return error message (a string) if there is an error checking wiki existence */
|
||||||
checkWikiExist(workspace: IWorkspace, options?: { shouldBeMainWiki?: boolean; showDialog?: boolean }): Promise<string | true>;
|
checkWikiExist(workspace: IWorkspace, options?: { shouldBeMainWiki?: boolean; showDialog?: boolean }): Promise<string | true>;
|
||||||
checkWikiStartLock(wikiFolderLocation: string): boolean;
|
checkWikiStartLock(wikiFolderLocation: string): boolean;
|
||||||
clearAllSyncIntervals(): void;
|
|
||||||
cloneSubWiki(
|
cloneSubWiki(
|
||||||
parentFolderLocation: string,
|
parentFolderLocation: string,
|
||||||
wikiFolderName: string,
|
wikiFolderName: string,
|
||||||
|
|
@ -106,7 +105,6 @@ export const WikiServiceIPCDescriptor = {
|
||||||
properties: {
|
properties: {
|
||||||
callWikiIpcServerRoute: ProxyPropertyType.Function,
|
callWikiIpcServerRoute: ProxyPropertyType.Function,
|
||||||
checkWikiExist: ProxyPropertyType.Function,
|
checkWikiExist: ProxyPropertyType.Function,
|
||||||
clearAllSyncIntervals: ProxyPropertyType.Function,
|
|
||||||
cloneSubWiki: ProxyPropertyType.Function,
|
cloneSubWiki: ProxyPropertyType.Function,
|
||||||
cloneWiki: ProxyPropertyType.Function,
|
cloneWiki: ProxyPropertyType.Function,
|
||||||
copyWikiTemplate: ProxyPropertyType.Function,
|
copyWikiTemplate: ProxyPropertyType.Function,
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import type { IWorkspaceViewService } from '@services/workspacesView/interface';
|
||||||
import { IContextService } from '@services/context/interface';
|
import { IContextService } from '@services/context/interface';
|
||||||
import { i18n } from '@services/libs/i18n';
|
import { i18n } from '@services/libs/i18n';
|
||||||
import { logger } from '@services/libs/log';
|
import { logger } from '@services/libs/log';
|
||||||
|
import { ISyncService } from '@services/sync/interface';
|
||||||
import { SupportedStorageServices } from '@services/types';
|
import { SupportedStorageServices } from '@services/types';
|
||||||
import { updateGhConfig } from '@services/wiki/plugin/ghPages';
|
import { updateGhConfig } from '@services/wiki/plugin/ghPages';
|
||||||
import { hasGit } from 'git-sync-js';
|
import { hasGit } from 'git-sync-js';
|
||||||
|
|
@ -48,6 +49,9 @@ export class WikiGitWorkspace implements IWikiGitWorkspaceService {
|
||||||
@lazyInject(serviceIdentifier.NotificationService)
|
@lazyInject(serviceIdentifier.NotificationService)
|
||||||
private readonly notificationService!: INotificationService;
|
private readonly notificationService!: INotificationService;
|
||||||
|
|
||||||
|
@lazyInject(serviceIdentifier.Sync)
|
||||||
|
private readonly syncService!: ISyncService;
|
||||||
|
|
||||||
public registerSyncBeforeShutdown(): void {
|
public registerSyncBeforeShutdown(): void {
|
||||||
const listener = async (event: Event): Promise<void> => {
|
const listener = async (event: Event): Promise<void> => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
@ -62,11 +66,7 @@ export class WikiGitWorkspace implements IWikiGitWorkspaceService {
|
||||||
if (workspace.readOnlyMode) {
|
if (workspace.readOnlyMode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const userInfo = await this.authService.getStorageServiceUserInfo(workspace.storageService);
|
await this.syncService.syncWikiIfNeeded(workspace);
|
||||||
if (userInfo !== undefined && workspace.gitUrl !== null) {
|
|
||||||
// TODO: use syncWikiIfNeeded
|
|
||||||
await this.gitService.commitAndSync(workspace, { remoteUrl: workspace.gitUrl, userInfo });
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import { IContextService } from '@services/context/interface';
|
||||||
import { IGitService } from '@services/git/interface';
|
import { IGitService } from '@services/git/interface';
|
||||||
import type { INativeService } from '@services/native/interface';
|
import type { INativeService } from '@services/native/interface';
|
||||||
import { IPagesService, PageType } from '@services/pages/interface';
|
import { IPagesService, PageType } from '@services/pages/interface';
|
||||||
|
import { ISyncService } from '@services/sync/interface';
|
||||||
import { SupportedStorageServices } from '@services/types';
|
import { SupportedStorageServices } from '@services/types';
|
||||||
import type { IViewService } from '@services/view/interface';
|
import type { IViewService } from '@services/view/interface';
|
||||||
import type { IWikiService } from '@services/wiki/interface';
|
import type { IWikiService } from '@services/wiki/interface';
|
||||||
|
|
@ -23,6 +24,7 @@ interface IWorkspaceMenuRequiredServices {
|
||||||
git: Pick<IGitService, 'commitAndSync'>;
|
git: Pick<IGitService, 'commitAndSync'>;
|
||||||
native: Pick<INativeService, 'openURI' | 'openPath' | 'openInEditor' | 'openInGitGuiApp' | 'getLocalHostUrlWithActualInfo'>;
|
native: Pick<INativeService, 'openURI' | 'openPath' | 'openInEditor' | 'openInGitGuiApp' | 'getLocalHostUrlWithActualInfo'>;
|
||||||
pages: Pick<IPagesService, 'setActivePage' | 'getActivePage'>;
|
pages: Pick<IPagesService, 'setActivePage' | 'getActivePage'>;
|
||||||
|
sync: Pick<ISyncService, 'syncWikiIfNeeded'>;
|
||||||
view: Pick<IViewService, 'reloadViewsWebContents' | 'getViewCurrentUrl'>;
|
view: Pick<IViewService, 'reloadViewsWebContents' | 'getViewCurrentUrl'>;
|
||||||
wiki: Pick<IWikiService, 'wikiOperationInBrowser' | 'wikiOperationInServer' | 'requestWikiSendActionMessage'>;
|
wiki: Pick<IWikiService, 'wikiOperationInBrowser' | 'wikiOperationInServer' | 'requestWikiSendActionMessage'>;
|
||||||
wikiGitWorkspace: Pick<IWikiGitWorkspaceService, 'removeWorkspace'>;
|
wikiGitWorkspace: Pick<IWikiGitWorkspaceService, 'removeWorkspace'>;
|
||||||
|
|
@ -130,37 +132,7 @@ export async function getWorkspaceMenuTemplate(
|
||||||
label: t('ContextMenu.SyncNow') + (isOnline ? '' : `(${t('ContextMenu.NoNetworkConnection')})`),
|
label: t('ContextMenu.SyncNow') + (isOnline ? '' : `(${t('ContextMenu.NoNetworkConnection')})`),
|
||||||
enabled: isOnline,
|
enabled: isOnline,
|
||||||
click: async () => {
|
click: async () => {
|
||||||
if (isSubWiki) {
|
await service.sync.syncWikiIfNeeded(workspace);
|
||||||
// TODO: use syncWikiIfNeeded
|
|
||||||
const hasChanges = await service.git.commitAndSync(workspace, { remoteUrl: gitUrl, userInfo });
|
|
||||||
if (hasChanges) {
|
|
||||||
if (mainWikiID === null) {
|
|
||||||
await service.workspaceView.restartWorkspaceViewService(id);
|
|
||||||
await service.view.reloadViewsWebContents(id);
|
|
||||||
} else {
|
|
||||||
// reload main workspace to reflect change (do this before watch-fs stable)
|
|
||||||
await service.workspaceView.restartWorkspaceViewService(mainWikiID);
|
|
||||||
await service.view.reloadViewsWebContents(mainWikiID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// sync all sub workspace
|
|
||||||
const mainHasChanges = await service.git.commitAndSync(workspace, { remoteUrl: gitUrl, userInfo });
|
|
||||||
const subWorkspaces = await service.workspace.getSubWorkspacesAsList(id);
|
|
||||||
const subHasChangesPromise = subWorkspaces.map(async (subWorkspace) => {
|
|
||||||
const { gitUrl: subGitUrl } = subWorkspace;
|
|
||||||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
||||||
if (!subGitUrl) return false;
|
|
||||||
const hasChanges = await service.git.commitAndSync(subWorkspace, { remoteUrl: subGitUrl, userInfo });
|
|
||||||
return hasChanges;
|
|
||||||
});
|
|
||||||
const subHasChange = (await Promise.all(subHasChangesPromise)).some(Boolean);
|
|
||||||
const hasChange = mainHasChanges || subHasChange;
|
|
||||||
if (hasChange) {
|
|
||||||
await service.workspaceView.restartWorkspaceViewService(id);
|
|
||||||
await service.view.reloadViewsWebContents(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import path from 'path';
|
||||||
import { BehaviorSubject, Observable } from 'rxjs';
|
import { BehaviorSubject, Observable } from 'rxjs';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { DELAY_MENU_REGISTER } from '@/constants/parameters';
|
||||||
import { getDefaultTidGiUrl } from '@/constants/urls';
|
import { getDefaultTidGiUrl } from '@/constants/urls';
|
||||||
import { fixSettingFileWhenError } from '@/helpers/configSetting';
|
import { fixSettingFileWhenError } from '@/helpers/configSetting';
|
||||||
import { IAuthenticationService } from '@services/auth/interface';
|
import { IAuthenticationService } from '@services/auth/interface';
|
||||||
|
|
@ -33,7 +34,6 @@ import { debouncedSetSettingFile } from './debouncedSetSettingFile';
|
||||||
import type { INewWorkspaceConfig, IWorkspace, IWorkspaceMetaData, IWorkspaceService, IWorkspaceWithMetadata } from './interface';
|
import type { INewWorkspaceConfig, IWorkspace, IWorkspaceMetaData, IWorkspaceService, IWorkspaceWithMetadata } from './interface';
|
||||||
import { registerMenu } from './registerMenu';
|
import { registerMenu } from './registerMenu';
|
||||||
import { workspaceSorter } from './utils';
|
import { workspaceSorter } from './utils';
|
||||||
import { DELAY_MENU_REGISTER } from '@/constants/parameters';
|
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class Workspace implements IWorkspaceService {
|
export class Workspace implements IWorkspaceService {
|
||||||
|
|
@ -212,6 +212,16 @@ export class Workspace implements IWorkspaceService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getMainWorkspace(subWorkspace: IWorkspace): IWorkspace | undefined {
|
||||||
|
const { mainWikiID, isSubWiki, mainWikiToLink } = subWorkspace;
|
||||||
|
if (!isSubWiki) return undefined;
|
||||||
|
if (mainWikiID) return this.getSync(mainWikiID);
|
||||||
|
const mainWorkspace = (this.getWorkspacesAsListSync() ?? []).find(
|
||||||
|
(workspaceToSearch) => mainWikiToLink === workspaceToSearch.wikiFolderLocation,
|
||||||
|
);
|
||||||
|
return mainWorkspace;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pure function that make sure workspace setting is consistent, or doing migration across updates
|
* Pure function that make sure workspace setting is consistent, or doing migration across updates
|
||||||
* @param workspaceToSanitize User input workspace or loaded workspace, that may contains bad values
|
* @param workspaceToSanitize User input workspace or loaded workspace, that may contains bad values
|
||||||
|
|
@ -226,9 +236,7 @@ export class Workspace implements IWorkspaceService {
|
||||||
const fixingValues: Partial<IWorkspace> = {};
|
const fixingValues: Partial<IWorkspace> = {};
|
||||||
// we add mainWikiID in creation, we fix this value for old existed workspaces
|
// we add mainWikiID in creation, we fix this value for old existed workspaces
|
||||||
if (workspaceToSanitize.isSubWiki && !workspaceToSanitize.mainWikiID) {
|
if (workspaceToSanitize.isSubWiki && !workspaceToSanitize.mainWikiID) {
|
||||||
const mainWorkspace = (this.getWorkspacesAsListSync() ?? []).find(
|
const mainWorkspace = this.getMainWorkspace(workspaceToSanitize);
|
||||||
(workspaceToSearch) => workspaceToSanitize.mainWikiToLink === workspaceToSearch.wikiFolderLocation,
|
|
||||||
);
|
|
||||||
if (mainWorkspace !== undefined) {
|
if (mainWorkspace !== undefined) {
|
||||||
fixingValues.mainWikiID = mainWorkspace.id;
|
fixingValues.mainWikiID = mainWorkspace.id;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -178,6 +178,11 @@ export interface IWorkspaceService {
|
||||||
getAllMetaData: () => Promise<Record<string, Partial<IWorkspaceMetaData>>>;
|
getAllMetaData: () => Promise<Record<string, Partial<IWorkspaceMetaData>>>;
|
||||||
getByWikiFolderLocation(wikiFolderLocation: string): Promise<IWorkspace | undefined>;
|
getByWikiFolderLocation(wikiFolderLocation: string): Promise<IWorkspace | undefined>;
|
||||||
getFirstWorkspace: () => Promise<IWorkspace | undefined>;
|
getFirstWorkspace: () => Promise<IWorkspace | undefined>;
|
||||||
|
/**
|
||||||
|
* Get parent workspace of a subWorkspace, if the workspace you provided is a main workspace, return undefined.
|
||||||
|
* @param subWorkspace your workspace object
|
||||||
|
*/
|
||||||
|
getMainWorkspace(subWorkspace: IWorkspace): IWorkspace | undefined;
|
||||||
getMetaData: (id: string) => Promise<Partial<IWorkspaceMetaData>>;
|
getMetaData: (id: string) => Promise<Partial<IWorkspaceMetaData>>;
|
||||||
getNextWorkspace: (id: string) => Promise<IWorkspace | undefined>;
|
getNextWorkspace: (id: string) => Promise<IWorkspace | undefined>;
|
||||||
getPreviousWorkspace: (id: string) => Promise<IWorkspace | undefined>;
|
getPreviousWorkspace: (id: string) => Promise<IWorkspace | undefined>;
|
||||||
|
|
@ -206,8 +211,8 @@ export interface IWorkspaceService {
|
||||||
export const WorkspaceServiceIPCDescriptor = {
|
export const WorkspaceServiceIPCDescriptor = {
|
||||||
channel: WorkspaceChannel.name,
|
channel: WorkspaceChannel.name,
|
||||||
properties: {
|
properties: {
|
||||||
countWorkspaces: ProxyPropertyType.Function,
|
|
||||||
clearActiveWorkspace: ProxyPropertyType.Function,
|
clearActiveWorkspace: ProxyPropertyType.Function,
|
||||||
|
countWorkspaces: ProxyPropertyType.Function,
|
||||||
create: ProxyPropertyType.Function,
|
create: ProxyPropertyType.Function,
|
||||||
get: ProxyPropertyType.Function,
|
get: ProxyPropertyType.Function,
|
||||||
get$: ProxyPropertyType.Function$,
|
get$: ProxyPropertyType.Function$,
|
||||||
|
|
@ -215,6 +220,7 @@ export const WorkspaceServiceIPCDescriptor = {
|
||||||
getAllMetaData: ProxyPropertyType.Function,
|
getAllMetaData: ProxyPropertyType.Function,
|
||||||
getByName: ProxyPropertyType.Function,
|
getByName: ProxyPropertyType.Function,
|
||||||
getFirstWorkspace: ProxyPropertyType.Function,
|
getFirstWorkspace: ProxyPropertyType.Function,
|
||||||
|
getMainWorkspace: ProxyPropertyType.Function,
|
||||||
getMetaData: ProxyPropertyType.Function,
|
getMetaData: ProxyPropertyType.Function,
|
||||||
getNextWorkspace: ProxyPropertyType.Function,
|
getNextWorkspace: ProxyPropertyType.Function,
|
||||||
getPreviousWorkspace: ProxyPropertyType.Function,
|
getPreviousWorkspace: ProxyPropertyType.Function,
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ import type { IGitService } from '@services/git/interface';
|
||||||
import { i18n } from '@services/libs/i18n';
|
import { i18n } from '@services/libs/i18n';
|
||||||
import { logger } from '@services/libs/log';
|
import { logger } from '@services/libs/log';
|
||||||
import type { IMenuService } from '@services/menu/interface';
|
import type { IMenuService } from '@services/menu/interface';
|
||||||
import { INativeService } from '@services/native/interface';
|
|
||||||
import type { IPreferenceService } from '@services/preferences/interface';
|
import type { IPreferenceService } from '@services/preferences/interface';
|
||||||
import serviceIdentifier from '@services/serviceIdentifier';
|
import serviceIdentifier from '@services/serviceIdentifier';
|
||||||
import { SupportedStorageServices } from '@services/types';
|
import { SupportedStorageServices } from '@services/types';
|
||||||
|
|
@ -26,6 +25,7 @@ import { WindowNames } from '@services/windows/WindowProperties';
|
||||||
import type { IWorkspace, IWorkspaceService } from '@services/workspaces/interface';
|
import type { IWorkspace, IWorkspaceService } from '@services/workspaces/interface';
|
||||||
|
|
||||||
import { DELAY_MENU_REGISTER } from '@/constants/parameters';
|
import { DELAY_MENU_REGISTER } from '@/constants/parameters';
|
||||||
|
import { ISyncService } from '@services/sync/interface';
|
||||||
import type { IInitializeWorkspaceOptions, IWorkspaceViewService } from './interface';
|
import type { IInitializeWorkspaceOptions, IWorkspaceViewService } from './interface';
|
||||||
import { registerMenu } from './registerMenu';
|
import { registerMenu } from './registerMenu';
|
||||||
|
|
||||||
|
|
@ -61,8 +61,8 @@ export class WorkspaceView implements IWorkspaceViewService {
|
||||||
@lazyInject(serviceIdentifier.WorkspaceView)
|
@lazyInject(serviceIdentifier.WorkspaceView)
|
||||||
private readonly workspaceViewService!: IWorkspaceViewService;
|
private readonly workspaceViewService!: IWorkspaceViewService;
|
||||||
|
|
||||||
@lazyInject(serviceIdentifier.NativeService)
|
@lazyInject(serviceIdentifier.Sync)
|
||||||
private readonly nativeService!: INativeService;
|
private readonly syncService!: ISyncService;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
@ -115,8 +115,11 @@ export class WorkspaceView implements IWorkspaceViewService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const syncGitWhenInitializeWorkspaceView = async () => {
|
const syncGitWhenInitializeWorkspaceView = async () => {
|
||||||
const { wikiFolderLocation, gitUrl: githubRepoUrl, storageService } = workspace;
|
const { wikiFolderLocation, gitUrl: githubRepoUrl, storageService, isSubWiki } = workspace;
|
||||||
|
// we are using syncWikiIfNeeded that handles recursive sync for all subwiki, so we only need to pass main wiki to it in this method.
|
||||||
|
if (isSubWiki) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// get sync process ready
|
// get sync process ready
|
||||||
try {
|
try {
|
||||||
if (workspace.syncOnStartup && storageService !== SupportedStorageServices.local && syncImmediately) {
|
if (workspace.syncOnStartup && storageService !== SupportedStorageServices.local && syncImmediately) {
|
||||||
|
|
@ -129,7 +132,11 @@ export class WorkspaceView implements IWorkspaceViewService {
|
||||||
throw new Error(i18n.t(`Error.MainWindowMissing`));
|
throw new Error(i18n.t(`Error.MainWindowMissing`));
|
||||||
}
|
}
|
||||||
const userInfo = await this.authService.getStorageServiceUserInfo(workspace.storageService);
|
const userInfo = await this.authService.getStorageServiceUserInfo(workspace.storageService);
|
||||||
if (userInfo === undefined) {
|
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||||
|
if (userInfo?.accessToken) {
|
||||||
|
// sync in non-blocking way
|
||||||
|
void this.syncService.syncWikiIfNeeded(workspace);
|
||||||
|
} else {
|
||||||
// user not login into Github or something else
|
// user not login into Github or something else
|
||||||
void dialog.showMessageBox(mainWindow, {
|
void dialog.showMessageBox(mainWindow, {
|
||||||
title: i18n.t('Dialog.StorageServiceUserInfoNoFound'),
|
title: i18n.t('Dialog.StorageServiceUserInfoNoFound'),
|
||||||
|
|
@ -138,15 +145,6 @@ export class WorkspaceView implements IWorkspaceViewService {
|
||||||
cancelId: 0,
|
cancelId: 0,
|
||||||
defaultId: 0,
|
defaultId: 0,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
// sync in non-blocking way
|
|
||||||
// TODO: use syncWikiIfNeeded
|
|
||||||
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) {
|
} catch (error) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue