diff --git a/src/preload/common/remote.ts b/src/preload/common/remote.ts index 1bcab8f2..5606014e 100644 --- a/src/preload/common/remote.ts +++ b/src/preload/common/remote.ts @@ -8,9 +8,9 @@ import * as service from './services'; import { windowName } from './browserViewMetaData'; export const remoteMethods = { - popContextMenu: (menus: MenuItemConstructorOptions[], parameters: IOnContextMenuInfo): (() => void) => { + popContextMenu: async (menus: MenuItemConstructorOptions[], parameters: IOnContextMenuInfo): Promise<() => void> => { const [ipcSafeMenus, unregister] = rendererMenuItemProxy(menus); - void service.menu.buildContextMenuAndPopup(ipcSafeMenus, parameters, windowName); + await service.menu.buildContextMenuAndPopup(ipcSafeMenus, parameters, windowName); return unregister; }, getCurrentWindow: async () => { diff --git a/src/preload/common/services.ts b/src/preload/common/services.ts index a6062dd0..dd1c412c 100644 --- a/src/preload/common/services.ts +++ b/src/preload/common/services.ts @@ -17,27 +17,27 @@ import { IPreferenceService, PreferenceServiceIPCDescriptor } from '@services/pr import { ISystemPreferenceService, SystemPreferenceServiceIPCDescriptor } from '@services/systemPreferences/interface'; import { IThemeService, ThemeServiceIPCDescriptor } from '@services/theme/interface'; import { IUpdaterService, UpdaterServiceIPCDescriptor } from '@services/updater/interface'; -import { IViewService, ViewServiceIPCDescriptor } from '@services/view/interface'; +// import { IViewService, ViewServiceIPCDescriptor } from '@services/view/interface'; import { IWikiService, WikiServiceIPCDescriptor } from '@services/wiki/interface'; import { IWikiGitWorkspaceService, WikiGitWorkspaceServiceIPCDescriptor } from '@services/wikiGitWorkspace/interface'; import { IWindowService, WindowServiceIPCDescriptor } from '@services/windows/interface'; import { IWorkspaceService, WorkspaceServiceIPCDescriptor } from '@services/workspaces/interface'; import { IWorkspaceViewService, WorkspaceViewServiceIPCDescriptor } from '@services/workspacesView/interface'; -export const auth = createProxy>(AuthenticationServiceIPCDescriptor); +export const auth = createProxy(AuthenticationServiceIPCDescriptor); export const context = createProxy(ContextServiceIPCDescriptor); export const git = createProxy(GitServiceIPCDescriptor); -export const menu = createProxy>(MenuServiceIPCDescriptor); +export const menu = createProxy(MenuServiceIPCDescriptor); export const native = createProxy(NativeServiceIPCDescriptor); export const notification = createProxy(NotificationServiceIPCDescriptor); export const preference = createProxy(PreferenceServiceIPCDescriptor); -export const systemPreference = createProxy>(SystemPreferenceServiceIPCDescriptor); -export const theme = createProxy>(ThemeServiceIPCDescriptor); -export const updater = createProxy>(UpdaterServiceIPCDescriptor); -export const view = createProxy>(ViewServiceIPCDescriptor); -export const wiki = createProxy>(WikiServiceIPCDescriptor); +export const systemPreference = createProxy(SystemPreferenceServiceIPCDescriptor); +export const theme = createProxy(ThemeServiceIPCDescriptor); +export const updater = createProxy(UpdaterServiceIPCDescriptor); +// export const view = createProxy>(ViewServiceIPCDescriptor); // view service is mostly internal +export const wiki = createProxy(WikiServiceIPCDescriptor); export const wikiGitWorkspace = createProxy(WikiGitWorkspaceServiceIPCDescriptor); -export const window = createProxy>(WindowServiceIPCDescriptor); +export const window = createProxy(WindowServiceIPCDescriptor); export const workspace = createProxy>(WorkspaceServiceIPCDescriptor); export const workspaceView = createProxy(WorkspaceViewServiceIPCDescriptor); @@ -52,7 +52,7 @@ export const descriptors = { systemPreference: SystemPreferenceServiceIPCDescriptor, theme: ThemeServiceIPCDescriptor, updater: UpdaterServiceIPCDescriptor, - view: ViewServiceIPCDescriptor, + // view: ViewServiceIPCDescriptor, wiki: WikiServiceIPCDescriptor, wikiGitWorkspace: WikiGitWorkspaceServiceIPCDescriptor, window: WindowServiceIPCDescriptor, diff --git a/src/services/auth/index.ts b/src/services/auth/index.ts index 9c3d2f29..2f4bb4ba 100644 --- a/src/services/auth/index.ts +++ b/src/services/auth/index.ts @@ -1,10 +1,8 @@ +/* eslint-disable @typescript-eslint/require-await */ /* eslint-disable unicorn/no-null */ import { injectable } from 'inversify'; import settings from 'electron-settings'; import { IAuthingUserInfo, SupportedStorageServices } from '@services/types'; -import { lazyInject } from '@services/container'; -import type { IWindowService } from '@services/windows/interface'; -import serviceIdentifier from '@services/serviceIdentifier'; import { IAuthenticationService, IUserInfos, ServiceEmailTypes, ServiceTokenTypes, ServiceUserNameTypes } from './interface'; import { BehaviorSubject } from 'rxjs'; import { IGitUserInfos } from '@services/git/interface'; @@ -16,8 +14,6 @@ const defaultUserInfos = { @injectable() export class Authentication implements IAuthenticationService { - @lazyInject(serviceIdentifier.Window) private readonly windowService!: IWindowService; - private cachedUserInfo: IUserInfos; public userInfo$: BehaviorSubject; @@ -30,10 +26,10 @@ export class Authentication implements IAuthenticationService { this.userInfo$.next(this.cachedUserInfo); } - public getStorageServiceUserInfo(serviceName: SupportedStorageServices): IGitUserInfos | undefined { - const gitUserName = this.get(`${serviceName}-userName` as ServiceUserNameTypes); - const email = this.get(`${serviceName}-email` as ServiceEmailTypes); - const accessToken = this.get(`${serviceName}-token` as ServiceTokenTypes); + public async getStorageServiceUserInfo(serviceName: SupportedStorageServices): Promise { + const gitUserName = await this.get(`${serviceName}-userName` as ServiceUserNameTypes); + const email = await this.get(`${serviceName}-email` as ServiceEmailTypes); + const accessToken = await this.get(`${serviceName}-token` as ServiceTokenTypes); if (gitUserName !== undefined && email !== undefined && accessToken !== undefined) { return { gitUserName, @@ -43,9 +39,9 @@ export class Authentication implements IAuthenticationService { } } - public getRandomStorageServiceUserInfo(): { name: SupportedStorageServices; info: IGitUserInfos } | undefined { + public async getRandomStorageServiceUserInfo(): Promise<{ name: SupportedStorageServices; info: IGitUserInfos } | undefined> { for (const serviceName of Object.values(SupportedStorageServices)) { - const info = this.getStorageServiceUserInfo(serviceName); + const info = await this.getStorageServiceUserInfo(serviceName); if (info?.accessToken !== undefined && info.accessToken.length > 0 && info?.email !== undefined && info?.gitUserName !== undefined) { return { name: serviceName, info }; } @@ -69,13 +65,13 @@ export class Authentication implements IAuthenticationService { * Batch update all UserInfos */ private async setUserInfos(newUserInfos: IUserInfos): Promise { - await settings.set(`userInfos`, newUserInfos as any); + await settings.set(`userInfos`, newUserInfos); } /** * get UserInfos, may return cached version */ - public getUserInfos = (): IUserInfos => { + public getUserInfos = async (): Promise => { // store in memory to boost performance if (this.cachedUserInfo === undefined) { return this.getInitUserInfoForCache(); @@ -83,13 +79,13 @@ export class Authentication implements IAuthenticationService { return this.cachedUserInfo; }; - public get(key: K): IUserInfos[K] | undefined { + public async get(key: K): Promise { if (this.cachedUserInfo[key] !== null && this.cachedUserInfo[key] !== undefined) { return this.cachedUserInfo[key]; } } - public set(key: K, value: IUserInfos[K]): void { + public async set(key: K, value: IUserInfos[K]): Promise { this.cachedUserInfo[key] = value; this.cachedUserInfo = { ...this.cachedUserInfo, ...this.sanitizeUserInfo(this.cachedUserInfo) }; this.updateUserInfoSubject(); diff --git a/src/services/auth/interface.ts b/src/services/auth/interface.ts index a0c57a25..865b0a3c 100644 --- a/src/services/auth/interface.ts +++ b/src/services/auth/interface.ts @@ -29,14 +29,14 @@ export type IUserInfos = { */ export interface IAuthenticationService { userInfo$: BehaviorSubject; - getStorageServiceUserInfo(serviceName: SupportedStorageServices): IGitUserInfos | undefined; + getStorageServiceUserInfo(serviceName: SupportedStorageServices): Promise; /** * Get a random storage info, useful for checking if user have any token in the storage */ - getRandomStorageServiceUserInfo(): { name: SupportedStorageServices; info: IGitUserInfos } | undefined; - getUserInfos: () => IUserInfos; - get(key: K): IUserInfos[K] | undefined; - set(key: K, value: IUserInfos[K]): void; + getRandomStorageServiceUserInfo(): Promise<{ name: SupportedStorageServices; info: IGitUserInfos } | undefined>; + getUserInfos: () => Promise; + get(key: K): Promise; + set(key: K, value: IUserInfos[K]): Promise; reset(): Promise; } export const AuthenticationServiceIPCDescriptor = { diff --git a/src/services/libs/i18n/buildLanguageMenu.ts b/src/services/libs/i18n/buildLanguageMenu.ts index fa8f583f..5edeab6c 100644 --- a/src/services/libs/i18n/buildLanguageMenu.ts +++ b/src/services/libs/i18n/buildLanguageMenu.ts @@ -42,5 +42,5 @@ export function buildLanguageMenu(): void { }); } - menuService.insertMenu('Language', subMenu); + void menuService.insertMenu('Language', subMenu); } diff --git a/src/services/menu/index.ts b/src/services/menu/index.ts index ac4d111b..687ec4a0 100644 --- a/src/services/menu/index.ts +++ b/src/services/menu/index.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-misused-promises */ +/* eslint-disable @typescript-eslint/require-await */ import { Menu, MenuItemConstructorOptions, shell, ContextMenuParams, WebContents, MenuItem, ipcMain } from 'electron'; import { debounce, take, drop, reverse } from 'lodash'; import { injectable } from 'inversify'; @@ -20,8 +22,8 @@ export class MenuService implements IMenuService { * Rebuild or create menubar from the latest menu template, will be call after some method change the menuTemplate * You don't need to call this after calling method like insertMenu, it will be call automatically. */ - public buildMenu(): void { - const latestTemplate = this.getCurrentMenuItemConstructorOptions(this.menuTemplate) ?? []; + public async buildMenu(): Promise { + const latestTemplate = (await this.getCurrentMenuItemConstructorOptions(this.menuTemplate)) ?? []; const menu = Menu.buildFromTemplate(latestTemplate); Menu.setApplicationMenu(menu); } @@ -31,26 +33,28 @@ export class MenuService implements IMenuService { * @param submenu menu options to get latest value * @returns MenuTemplate that `Menu.buildFromTemplate` wants */ - private getCurrentMenuItemConstructorOptions( + private async getCurrentMenuItemConstructorOptions( submenu?: Array, - ): MenuItemConstructorOptions[] | undefined { + ): Promise { if (submenu === undefined) return; - return submenu.map((item) => ({ - ...item, - label: typeof item.label === 'function' ? item.label() : item.label, - enabled: typeof item.enabled === 'function' ? item.enabled() : item.enabled, - submenu: - typeof item.submenu === 'function' - ? this.getCurrentMenuItemConstructorOptions(item.submenu()) - : item.submenu instanceof Menu - ? item.submenu - : this.getCurrentMenuItemConstructorOptions(item.submenu), - })); + return await Promise.all( + submenu.map(async (item) => ({ + ...item, + label: typeof item.label === 'function' ? item.label() : item.label, + enabled: typeof item.enabled === 'function' ? await item.enabled() : item.enabled, + submenu: + typeof item.submenu === 'function' + ? await this.getCurrentMenuItemConstructorOptions(item.submenu()) + : item.submenu instanceof Menu + ? item.submenu + : await this.getCurrentMenuItemConstructorOptions(item.submenu), + })), + ); } constructor() { // debounce so build menu won't be call very frequently on app launch, where every services are registering menu items - this.buildMenu = debounce(this.buildMenu.bind(this), 50); + this.buildMenu = debounce(this.buildMenu.bind(this), 50) as () => Promise; // add some default app menus this.menuTemplate = [ { @@ -121,8 +125,9 @@ export class MenuService implements IMenuService { } /** Register `on('context-menu', openContextMenuForWindow)` for a window, return an unregister function */ - public initContextMenuForWindowWebContents(webContents: WebContents): () => void { - const openContextMenuForWindow = (event: Electron.Event, parameters: ContextMenuParams): void => this.buildContextMenuAndPopup([], parameters, webContents); + public async initContextMenuForWindowWebContents(webContents: WebContents): Promise<() => void> { + const openContextMenuForWindow = async (event: Electron.Event, parameters: ContextMenuParams): Promise => + await this.buildContextMenuAndPopup([], parameters, webContents); webContents.on('context-menu', openContextMenuForWindow); return () => { @@ -141,7 +146,7 @@ export class MenuService implements IMenuService { * @param afterSubMenu The `id` or `role` of a submenu you want your submenu insert after. `null` means inserted as first submenu item; `undefined` means inserted as last submenu item; * @param withSeparator Need to insert a separator first, before insert menu items */ - public insertMenu(menuID: string, menuItems: DeferredMenuItemConstructorOptions[], afterSubMenu?: string | null, withSeparator = false): void { + public async insertMenu(menuID: string, menuItems: DeferredMenuItemConstructorOptions[], afterSubMenu?: string | null, withSeparator = false): Promise { let foundMenuName = false; // try insert menu into an existed menu's submenu for (const menu of this.menuTemplate) { @@ -199,14 +204,14 @@ export class MenuService implements IMenuService { submenu: menuItems, }); } - this.buildMenu(); + await this.buildMenu(); } - public buildContextMenuAndPopup( + public async buildContextMenuAndPopup( template: MenuItemConstructorOptions[] | IpcSafeMenuItem[], info: IOnContextMenuInfo, webContentsOrWindowName: WindowNames | WebContents = WindowNames.main, - ): void { + ): Promise { let webContents: WebContents; if (typeof webContentsOrWindowName === 'string') { const windowToPopMenu = this.windowService.get(webContentsOrWindowName); diff --git a/src/services/menu/interface.ts b/src/services/menu/interface.ts index 21e63bad..60e507ea 100644 --- a/src/services/menu/interface.ts +++ b/src/services/menu/interface.ts @@ -11,7 +11,7 @@ import type { IpcSafeMenuItem } from './rendererMenuItemProxy'; */ export interface DeferredMenuItemConstructorOptions extends Omit { label?: (() => string) | string; - enabled?: (() => boolean) | boolean; + enabled?: (() => boolean) | (() => Promise) | boolean; submenu?: | (() => Array) | Array; @@ -43,10 +43,10 @@ export interface IOnContextMenuInfo { * Handle creation of app menu, other services can register their menu tab and menu items here. */ export interface IMenuService { - buildMenu(): void; - initContextMenuForWindowWebContents(webContents: WebContents): () => void; - insertMenu(menuID: string, menuItems: DeferredMenuItemConstructorOptions[], afterSubMenu?: string | null, withSeparator?: boolean): void; - buildContextMenuAndPopup(template: MenuItemConstructorOptions[] | IpcSafeMenuItem[], info: IOnContextMenuInfo, windowName?: WindowNames): void; + buildMenu(): Promise; + initContextMenuForWindowWebContents(webContents: WebContents): Promise<() => void>; + insertMenu(menuID: string, menuItems: DeferredMenuItemConstructorOptions[], afterSubMenu?: string | null, withSeparator?: boolean): Promise; + buildContextMenuAndPopup(template: MenuItemConstructorOptions[] | IpcSafeMenuItem[], info: IOnContextMenuInfo, windowName?: WindowNames): Promise; } export const MenuServiceIPCDescriptor = { channel: MenuChannel.name, diff --git a/src/services/systemPreferences/index.ts b/src/services/systemPreferences/index.ts index 0728b8ef..f29247a3 100644 --- a/src/services/systemPreferences/index.ts +++ b/src/services/systemPreferences/index.ts @@ -1,26 +1,23 @@ +/* eslint-disable @typescript-eslint/require-await */ import { app } from 'electron'; import { injectable } from 'inversify'; import { BehaviorSubject } from 'rxjs'; import { ISystemPreferenceService, IUsedElectionSettings } from './interface'; -import serviceIdentifier from '@services/serviceIdentifier'; -import { IWindowService } from '@services/windows/interface'; -import { lazyInject } from '@services/container'; - @injectable() export class SystemPreference implements ISystemPreferenceService { - @lazyInject(serviceIdentifier.Window) private readonly windowService!: IWindowService; public systemPreference$: BehaviorSubject; constructor() { - this.systemPreference$ = new BehaviorSubject(this.getSystemPreferences()); + this.systemPreference$ = new BehaviorSubject({ openAtLogin: 'no' }); + void this.updatePreferenceSubject(); } - private updatePreferenceSubject(): void { - this.systemPreference$.next(this.getSystemPreferences()); + private async updatePreferenceSubject(): Promise { + this.systemPreference$.next(await this.getSystemPreferences()); } - public get(key: K): IUsedElectionSettings[K] { + public async get(key: K): Promise { switch (key) { case 'openAtLogin': { // return our custom setting enum, to be cross-platform @@ -36,13 +33,13 @@ export class SystemPreference implements ISystemPreferenceService { } } - public getSystemPreferences(): IUsedElectionSettings { + public async getSystemPreferences(): Promise { return { - openAtLogin: this.get('openAtLogin'), + openAtLogin: await this.get('openAtLogin'), }; } - public setSystemPreference(key: K, value: IUsedElectionSettings[K]): void { + public async setSystemPreference(key: K, value: IUsedElectionSettings[K]): Promise { switch (key) { case 'openAtLogin': { app.setLoginItemSettings({ @@ -55,6 +52,6 @@ export class SystemPreference implements ISystemPreferenceService { break; } } - this.updatePreferenceSubject(); + await this.updatePreferenceSubject(); } } diff --git a/src/services/systemPreferences/interface.ts b/src/services/systemPreferences/interface.ts index 221ae6ce..5456aece 100644 --- a/src/services/systemPreferences/interface.ts +++ b/src/services/systemPreferences/interface.ts @@ -12,9 +12,9 @@ export interface IUsedElectionSettings { */ export interface ISystemPreferenceService { systemPreference$: BehaviorSubject; - get(key: K): IUsedElectionSettings[K]; - getSystemPreferences(): IUsedElectionSettings; - setSystemPreference(key: K, value: IUsedElectionSettings[K]): void; + get(key: K): Promise; + getSystemPreferences(): Promise; + setSystemPreference(key: K, value: IUsedElectionSettings[K]): Promise; } export const SystemPreferenceServiceIPCDescriptor = { channel: SystemPreferenceChannel.name, diff --git a/src/services/updater/index.ts b/src/services/updater/index.ts index 4d7c1dcb..99592cc9 100644 --- a/src/services/updater/index.ts +++ b/src/services/updater/index.ts @@ -40,7 +40,7 @@ export class Updater implements IUpdaterService { ...newUpdaterMetaData, }; this.updateUpdaterSubject(); - this.menuService.buildMenu(); + void this.menuService.buildMenu(); } public async checkForUpdates(isSilent: boolean): Promise { diff --git a/src/services/view/index.ts b/src/services/view/index.ts index 42cd52d8..0327ad39 100644 --- a/src/services/view/index.ts +++ b/src/services/view/index.ts @@ -46,10 +46,10 @@ export class View implements IViewService { } private async registerMenu(): Promise { - const hasWorkspaces = this.workspaceService.countWorkspaces() > 0; + const hasWorkspaces = (await this.workspaceService.countWorkspaces()) > 0; const sidebar = await this.preferenceService.get('sidebar'); const titleBar = await this.preferenceService.get('titleBar'); - this.menuService.insertMenu('View', [ + await this.menuService.insertMenu('View', [ { label: () => (sidebar ? 'Hide Sidebar' : 'Show Sidebar'), accelerator: 'CmdOrCtrl+Alt+S', @@ -276,7 +276,7 @@ export class View implements IViewService { // start wiki on startup, or on sub-wiki creation await this.wikiService.wikiStartup(workspace); void view.webContents.loadURL(initialUrl); - const unregisterContextMenu = this.menuService.initContextMenuForWindowWebContents(view.webContents); + const unregisterContextMenu = await this.menuService.initContextMenuForWindowWebContents(view.webContents); view.webContents.on('destroyed', () => { unregisterContextMenu(); }); @@ -296,7 +296,7 @@ export class View implements IViewService { // FIXME: is this useful? // browserWindow.send('close-find-in-page'); } - const workspace = this.workspaceService.get(id); + const workspace = await this.workspaceService.get(id); if (this.getView(id) === undefined && workspace !== undefined) { return await this.addView(browserWindow, workspace); } else { @@ -337,7 +337,7 @@ export class View implements IViewService { } Object.keys(this.views).forEach((id) => { const view = this.getView(id); - const workspace = this.workspaceService.get(id); + const workspace = await this.workspaceService.get(id); if (view !== undefined && workspace !== undefined) { view.webContents.audioMuted = workspace.disableAudio || this.shouldMuteAudio; } @@ -382,8 +382,8 @@ export class View implements IViewService { }); } - public getActiveBrowserView(): BrowserView | undefined { - const workspace = this.workspaceService.getActiveWorkspace(); + public async getActiveBrowserView(): Promise { + const workspace = await this.workspaceService.getActiveWorkspace(); if (workspace !== undefined) { return this.getView(workspace.id); } diff --git a/src/services/view/interface.ts b/src/services/view/interface.ts index a152108e..8fc3d61c 100644 --- a/src/services/view/interface.ts +++ b/src/services/view/interface.ts @@ -18,7 +18,7 @@ export interface IViewService { hibernateView: (id: string) => void; reloadViewsWebContentsIfDidFailLoad: () => void; reloadViewsWebContents: () => void; - getActiveBrowserView: () => BrowserView | undefined; + getActiveBrowserView: () => Promise; realignActiveView: (browserWindow: BrowserWindow, activeId: string) => Promise; } export const ViewServiceIPCDescriptor = { diff --git a/src/services/wiki/index.ts b/src/services/wiki/index.ts index 8eaa7124..d9c7896f 100644 --- a/src/services/wiki/index.ts +++ b/src/services/wiki/index.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/require-await */ /* eslint-disable @typescript-eslint/no-dynamic-delete */ import { injectable } from 'inversify'; import { delay } from 'bluebird'; @@ -346,9 +347,9 @@ export class Wiki implements IWikiService { // do nothing } - const userInfo = this.authService.getStorageServiceUserInfo(workspace.storageService); + const userInfo = await this.authService.getStorageServiceUserInfo(workspace.storageService); // pass empty editor username if undefined - const userName = this.authService.get('userName') ?? ''; + const userName = (await this.authService.get('userName')) ?? ''; const { name: wikiPath, gitUrl: githubRepoUrl, port, isSubWiki, id, mainWikiToLink } = workspace; // if is main wiki if (!isSubWiki) { @@ -504,7 +505,7 @@ export class Wiki implements IWikiService { logger.info('All wiki watcher is stopped', { function: 'stopWatchAllWiki' }); } - public updateSubWikiPluginContent(mainWikiPath: string, newConfig?: IWorkspace, oldConfig?: IWorkspace): void { + public async updateSubWikiPluginContent(mainWikiPath: string, newConfig?: IWorkspace, oldConfig?: IWorkspace): Promise { return updateSubWikiPluginContent(mainWikiPath, newConfig, oldConfig); } } diff --git a/src/services/wiki/interface.ts b/src/services/wiki/interface.ts index 3c834579..1cb28b0c 100644 --- a/src/services/wiki/interface.ts +++ b/src/services/wiki/interface.ts @@ -8,14 +8,14 @@ import type { ISubWikiPluginContent } from './update-plugin-content'; * Handle wiki worker startup and restart */ export interface IWikiService { - updateSubWikiPluginContent(mainWikiPath: string, newConfig?: IWorkspace, oldConfig?: IWorkspace): void; + updateSubWikiPluginContent(mainWikiPath: string, newConfig?: IWorkspace, oldConfig?: IWorkspace): Promise; startWiki(homePath: string, tiddlyWikiPort: number, userName: string): Promise; stopWiki(homePath: string): Promise; stopAllWiki(): Promise; copyWikiTemplate(newFolderPath: string, folderName: string): Promise; getSubWikiPluginContent(mainWikiPath: string): Promise; - requestWikiSendActionMessage(actionMessage: string): void; - requestOpenTiddlerInWiki(tiddlerName: string): void; + requestWikiSendActionMessage(actionMessage: string): Promise; + requestOpenTiddlerInWiki(tiddlerName: string): Promise; linkWiki(mainWikiPath: string, folderName: string, subWikiPath: string): Promise; createWiki(newFolderPath: string, folderName: string): Promise; createSubWiki(newFolderPath: string, folderName: string, mainWikiPath: string, tagName?: string, onlyLink?: boolean): Promise; diff --git a/src/services/wikiGitWorkspace/index.ts b/src/services/wikiGitWorkspace/index.ts index 2547aa08..395b87bb 100644 --- a/src/services/wikiGitWorkspace/index.ts +++ b/src/services/wikiGitWorkspace/index.ts @@ -69,7 +69,7 @@ export class WikiGitWorkspace implements IWikiGitWorkspaceService { }); try { if (response === 0 || response === 1) { - const workspace = this.workspaceService.get(id); + const workspace = await this.workspaceService.get(id); if (workspace === undefined) { throw new Error(`Need to get workspace with id ${id} but failed`); } @@ -77,19 +77,19 @@ export class WikiGitWorkspace implements IWikiGitWorkspaceService { await this.wikiService.stopWiki(workspace.name).catch((error: any) => logger.error((error as Error).message, error)); await this.wikiService.removeWiki(workspace.name, workspace.isSubWiki ? workspace.mainWikiToLink : undefined, response === 0); await this.workspaceViewService.removeWorkspaceView(id); - this.menuService.buildMenu(); + await this.menuService.buildMenu(); // restart the main wiki to load content from private wiki const mainWikiPath = workspace.mainWikiToLink; const mainWorkspace = this.workspaceService.getByName(mainWikiPath); if (mainWorkspace === undefined) { throw new Error(`Need to get mainWorkspace with name ${mainWikiPath} but failed`); } - const userName = this.authService.get('userName') ?? ''; + const userName = (await this.authService.get('userName')) ?? ''; await this.wikiService.stopWiki(mainWikiPath); await this.wikiService.startWiki(mainWikiPath, mainWorkspace.port, userName); // remove folderName from fileSystemPaths if (workspace.isSubWiki) { - this.wikiService.updateSubWikiPluginContent(mainWikiPath, undefined, { + await this.wikiService.updateSubWikiPluginContent(mainWikiPath, undefined, { ...workspace, subWikiFolderName: path.basename(workspace.name), }); diff --git a/src/services/windows/index.ts b/src/services/windows/index.ts index 5fabdc43..ec6d69d4 100644 --- a/src/services/windows/index.ts +++ b/src/services/windows/index.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/require-await */ +/* eslint-disable @typescript-eslint/no-misused-promises */ /* eslint-disable @typescript-eslint/consistent-type-assertions */ import { BrowserWindow, ipcMain, dialog, app, clipboard, BrowserWindowConstructorOptions } from 'electron'; import { injectable } from 'inversify'; @@ -33,10 +35,10 @@ export class Window implements IWindowService { @lazyInject(serviceIdentifier.MenuService) private readonly menuService!: IMenuService; constructor() { - this.registerMenu(); + void this.registerMenu(); } - public findInPage(text: string, forward?: boolean, windowName: WindowNames = WindowNames.main): void { + public async findInPage(text: string, forward?: boolean, windowName: WindowNames = WindowNames.main): Promise { const mainWindow = this.get(windowName); const contents = mainWindow?.getBrowserView()?.webContents; if (contents !== undefined) { @@ -88,7 +90,7 @@ export class Window implements IWindowService { return this.windows[windowName]; } - public close(name: WindowNames): void { + public async close(name: WindowNames): Promise { this.get(name)?.close(); } @@ -99,8 +101,8 @@ export class Window implements IWindowService { ): Promise { const existedWindow = this.get(windowName); // update window meta - this.setWindowMeta(windowName, meta); - const existedWindowMeta = this.getWindowMeta(windowName); + await this.setWindowMeta(windowName, meta); + const existedWindowMeta = await this.getWindowMeta(windowName); const attachToMenubar: boolean = await this.preferenceService.get('attachToMenubar'); const titleBar: boolean = await this.preferenceService.get('titleBar'); @@ -173,7 +175,7 @@ export class Window implements IWindowService { } else { newWindow.setMenuBarVisibility(false); } - const unregisterContextMenu = this.menuService.initContextMenuForWindowWebContents(newWindow.webContents); + const unregisterContextMenu = await this.menuService.initContextMenuForWindowWebContents(newWindow.webContents); newWindow.on('closed', () => { this.windows[windowName] = undefined; unregisterContextMenu(); @@ -182,7 +184,7 @@ export class Window implements IWindowService { if (isMainWindow) { // handle window show and Webview/browserView show webContentLoadingPromise = new Promise((resolve) => { - newWindow.once('ready-to-show', () => { + newWindow.once('ready-to-show', async () => { const mainWindow = this.get(WindowNames.main); if (mainWindow === undefined) return; const { wasOpenedAsHidden } = app.getLoginItemSettings(); @@ -193,7 +195,7 @@ export class Window implements IWindowService { // after the UI is fully loaded // if not, BrowserView mouseover event won't work correctly // https://github.com/atomery/webcatalog/issues/812 - this.workspaceViewService.realignActiveWorkspace(); + await this.workspaceViewService.realignActiveWorkspace(); // ensure redux is loaded first // if not, redux might not be able catch changes sent from ipcMain if (!mainWindow.webContents.isLoading()) { @@ -230,10 +232,10 @@ export class Window implements IWindowService { } }); // Hide window instead closing on macos - newWindow.on('close', (event) => { + newWindow.on('close', async (event) => { const mainWindow = this.get(WindowNames.main); if (mainWindow === undefined) return; - if (process.platform === 'darwin' && this.getWindowMeta(WindowNames.main)?.forceClose !== true) { + if (process.platform === 'darwin' && (await this.getWindowMeta(WindowNames.main))?.forceClose !== true) { event.preventDefault(); // https://github.com/electron/electron/issues/6033#issuecomment-242023295 if (mainWindow.isFullScreen()) { @@ -258,33 +260,33 @@ export class Window implements IWindowService { view?.webContents?.focus(); }); - newWindow.on('enter-full-screen', () => { + newWindow.on('enter-full-screen', async () => { const mainWindow = this.get(WindowNames.main); if (mainWindow === undefined) return; mainWindow?.webContents.send('is-fullscreen-updated', true); - this.workspaceViewService.realignActiveWorkspace(); + await this.workspaceViewService.realignActiveWorkspace(); }); - newWindow.on('leave-full-screen', () => { + newWindow.on('leave-full-screen', async () => { const mainWindow = this.get(WindowNames.main); if (mainWindow === undefined) return; mainWindow?.webContents.send('is-fullscreen-updated', false); - this.workspaceViewService.realignActiveWorkspace(); + await this.workspaceViewService.realignActiveWorkspace(); }); } - public isFullScreen(windowName = WindowNames.main): boolean | undefined { + public async isFullScreen(windowName = WindowNames.main): Promise { return this.windows[windowName]?.isFullScreen(); } - public setWindowMeta(windowName: N, meta: WindowMeta[N]): void { + public async setWindowMeta(windowName: N, meta: WindowMeta[N]): Promise { this.windowMeta[windowName] = meta; } - public updateWindowMeta(windowName: N, meta: WindowMeta[N]): void { + public async updateWindowMeta(windowName: N, meta: WindowMeta[N]): Promise { this.windowMeta[windowName] = { ...this.windowMeta[windowName], ...meta }; } - public getWindowMeta(windowName: N): WindowMeta[N] | undefined { + public async getWindowMeta(windowName: N): Promise { return this.windowMeta[windowName] as WindowMeta[N]; } @@ -293,7 +295,7 @@ export class Window implements IWindowService { * @param channel ipc channel to send * @param arguments_ any messages */ - public sendToAllWindows = (channel: Channels, ...arguments_: unknown[]): void => { + public sendToAllWindows = async (channel: Channels, ...arguments_: unknown[]): Promise => { const wins = BrowserWindow.getAllWindows(); wins.forEach((win) => { win.webContents.send(channel, ...arguments_); @@ -303,7 +305,7 @@ export class Window implements IWindowService { public async goHome(windowName: WindowNames = WindowNames.main): Promise { const win = this.get(windowName); const contents = win?.getBrowserView()?.webContents; - const activeWorkspace = this.workspaceService.getActiveWorkspace(); + const activeWorkspace = await this.workspaceService.getActiveWorkspace(); if (contents !== undefined && activeWorkspace !== undefined && win !== undefined) { await contents.loadURL(activeWorkspace.homeUrl); contents.send(WindowChannel.updateCanGoBack, contents.canGoBack()); @@ -311,7 +313,7 @@ export class Window implements IWindowService { } } - public goBack(windowName: WindowNames = WindowNames.main): void { + public async goBack(windowName: WindowNames = WindowNames.main): Promise { const win = this.get(windowName); const contents = win?.getBrowserView()?.webContents; if (contents?.canGoBack() === true) { @@ -321,7 +323,7 @@ export class Window implements IWindowService { } } - public goForward(windowName: WindowNames = WindowNames.main): void { + public async goForward(windowName: WindowNames = WindowNames.main): Promise { const win = this.get(windowName); const contents = win?.getBrowserView()?.webContents; if (contents?.canGoForward() === true) { @@ -331,7 +333,7 @@ export class Window implements IWindowService { } } - public reload(windowName: WindowNames = WindowNames.main): void { + public async reload(windowName: WindowNames = WindowNames.main): Promise { const win = this.get(windowName); win?.getBrowserView()?.webContents?.reload(); } @@ -350,8 +352,8 @@ export class Window implements IWindowService { } } - private registerMenu(): void { - this.menuService.insertMenu( + private async registerMenu(): Promise { + await this.menuService.insertMenu( 'window', [ // `role: 'zoom'` is only supported on macOS @@ -372,7 +374,7 @@ export class Window implements IWindowService { 'close', ); - this.menuService.insertMenu('Edit', [ + await this.menuService.insertMenu('Edit', [ { label: 'Find', accelerator: 'CmdOrCtrl+F', @@ -386,7 +388,7 @@ export class Window implements IWindowService { view?.setBounds(await getViewBounds(contentSize as [number, number], true)); } }, - enabled: () => this.workspaceService.countWorkspaces() > 0, + enabled: async () => (await this.workspaceService.countWorkspaces()) > 0, }, { label: 'Find Next', @@ -395,7 +397,7 @@ export class Window implements IWindowService { const mainWindow = this.get(WindowNames.main); mainWindow?.webContents?.send('request-back-find-in-page', true); }, - enabled: () => this.workspaceService.countWorkspaces() > 0, + enabled: async () => (await this.workspaceService.countWorkspaces()) > 0, }, { label: 'Find Previous', @@ -404,16 +406,16 @@ export class Window implements IWindowService { const mainWindow = this.get(WindowNames.main); mainWindow?.webContents?.send('request-back-find-in-page', false); }, - enabled: () => this.workspaceService.countWorkspaces() > 0, + enabled: async () => (await this.workspaceService.countWorkspaces()) > 0, }, ]); - this.menuService.insertMenu('History', [ + await this.menuService.insertMenu('History', [ { label: 'Home', accelerator: 'Shift+CmdOrCtrl+H', click: async () => await this.goHome(), - enabled: () => this.workspaceService.countWorkspaces() > 0, + enabled: async () => (await this.workspaceService.countWorkspaces()) > 0, }, { label: 'Back', @@ -431,7 +433,7 @@ export class Window implements IWindowService { } ipcMain.emit('request-go-back'); }, - enabled: () => this.workspaceService.countWorkspaces() > 0, + enabled: async () => (await this.workspaceService.countWorkspaces()) > 0, }, { label: 'Forward', @@ -448,7 +450,7 @@ export class Window implements IWindowService { } ipcMain.emit('request-go-forward'); }, - enabled: () => this.workspaceService.countWorkspaces() > 0, + enabled: async () => (await this.workspaceService.countWorkspaces()) > 0, }, { type: 'separator' }, { @@ -471,13 +473,13 @@ export class Window implements IWindowService { clipboard.writeText(url); } }, - enabled: () => this.workspaceService.countWorkspaces() > 0, + enabled: async () => (await this.workspaceService.countWorkspaces()) > 0, }, ]); if (process.platform === 'darwin') { // TODO: restore updater options here - this.menuService.insertMenu('TiddlyGit', [ + await this.menuService.insertMenu('TiddlyGit', [ { label: () => i18n.t('ContextMenu.About'), click: async () => await this.open(WindowNames.about), diff --git a/src/services/windows/interface.ts b/src/services/windows/interface.ts index e992f8a3..c7982334 100644 --- a/src/services/windows/interface.ts +++ b/src/services/windows/interface.ts @@ -7,22 +7,23 @@ import { WindowNames, WindowMeta } from './WindowProperties'; * Create and manage window open and destroy, you can get all opened electron window instance here */ export interface IWindowService { + /** get window, this should not be called in renderer side */ get(windowName: WindowNames): BrowserWindow | undefined; open(windowName: N, meta?: WindowMeta[N], recreate?: boolean | ((windowMeta: WindowMeta[N]) => boolean)): Promise; - close(name: WindowNames): void; - setWindowMeta(windowName: N, meta?: WindowMeta[N]): void; - updateWindowMeta(windowName: N, meta?: WindowMeta[N]): void; - getWindowMeta(windowName: N): WindowMeta[N] | undefined; - sendToAllWindows: (channel: Channels, ...arguments_: unknown[]) => void; + close(name: WindowNames): Promise; + setWindowMeta(windowName: N, meta?: WindowMeta[N]): Promise; + updateWindowMeta(windowName: N, meta?: WindowMeta[N]): Promise; + getWindowMeta(windowName: N): Promise; + sendToAllWindows: (channel: Channels, ...arguments_: unknown[]) => Promise; requestShowRequireRestartDialog(): Promise; - isFullScreen(windowName?: WindowNames): boolean | undefined; + isFullScreen(windowName?: WindowNames): Promise; goHome(windowName: WindowNames): Promise; - goBack(windowName: WindowNames): void; - goForward(windowName: WindowNames): void; + goBack(windowName: WindowNames): Promise; + goForward(windowName: WindowNames): Promise; loadURL(windowName: WindowNames, newUrl?: string): Promise; - reload(windowName: WindowNames): void; + reload(windowName: WindowNames): Promise; clearStorageData(windowName?: WindowNames): Promise; - findInPage(text: string, forward?: boolean | undefined, windowName?: WindowNames): void; + findInPage(text: string, forward?: boolean | undefined, windowName?: WindowNames): Promise; stopFindInPage(close?: boolean | undefined, windowName?: WindowNames): Promise; } export const WindowServiceIPCDescriptor = { diff --git a/src/services/workspaces/index.ts b/src/services/workspaces/index.ts index 6b349840..34abeadf 100644 --- a/src/services/workspaces/index.ts +++ b/src/services/workspaces/index.ts @@ -41,58 +41,58 @@ export class Workspace implements IWorkspaceService { constructor() { this.workspaces = this.getInitWorkspacesForCache(); - this.registerMenu(); + void this.registerMenu(); this.workspaces$ = new BehaviorSubject>(this.workspaces); } - private updateWorkspaceSubject(): void { - this.workspaces$.next(this.getWorkspaces()); + private async updateWorkspaceSubject(): Promise { + this.workspaces$.next(await this.getWorkspaces()); } - private registerMenu(): void { - this.menuService.insertMenu('Workspaces', [ + private async registerMenu(): Promise { + await this.menuService.insertMenu('Workspaces', [ { label: 'Select Next Workspace', - click: () => { - const currentActiveWorkspace = this.getActiveWorkspace(); + click: async () => { + const currentActiveWorkspace = await this.getActiveWorkspace(); if (currentActiveWorkspace === undefined) return; - const nextWorkspace = this.getNextWorkspace(currentActiveWorkspace.id); + const nextWorkspace = await this.getNextWorkspace(currentActiveWorkspace.id); if (nextWorkspace === undefined) return; - return this.workspaceViewService.setActiveWorkspaceView(nextWorkspace.id); + await this.workspaceViewService.setActiveWorkspaceView(nextWorkspace.id); }, accelerator: 'CmdOrCtrl+Shift+]', - enabled: () => this.countWorkspaces() > 0, + enabled: async () => (await this.countWorkspaces()) > 0, }, { label: 'Select Previous Workspace', - click: () => { - const currentActiveWorkspace = this.getActiveWorkspace(); + click: async () => { + const currentActiveWorkspace = await this.getActiveWorkspace(); if (currentActiveWorkspace === undefined) return; - const previousWorkspace = this.getPreviousWorkspace(currentActiveWorkspace.id); + const previousWorkspace = await this.getPreviousWorkspace(currentActiveWorkspace.id); if (previousWorkspace === undefined) return; - return this.workspaceViewService.setActiveWorkspaceView(previousWorkspace.id); + await this.workspaceViewService.setActiveWorkspaceView(previousWorkspace.id); }, accelerator: 'CmdOrCtrl+Shift+[', - enabled: () => this.countWorkspaces() > 0, + enabled: async () => (await this.countWorkspaces()) > 0, }, { type: 'separator' }, { label: 'Edit Current Workspace', - click: () => { - const currentActiveWorkspace = this.getActiveWorkspace(); + click: async () => { + const currentActiveWorkspace = await this.getActiveWorkspace(); if (currentActiveWorkspace === undefined) return; - return this.windowService.open(WindowNames.editWorkspace, { workspaceID: currentActiveWorkspace.id }); + await this.windowService.open(WindowNames.editWorkspace, { workspaceID: currentActiveWorkspace.id }); }, - enabled: () => this.countWorkspaces() > 0, + enabled: async () => (await this.countWorkspaces()) > 0, }, { label: 'Remove Current Workspace', - click: () => { - const currentActiveWorkspace = this.getActiveWorkspace(); + click: async () => { + const currentActiveWorkspace = await this.getActiveWorkspace(); if (currentActiveWorkspace === undefined) return; - return this.remove(currentActiveWorkspace.id); + await this.remove(currentActiveWorkspace.id); }, - enabled: () => this.countWorkspaces() > 0, + enabled: async () => (await this.countWorkspaces()) > 0, }, { type: 'separator' }, { @@ -107,8 +107,8 @@ export class Workspace implements IWorkspaceService { /** * Update items like "activate workspace1" or "open devtool in workspace1" in the menu */ - private updateWorkspaceMenuItems(): void { - const newMenuItems = this.getWorkspacesAsList().flatMap((workspace, index) => [ + private async updateWorkspaceMenuItems(): Promise { + const newMenuItems = (await this.getWorkspacesAsList()).flatMap((workspace, index) => [ { // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions label: workspace.name || `Workspace ${index + 1}`, @@ -117,20 +117,20 @@ export class Workspace implements IWorkspaceService { click: async () => { await this.workspaceViewService.setActiveWorkspaceView(workspace.id); // manually update menu since we have alter the active workspace - this.menuService.buildMenu(); + await this.menuService.buildMenu(); }, accelerator: `CmdOrCtrl+${index + 1}`, }, { // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions label: workspace.name || `Workspace ${index + 1}`, - click: () => { + click: async () => { const view = this.viewService.getView(workspace.id); view.webContents.toggleDevTools(); }, }, ]); - this.menuService.insertMenu('Workspaces', newMenuItems); + await this.menuService.insertMenu('Workspaces', newMenuItems); } /** @@ -145,22 +145,22 @@ export class Workspace implements IWorkspaceService { : {}; }; - public getWorkspaces(): Record { + public async getWorkspaces(): Promise> { return this.workspaces; } - public countWorkspaces(): number { + public async countWorkspaces(): Promise { return Object.keys(this.workspaces).length; } /** * Get sorted workspace list */ - public getWorkspacesAsList(): IWorkspace[] { + public async getWorkspacesAsList(): Promise { return Object.values(this.workspaces).sort((a, b) => a.order - b.order); } - public get(id: string): IWorkspace | undefined { + public async get(id: string): Promise { return this.workspaces[id]; } @@ -172,12 +172,12 @@ export class Workspace implements IWorkspaceService { this.workspaces[id] = this.sanitizeWorkspace(workspace); await this.reactBeforeWorkspaceChanged(workspace); await settings.set(`workspaces.${id}`, { ...workspace }); - this.updateWorkspaceSubject(); - this.updateWorkspaceMenuItems(); + await this.updateWorkspaceSubject(); + await this.updateWorkspaceMenuItems(); } public async update(id: string, workspaceSetting: Partial): Promise { - const workspace = this.get(id); + const workspace = await this.get(id); if (workspace === undefined) { return; } @@ -210,7 +210,7 @@ export class Workspace implements IWorkspaceService { private async reactBeforeWorkspaceChanged(newWorkspaceConfig: IWorkspace): Promise { const { id, tagName } = newWorkspaceConfig; if (this.workspaces[id].isSubWiki && typeof tagName === 'string' && tagName.length > 0 && this.workspaces[id].tagName !== tagName) { - this.wikiService.updateSubWikiPluginContent(this.workspaces[id].mainWikiToLink, newWorkspaceConfig, { + await this.wikiService.updateSubWikiPluginContent(this.workspaces[id].mainWikiToLink, newWorkspaceConfig, { ...newWorkspaceConfig, tagName: this.workspaces[id].tagName, }); @@ -218,12 +218,12 @@ export class Workspace implements IWorkspaceService { } } - public getByName(name: string): IWorkspace | undefined { - return this.getWorkspacesAsList().find((workspace) => workspace.name === name); + public async getByName(name: string): Promise { + return (await this.getWorkspacesAsList()).find((workspace) => workspace.name === name); } - public getPreviousWorkspace = (id: string): IWorkspace | undefined => { - const workspaceList = this.getWorkspacesAsList(); + public getPreviousWorkspace = async (id: string): Promise => { + const workspaceList = await this.getWorkspacesAsList(); let currentWorkspaceIndex = 0; for (const [index, workspace] of workspaceList.entries()) { if (workspace.id === id) { @@ -237,8 +237,8 @@ export class Workspace implements IWorkspaceService { return workspaceList[currentWorkspaceIndex - 1]; }; - public getNextWorkspace = (id: string): IWorkspace | undefined => { - const workspaceList = this.getWorkspacesAsList(); + public getNextWorkspace = async (id: string): Promise => { + const workspaceList = await this.getWorkspacesAsList(); let currentWorkspaceIndex = 0; for (const [index, workspace] of workspaceList.entries()) { if (workspace.id === id) { @@ -252,16 +252,16 @@ export class Workspace implements IWorkspaceService { return workspaceList[currentWorkspaceIndex + 1]; }; - public getActiveWorkspace = (): IWorkspace | undefined => { - return this.getWorkspacesAsList().find((workspace) => workspace.active); + public getActiveWorkspace = async (): Promise => { + return (await this.getWorkspacesAsList()).find((workspace) => workspace.active); }; - public getFirstWorkspace = (): IWorkspace | undefined => { - return this.getWorkspacesAsList()[0]; + public getFirstWorkspace = async (): Promise => { + return (await this.getWorkspacesAsList())[0]; }; public async setActiveWorkspace(id: string): Promise { - const currentActiveWorkspace = this.getActiveWorkspace(); + const currentActiveWorkspace = await this.getActiveWorkspace(); if (currentActiveWorkspace !== undefined) { if (currentActiveWorkspace.id === id) { return; @@ -279,7 +279,7 @@ export class Workspace implements IWorkspaceService { * @param sourcePicturePath image path, could be an image in app's resource folder or temp folder, we will copy it into app data folder */ public async setWorkspacePicture(id: string, sourcePicturePath: string): Promise { - const workspace = this.get(id); + const workspace = await this.get(id); if (workspace === undefined) { throw new Error(`Try to setWorkspacePicture() but this workspace is not existed ${id}`); } @@ -307,7 +307,7 @@ export class Workspace implements IWorkspaceService { await new Promise((resolve) => { newImage.clone().resize(128, 128).quality(100).write(destinationPicturePath, resolve); }); - const currentPicturePath = this.get(id)?.picturePath; + const currentPicturePath = (await this.get(id))?.picturePath; await this.update(id, { picturePath: destinationPicturePath, }); @@ -322,7 +322,7 @@ export class Workspace implements IWorkspaceService { } public async removeWorkspacePicture(id: string): Promise { - const workspace = this.get(id); + const workspace = await this.get(id); if (workspace === undefined) { throw new Error(`Try to removeWorkspacePicture() but this workspace is not existed ${id}`); } @@ -348,15 +348,15 @@ export class Workspace implements IWorkspaceService { const { name } = this.workspaces[id]; await this.wikiService.stopWiki(name); await this.wikiService.stopWatchWiki(name); - this.updateWorkspaceMenuItems(); - this.updateWorkspaceSubject(); + await this.updateWorkspaceMenuItems(); + await this.updateWorkspaceSubject(); } public async create(newWorkspaceConfig: Omit): Promise { const newID = uuid(); // find largest order - const workspaceLst = this.getWorkspacesAsList(); + const workspaceLst = await this.getWorkspacesAsList(); let max = 0; for (const element of workspaceLst) { if (element.order > max) { @@ -383,9 +383,9 @@ export class Workspace implements IWorkspaceService { */ private metaData: Record> = {}; - public getMetaData = (id: string): Partial => this.metaData[id] ?? {}; + public getMetaData = async (id: string): Promise> => this.metaData[id] ?? {}; - public getAllMetaData = (): Record> => this.metaData; + public getAllMetaData = async (): Promise>> => this.metaData; public updateMetaData = async (id: string, options: Partial): Promise => { this.metaData[id] = { diff --git a/src/services/workspaces/interface.ts b/src/services/workspaces/interface.ts index c14eab49..17fed9ca 100644 --- a/src/services/workspaces/interface.ts +++ b/src/services/workspaces/interface.ts @@ -81,14 +81,14 @@ export interface IWorkspaceMetaData { */ export interface IWorkspaceService { workspaces$: BehaviorSubject>; - getWorkspacesAsList(): IWorkspace[]; - get(id: string): IWorkspace | undefined; + getWorkspacesAsList(): Promise; + get(id: string): Promise; get$(id: string): Observable; create(newWorkspaceConfig: Omit): Promise; - getWorkspaces(): Record; - countWorkspaces(): number; - getMetaData: (id: string) => Partial; - getAllMetaData: () => Record>; + getWorkspaces(): Promise>; + countWorkspaces(): Promise; + getMetaData: (id: string) => Promise>; + getAllMetaData: () => Promise>>; updateMetaData: (id: string, options: Partial) => Promise; set(id: string, workspace: IWorkspace): Promise; update(id: string, workspaceSetting: Partial): Promise; @@ -97,11 +97,11 @@ export interface IWorkspaceService { setWorkspacePicture(id: string, sourcePicturePath: string): Promise; removeWorkspacePicture(id: string): Promise; remove(id: string): Promise; - getByName(name: string): IWorkspace | undefined; - getPreviousWorkspace: (id: string) => IWorkspace | undefined; - getNextWorkspace: (id: string) => IWorkspace | undefined; - getActiveWorkspace: () => IWorkspace | undefined; - getFirstWorkspace: () => IWorkspace | undefined; + getByName(name: string): Promise; + getPreviousWorkspace: (id: string) => Promise; + getNextWorkspace: (id: string) => Promise; + getActiveWorkspace: () => Promise; + getFirstWorkspace: () => Promise; } export const WorkspaceServiceIPCDescriptor = { channel: WorkspaceChannel.name, diff --git a/src/services/workspacesView/index.ts b/src/services/workspacesView/index.ts index e23edb01..936df9a3 100644 --- a/src/services/workspacesView/index.ts +++ b/src/services/workspacesView/index.ts @@ -29,14 +29,14 @@ export class WorkspaceView implements IWorkspaceViewService { @lazyInject(serviceIdentifier.MenuService) private readonly menuService!: IMenuService; constructor() { - this.registerMenu(); + void this.registerMenu(); } /** * Prepare workspaces on startup */ public async initializeAllWorkspaceView(): Promise { - const workspaces = this.workspaceService.getWorkspaces(); + const workspaces = await this.workspaceService.getWorkspaces(); for (const workspaceID in workspaces) { const workspace = workspaces[workspaceID]; if (((await this.preferenceService.get('hibernateUnusedWorkspacesAtLaunch')) || workspace.hibernateWhenUnused) && !workspace.active) { @@ -53,20 +53,20 @@ export class WorkspaceView implements IWorkspaceViewService { await this.viewService.addView(mainWindow, workspace); } try { - const userInfo = this.authService.getStorageServiceUserInfo(workspace.storageService); + const userInfo = await this.authService.getStorageServiceUserInfo(workspace.storageService); // TODO: rename name to wikiPath const { name: wikiPath, gitUrl: githubRepoUrl } = workspace; // wait for main wiki's watch-fs plugin to be fully initialized // and also wait for wiki BrowserView to be able to receive command // eslint-disable-next-line global-require - let workspaceMetadata = this.workspaceService.getMetaData(workspaceID); + let workspaceMetadata = await this.workspaceService.getMetaData(workspaceID); // wait for main wiki webview loaded if (!workspace.isSubWiki) { // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions while (workspaceMetadata.isLoading !== false) { // eslint-disable-next-line no-await-in-loop await delay(500); - workspaceMetadata = this.workspaceService.getMetaData(workspaceID); + workspaceMetadata = await this.workspaceService.getMetaData(workspaceID); } // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions if (workspaceMetadata.didFailLoadErrorMessage) { @@ -87,18 +87,18 @@ export class WorkspaceView implements IWorkspaceViewService { if (typeof id === 'string' && id.length > 0) { // if id is defined, switch to that workspace await this.setActiveWorkspaceView(id); - this.menuService.buildMenu(); + await this.menuService.buildMenu(); // load url in the current workspace - const activeWorkspace = this.workspaceService.getActiveWorkspace(); + const activeWorkspace = await this.workspaceService.getActiveWorkspace(); if (activeWorkspace !== undefined) { await this.loadURL(url, activeWorkspace.id); } } } - private registerMenu(): void { - const hasWorkspaces = this.workspaceService.countWorkspaces() > 0; - this.menuService.insertMenu( + private async registerMenu(): Promise { + const hasWorkspaces = (await this.workspaceService.countWorkspaces()) > 0; + await this.menuService.insertMenu( 'window', [ { @@ -107,7 +107,7 @@ export class WorkspaceView implements IWorkspaceViewService { { label: 'Open Developer Tools of Active Workspace', accelerator: 'CmdOrCtrl+Option+I', - click: () => this.viewService.getActiveBrowserView()?.webContents?.openDevTools(), + click: async () => (await this.viewService.getActiveBrowserView())?.webContents?.openDevTools(), enabled: hasWorkspaces, }, ], @@ -147,7 +147,7 @@ export class WorkspaceView implements IWorkspaceViewService { public async wakeUpWorkspaceView(id: string): Promise { const mainWindow = this.windowService.get(WindowNames.main); - const workspace = this.workspaceService.get(id); + const workspace = await this.workspaceService.get(id); if (mainWindow !== undefined && workspace !== undefined) { await this.viewService.addView(mainWindow, workspace); await this.workspaceService.update(id, { @@ -157,7 +157,7 @@ export class WorkspaceView implements IWorkspaceViewService { } public async hibernateWorkspaceView(id: string): Promise { - if (this.workspaceService.get(id)?.active !== true) { + if ((await this.workspaceService.get(id))?.active !== true) { this.viewService.hibernateView(id); await this.workspaceService.update(id, { hibernated: true, @@ -167,7 +167,7 @@ export class WorkspaceView implements IWorkspaceViewService { public async setActiveWorkspaceView(id: string): Promise { const mainWindow = this.windowService.get(WindowNames.main); - const oldActiveWorkspace = this.workspaceService.getActiveWorkspace(); + const oldActiveWorkspace = await this.workspaceService.getActiveWorkspace(); if (mainWindow !== undefined && oldActiveWorkspace !== undefined) { await this.workspaceService.setActiveWorkspace(id); @@ -183,14 +183,14 @@ export class WorkspaceView implements IWorkspaceViewService { public async removeWorkspaceView(id: string): Promise { const mainWindow = this.windowService.get(WindowNames.main); // if there's only one workspace left, clear all - if (this.workspaceService.countWorkspaces() === 1) { + if ((await this.workspaceService.countWorkspaces()) === 1) { if (mainWindow !== undefined) { // eslint-disable-next-line unicorn/no-null mainWindow.setBrowserView(null); mainWindow.setTitle(app.name); } - } else if (this.workspaceService.countWorkspaces() > 1 && this.workspaceService.get(id)?.active === true) { - const previousWorkspace = this.workspaceService.getPreviousWorkspace(id); + } else if ((await this.workspaceService.countWorkspaces()) > 1 && (await this.workspaceService.get(id))?.active === true) { + const previousWorkspace = await this.workspaceService.getPreviousWorkspace(id); if (previousWorkspace !== undefined) { await this.setActiveWorkspaceView(previousWorkspace.id); } @@ -221,18 +221,19 @@ export class WorkspaceView implements IWorkspaceViewService { public async clearBrowsingData(): Promise { await session.defaultSession.clearStorageData(); - const workspaces = this.workspaceService.getWorkspaces(); + const workspaces = await this.workspaceService.getWorkspaces(); await Promise.all(Object.keys(workspaces).map(async (id) => await session.fromPartition(`persist:${id}`).clearStorageData())); // shared session await session.fromPartition('persist:shared').clearStorageData(); } - public async loadURL(url: string, id: string | undefined = this.workspaceService.getActiveWorkspace()?.id): Promise { + public async loadURL(url: string, id: string | undefined): Promise { const mainWindow = this.windowService.get(WindowNames.main); - if (mainWindow !== undefined && id !== undefined) { - await this.workspaceService.setActiveWorkspace(id); - await this.viewService.setActiveView(mainWindow, id); + const activeID = id ?? (await this.workspaceService.getActiveWorkspace())?.id; + if (mainWindow !== undefined && activeID !== undefined) { + await this.workspaceService.setActiveWorkspace(activeID); + await this.viewService.setActiveView(mainWindow, activeID); const browserView = mainWindow.getBrowserView(); if (browserView !== null) { @@ -250,13 +251,13 @@ export class WorkspaceView implements IWorkspaceViewService { // this function only call browserView.setBounds // do not attempt to recall browserView.webContents.focus() // as it breaks page focus (cursor, scroll bar not visible) - this.realignActiveWorkspaceView(); + await this.realignActiveWorkspaceView(); // TODO: why we need to rebuild menu? - this.menuService.buildMenu(); + await this.menuService.buildMenu(); } - private realignActiveWorkspaceView(): void { - const activeWorkspace = this.workspaceService.getActiveWorkspace(); + private async realignActiveWorkspaceView(): Promise { + const activeWorkspace = await this.workspaceService.getActiveWorkspace(); const mainWindow = this.windowService.get(WindowNames.main); if (activeWorkspace !== undefined && mainWindow !== undefined) { void this.viewService.realignActiveView(mainWindow, activeWorkspace.id);