mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2026-01-30 12:23:12 -08:00
feat: add notification to tell user restart complete
This commit is contained in:
parent
c351f4519e
commit
2608106877
9 changed files with 116 additions and 41 deletions
|
|
@ -40,7 +40,9 @@
|
|||
"SearchWithGoogle": "Search With Google",
|
||||
"Cut": "Cut",
|
||||
"Copy": "Copy",
|
||||
"Paste": "Paste"
|
||||
"Paste": "Paste",
|
||||
"RestartService": "Restart Service",
|
||||
"RestartServiceComplete": "Restart Service Complete"
|
||||
},
|
||||
"AddWorkspace": {
|
||||
"MainPageTipWithoutSidebar": "<0>Click </0><strong>Workspaces > Add Workspace</strong><2> on the menu to start using TiddlyWiki!</2>",
|
||||
|
|
|
|||
|
|
@ -41,7 +41,9 @@
|
|||
"CopyLink": "复制链接",
|
||||
"OpenLinkInBrowser": "在浏览器中打开链接",
|
||||
"Paste": "粘贴",
|
||||
"SearchWithGoogle": "用 Google 搜索"
|
||||
"SearchWithGoogle": "用 Google 搜索",
|
||||
"RestartService": "重启服务",
|
||||
"RestartServiceComplete": "重启服务成功"
|
||||
},
|
||||
"Menu": {
|
||||
"TiddlyGit": "太记",
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ export enum WikiChannel {
|
|||
getTiddlerTextDone = 'wiki-get-tiddler-text-done',
|
||||
/** show message inside tiddlywiki to show git sync progress */
|
||||
syncProgress = 'wiki-sync-progress',
|
||||
generalNotification = 'wiki-notification-tiddly-git',
|
||||
/** used to show wiki creation messages in the TiddlyGit UI for user to read */
|
||||
createProgress = 'wiki-create-progress',
|
||||
openTiddler = 'wiki-open-tiddler',
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import WorkspaceSelector from './WorkspaceSelector';
|
|||
import { IWorkspace } from '@services/workspaces/interface';
|
||||
|
||||
import defaultIcon from '@/images/default-icon.png';
|
||||
import { WikiChannel } from '@/constants/channels';
|
||||
|
||||
export interface ISortableItemProps {
|
||||
index: number;
|
||||
|
|
@ -64,6 +65,17 @@ export function SortableWorkspaceSelector({ index, workspace, showSidebarShortcu
|
|||
label: t('ContextMenu.Reload'),
|
||||
click: async () => await window.service.view.reloadViewsWebContents(id),
|
||||
},
|
||||
{
|
||||
label: t('ContextMenu.RestartService'),
|
||||
click: async () => {
|
||||
const workspaceToRestart = await window.service.workspace.get(id);
|
||||
if (workspaceToRestart !== undefined) {
|
||||
await window.service.wiki.restartWiki(workspaceToRestart);
|
||||
await window.service.view.reloadViewsWebContents(id);
|
||||
await window.service.wiki.wikiOperation(WikiChannel.generalNotification, [t('ContextMenu.RestartServiceComplete')]);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
if (!active && !isSubWiki) {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,12 @@ ipcRenderer.on(WikiChannel.syncProgress, async (event, message: string) => {
|
|||
$tw.notifier.display('$:/state/notification/${WikiChannel.syncProgress}');
|
||||
`);
|
||||
});
|
||||
ipcRenderer.on(WikiChannel.generalNotification, async (event, message: string) => {
|
||||
await webFrame.executeJavaScript(`
|
||||
$tw.wiki.addTiddler({ title: '$:/state/notification/${WikiChannel.generalNotification}', text: '${message}' });
|
||||
$tw.notifier.display('$:/state/notification/${WikiChannel.generalNotification}');
|
||||
`);
|
||||
});
|
||||
// open a tiddler
|
||||
ipcRenderer.on(WikiChannel.openTiddler, async (event, tiddlerName: string) => {
|
||||
await webFrame.executeJavaScript(`
|
||||
|
|
|
|||
|
|
@ -1,31 +1,11 @@
|
|||
/* eslint-disable global-require */
|
||||
import Transport from 'winston-transport';
|
||||
|
||||
import { container } from '@services/container';
|
||||
import type { IViewService } from '@services/view/interface';
|
||||
import type { IWindowService } from '@services/windows/interface';
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
import { WindowNames } from '@services/windows/WindowProperties';
|
||||
import { WikiChannel } from '@/constants/channels';
|
||||
|
||||
const handlers = {
|
||||
[WikiChannel.createProgress]: (message: string) => {
|
||||
const windowService = container.get<IWindowService>(serviceIdentifier.Window);
|
||||
const createWorkspaceWindow = windowService.get(WindowNames.addWorkspace);
|
||||
createWorkspaceWindow?.webContents?.send(WikiChannel.createProgress, message);
|
||||
},
|
||||
[WikiChannel.syncProgress]: async (message: string) => {
|
||||
const viewService = container.get<IViewService>(serviceIdentifier.View);
|
||||
const browserView = await viewService.getActiveBrowserView();
|
||||
browserView?.webContents?.send(WikiChannel.syncProgress, message);
|
||||
},
|
||||
};
|
||||
|
||||
export type IHandlers = typeof handlers;
|
||||
import { IWikiOperations, wikiOperations } from '@services/wiki/wikiOperations';
|
||||
|
||||
export interface IInfo {
|
||||
/** which method or handler function we are logging for */
|
||||
handler: keyof IHandlers;
|
||||
handler: keyof IWikiOperations;
|
||||
/** the detailed massage for debugging */
|
||||
message: string;
|
||||
}
|
||||
|
|
@ -40,8 +20,8 @@ export default class RendererTransport extends Transport {
|
|||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||
if (info.handler && info.handler in handlers) {
|
||||
void handlers[info.handler](info.message);
|
||||
if (info.handler && info.handler in wikiOperations) {
|
||||
void wikiOperations[info.handler](info.message);
|
||||
}
|
||||
|
||||
callback();
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import type { WikiWorker } from './wikiWorker';
|
|||
// @ts-expect-error it don't want .ts
|
||||
// eslint-disable-next-line import/no-webpack-loader-syntax
|
||||
import workerURL from 'threads-plugin/dist/loader?name=wikiWorker!./wikiWorker.ts';
|
||||
import { IWikiOperations, wikiOperations } from './wikiOperations';
|
||||
|
||||
@injectable()
|
||||
export class Wiki implements IWikiService {
|
||||
|
|
@ -379,8 +380,20 @@ export class Wiki implements IWikiService {
|
|||
return this.justStartedWiki[wikiFolderLocation] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Watch wiki change so we can trigger git sync
|
||||
* Simply do some check before calling `this.watchWikiForDebounceCommitAndSync`
|
||||
*/
|
||||
private async tryWatchForSync(workspace: IWorkspace, watchPath?: string): Promise<void> {
|
||||
const { wikiFolderLocation, gitUrl: githubRepoUrl, storageService } = workspace;
|
||||
const userInfo = await this.authService.getStorageServiceUserInfo(storageService);
|
||||
if (storageService !== SupportedStorageServices.local && typeof githubRepoUrl === 'string' && userInfo !== undefined) {
|
||||
await this.watchWikiForDebounceCommitAndSync(wikiFolderLocation, githubRepoUrl, userInfo, watchPath);
|
||||
}
|
||||
}
|
||||
|
||||
public async wikiStartup(workspace: IWorkspace): Promise<void> {
|
||||
const { wikiFolderLocation, gitUrl: githubRepoUrl, port, isSubWiki, mainWikiToLink, storageService } = workspace;
|
||||
const { wikiFolderLocation, port, isSubWiki, mainWikiToLink } = workspace;
|
||||
|
||||
// remove $:/StoryList, otherwise it sometimes cause $__StoryList_1.tid to be generated
|
||||
try {
|
||||
|
|
@ -389,21 +402,15 @@ export class Wiki implements IWikiService {
|
|||
// do nothing
|
||||
}
|
||||
|
||||
const userInfo = await this.authService.getStorageServiceUserInfo(storageService);
|
||||
// use workspace specific userName first, and fall back to preferences' userName, pass empty editor username if undefined
|
||||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||
const userName = (workspace.userName || (await this.authService.get('userName'))) ?? '';
|
||||
/** watch wiki change so we can trigger git sync */
|
||||
const tryWatchForSync = async (watchPath?: string): Promise<void> => {
|
||||
if (storageService !== SupportedStorageServices.local && typeof githubRepoUrl === 'string' && userInfo !== undefined) {
|
||||
await this.watchWikiForDebounceCommitAndSync(wikiFolderLocation, githubRepoUrl, userInfo, watchPath);
|
||||
}
|
||||
};
|
||||
|
||||
// if is main wiki
|
||||
if (!isSubWiki) {
|
||||
await this.startWiki(wikiFolderLocation, port, userName);
|
||||
// sync to cloud, do this in a non-blocking way
|
||||
void tryWatchForSync(path.join(wikiFolderLocation, TIDDLERS_PATH));
|
||||
void this.tryWatchForSync(workspace, path.join(wikiFolderLocation, TIDDLERS_PATH));
|
||||
} else {
|
||||
// if is private repo wiki
|
||||
// if we are creating a sub-wiki just now, restart the main wiki to load content from private wiki
|
||||
|
|
@ -412,17 +419,33 @@ export class Wiki implements IWikiService {
|
|||
if (mainWorkspace === undefined) {
|
||||
throw new Error(`mainWorkspace is undefined in wikiStartup() for mainWikiPath ${mainWikiToLink}`);
|
||||
}
|
||||
await this.stopWatchWiki(mainWikiToLink);
|
||||
await this.stopWiki(mainWikiToLink);
|
||||
await this.startWiki(mainWikiToLink, mainWorkspace.port, userName);
|
||||
// sync main wiki to cloud, do this in a non-blocking way
|
||||
void tryWatchForSync(path.join(mainWikiToLink, TIDDLERS_PATH));
|
||||
await this.restartWiki(mainWorkspace);
|
||||
// sync self to cloud, subwiki's content is all in root folder path, do this in a non-blocking way
|
||||
void tryWatchForSync();
|
||||
void this.tryWatchForSync(workspace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async restartWiki(workspace: IWorkspace): Promise<void> {
|
||||
const { wikiFolderLocation, port, userName: workspaceUserName, isSubWiki } = workspace;
|
||||
// use workspace specific userName first, and fall back to preferences' userName, pass empty editor username if undefined
|
||||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||
const userName = (workspaceUserName || (await this.authService.get('userName'))) ?? '';
|
||||
|
||||
await this.stopWatchWiki(wikiFolderLocation);
|
||||
if (!isSubWiki) {
|
||||
await this.stopWiki(wikiFolderLocation);
|
||||
await this.startWiki(wikiFolderLocation, port, userName);
|
||||
}
|
||||
if (isSubWiki) {
|
||||
// sync sub wiki to cloud, do this in a non-blocking way
|
||||
void this.tryWatchForSync(workspace, wikiFolderLocation);
|
||||
} else {
|
||||
// sync main wiki to cloud, do this in a non-blocking way
|
||||
void this.tryWatchForSync(workspace, path.join(wikiFolderLocation, TIDDLERS_PATH));
|
||||
}
|
||||
}
|
||||
|
||||
// watch-wiki.ts
|
||||
private readonly frequentlyChangedFileThatShouldBeIgnoredFromWatch = ['output', /\$__StoryList/];
|
||||
private readonly topLevelFoldersToIgnored = ['node_modules', '.git'];
|
||||
|
|
@ -512,4 +535,19 @@ export class Wiki implements IWikiService {
|
|||
public async updateSubWikiPluginContent(mainWikiPath: string, newConfig?: IWorkspace, oldConfig?: IWorkspace): Promise<void> {
|
||||
return updateSubWikiPluginContent(mainWikiPath, newConfig, oldConfig);
|
||||
}
|
||||
|
||||
public wikiOperation<OP extends keyof IWikiOperations>(
|
||||
operationType: OP,
|
||||
arguments_: Parameters<IWikiOperations[OP]>,
|
||||
): undefined | ReturnType<IWikiOperations[OP]> {
|
||||
if (typeof wikiOperations[operationType] !== 'function') {
|
||||
throw new TypeError(`${operationType} gets no useful handler`);
|
||||
}
|
||||
if (!Array.isArray(arguments_)) {
|
||||
// TODO: better type handling here
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/restrict-template-expressions
|
||||
throw new TypeError(`${(arguments_ as any) ?? ''} (${typeof arguments_}) is not a good argument array for ${operationType}`);
|
||||
}
|
||||
return wikiOperations[operationType].apply(undefined, arguments_) as unknown as ReturnType<IWikiOperations[OP]>;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { WikiChannel } from '@/constants/channels';
|
|||
import { IWorkspace } from '@services/workspaces/interface';
|
||||
import { IGitUserInfos } from '@services/git/interface';
|
||||
import type { ISubWikiPluginContent } from './plugin/subWikiPlugin';
|
||||
import { IWikiOperations } from './wikiOperations';
|
||||
|
||||
export type IWikiMessage = IWikiLogMessage | IWikiControlMessage;
|
||||
export interface IWikiLogMessage {
|
||||
|
|
@ -30,6 +31,7 @@ export interface IWikiService {
|
|||
/** call wiki worker to actually start nodejs wiki */
|
||||
startWiki(homePath: string, tiddlyWikiPort: number, userName: string): Promise<void>;
|
||||
stopWiki(homePath: string): Promise<void>;
|
||||
restartWiki(workspace: IWorkspace): Promise<void>;
|
||||
stopAllWiki(): Promise<void>;
|
||||
copyWikiTemplate(newFolderPath: string, folderName: string): Promise<void>;
|
||||
getSubWikiPluginContent(mainWikiPath: string): Promise<ISubWikiPluginContent[]>;
|
||||
|
|
@ -66,6 +68,7 @@ export interface IWikiService {
|
|||
setWikiStartLockOn(wikiFolderLocation: string): void;
|
||||
setAllWikiStartLockOff(): void;
|
||||
checkWikiStartLock(wikiFolderLocation: string): boolean;
|
||||
wikiOperation<OP extends keyof IWikiOperations>(operationType: OP, arguments_: Parameters<IWikiOperations[OP]>): undefined | ReturnType<IWikiOperations[OP]>;
|
||||
}
|
||||
export const WikiServiceIPCDescriptor = {
|
||||
channel: WikiChannel.name,
|
||||
|
|
@ -73,6 +76,7 @@ export const WikiServiceIPCDescriptor = {
|
|||
updateSubWikiPluginContent: ProxyPropertyType.Function,
|
||||
startWiki: ProxyPropertyType.Function,
|
||||
stopWiki: ProxyPropertyType.Function,
|
||||
restartWiki: ProxyPropertyType.Function,
|
||||
stopAllWiki: ProxyPropertyType.Function,
|
||||
copyWikiTemplate: ProxyPropertyType.Function,
|
||||
getSubWikiPluginContent: ProxyPropertyType.Function,
|
||||
|
|
@ -89,5 +93,6 @@ export const WikiServiceIPCDescriptor = {
|
|||
watchWikiForDebounceCommitAndSync: ProxyPropertyType.Function,
|
||||
stopWatchWiki: ProxyPropertyType.Function,
|
||||
stopWatchAllWiki: ProxyPropertyType.Function,
|
||||
wikiOperation: ProxyPropertyType.Function,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
29
src/services/wiki/wikiOperations.ts
Normal file
29
src/services/wiki/wikiOperations.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import { WikiChannel } from '@/constants/channels';
|
||||
import { container } from '@services/container';
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
import { IViewService } from '@services/view/interface';
|
||||
import { IWindowService } from '@services/windows/interface';
|
||||
import { WindowNames } from '@services/windows/WindowProperties';
|
||||
|
||||
/**
|
||||
* Handle sending message to trigger operations defined in `src/preload/wikiOperation.ts`
|
||||
*/
|
||||
export const wikiOperations = {
|
||||
[WikiChannel.createProgress]: (message: string): void => {
|
||||
const windowService = container.get<IWindowService>(serviceIdentifier.Window);
|
||||
const createWorkspaceWindow = windowService.get(WindowNames.addWorkspace);
|
||||
createWorkspaceWindow?.webContents?.send(WikiChannel.createProgress, message);
|
||||
},
|
||||
[WikiChannel.syncProgress]: async (message: string): Promise<void> => {
|
||||
const viewService = container.get<IViewService>(serviceIdentifier.View);
|
||||
const browserView = await viewService.getActiveBrowserView();
|
||||
browserView?.webContents?.send(WikiChannel.syncProgress, message);
|
||||
},
|
||||
[WikiChannel.generalNotification]: async (message: string): Promise<void> => {
|
||||
const viewService = container.get<IViewService>(serviceIdentifier.View);
|
||||
const browserView = await viewService.getActiveBrowserView();
|
||||
browserView?.webContents?.send(WikiChannel.generalNotification, message);
|
||||
},
|
||||
// TODO: add more operations here from `src/preload/wikiOperation.ts`
|
||||
};
|
||||
export type IWikiOperations = typeof wikiOperations;
|
||||
Loading…
Add table
Add a link
Reference in a new issue