mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2026-01-30 04:11:33 -08:00
fix: circular dependency
This commit is contained in:
parent
9d32ffd57e
commit
9385b84da8
27 changed files with 495 additions and 320 deletions
|
|
@ -42,6 +42,7 @@ module.exports = {
|
|||
},
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/method-signature-style': 'off',
|
||||
'@typescript-eslint/member-delimiter-style': [
|
||||
'warn',
|
||||
{
|
||||
|
|
|
|||
15
package-lock.json
generated
15
package-lock.json
generated
|
|
@ -2436,6 +2436,15 @@
|
|||
"@types/responselike": "*"
|
||||
}
|
||||
},
|
||||
"@types/circular-dependency-plugin": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/circular-dependency-plugin/-/circular-dependency-plugin-5.0.1.tgz",
|
||||
"integrity": "sha512-FdtMz/DdrqeSTTXwvb7SRUF+Lmh8a8snyGDb7+1+SxxgjHUScyZQDq/1RcL2JCmPAhbNODfqxgRNkB1HWLcZnQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/webpack": "*"
|
||||
}
|
||||
},
|
||||
"@types/classnames": {
|
||||
"version": "2.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.2.11.tgz",
|
||||
|
|
@ -5047,6 +5056,12 @@
|
|||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"circular-dependency-plugin": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.2.2.tgz",
|
||||
"integrity": "sha512-g38K9Cm5WRwlaH6g03B9OEz/0qRizI+2I7n+Gz+L5DxXJAPAiWQvwlYNm1V1jkdpUv95bOe/ASm2vfi/G560jQ==",
|
||||
"dev": true
|
||||
},
|
||||
"class-utils": {
|
||||
"version": "0.3.6",
|
||||
"resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@
|
|||
"@material-ui/lab": "4.0.0-alpha.57",
|
||||
"@material-ui/pickers": "^4.0.0-alpha.12",
|
||||
"@types/bluebird": "^3.5.33",
|
||||
"@types/circular-dependency-plugin": "^5.0.1",
|
||||
"@types/classnames": "2.2.11",
|
||||
"@types/copy-webpack-plugin": "^6.4.0",
|
||||
"@types/csp-html-webpack-plugin": "3.0.0",
|
||||
|
|
@ -142,6 +143,7 @@
|
|||
"@typescript-eslint/eslint-plugin": "4.11.1",
|
||||
"@typescript-eslint/parser": "4.11.1",
|
||||
"ace-builds": "1.4.12",
|
||||
"circular-dependency-plugin": "^5.2.2",
|
||||
"classnames": "2.2.6",
|
||||
"copy-webpack-plugin": "^6.4.1",
|
||||
"csp-html-webpack-plugin": "5.0.1",
|
||||
|
|
|
|||
62
src/main.ts
62
src/main.ts
|
|
@ -15,45 +15,45 @@ import loadListeners from '@services/listeners';
|
|||
import MAILTO_URLS from '@services/constants/mailto-urls';
|
||||
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
import { Authentication } from '@services/auth';
|
||||
import { Git } from '@services/git';
|
||||
import { MenuService } from '@services/menu';
|
||||
import { IAuthenticationService, Authentication } from '@services/auth';
|
||||
import { IGitService, Git } from '@services/git';
|
||||
import { IMenuService, MenuService } from '@services/menu';
|
||||
import { Notification } from '@services/notifications';
|
||||
import { Preference } from '@services/preferences';
|
||||
import { IPreferenceService, Preference } from '@services/preferences';
|
||||
import { SystemPreference } from '@services/systemPreferences';
|
||||
import { Updater } from '@services/updater';
|
||||
import { View } from '@services/view';
|
||||
import { Wiki } from '@services/wiki';
|
||||
import { IViewService, View } from '@services/view';
|
||||
import { IWikiService, Wiki } from '@services/wiki';
|
||||
import { WikiGitWorkspace } from '@services/wikiGitWorkspace';
|
||||
import { Window } from '@services/windows';
|
||||
import { IWindowService, Window } from '@services/windows';
|
||||
import { WindowNames } from '@services/windows/WindowProperties';
|
||||
import { Workspace } from '@services/workspaces';
|
||||
import { WorkspaceView } from '@services/workspacesView';
|
||||
import { IWorkspaceService, Workspace } from '@services/workspaces';
|
||||
import { IWorkspaceViewService, WorkspaceView } from '@services/workspacesView';
|
||||
|
||||
const gotTheLock = app.requestSingleInstanceLock();
|
||||
|
||||
container.bind<Authentication>(serviceIdentifier.Authentication).to(Authentication);
|
||||
container.bind<Git>(serviceIdentifier.Git).to(Git);
|
||||
container.bind<MenuService>(serviceIdentifier.View).to(MenuService);
|
||||
container.bind<Notification>(serviceIdentifier.Notification).to(Notification);
|
||||
container.bind<Preference>(serviceIdentifier.Preference).to(Preference);
|
||||
container.bind<SystemPreference>(serviceIdentifier.SystemPreference).to(SystemPreference);
|
||||
container.bind<Updater>(serviceIdentifier.Updater).to(Updater);
|
||||
container.bind<View>(serviceIdentifier.View).to(View);
|
||||
container.bind<Wiki>(serviceIdentifier.Wiki).to(Wiki);
|
||||
container.bind<WikiGitWorkspace>(serviceIdentifier.WikiGitWorkspace).to(WikiGitWorkspace);
|
||||
container.bind<Window>(serviceIdentifier.Window).to(Window);
|
||||
container.bind<Workspace>(serviceIdentifier.Workspace).to(Workspace);
|
||||
container.bind<WorkspaceView>(serviceIdentifier.WorkspaceView).to(WorkspaceView);
|
||||
const authService = container.resolve(Authentication);
|
||||
const gitService = container.resolve(Git);
|
||||
const menuService = container.resolve(MenuService);
|
||||
const preferenceService = container.resolve(Preference);
|
||||
const viewService = container.resolve(View);
|
||||
const wikiService = container.resolve(Wiki);
|
||||
const windowService = container.resolve(Window);
|
||||
const workspaceService = container.resolve(Workspace);
|
||||
const workspaceViewService = container.resolve(WorkspaceView);
|
||||
container.bind<Authentication>(serviceIdentifier.Authentication).to(Authentication).inSingletonScope();
|
||||
container.bind<Git>(serviceIdentifier.Git).to(Git).inSingletonScope();
|
||||
container.bind<MenuService>(serviceIdentifier.MenuService).to(MenuService).inSingletonScope();
|
||||
container.bind<Notification>(serviceIdentifier.Notification).to(Notification).inSingletonScope();
|
||||
container.bind<Preference>(serviceIdentifier.Preference).to(Preference).inSingletonScope();
|
||||
container.bind<SystemPreference>(serviceIdentifier.SystemPreference).to(SystemPreference).inSingletonScope();
|
||||
container.bind<Updater>(serviceIdentifier.Updater).to(Updater).inSingletonScope();
|
||||
container.bind<View>(serviceIdentifier.View).to(View).inSingletonScope();
|
||||
container.bind<Wiki>(serviceIdentifier.Wiki).to(Wiki).inSingletonScope();
|
||||
container.bind<WikiGitWorkspace>(serviceIdentifier.WikiGitWorkspace).to(WikiGitWorkspace).inSingletonScope();
|
||||
container.bind<Window>(serviceIdentifier.Window).to(Window).inSingletonScope();
|
||||
container.bind<Workspace>(serviceIdentifier.Workspace).to(Workspace).inSingletonScope();
|
||||
container.bind<WorkspaceView>(serviceIdentifier.WorkspaceView).to(WorkspaceView).inSingletonScope();
|
||||
const authService = container.get<IAuthenticationService>(serviceIdentifier.Authentication);
|
||||
const gitService = container.get<IGitService>(serviceIdentifier.Git);
|
||||
const menuService = container.get<IMenuService>(serviceIdentifier.MenuService);
|
||||
const preferenceService = container.get<IPreferenceService>(serviceIdentifier.Preference);
|
||||
const viewService = container.get<IViewService>(serviceIdentifier.View);
|
||||
const wikiService = container.get<IWikiService>(serviceIdentifier.Wiki);
|
||||
const windowService = container.get<IWindowService>(serviceIdentifier.Window);
|
||||
const workspaceService = container.get<IWorkspaceService>(serviceIdentifier.Workspace);
|
||||
const workspaceViewService = container.get<IWorkspaceViewService>(serviceIdentifier.WorkspaceView);
|
||||
|
||||
app.on('second-instance', () => {
|
||||
// Someone tried to run a second instance, we should focus our window.
|
||||
|
|
|
|||
|
|
@ -12,8 +12,13 @@ export type IUserInfos = typeof defaultUserInfos;
|
|||
/**
|
||||
* Handle login to Github GitLab Coding.net
|
||||
*/
|
||||
export interface IAuthenticationService {
|
||||
getUserInfos: () => IUserInfos;
|
||||
get<K extends keyof IUserInfos>(key: K): IUserInfos[K] | undefined;
|
||||
reset(): Promise<void>;
|
||||
}
|
||||
@injectable()
|
||||
export class Authentication {
|
||||
export class Authentication implements IAuthenticationService {
|
||||
cachedUserInfo: IUserInfos;
|
||||
readonly version = '2021.1';
|
||||
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ import isDev from 'electron-is-dev';
|
|||
|
||||
import * as gitSync from './sync';
|
||||
import * as github from './github';
|
||||
import serviceIdentifiers from '@services/serviceIdentifier';
|
||||
import { View } from '@services/view';
|
||||
import { Preference } from '@services/preferences';
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
import type { IViewService } from '@services/view';
|
||||
import type { IPreferenceService } from '@services/preferences';
|
||||
import { logger } from '@services/libs/log';
|
||||
import i18n from '@services/libs/i18n';
|
||||
import { IUserInfo } from '@services/types';
|
||||
|
|
@ -17,13 +17,20 @@ import { IUserInfo } from '@services/types';
|
|||
* System Preferences are not stored in storage but stored in macOS Preferences.
|
||||
* It can be retrieved and changed using Electron APIs
|
||||
*/
|
||||
export interface IGitService {
|
||||
debounceCommitAndSync: (wikiFolderPath: string, githubRepoUrl: string, userInfo: IUserInfo) => Promise<void> | undefined;
|
||||
updateGitInfoTiddler(githubRepoName: string): Promise<void>;
|
||||
initWikiGit(wikiFolderPath: string, githubRepoUrl: string, userInfo: IUserInfo, isMainWiki: boolean): Promise<void>;
|
||||
commitAndSync(wikiFolderPath: string, githubRepoUrl: string, userInfo: IUserInfo): Promise<void>;
|
||||
clone(githubRepoUrl: string, repoFolderPath: string, userInfo: IUserInfo): Promise<void>;
|
||||
}
|
||||
@injectable()
|
||||
export class Git {
|
||||
export class Git implements IGitService {
|
||||
disableSyncOnDevelopment = true;
|
||||
|
||||
constructor(
|
||||
@inject(serviceIdentifiers.View) private readonly viewService: View,
|
||||
@inject(serviceIdentifiers.Preference) private readonly preferenceService: Preference,
|
||||
@inject(serviceIdentifier.View) private readonly viewService: IViewService,
|
||||
@inject(serviceIdentifier.Preference) private readonly preferenceService: IPreferenceService,
|
||||
) {
|
||||
const syncDebounceInterval = this.preferenceService.get('syncDebounceInterval');
|
||||
this.debounceCommitAndSync = debounce(this.commitAndSync.bind(this), syncDebounceInterval);
|
||||
|
|
@ -32,7 +39,7 @@ export class Git {
|
|||
|
||||
public debounceCommitAndSync: (wikiFolderPath: string, githubRepoUrl: string, userInfo: IUserInfo) => Promise<void> | undefined;
|
||||
|
||||
init(): void {
|
||||
private init(): void {
|
||||
ipcMain.handle('get-workspaces-remote', async (_event, wikiFolderPath) => {
|
||||
return await github.getRemoteUrl(wikiFolderPath);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import { container } from '@services/container';
|
||||
import { Window } from '@services/windows';
|
||||
import { Preference } from '@services/preferences';
|
||||
import type { IWindowService } from '@services/windows';
|
||||
import type { IPreferenceService } from '@services/preferences';
|
||||
import { WindowNames } from '@services/windows/WindowProperties';
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
|
||||
export default function getViewBounds(
|
||||
contentSize: [number, number],
|
||||
|
|
@ -9,9 +10,9 @@ export default function getViewBounds(
|
|||
height?: number,
|
||||
width?: number,
|
||||
): { x: number; y: number; height: number; width: number } {
|
||||
const mainWindow = container.resolve(Window).get(WindowNames.main);
|
||||
const mainWindow = container.get<IWindowService>(serviceIdentifier.Window).get(WindowNames.main);
|
||||
const isFullScreen = mainWindow?.isFullScreen();
|
||||
const preferencesService = container.resolve(Preference);
|
||||
const preferencesService = container.get<IPreferenceService>(serviceIdentifier.Preference);
|
||||
const showSidebar = preferencesService.get('sidebar');
|
||||
const showTitleBar = process.platform === 'darwin' && preferencesService.get('titleBar') && isFullScreen !== true;
|
||||
const showNavigationBar =
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import { ipcMain } from 'electron';
|
||||
|
||||
import { container } from '@services/container';
|
||||
import { Window } from '@services/windows';
|
||||
import type { IWindowService } from '@services/windows';
|
||||
import { WindowNames } from '@services/windows/WindowProperties';
|
||||
import { mainBindings } from './i18next-electron-fs-backend';
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
|
||||
export default function bindI18nListener(): void {
|
||||
const windows = container.resolve(Window);
|
||||
const windows = container.get<IWindowService>(serviceIdentifier.Window);
|
||||
const mainWindow = windows.get(WindowNames.main);
|
||||
if (mainWindow === undefined) {
|
||||
throw new Error('Window is undefined in bindI18nListener()');
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ import fs from 'fs-extra';
|
|||
import path from 'path';
|
||||
import { IpcRenderer, IpcMain, BrowserWindow, IpcMainInvokeEvent, IpcRendererEvent, MenuItemConstructorOptions } from 'electron';
|
||||
|
||||
import { Window } from '@services/windows';
|
||||
import { Preference } from '@services/preferences';
|
||||
import { View } from '@services/view';
|
||||
import { MenuService } from '@services/menu';
|
||||
import type { IWindowService } from '@services/windows';
|
||||
import type { IPreferenceService } from '@services/preferences';
|
||||
import type { IViewService } from '@services/view';
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
import { container } from '@services/container';
|
||||
import { LOCALIZATION_FOLDER } from '@services/constants/paths';
|
||||
import { I18NChannels } from '@/constants/channels';
|
||||
|
|
@ -63,7 +63,7 @@ export const preloadBindings = function (
|
|||
export const mainBindings = function (ipcMain: IpcMain, browserWindow: BrowserWindow): void {
|
||||
ipcMain.handle(I18NChannels.readFileRequest, (_event: IpcMainInvokeEvent, readFileArgs: IReadFileRequest) => {
|
||||
const localeFilePath = path.join(LOCALIZATION_FOLDER, readFileArgs.filename);
|
||||
const windowService = container.resolve(Window);
|
||||
const windowService = container.get<IWindowService>(serviceIdentifier.Window);
|
||||
fs.readFile(localeFilePath, 'utf8', (error, data) => {
|
||||
windowService.sendToAllWindows(I18NChannels.readFileResponse, {
|
||||
key: readFileArgs.key,
|
||||
|
|
@ -76,7 +76,7 @@ export const mainBindings = function (ipcMain: IpcMain, browserWindow: BrowserWi
|
|||
ipcMain.handle(I18NChannels.writeFileRequest, (_event: IpcMainInvokeEvent, writeFileArgs: IWriteFileRequest) => {
|
||||
const localeFilePath = path.join(LOCALIZATION_FOLDER, writeFileArgs.filename);
|
||||
const localeFileFolderPath = path.dirname(localeFilePath);
|
||||
const windowService = container.resolve(Window);
|
||||
const windowService = container.get<IWindowService>(serviceIdentifier.Window);
|
||||
fs.ensureDir(localeFileFolderPath, (directoryCreationError?: Error) => {
|
||||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||
if (directoryCreationError) {
|
||||
|
|
@ -110,10 +110,10 @@ const whiteListedLanguages = Object.keys(whitelistMap);
|
|||
* Register languages into language menu, call this function after container init
|
||||
*/
|
||||
export function buildLanguageMenu(): void {
|
||||
const preferenceService = container.resolve(Preference);
|
||||
const windowService = container.resolve(Window);
|
||||
const viewService = container.resolve(View);
|
||||
const menuService = container.resolve(MenuService);
|
||||
const preferenceService = container.get<IPreferenceService>(serviceIdentifier.Preference);
|
||||
const windowService = container.get<IWindowService>(serviceIdentifier.Window);
|
||||
const viewService = container.get<IViewService>(serviceIdentifier.View);
|
||||
const menuService = container.get<IMenuServiceService>(serviceIdentifier.MenuService);
|
||||
const subMenu: MenuItemConstructorOptions[] = [];
|
||||
for (const language of whiteListedLanguages) {
|
||||
subMenu.push({
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import i18n from 'i18next';
|
||||
|
||||
import { container } from '@services/container';
|
||||
import { Preference } from '@services/preferences';
|
||||
import type { IPreferenceService } from '@services/preferences';
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
|
||||
export default async function useDefaultLanguage(i18next: typeof i18n): Promise<void> {
|
||||
const preferences = container.resolve(Preference);
|
||||
const preferences = container.get<IPreferenceService>(serviceIdentifier.Preference);
|
||||
const language = preferences.get('language');
|
||||
if (typeof language === 'string') {
|
||||
await i18next.changeLanguage(language);
|
||||
|
|
|
|||
|
|
@ -2,18 +2,19 @@
|
|||
import Transport from 'winston-transport';
|
||||
|
||||
import { container } from '@services/container';
|
||||
import { View } from '@services/view';
|
||||
import { Window } from '@services/windows';
|
||||
import type { IViewService } from '@services/view';
|
||||
import type { IWindowService } from '@services/windows';
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
import { WindowNames } from '@services/windows/WindowProperties';
|
||||
|
||||
const handlers = {
|
||||
createWikiProgress: (message: string) => {
|
||||
const windowService = container.resolve(Window);
|
||||
const windowService = container.get<IWindowService>(serviceIdentifier.Window);
|
||||
const createWorkspaceWindow = windowService.get(WindowNames.addWorkspace);
|
||||
createWorkspaceWindow?.webContents?.send('create-wiki-progress', message);
|
||||
},
|
||||
wikiSyncProgress: (message: string) => {
|
||||
const viewService = container.resolve(View);
|
||||
const viewService = container.get<IViewService>(serviceIdentifier.View);
|
||||
const browserView = viewService.getActiveBrowserView();
|
||||
browserView?.webContents?.send('wiki-sync-progress', message);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
import { Menu, MenuItemConstructorOptions, shell } from 'electron';
|
||||
import { debounce, take, drop } from 'lodash';
|
||||
import { injectable, inject } from 'inversify';
|
||||
import serviceIdentifiers from '@services/serviceIdentifier';
|
||||
import { Preference } from '@services/preferences';
|
||||
import { View } from '@services/view';
|
||||
import { injectable } from 'inversify';
|
||||
|
||||
interface DeferredMenuItemConstructorOptions extends Omit<MenuItemConstructorOptions, 'label' | 'enabled' | 'submenu'> {
|
||||
label?: (() => string) | string;
|
||||
|
|
@ -13,8 +10,15 @@ interface DeferredMenuItemConstructorOptions extends Omit<MenuItemConstructorOpt
|
|||
| Array<MenuItemConstructorOptions | DeferredMenuItemConstructorOptions>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle creation of app menu, other services can register their menu tab and menu items here.
|
||||
*/
|
||||
export interface IMenuService {
|
||||
buildMenu(): void;
|
||||
insertMenu(menuID: string, menuItems: DeferredMenuItemConstructorOptions[], afterSubMenu?: string | null, withSeparator = false): void;
|
||||
}
|
||||
@injectable()
|
||||
export class MenuService {
|
||||
export class MenuService implements IMenuService {
|
||||
private readonly menuTemplate: DeferredMenuItemConstructorOptions[];
|
||||
|
||||
/**
|
||||
|
|
@ -42,10 +46,7 @@ export class MenuService {
|
|||
}));
|
||||
}
|
||||
|
||||
constructor(
|
||||
@inject(serviceIdentifiers.Preference) private readonly preferenceService: Preference,
|
||||
@inject(serviceIdentifiers.View) private readonly viewService: View,
|
||||
) {
|
||||
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);
|
||||
// add some default app menus
|
||||
|
|
@ -124,7 +125,7 @@ export class MenuService {
|
|||
* @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
|
||||
*/
|
||||
insertMenu(menuID: string, menuItems: DeferredMenuItemConstructorOptions[], afterSubMenu?: string | null, withSeparator = false): void {
|
||||
public insertMenu(menuID: string, menuItems: DeferredMenuItemConstructorOptions[], afterSubMenu?: string | null, withSeparator = false): void {
|
||||
let foundMenuName = false;
|
||||
// try insert menu into an existed menu's submenu
|
||||
for (const menu of this.menuTemplate) {
|
||||
|
|
@ -162,9 +163,9 @@ export class MenuService {
|
|||
const afterSubMenuIndex = menu.submenu.findIndex((item) => item.id === afterSubMenu || item.role === afterSubMenu);
|
||||
if (afterSubMenuIndex === -1) {
|
||||
throw new Error(
|
||||
`You try to insert menu with afterSubMenu ${afterSubMenu}, but we can not found it in menu ${
|
||||
`You try to insert menu with afterSubMenu "${afterSubMenu}" in menu "${menuID}", but we can not found it in menu "${
|
||||
menu.id ?? menu.role ?? JSON.stringify(menu)
|
||||
}, please specific a menuitem with correct id attribute`,
|
||||
}", please specific a menuitem with correct id attribute`,
|
||||
);
|
||||
}
|
||||
menu.submenu = [...take(menu.submenu, afterSubMenuIndex + 1), ...menuItems, ...drop(menu.submenu, afterSubMenuIndex - 1)];
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { injectable, inject } from 'inversify';
|
||||
import serviceIdentifiers from '@services/serviceIdentifier';
|
||||
import { Preference } from '@services/preferences';
|
||||
import { View } from '@services/view';
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
import type { IPreferenceService } from '@services/preferences';
|
||||
import type { IViewService } from '@services/view';
|
||||
|
||||
export interface IPauseNotificationsInfo {
|
||||
reason: string;
|
||||
|
|
@ -9,11 +9,18 @@ export interface IPauseNotificationsInfo {
|
|||
schedule: { from: Date; to: Date };
|
||||
}
|
||||
|
||||
/**
|
||||
* Preference and method about notification, to set and pause notification.
|
||||
*/
|
||||
export interface INotificationService {
|
||||
updatePauseNotificationsInfo(): void;
|
||||
getPauseNotificationsInfo: () => IPauseNotificationsInfo | undefined;
|
||||
}
|
||||
@injectable()
|
||||
export class Notification {
|
||||
export class Notification implements INotificationService {
|
||||
constructor(
|
||||
@inject(serviceIdentifiers.Preference) private readonly preferenceService: Preference,
|
||||
@inject(serviceIdentifiers.View) private readonly viewService: View,
|
||||
@inject(serviceIdentifier.Preference) private readonly preferenceService: IPreferenceService,
|
||||
@inject(serviceIdentifier.View) private readonly viewService: IViewService,
|
||||
) {}
|
||||
|
||||
private pauseNotificationsInfo?: IPauseNotificationsInfo;
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ import path from 'path';
|
|||
import semver from 'semver';
|
||||
import settings from 'electron-settings';
|
||||
|
||||
import serviceIdentifiers from '@services/serviceIdentifier';
|
||||
import { Window } from '@services/windows';
|
||||
import { WorkspaceView } from '@services/workspacesView';
|
||||
import { Notification } from '@services/notifications';
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
import type { IWindowService } from '@services/windows';
|
||||
import type { IWorkspaceViewService } from '@services/workspacesView';
|
||||
import type { INotificationService } from '@services/notifications';
|
||||
import { WindowNames } from '@services/windows/WindowProperties';
|
||||
import { PreferenceChannel } from '@/constants/channels';
|
||||
import { container } from '@services/container';
|
||||
|
|
@ -82,11 +82,20 @@ const defaultPreferences = {
|
|||
};
|
||||
export type IPreferences = typeof defaultPreferences;
|
||||
|
||||
/**
|
||||
* Getter and setter for app business logic preferences.
|
||||
*/
|
||||
export interface IPreferenceService {
|
||||
set<K extends keyof IPreferences>(key: K, value: IPreferences[K]): Promise<void>;
|
||||
getPreferences: () => IPreferences;
|
||||
get<K extends keyof IPreferences>(key: K): IPreferences[K];
|
||||
reset(): Promise<void>;
|
||||
}
|
||||
@injectable()
|
||||
export class Preference {
|
||||
@lazyInject(serviceIdentifiers.Window) private readonly windowService!: Window;
|
||||
@lazyInject(serviceIdentifiers.Notification) private readonly notificationService!: Notification;
|
||||
@lazyInject(serviceIdentifiers.WorkspaceView) private readonly workspaceViewService!: WorkspaceView;
|
||||
@lazyInject(serviceIdentifier.Window) private readonly windowService!: IWindowService;
|
||||
@lazyInject(serviceIdentifier.Notification) private readonly notificationService!: INotificationService;
|
||||
@lazyInject(serviceIdentifier.WorkspaceView) private readonly workspaceViewService!: IWorkspaceViewService;
|
||||
|
||||
cachedPreferences: IPreferences;
|
||||
readonly version = '2018.2';
|
||||
|
|
@ -149,7 +158,7 @@ export class Preference {
|
|||
/**
|
||||
* load preferences in sync, and ensure it is an Object
|
||||
*/
|
||||
getInitPreferencesForCache = (): IPreferences => {
|
||||
private readonly getInitPreferencesForCache = (): IPreferences => {
|
||||
let preferencesFromDisk = settings.getSync(`preferences.${this.version}`) ?? {};
|
||||
preferencesFromDisk = typeof preferencesFromDisk === 'object' && !Array.isArray(preferencesFromDisk) ? preferencesFromDisk : {};
|
||||
return { ...defaultPreferences, ...this.sanitizePreference(preferencesFromDisk) };
|
||||
|
|
|
|||
|
|
@ -6,22 +6,23 @@ import { contextBridge } from 'electron';
|
|||
|
||||
import { container } from '@services/container';
|
||||
import { getModifiedFileList } from '@services/git/inspect';
|
||||
import { Git } from '@services/git';
|
||||
import { Workspace } from '@services/workspaces';
|
||||
import { Authentication } from '@services/auth';
|
||||
import type { IGitService } from '@services/git';
|
||||
import type { IWorkspaceService } from '@services/workspaces';
|
||||
import type { IAuthenticationService } from '@services/auth';
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
|
||||
contextBridge.exposeInMainWorld('git', {
|
||||
getModifiedFileList,
|
||||
commitAndSync: (wikiPath: string, githubRepoUrl: string) => {
|
||||
const gitService = container.resolve(Git);
|
||||
const authService = container.resolve(Authentication);
|
||||
const gitService = container.get<IGitService>(serviceIdentifier.Git);
|
||||
const authService = container.get<IAuthenticationService>(serviceIdentifier.Authentication);
|
||||
const userInfo = authService.get('authing');
|
||||
if (userInfo !== undefined) {
|
||||
return gitService.commitAndSync(wikiPath, githubRepoUrl, userInfo);
|
||||
}
|
||||
},
|
||||
getWorkspacesAsList: () => {
|
||||
const workspaceService = container.resolve(Workspace);
|
||||
const workspaceService = container.get<IWorkspaceService>(serviceIdentifier.Workspace);
|
||||
return workspaceService.getWorkspacesAsList();
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,13 +9,18 @@ interface IUsedElectionSettings {
|
|||
* System Preferences are not stored in storage but stored in macOS Preferences.
|
||||
* It can be retrieved and changed using Electron APIs
|
||||
*/
|
||||
export interface ISystemPreferenceService {
|
||||
get<K extends keyof IUsedElectionSettings>(key: K): IUsedElectionSettings[K];
|
||||
getSystemPreferences(): IUsedElectionSettings;
|
||||
setSystemPreference<K extends keyof IUsedElectionSettings>(key: K, value: IUsedElectionSettings[K]): void;
|
||||
}
|
||||
@injectable()
|
||||
export class SystemPreference {
|
||||
export class SystemPreference implements ISystemPreferenceService {
|
||||
constructor() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
init(): void {
|
||||
private init(): void {
|
||||
ipcMain.handle('get-system-preference', (event, key: keyof IUsedElectionSettings) => {
|
||||
return this.get(key);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,23 +4,24 @@ import { injectable, inject } from 'inversify';
|
|||
import { autoUpdater, UpdateInfo } from 'electron-updater';
|
||||
import type { ProgressInfo } from 'builder-util-runtime';
|
||||
|
||||
import serviceIdentifiers from '@services/serviceIdentifier';
|
||||
import { Window } from '@services/windows';
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
import type { IWindowService } from '@services/windows';
|
||||
import { WindowNames } from '@services/windows/WindowProperties';
|
||||
|
||||
// FIXME: use electron-forge 's auto update solution, maybe see https://headspring.com/2020/09/24/building-signing-and-publishing-electron-forge-applications-for-windows/
|
||||
// TODO: use electron-forge 's auto update solution, maybe see https://headspring.com/2020/09/24/building-signing-and-publishing-electron-forge-applications-for-windows/
|
||||
export interface IUpdaterService {}
|
||||
@injectable()
|
||||
export class Updater {
|
||||
constructor(@inject(serviceIdentifiers.Window) private readonly windowService: Window) {}
|
||||
export class Updater implements IUpdaterService {
|
||||
constructor(@inject(serviceIdentifier.Window) private readonly windowService: IWindowService) {}
|
||||
|
||||
init(): void {
|
||||
private init(): void {
|
||||
(global as any).updateSilent = true;
|
||||
global.updaterObj = {};
|
||||
this.configAutoUpdater();
|
||||
this.initIPC();
|
||||
}
|
||||
|
||||
initIPC(): void {
|
||||
private initIPC(): void {
|
||||
ipcMain.handle('request-check-for-updates', async (_event, isSilent) => {
|
||||
// https://github.com/electron-userland/electron-builder/issues/4028
|
||||
if (!autoUpdater.isUpdaterActive()) {
|
||||
|
|
@ -69,7 +70,7 @@ export class Updater {
|
|||
});
|
||||
}
|
||||
|
||||
configAutoUpdater(): void {
|
||||
private configAutoUpdater(): void {
|
||||
autoUpdater.on('checking-for-update', () => {
|
||||
global.updaterObj = {
|
||||
status: 'checking-for-update',
|
||||
|
|
|
|||
|
|
@ -1,34 +1,57 @@
|
|||
import { BrowserView, BrowserWindow, WebContents, app, session, dialog, ipcMain } from 'electron';
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { injectable } from 'inversify';
|
||||
import getDecorators from 'inversify-inject-decorators';
|
||||
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
import type { IPreferenceService } from '@services/preferences';
|
||||
import type { IWorkspaceService } from '@services/workspaces';
|
||||
import type { IWorkspaceViewService } from '@services/workspacesView';
|
||||
import type { IWikiService } from '@services/wiki';
|
||||
import type { IAuthenticationService } from '@services/auth';
|
||||
import type { IWindowService } from '@services/windows';
|
||||
import type { IMenuService } from '@services/menu';
|
||||
|
||||
import serviceIdentifiers from '@services/serviceIdentifier';
|
||||
import { Preference } from '@services/preferences';
|
||||
import { Workspace } from '@services/workspaces';
|
||||
import { WorkspaceView } from '@services/workspacesView';
|
||||
import { Wiki } from '@services/wiki';
|
||||
import { Authentication } from '@services/auth';
|
||||
import { Window } from '@services/windows';
|
||||
import { MenuService } from '@services/menu';
|
||||
import { WindowNames, IBrowserViewMetaData } from '@services/windows/WindowProperties';
|
||||
import i18n from '../libs/i18n';
|
||||
import i18n from '@services/libs/i18n';
|
||||
import getViewBounds from '@services/libs/get-view-bounds';
|
||||
import { extractDomain } from '@services/libs/url';
|
||||
import { IWorkspace } from '@services/types';
|
||||
import setupViewEventHandlers from './setupViewEventHandlers';
|
||||
import getFromRenderer from '@services/libs/getFromRenderer';
|
||||
import { MetaDataChannel } from '@/constants/channels';
|
||||
import { container } from '@services/container';
|
||||
|
||||
const { lazyInject } = getDecorators(container);
|
||||
|
||||
/**
|
||||
* BrowserView related things, the BrowserView is the webview like frame that renders our wiki website.
|
||||
*/
|
||||
export interface IViewService {
|
||||
addView: (browserWindow: BrowserWindow, workspace: IWorkspace) => Promise<void>;
|
||||
getView: (id: string) => BrowserView;
|
||||
forEachView: (functionToRun: (view: BrowserView, id: string) => void) => void;
|
||||
setActiveView: (browserWindow: BrowserWindow, id: string) => Promise<void>;
|
||||
removeView: (id: string) => void;
|
||||
setViewsAudioPref: (_shouldMuteAudio?: boolean) => void;
|
||||
setViewsNotificationsPref: (_shouldPauseNotifications?: boolean) => void;
|
||||
hibernateView: (id: string) => void;
|
||||
reloadViewsDarkReader: () => void;
|
||||
reloadViewsWebContentsIfDidFailLoad: () => void;
|
||||
reloadViewsWebContents: () => void;
|
||||
getActiveBrowserView: () => BrowserView | undefined;
|
||||
realignActiveView: (browserWindow: BrowserWindow, activeId: string) => void;
|
||||
}
|
||||
@injectable()
|
||||
export class View {
|
||||
constructor(
|
||||
@inject(serviceIdentifiers.Preference) private readonly preferenceService: Preference,
|
||||
@inject(serviceIdentifiers.Wiki) private readonly wikiService: Wiki,
|
||||
@inject(serviceIdentifiers.Window) private readonly windowService: Window,
|
||||
@inject(serviceIdentifiers.Workspace) private readonly workspaceService: Workspace,
|
||||
@inject(serviceIdentifiers.Authentication) private readonly authService: Authentication,
|
||||
@inject(serviceIdentifiers.MenuService) private readonly menuService: MenuService,
|
||||
@inject(serviceIdentifiers.WorkspaceView) private readonly workspaceViewService: WorkspaceView,
|
||||
) {
|
||||
export class View implements IViewService {
|
||||
@lazyInject(serviceIdentifier.Preference) private readonly preferenceService!: IPreferenceService;
|
||||
@lazyInject(serviceIdentifier.Wiki) private readonly wikiService!: IWikiService;
|
||||
@lazyInject(serviceIdentifier.Window) private readonly windowService!: IWindowService;
|
||||
@lazyInject(serviceIdentifier.Workspace) private readonly workspaceService!: IWorkspaceService;
|
||||
@lazyInject(serviceIdentifier.Authentication) private readonly authService!: IAuthenticationService;
|
||||
@lazyInject(serviceIdentifier.MenuService) private readonly menuService!: IMenuService;
|
||||
@lazyInject(serviceIdentifier.WorkspaceView) private readonly workspaceViewService!: IWorkspaceViewService;
|
||||
|
||||
constructor() {
|
||||
this.initIPCHandlers();
|
||||
this.registerMenu();
|
||||
}
|
||||
|
|
@ -404,10 +427,8 @@ export class View {
|
|||
Object.keys(this.views).forEach((id) => {
|
||||
const view = this.getView(id);
|
||||
const workspace = this.workspaceService.get(id);
|
||||
if (view !== undefined) {
|
||||
if (workspace !== undefined) {
|
||||
view.webContents.audioMuted = workspace.disableAudio || this.shouldMuteAudio;
|
||||
}
|
||||
if (view !== undefined && workspace !== undefined) {
|
||||
view.webContents.audioMuted = workspace.disableAudio || this.shouldMuteAudio;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@ import getViewBounds from '@services/libs/get-view-bounds';
|
|||
import { extractDomain, isInternalUrl } from '@services/libs/url';
|
||||
import { buildResourcePath } from '@services/constants/paths';
|
||||
|
||||
import { Preference } from '@services/preferences';
|
||||
import { Workspace } from '@services/workspaces';
|
||||
import { WorkspaceView } from '@services/workspacesView';
|
||||
import { Window } from '@services/windows';
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
import type { IPreferenceService } from '@services/preferences';
|
||||
import type { IWorkspaceService } from '@services/workspaces';
|
||||
import type { IWorkspaceViewService } from '@services/workspacesView';
|
||||
import type { IWindowService } from '@services/windows';
|
||||
import { WindowNames, IBrowserViewMetaData } from '@services/windows/WindowProperties';
|
||||
import { container } from '@services/container';
|
||||
|
||||
|
|
@ -32,10 +33,10 @@ export default function setupViewEventHandlers(
|
|||
{ workspace, shouldPauseNotifications, sharedWebPreferences }: IViewContext,
|
||||
{ adjustUserAgentByUrl }: IViewModifier,
|
||||
): void {
|
||||
const workspaceService = container.resolve(Workspace);
|
||||
const workspaceViewService = container.resolve(WorkspaceView);
|
||||
const windowService = container.resolve(Window);
|
||||
const preferenceService = container.resolve(Preference);
|
||||
const workspaceService = container.get<IWorkspaceService>(serviceIdentifier.Workspace);
|
||||
const workspaceViewService = container.get<IWorkspaceViewService>(serviceIdentifier.WorkspaceView);
|
||||
const windowService = container.get<IWindowService>(serviceIdentifier.Window);
|
||||
const preferenceService = container.get<IPreferenceService>(serviceIdentifier.Preference);
|
||||
|
||||
view.webContents.once('did-stop-loading', () => {
|
||||
view.webContents.send('should-pause-notifications-changed', workspace.disableNotifications || shouldPauseNotifications);
|
||||
|
|
@ -297,7 +298,7 @@ function handleNewWindow(
|
|||
_postBody: Electron.PostBody,
|
||||
newWindowContext: INewWindowContext,
|
||||
): void {
|
||||
const workspaceService = container.resolve(Workspace);
|
||||
const workspaceService = container.get<IWorkspaceService>(serviceIdentifier.Workspace);
|
||||
const { view, workspace, sharedWebPreferences, adjustUserAgentByUrl } = newWindowContext;
|
||||
|
||||
const appUrl = workspaceService.get(workspace.id)?.homeUrl;
|
||||
|
|
|
|||
|
|
@ -8,34 +8,63 @@ import isDev from 'electron-is-dev';
|
|||
import { dialog, ipcMain } from 'electron';
|
||||
import chokidar from 'chokidar';
|
||||
import { trim, compact, debounce } from 'lodash';
|
||||
import getDecorators from 'inversify-inject-decorators';
|
||||
|
||||
import serviceIdentifiers from '@services/serviceIdentifier';
|
||||
import { Authentication } from '@services/auth';
|
||||
import { Window } from '@services/windows';
|
||||
import { View } from '@services/view';
|
||||
import { Workspace } from '@services/workspaces';
|
||||
import { Git } from '@services/git';
|
||||
import { WorkspaceView } from '@services/workspacesView';
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
import type { IAuthenticationService } from '@services/auth';
|
||||
import type { IWindowService } from '@services/windows';
|
||||
import type { IViewService } from '@services/view';
|
||||
import type { IWorkspaceService } from '@services/workspaces';
|
||||
import type { IGitService } from '@services/git';
|
||||
import type { IWorkspaceViewService } from '@services/workspacesView';
|
||||
import { IWorkspace, IUserInfo } from '@services/types';
|
||||
import { WindowNames } from '@services/windows/WindowProperties';
|
||||
import { logger, wikiOutputToFile, refreshOutputFile } from '@services/libs/log';
|
||||
import i18n from '@services/libs/i18n';
|
||||
import { TIDDLYWIKI_TEMPLATE_FOLDER_PATH, TIDDLERS_PATH } from '@services/constants/paths';
|
||||
import { updateSubWikiPluginContent, getSubWikiPluginContent } from './update-plugin-content';
|
||||
import { container } from '@services/container';
|
||||
|
||||
const { lazyInject } = getDecorators(container);
|
||||
|
||||
/**
|
||||
* Handle wiki worker startup and restart
|
||||
*/
|
||||
export interface IWikiService {
|
||||
updateSubWikiPluginContent(mainWikiPath: string, newConfig?: IWorkspace, oldConfig?: IWorkspace): void;
|
||||
startWiki(homePath: string, tiddlyWikiPort: number, userName: string): Promise<void>;
|
||||
stopWiki(homePath: string): Promise<void>;
|
||||
stopAllWiki(): Promise<void>;
|
||||
linkWiki(mainWikiPath: string, folderName: string, subWikiPath: string): Promise<void>;
|
||||
createWiki(newFolderPath: string, folderName: string): Promise<void>;
|
||||
createSubWiki(newFolderPath: string, folderName: string, mainWikiPath: string, tagName?: string, onlyLink?: boolean): Promise<void>;
|
||||
removeWiki(wikiPath: string, mainWikiToUnLink?: string, onlyRemoveLink?: boolean): Promise<void>;
|
||||
ensureWikiExist(wikiPath: string, shouldBeMainWiki: boolean): Promise<void>;
|
||||
cloneWiki(parentFolderLocation: string, wikiFolderName: string, githubWikiUrl: string, userInfo: IUserInfo): Promise<void>;
|
||||
cloneSubWiki(
|
||||
parentFolderLocation: string,
|
||||
wikiFolderName: string,
|
||||
mainWikiPath: string,
|
||||
githubWikiUrl: string,
|
||||
userInfo: IUserInfo,
|
||||
tagName?: string,
|
||||
): Promise<void>;
|
||||
wikiStartup(workspace: IWorkspace): Promise<void>;
|
||||
startNodeJSWiki(homePath: string, port: number, userName: string, workspaceID: string): Promise<void>;
|
||||
watchWiki(wikiRepoPath: string, githubRepoUrl: string, userInfo: IUserInfo, wikiFolderPath?: string): Promise<void>;
|
||||
stopWatchWiki(wikiRepoPath: string): Promise<void>;
|
||||
stopWatchAllWiki(): Promise<void>;
|
||||
}
|
||||
@injectable()
|
||||
export class Wiki {
|
||||
constructor(
|
||||
@inject(serviceIdentifiers.Authentication) private readonly authService: Authentication,
|
||||
@inject(serviceIdentifiers.Window) private readonly windowService: Window,
|
||||
@inject(serviceIdentifiers.Git) private readonly gitService: Git,
|
||||
@inject(serviceIdentifiers.Workspace) private readonly workspaceService: Workspace,
|
||||
@inject(serviceIdentifiers.View) private readonly viewService: View,
|
||||
@inject(serviceIdentifiers.WorkspaceView) private readonly workspaceViewService: WorkspaceView,
|
||||
) {
|
||||
@lazyInject(serviceIdentifier.Authentication) private readonly authService!: IAuthenticationService;
|
||||
@lazyInject(serviceIdentifier.Window) private readonly windowService!: IWindowService;
|
||||
@lazyInject(serviceIdentifier.Git) private readonly gitService!: IGitService;
|
||||
@lazyInject(serviceIdentifier.Workspace) private readonly workspaceService!: IWorkspaceService;
|
||||
@lazyInject(serviceIdentifier.View) private readonly viewService!: IViewService;
|
||||
@lazyInject(serviceIdentifier.WorkspaceView) private readonly workspaceViewService!: IWorkspaceViewService;
|
||||
|
||||
constructor() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
|
|
@ -321,7 +350,7 @@ export class Wiki {
|
|||
}
|
||||
}
|
||||
|
||||
public async cloneWiki(parentFolderLocation: string, wikiFolderName: string, githubWikiUrl: any, userInfo: IUserInfo): Promise<void> {
|
||||
public async cloneWiki(parentFolderLocation: string, wikiFolderName: string, githubWikiUrl: string, userInfo: IUserInfo): Promise<void> {
|
||||
this.logProgress(i18n.t('AddWorkspace.StartCloningWiki'));
|
||||
const newWikiPath = path.join(parentFolderLocation, wikiFolderName);
|
||||
if (!(await fs.pathExists(parentFolderLocation))) {
|
||||
|
|
@ -538,7 +567,7 @@ export class Wiki {
|
|||
logger.info('All wiki watcher is stopped', { function: 'stopWatchAllWiki' });
|
||||
}
|
||||
|
||||
updateSubWikiPluginContent(mainWikiPath: string, newConfig?: IWorkspace, oldConfig?: IWorkspace): void {
|
||||
public updateSubWikiPluginContent(mainWikiPath: string, newConfig?: IWorkspace, oldConfig?: IWorkspace): void {
|
||||
return updateSubWikiPluginContent(mainWikiPath, newConfig, oldConfig);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,91 +2,89 @@ import path from 'path';
|
|||
import { ipcMain, dialog } from 'electron';
|
||||
import { injectable, inject } from 'inversify';
|
||||
|
||||
import serviceIdentifiers from '@services/serviceIdentifier';
|
||||
import { Wiki } from '@services/wiki';
|
||||
import { Git } from '@services/git';
|
||||
import { Workspace } from '@services/workspaces';
|
||||
import { WorkspaceView } from '@services/workspacesView';
|
||||
import { Window } from '@services/windows';
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
import type { IWikiService } from '@services/wiki';
|
||||
import type { IGitService } from '@services/git';
|
||||
import type { IWorkspaceService } from '@services/workspaces';
|
||||
import type { IWorkspaceViewService } from '@services/workspacesView';
|
||||
import type { IWindowService } from '@services/windows';
|
||||
import { WindowNames } from '@services/windows/WindowProperties';
|
||||
import { Authentication } from '@services/auth';
|
||||
import type { IAuthenticationService } from '@services/auth';
|
||||
|
||||
import { logger } from '@services/libs/log';
|
||||
import i18n from '@services/libs/i18n';
|
||||
import { IUserInfo } from './types';
|
||||
|
||||
/**
|
||||
* Deal with operations that needs to create a wiki and a git repo at once in a workspace
|
||||
*/
|
||||
export interface IWikiGitWorkspaceService {
|
||||
initWikiGit: (wikiFolderPath: string, githubRepoUrl: string, userInfo: IUserInfo, isMainWiki: boolean) => Promise<string>;
|
||||
removeWorkspace: (id: string) => Promise<void>;
|
||||
}
|
||||
@injectable()
|
||||
export class WikiGitWorkspace {
|
||||
constructor(
|
||||
@inject(serviceIdentifiers.Wiki) private readonly wikiService: Wiki,
|
||||
@inject(serviceIdentifiers.Git) private readonly gitService: Git,
|
||||
@inject(serviceIdentifiers.Workspace) private readonly workspaceService: Workspace,
|
||||
@inject(serviceIdentifiers.Window) private readonly windowService: Window,
|
||||
@inject(serviceIdentifiers.WorkspaceView) private readonly workspaceViewService: WorkspaceView,
|
||||
@inject(serviceIdentifiers.Authentication) private readonly authService: Authentication,
|
||||
) {
|
||||
this.init();
|
||||
}
|
||||
@inject(serviceIdentifier.Wiki) private readonly wikiService: IWikiService,
|
||||
@inject(serviceIdentifier.Git) private readonly gitService: IGitService,
|
||||
@inject(serviceIdentifier.Workspace) private readonly workspaceService: IWorkspaceService,
|
||||
@inject(serviceIdentifier.Window) private readonly windowService: IWindowService,
|
||||
@inject(serviceIdentifier.WorkspaceView) private readonly workspaceViewService: IWorkspaceViewService,
|
||||
@inject(serviceIdentifier.Authentication) private readonly authService: IAuthenticationService,
|
||||
) {}
|
||||
|
||||
private init(): void {
|
||||
ipcMain.handle('request-init-wiki-git', async (_event, wikiFolderPath, githubRepoUrl, userInfo, isMainWiki) => {
|
||||
public initWikiGit = async (wikiFolderPath: string, githubRepoUrl: string, userInfo: IUserInfo, isMainWiki: boolean): Promise<string> => {
|
||||
try {
|
||||
await this.gitService.initWikiGit(wikiFolderPath, githubRepoUrl, userInfo, isMainWiki);
|
||||
return '';
|
||||
} catch (error) {
|
||||
console.info(error);
|
||||
await this.wikiService.removeWiki(wikiFolderPath);
|
||||
return String(error);
|
||||
}
|
||||
};
|
||||
|
||||
public removeWorkspace = async (id: string): Promise<void> => {
|
||||
const mainWindow = this.windowService.get(WindowNames.main);
|
||||
if (mainWindow !== undefined) {
|
||||
const { response } = await dialog.showMessageBox(mainWindow, {
|
||||
type: 'question',
|
||||
buttons: [i18n.t('WorkspaceSelector.RemoveWorkspace'), i18n.t('WorkspaceSelector.RemoveWorkspaceAndDelete'), i18n.t('Cancel')],
|
||||
message: i18n.t('WorkspaceSelector.AreYouSure'),
|
||||
cancelId: 2,
|
||||
});
|
||||
try {
|
||||
await this.gitService.initWikiGit(wikiFolderPath, githubRepoUrl, userInfo, isMainWiki);
|
||||
return '';
|
||||
} catch (error) {
|
||||
console.info(error);
|
||||
await this.wikiService.removeWiki(wikiFolderPath);
|
||||
return String(error);
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle(
|
||||
'request-remove-workspace',
|
||||
async (_event, id: string): Promise<void> => {
|
||||
const mainWindow = this.windowService.get(WindowNames.main);
|
||||
if (mainWindow !== undefined) {
|
||||
const { response } = await dialog.showMessageBox(mainWindow, {
|
||||
type: 'question',
|
||||
buttons: [i18n.t('WorkspaceSelector.RemoveWorkspace'), i18n.t('WorkspaceSelector.RemoveWorkspaceAndDelete'), i18n.t('Cancel')],
|
||||
message: i18n.t('WorkspaceSelector.AreYouSure'),
|
||||
cancelId: 2,
|
||||
});
|
||||
try {
|
||||
if (response === 0 || response === 1) {
|
||||
const workspace = this.workspaceService.get(id);
|
||||
if (workspace === undefined) {
|
||||
throw new Error(`Need to get workspace with id ${id} but failed`);
|
||||
}
|
||||
await this.wikiService.stopWatchWiki(workspace.name).catch((error) => logger.error((error as Error).message, error));
|
||||
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);
|
||||
// TODO: createMenu();
|
||||
// createMenu();
|
||||
// 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') ?? '';
|
||||
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, {
|
||||
...workspace,
|
||||
subWikiFolderName: path.basename(workspace.name),
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error((error as Error).message, error);
|
||||
if (response === 0 || response === 1) {
|
||||
const workspace = this.workspaceService.get(id);
|
||||
if (workspace === undefined) {
|
||||
throw new Error(`Need to get workspace with id ${id} but failed`);
|
||||
}
|
||||
await this.wikiService.stopWatchWiki(workspace.name).catch((error) => logger.error((error as Error).message, error));
|
||||
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);
|
||||
// TODO: createMenu();
|
||||
// createMenu();
|
||||
// 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') ?? '';
|
||||
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, {
|
||||
...workspace,
|
||||
subWikiFolderName: path.basename(workspace.name),
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error((error as Error).message, error);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,17 @@
|
|||
import { BrowserWindow, ipcMain, dialog, app, App, remote, clipboard, BrowserWindowConstructorOptions } from 'electron';
|
||||
import isDevelopment from 'electron-is-dev';
|
||||
import { injectable, inject } from 'inversify';
|
||||
import getDecorators from 'inversify-inject-decorators';
|
||||
import windowStateKeeper, { State as windowStateKeeperState } from 'electron-window-state';
|
||||
|
||||
import { IBrowserViewMetaData, WindowNames, windowDimension, WindowMeta, CodeInjectionType } from '@services/windows/WindowProperties';
|
||||
import serviceIdentifiers from '@services/serviceIdentifier';
|
||||
import { Preference } from '@services/preferences';
|
||||
import { Workspace } from '@services/workspaces';
|
||||
import { WorkspaceView } from '@services/workspacesView';
|
||||
import { MenuService } from '@services/menu';
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
|
||||
import type { IPreferenceService } from '@services/preferences';
|
||||
import type { IWorkspaceService } from '@services/workspaces';
|
||||
import type { IWorkspaceViewService } from '@services/workspacesView';
|
||||
import type { IMenuService } from '@services/menu';
|
||||
import { container } from '@services/container';
|
||||
import { Channels, WindowChannel, MetaDataChannel } from '@/constants/channels';
|
||||
|
||||
import i18n from '@services/libs/i18n';
|
||||
|
|
@ -17,17 +20,35 @@ import getViewBounds from '@services/libs/get-view-bounds';
|
|||
import getFromRenderer from '@services/libs/getFromRenderer';
|
||||
import handleAttachToMenuBar from './handleAttachToMenuBar';
|
||||
|
||||
const { lazyInject } = getDecorators(container);
|
||||
|
||||
/**
|
||||
* Create and manage window open and destroy, you can get all opened electron window instance here
|
||||
*/
|
||||
export interface IWindowService {
|
||||
get(windowName: WindowNames): BrowserWindow | undefined;
|
||||
open<N extends WindowNames>(windowName: N, meta?: WindowMeta[N], recreate?: boolean | ((windowMeta: WindowMeta[N]) => boolean)): Promise<void>;
|
||||
setWindowMeta<N extends WindowNames>(windowName: N, meta?: WindowMeta[N]): void;
|
||||
updateWindowMeta<N extends WindowNames>(windowName: N, meta?: WindowMeta[N]): void;
|
||||
getWindowMeta<N extends WindowNames>(windowName: N): WindowMeta[N];
|
||||
sendToAllWindows: (channel: Channels, ...arguments_: unknown[]) => void;
|
||||
goHome(windowName: WindowNames): Promise<void>;
|
||||
goBack(windowName: WindowNames): void;
|
||||
goForward(windowName: WindowNames): void;
|
||||
reload(windowName: WindowNames): void;
|
||||
showMessageBox(message: Electron.MessageBoxOptions['message'], type?: Electron.MessageBoxOptions['type']): void;
|
||||
}
|
||||
@injectable()
|
||||
export class Window {
|
||||
private windows = {} as Record<WindowNames, BrowserWindow | undefined>;
|
||||
private windowMeta = {} as WindowMeta;
|
||||
|
||||
constructor(
|
||||
@inject(serviceIdentifiers.Preference) private readonly preferenceService: Preference,
|
||||
@inject(serviceIdentifiers.Workspace) private readonly workspaceService: Workspace,
|
||||
@inject(serviceIdentifiers.WorkspaceView) private readonly workspaceViewService: WorkspaceView,
|
||||
@inject(serviceIdentifiers.MenuService) private readonly menuService: MenuService,
|
||||
) {
|
||||
@lazyInject(serviceIdentifier.Preference) private readonly preferenceService!: IPreferenceService;
|
||||
@lazyInject(serviceIdentifier.Workspace) private readonly workspaceService!: IWorkspaceService;
|
||||
@lazyInject(serviceIdentifier.WorkspaceView) private readonly workspaceViewService!: IWorkspaceViewService;
|
||||
@lazyInject(serviceIdentifier.MenuService) private readonly menuService!: IMenuService;
|
||||
|
||||
constructor() {
|
||||
this.initIPCHandlers();
|
||||
this.registerMenu();
|
||||
}
|
||||
|
|
@ -391,45 +412,41 @@ export class Window {
|
|||
'close',
|
||||
);
|
||||
|
||||
this.menuService.insertMenu(
|
||||
'Edit',
|
||||
[
|
||||
{
|
||||
label: 'Find',
|
||||
accelerator: 'CmdOrCtrl+F',
|
||||
click: () => {
|
||||
const mainWindow = this.get(WindowNames.main);
|
||||
if (mainWindow !== undefined) {
|
||||
mainWindow.webContents.focus();
|
||||
mainWindow.webContents.send('open-find-in-page');
|
||||
const contentSize = mainWindow.getContentSize();
|
||||
const view = mainWindow.getBrowserView();
|
||||
view?.setBounds(getViewBounds(contentSize as [number, number], true));
|
||||
}
|
||||
},
|
||||
enabled: () => this.workspaceService.countWorkspaces() > 0,
|
||||
this.menuService.insertMenu('Edit', [
|
||||
{
|
||||
label: 'Find',
|
||||
accelerator: 'CmdOrCtrl+F',
|
||||
click: () => {
|
||||
const mainWindow = this.get(WindowNames.main);
|
||||
if (mainWindow !== undefined) {
|
||||
mainWindow.webContents.focus();
|
||||
mainWindow.webContents.send('open-find-in-page');
|
||||
const contentSize = mainWindow.getContentSize();
|
||||
const view = mainWindow.getBrowserView();
|
||||
view?.setBounds(getViewBounds(contentSize as [number, number], true));
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Find Next',
|
||||
accelerator: 'CmdOrCtrl+G',
|
||||
click: () => {
|
||||
const mainWindow = this.get(WindowNames.main);
|
||||
mainWindow?.webContents?.send('request-back-find-in-page', true);
|
||||
},
|
||||
enabled: () => this.workspaceService.countWorkspaces() > 0,
|
||||
enabled: () => this.workspaceService.countWorkspaces() > 0,
|
||||
},
|
||||
{
|
||||
label: 'Find Next',
|
||||
accelerator: 'CmdOrCtrl+G',
|
||||
click: () => {
|
||||
const mainWindow = this.get(WindowNames.main);
|
||||
mainWindow?.webContents?.send('request-back-find-in-page', true);
|
||||
},
|
||||
{
|
||||
label: 'Find Previous',
|
||||
accelerator: 'Shift+CmdOrCtrl+G',
|
||||
click: () => {
|
||||
const mainWindow = this.get(WindowNames.main);
|
||||
mainWindow?.webContents?.send('request-back-find-in-page', false);
|
||||
},
|
||||
enabled: () => this.workspaceService.countWorkspaces() > 0,
|
||||
enabled: () => this.workspaceService.countWorkspaces() > 0,
|
||||
},
|
||||
{
|
||||
label: 'Find Previous',
|
||||
accelerator: 'Shift+CmdOrCtrl+G',
|
||||
click: () => {
|
||||
const mainWindow = this.get(WindowNames.main);
|
||||
mainWindow?.webContents?.send('request-back-find-in-page', false);
|
||||
},
|
||||
],
|
||||
'close',
|
||||
);
|
||||
enabled: () => this.workspaceService.countWorkspaces() > 0,
|
||||
},
|
||||
]);
|
||||
|
||||
this.menuService.insertMenu('History', [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,20 +12,45 @@ import isUrl from 'is-url';
|
|||
import download from 'download';
|
||||
import tmp from 'tmp';
|
||||
|
||||
import serviceIdentifiers from '@services/serviceIdentifier';
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
import { container } from '@services/container';
|
||||
import { Wiki } from '@services/wiki';
|
||||
import { View } from '@services/view';
|
||||
import { WorkspaceView } from '@services/workspacesView';
|
||||
import { Window } from '@services/windows';
|
||||
import type { IWikiService } from '@services/wiki';
|
||||
import type { IViewService } from '@services/view';
|
||||
import type { IWorkspaceViewService } from '@services/workspacesView';
|
||||
import type { IWindowService } from '@services/windows';
|
||||
import type { IMenuService } from '@services/menu';
|
||||
import { WindowNames } from '@services/windows/WindowProperties';
|
||||
import { MenuService } from '@services/menu';
|
||||
import { IWorkspace, IWorkspaceMetaData } from '@services/types';
|
||||
|
||||
const { lazyInject } = getDecorators(container);
|
||||
|
||||
/**
|
||||
* Manage workspace level preferences and workspace metadata.
|
||||
*/
|
||||
export interface IWorkspaceService {
|
||||
getWorkspacesAsList(): IWorkspace[];
|
||||
get(id: string): IWorkspace | undefined;
|
||||
create(newWorkspaceConfig: Omit<IWorkspace, 'active' | 'hibernated' | 'id' | 'order'>): Promise<IWorkspace>;
|
||||
getWorkspaces(): Record<string, IWorkspace>;
|
||||
countWorkspaces(): number;
|
||||
getMetaData: (id: string) => Partial<IWorkspaceMetaData>;
|
||||
getAllMetaData: () => Record<string, Partial<IWorkspaceMetaData>>;
|
||||
updateMetaData: (id: string, options: Partial<IWorkspaceMetaData>) => void;
|
||||
set(id: string, workspace: IWorkspace): Promise<void>;
|
||||
update(id: string, workspaceSetting: Partial<IWorkspace>): Promise<void>;
|
||||
setWorkspaces(newWorkspaces: Record<string, IWorkspace>): Promise<void>;
|
||||
setActiveWorkspace(id: string): Promise<void>;
|
||||
setWorkspacePicture(id: string, sourcePicturePath: string): Promise<void>;
|
||||
removeWorkspacePicture(id: string): Promise<void>;
|
||||
remove(id: string): Promise<void>;
|
||||
getByName(name: string): IWorkspace | undefined;
|
||||
getPreviousWorkspace: (id: string) => IWorkspace | undefined;
|
||||
getNextWorkspace: (id: string) => IWorkspace | undefined;
|
||||
getActiveWorkspace: () => IWorkspace | undefined;
|
||||
getFirstWorkspace: () => IWorkspace | undefined;
|
||||
}
|
||||
@injectable()
|
||||
export class Workspace {
|
||||
export class Workspace implements IWorkspaceService {
|
||||
/**
|
||||
* version of current setting schema
|
||||
*/
|
||||
|
|
@ -35,11 +60,11 @@ export class Workspace {
|
|||
*/
|
||||
workspaces: Record<string, IWorkspace> = {};
|
||||
|
||||
@lazyInject(serviceIdentifiers.Wiki) private readonly wikiService!: Wiki;
|
||||
@lazyInject(serviceIdentifiers.Window) private readonly windowService!: Window;
|
||||
@lazyInject(serviceIdentifiers.View) private readonly viewService!: View;
|
||||
@lazyInject(serviceIdentifiers.WorkspaceView) private readonly workspaceViewService!: WorkspaceView;
|
||||
@lazyInject(serviceIdentifiers.MenuService) private readonly menuService!: MenuService;
|
||||
@lazyInject(serviceIdentifier.Wiki) private readonly wikiService!: IWikiService;
|
||||
@lazyInject(serviceIdentifier.Window) private readonly windowService!: IWindowService;
|
||||
@lazyInject(serviceIdentifier.View) private readonly viewService!: IViewService;
|
||||
@lazyInject(serviceIdentifier.WorkspaceView) private readonly workspaceViewService!: IWorkspaceViewService;
|
||||
@lazyInject(serviceIdentifier.MenuService) private readonly menuService!: IMenuService;
|
||||
|
||||
constructor() {
|
||||
this.workspaces = this.getInitWorkspacesForCache();
|
||||
|
|
@ -178,22 +203,22 @@ export class Workspace {
|
|||
/**
|
||||
* Get sorted workspace list
|
||||
*/
|
||||
getWorkspacesAsList(): IWorkspace[] {
|
||||
public getWorkspacesAsList(): IWorkspace[] {
|
||||
return Object.values(this.workspaces).sort((a, b) => a.order - b.order);
|
||||
}
|
||||
|
||||
get(id: string): IWorkspace | undefined {
|
||||
public get(id: string): IWorkspace | undefined {
|
||||
return this.workspaces[id];
|
||||
}
|
||||
|
||||
async set(id: string, workspace: IWorkspace): Promise<void> {
|
||||
public async set(id: string, workspace: IWorkspace): Promise<void> {
|
||||
this.workspaces[id] = this.sanitizeWorkspace(workspace);
|
||||
await this.reactBeforeWorkspaceChanged(workspace);
|
||||
await settings.set(`workspaces.${this.version}.${id}`, { ...workspace });
|
||||
this.updateWorkspaceMenuItems();
|
||||
}
|
||||
|
||||
async update(id: string, workspaceSetting: Partial<IWorkspace>): Promise<void> {
|
||||
public async update(id: string, workspaceSetting: Partial<IWorkspace>): Promise<void> {
|
||||
const workspace = this.get(id);
|
||||
if (workspace === undefined) {
|
||||
return;
|
||||
|
|
@ -201,7 +226,7 @@ export class Workspace {
|
|||
await this.set(id, { ...workspace, ...workspaceSetting });
|
||||
}
|
||||
|
||||
async setWorkspaces(newWorkspaces: Record<string, IWorkspace>): Promise<void> {
|
||||
public async setWorkspaces(newWorkspaces: Record<string, IWorkspace>): Promise<void> {
|
||||
for (const id in newWorkspaces) {
|
||||
await this.set(id, newWorkspaces[id]);
|
||||
}
|
||||
|
|
@ -232,11 +257,11 @@ export class Workspace {
|
|||
}
|
||||
}
|
||||
|
||||
getByName(name: string): IWorkspace | undefined {
|
||||
public getByName(name: string): IWorkspace | undefined {
|
||||
return this.getWorkspacesAsList().find((workspace) => workspace.name === name);
|
||||
}
|
||||
|
||||
getPreviousWorkspace = (id: string): IWorkspace | undefined => {
|
||||
public getPreviousWorkspace = (id: string): IWorkspace | undefined => {
|
||||
const workspaceList = this.getWorkspacesAsList();
|
||||
let currentWorkspaceIndex = 0;
|
||||
for (const [index, workspace] of workspaceList.entries()) {
|
||||
|
|
@ -251,7 +276,7 @@ export class Workspace {
|
|||
return workspaceList[currentWorkspaceIndex - 1];
|
||||
};
|
||||
|
||||
getNextWorkspace = (id: string): IWorkspace | undefined => {
|
||||
public getNextWorkspace = (id: string): IWorkspace | undefined => {
|
||||
const workspaceList = this.getWorkspacesAsList();
|
||||
let currentWorkspaceIndex = 0;
|
||||
for (const [index, workspace] of workspaceList.entries()) {
|
||||
|
|
@ -266,15 +291,15 @@ export class Workspace {
|
|||
return workspaceList[currentWorkspaceIndex + 1];
|
||||
};
|
||||
|
||||
getActiveWorkspace = (): IWorkspace | undefined => {
|
||||
public getActiveWorkspace = (): IWorkspace | undefined => {
|
||||
return this.getWorkspacesAsList().find((workspace) => workspace.active);
|
||||
};
|
||||
|
||||
getFirstWorkspace = (): IWorkspace | undefined => {
|
||||
public getFirstWorkspace = (): IWorkspace | undefined => {
|
||||
return this.getWorkspacesAsList()[0];
|
||||
};
|
||||
|
||||
async setActiveWorkspace(id: string): Promise<void> {
|
||||
public async setActiveWorkspace(id: string): Promise<void> {
|
||||
const currentActiveWorkspace = this.getActiveWorkspace();
|
||||
if (currentActiveWorkspace !== undefined) {
|
||||
if (currentActiveWorkspace.id === id) {
|
||||
|
|
@ -292,7 +317,7 @@ export class Workspace {
|
|||
* @param id workspace id
|
||||
* @param sourcePicturePath image path, could be an image in app's resource folder or temp folder, we will copy it into app data folder
|
||||
*/
|
||||
async setWorkspacePicture(id: string, sourcePicturePath: string): Promise<void> {
|
||||
public async setWorkspacePicture(id: string, sourcePicturePath: string): Promise<void> {
|
||||
const workspace = this.get(id);
|
||||
if (workspace === undefined) {
|
||||
throw new Error(`Try to setWorkspacePicture() but this workspace is not existed ${id}`);
|
||||
|
|
@ -335,7 +360,7 @@ export class Workspace {
|
|||
}
|
||||
}
|
||||
|
||||
async removeWorkspacePicture(id: string): Promise<void> {
|
||||
public async removeWorkspacePicture(id: string): Promise<void> {
|
||||
const workspace = this.get(id);
|
||||
if (workspace === undefined) {
|
||||
throw new Error(`Try to removeWorkspacePicture() but this workspace is not existed ${id}`);
|
||||
|
|
@ -350,7 +375,7 @@ export class Workspace {
|
|||
}
|
||||
}
|
||||
|
||||
async remove(id: string): Promise<void> {
|
||||
public async remove(id: string): Promise<void> {
|
||||
if (id in this.workspaces) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete this.workspaces[id];
|
||||
|
|
@ -365,7 +390,7 @@ export class Workspace {
|
|||
this.updateWorkspaceMenuItems();
|
||||
}
|
||||
|
||||
async create(newWorkspaceConfig: Omit<IWorkspace, 'active' | 'hibernated' | 'id' | 'order'>): Promise<IWorkspace> {
|
||||
public async create(newWorkspaceConfig: Omit<IWorkspace, 'active' | 'hibernated' | 'id' | 'order'>): Promise<IWorkspace> {
|
||||
const newID = uuid();
|
||||
|
||||
// find largest order
|
||||
|
|
|
|||
|
|
@ -1,26 +1,36 @@
|
|||
import { app, ipcMain, session } from 'electron';
|
||||
import { injectable, inject } from 'inversify';
|
||||
|
||||
import serviceIdentifiers from '@services/serviceIdentifier';
|
||||
import { View } from '@services/view';
|
||||
import { Workspace } from '@services/workspaces';
|
||||
import { Window } from '@services/windows';
|
||||
import { MenuService } from '@services/menu';
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
import type { IViewService } from '@services/view';
|
||||
import type { IWorkspaceService } from '@services/workspaces';
|
||||
import type { IWindowService } from '@services/windows';
|
||||
import type { IMenuService } from '@services/menu';
|
||||
import { IWorkspace } from '@services/types';
|
||||
import { WindowNames } from '@services/windows/WindowProperties';
|
||||
import { Preference } from '@services/preferences';
|
||||
|
||||
/**
|
||||
* Deal with operations that needs to create a workspace and a browserView at once
|
||||
*/
|
||||
export interface IWorkspaceViewService {
|
||||
createWorkspaceView(workspaceOptions: IWorkspace): Promise<void>;
|
||||
setWorkspaceView(id: string, workspaceOptions: IWorkspace): Promise<void>;
|
||||
setWorkspaceViews(workspaces: Record<string, IWorkspace>): Promise<void>;
|
||||
wakeUpWorkspaceView(id: string): Promise<void>;
|
||||
hibernateWorkspaceView(id: string): Promise<void>;
|
||||
setActiveWorkspaceView(id: string): Promise<void>;
|
||||
removeWorkspaceView(id: string): Promise<void>;
|
||||
clearBrowsingData(): Promise<void>;
|
||||
loadURL(url: string, id: string): Promise<void>;
|
||||
realignActiveWorkspace(): void;
|
||||
}
|
||||
@injectable()
|
||||
export class WorkspaceView {
|
||||
export class WorkspaceView implements IWorkspaceViewService {
|
||||
constructor(
|
||||
@inject(serviceIdentifiers.View) private readonly viewService: View,
|
||||
@inject(serviceIdentifiers.Workspace) private readonly workspaceService: Workspace,
|
||||
@inject(serviceIdentifiers.Window) private readonly windowService: Window,
|
||||
@inject(serviceIdentifiers.Preference) private readonly preferenceService: Preference,
|
||||
@inject(serviceIdentifiers.MenuService) private readonly menuService: MenuService,
|
||||
@inject(serviceIdentifier.View) private readonly viewService: IViewService,
|
||||
@inject(serviceIdentifier.Workspace) private readonly workspaceService: IWorkspaceService,
|
||||
@inject(serviceIdentifier.Window) private readonly windowService: IWindowService,
|
||||
@inject(serviceIdentifier.MenuService) private readonly menuService: IMenuService,
|
||||
) {
|
||||
this.initIPCHandlers();
|
||||
this.registerMenu();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
// @ts-expect-error ts-migrate(2451) FIXME: Cannot redeclare block-scoped variable 'webpackAli... Remove this comment to see the full error message
|
||||
const { webpackAlias } = require('./webpack.alias');
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
const plugins = require('./webpack.plugins');
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
|
|
@ -13,12 +13,7 @@ module.exports = {
|
|||
module: {
|
||||
rules: require('./webpack.rules'),
|
||||
},
|
||||
plugins: [
|
||||
new CopyPlugin({
|
||||
// to is relative to ./.webpack/main/
|
||||
patterns: [{ from: 'src/services/wiki/wiki-worker.js', to: 'wiki-worker.js' }],
|
||||
}),
|
||||
],
|
||||
plugins: plugins.main,
|
||||
resolve: {
|
||||
alias: webpackAlias,
|
||||
extensions: ['.js', '.ts', '.jsx', '.tsx', '.json'],
|
||||
|
|
|
|||
|
|
@ -2,8 +2,29 @@
|
|||
const webpack = require('webpack');
|
||||
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
||||
const CspHtmlWebpackPlugin = require('csp-html-webpack-plugin');
|
||||
const CircularDependencyPlugin = require('circular-dependency-plugin');
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
|
||||
module.exports = [
|
||||
exports.main = [
|
||||
// new ForkTsCheckerWebpackPlugin(),
|
||||
new CopyPlugin({
|
||||
// to is relative to ./.webpack/main/
|
||||
patterns: [{ from: 'src/services/wiki/wiki-worker.js', to: 'wiki-worker.js' }],
|
||||
}),
|
||||
new CircularDependencyPlugin({
|
||||
// exclude detection of files based on a RegExp
|
||||
exclude: /node_modules/,
|
||||
// add errors to webpack instead of warnings
|
||||
failOnError: true,
|
||||
// allow import cycles that include an asyncronous import,
|
||||
// e.g. via import(/* webpackMode: "weak" */ './file.js')
|
||||
allowAsyncCycles: true,
|
||||
// set the current working directory for displaying module paths
|
||||
cwd: process.cwd(),
|
||||
}),
|
||||
];
|
||||
|
||||
exports.renderer = [
|
||||
// new ForkTsCheckerWebpackPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': '{}',
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ module.exports = {
|
|||
module: {
|
||||
rules,
|
||||
},
|
||||
plugins: plugins,
|
||||
plugins: plugins.renderer,
|
||||
resolve: {
|
||||
alias: webpackAlias,
|
||||
extensions: ['.js', '.ts', '.jsx', '.tsx', '.css'],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue