mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2026-03-02 12:00:45 -08:00
feat: allow switch workspace using context menu when sidebar is off
This commit is contained in:
parent
ef25c6c8c4
commit
95de620681
8 changed files with 150 additions and 67 deletions
|
|
@ -2,6 +2,7 @@
|
|||
"Hello": "Hello",
|
||||
"WorkspaceSelector": {
|
||||
"Add": "Add",
|
||||
"OpenWorkspaceTagTiddler": "Open {{tagName}}",
|
||||
"EditWorkspace": "Edit Workspace",
|
||||
"RemoveWorkspace": "Remove Workspace",
|
||||
"AreYouSure": "Are you sure you want to remove this workspace? \nRemoving the workspace will delete the workspace in this application, but will not delete the folders from the hard drive. \nBut, if you choose to delete the Wiki folder as well, all contents will be deleted.",
|
||||
|
|
@ -295,7 +296,7 @@
|
|||
"DoubleWikiInstanceError": "E-4 DoubleWikiInstanceError",
|
||||
"DoubleWikiInstanceErrorDescription": "E-4 You started the same Wiki twice. This may be caused by a bug in the program.",
|
||||
"InsertMenuAfterSubMenuIndexError": "E-5 InsertMenuAfterSubMenuIndexError",
|
||||
"InsertMenuAfterSubMenuIndexErrorDescription": "E-5 You try to insert menu with afterSubMenu \"{afterSubMenu}\" in menu \"{menuID}\", but we can not found it in menu \"{menu}\", please specific a menuitem with correct id attribute",
|
||||
"InsertMenuAfterSubMenuIndexErrorDescription": "E-5 You try to insert menu with afterSubMenu \"{{afterSubMenu}}\" in menu \"{{menuID}}\", but we can not found it in menu \"{{menu}}\", please specific a menuitem with correct id attribute",
|
||||
"InitWikiGitSyncedWikiNoGitUserInfoError": "E-6 InitWikiGitSyncedWikiNoGitUserInfoErrorDescription",
|
||||
"InitWikiGitSyncedWikiNoGitUserInfoErrorDescription": "E-6 Initializing the note repository synchronized to the cloud requires you to select a cloud git repository address and provide the certification credentials for the corresponding cloud service. However, this information is not currently available.",
|
||||
"MainWindowMissing": "E-7 This program can't access main window data, can't run normally.",
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
"LinOnetwo": "林一二",
|
||||
"WorkspaceSelector": {
|
||||
"Add": "添加",
|
||||
"OpenWorkspaceTagTiddler": "打开 {{tagName}}",
|
||||
"EditWorkspace": "编辑工作区",
|
||||
"EditCurrentWorkspace": "编辑当前工作区",
|
||||
"ReloadCurrentWorkspace": "刷新当前工作区",
|
||||
|
|
@ -326,7 +327,7 @@
|
|||
"DoubleWikiInstanceError": "E-4 重复启动维基错误",
|
||||
"DoubleWikiInstanceErrorDescription": "E-4 你启动了同一个Wiki两次,这可能是程序bug导致的。",
|
||||
"InsertMenuAfterSubMenuIndexError": "E-5 插入目录模板到现有目录后错误",
|
||||
"InsertMenuAfterSubMenuIndexErrorDescription": "E-5 你尝试插入目录,且 afterSubMenu \"{afterSubMenu}\" 在目录 menuID \"{menuID}\" 内,但我们无法在目录 \"{menu}\" 里找到它,请用正确的 menuID 指定一个目录。",
|
||||
"InsertMenuAfterSubMenuIndexErrorDescription": "E-5 你尝试插入目录,且 afterSubMenu \"{{afterSubMenu}}\" 在目录 menuID \"{{menuID}}\" 内,但我们无法在目录 \"{{menu}}\" 里找到它,请用正确的 menuID 指定一个目录。",
|
||||
"InitWikiGitSyncedWikiNoGitUserInfoError": "E-6 笔记仓库初始化失败因为没有提供Git信息错误",
|
||||
"InitWikiGitSyncedWikiNoGitUserInfoErrorDescription": "E-6 初始化同步到云端的笔记仓库需要你选择一个云端的 git 仓库地址,还有提供相应云服务的认证凭证,然而目前没有获得这些信息。",
|
||||
"MainWindowMissing": "E-7 程序无法获取主窗口信息,无法正常运行。",
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ export function workspaceConfigFromForm(form: IWikiWorkspaceForm, isCreateMainWo
|
|||
gitUrl: isCreateSyncedWorkspace ? form.gitRepoUrl : null,
|
||||
isSubWiki: !isCreateMainWorkspace,
|
||||
mainWikiToLink: !isCreateMainWorkspace ? form.mainWikiToLink.wikiFolderLocation : null,
|
||||
mainWikiID: !isCreateMainWorkspace ? form.mainWikiToLink.id : null,
|
||||
name: form.wikiFolderName,
|
||||
storageService: form.storageProvider,
|
||||
tagName: !isCreateMainWorkspace ? form.tagName : null,
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ import { CSS } from '@dnd-kit/utilities';
|
|||
import { WindowNames } from '@services/windows/WindowProperties';
|
||||
import WorkspaceSelector from './WorkspaceSelector';
|
||||
import { IWorkspace } from '@services/workspaces/interface';
|
||||
import { getWorkspaceMenuTemplate, openWorkspaceTagTiddler } from '@services/workspaces/getWorkspaceMenuTemplate';
|
||||
|
||||
import defaultIcon from '@/images/default-icon.png';
|
||||
import { WikiChannel } from '@/constants/channels';
|
||||
|
||||
export interface ISortableItemProps {
|
||||
index: number;
|
||||
|
|
@ -29,68 +29,12 @@ export function SortableWorkspaceSelector({ index, workspace, showSidebarShortcu
|
|||
style={style}
|
||||
{...attributes}
|
||||
{...listeners}
|
||||
onClick={async () => {
|
||||
if (isSubWiki) {
|
||||
if (typeof tagName === 'string') {
|
||||
await window.service.wiki.requestOpenTiddlerInWiki(tagName);
|
||||
}
|
||||
} else {
|
||||
const activeWorkspace = await window.service.workspace.getActiveWorkspace();
|
||||
if (activeWorkspace?.id === id) {
|
||||
await window.service.wiki.requestWikiSendActionMessage('tm-home');
|
||||
} else {
|
||||
await window.service.workspaceView.setActiveWorkspaceView(id);
|
||||
}
|
||||
}
|
||||
}}
|
||||
onClick={async () => await openWorkspaceTagTiddler(workspace, window.service)}
|
||||
onContextMenu={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const template = [
|
||||
{
|
||||
label: t('WorkspaceSelector.EditWorkspace'),
|
||||
click: async () => {
|
||||
await window.service.window.open(WindowNames.editWorkspace, { workspaceID: id });
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('WorkspaceSelector.RemoveWorkspace'),
|
||||
click: async () => await window.service.wikiGitWorkspace.removeWorkspace(id),
|
||||
},
|
||||
{
|
||||
label: t('WorkspaceSelector.OpenWorkspaceFolder'),
|
||||
click: async () => await window.service.native.open(wikiFolderLocation, true),
|
||||
},
|
||||
{
|
||||
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) {
|
||||
template.splice(1, 0, {
|
||||
label: hibernated ? t('WorkspaceSelector.WakeUpWorkspace') : t('WorkspaceSelector.HibernateWorkspace'),
|
||||
click: async () => {
|
||||
if (hibernated) {
|
||||
return await window.service.workspaceView.wakeUpWorkspaceView(id);
|
||||
}
|
||||
return await window.service.workspaceView.hibernateWorkspaceView(id);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
void window.remote.buildContextMenuAndPopup(template, { x: event.clientX, y: event.clientY, editFlags: { canCopy: false } });
|
||||
const workspaceContextMenuTemplate = getWorkspaceMenuTemplate(workspace, t, window.service);
|
||||
void window.remote.buildContextMenuAndPopup(workspaceContextMenuTemplate, { x: event.clientX, y: event.clientY, editFlags: { canCopy: false } });
|
||||
}}>
|
||||
<WorkspaceSelector
|
||||
active={active}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,15 @@ import { DeferredMenuItemConstructorOptions } from './interface';
|
|||
import { WindowNames } from '@services/windows/WindowProperties';
|
||||
import { lazyInject } from '@services/container';
|
||||
import serviceIdentifier from '@services/serviceIdentifier';
|
||||
import type { IWindowService } from '@services/windows/interface';
|
||||
import type { INativeService } from '@services/native/interface';
|
||||
import type { IPreferenceService } from '@services/preferences/interface';
|
||||
import type { IViewService } from '@services/view/interface';
|
||||
import type { IWikiGitWorkspaceService } from '@services/wikiGitWorkspace/interface';
|
||||
import type { IWikiService } from '@services/wiki/interface';
|
||||
import type { IWindowService } from '@services/windows/interface';
|
||||
import type { IWorkspaceService } from '@services/workspaces/interface';
|
||||
import type { IWorkspaceViewService } from '@services/workspacesView/interface';
|
||||
import { getWorkspaceMenuTemplate } from '@services/workspaces/getWorkspaceMenuTemplate';
|
||||
import { logger } from '@services/libs/log';
|
||||
import i18next from '@services/libs/i18n';
|
||||
import ContextMenuBuilder from './contextMenuBuilder';
|
||||
|
|
@ -19,8 +25,13 @@ import { InsertMenuAfterSubMenuIndexError } from './error';
|
|||
|
||||
@injectable()
|
||||
export class MenuService implements IMenuService {
|
||||
@lazyInject(serviceIdentifier.Window) private readonly windowService!: IWindowService;
|
||||
@lazyInject(serviceIdentifier.NativeService) private readonly nativeService!: INativeService;
|
||||
@lazyInject(serviceIdentifier.Preference) private readonly preferenceService!: IPreferenceService;
|
||||
@lazyInject(serviceIdentifier.View) private readonly viewService!: IViewService;
|
||||
@lazyInject(serviceIdentifier.Wiki) private readonly wikiService!: IWikiService;
|
||||
@lazyInject(serviceIdentifier.WikiGitWorkspace) private readonly wikiGitWorkspaceService!: IWikiGitWorkspaceService;
|
||||
@lazyInject(serviceIdentifier.Window) private readonly windowService!: IWindowService;
|
||||
@lazyInject(serviceIdentifier.Workspace) private readonly workspaceService!: IWorkspaceService;
|
||||
@lazyInject(serviceIdentifier.WorkspaceView) private readonly workspaceViewService!: IWorkspaceViewService;
|
||||
|
||||
private _menuTemplate?: DeferredMenuItemConstructorOptions[];
|
||||
|
|
@ -328,6 +339,32 @@ export class MenuService implements IMenuService {
|
|||
const sidebar = await this.preferenceService.get('sidebar');
|
||||
const contextMenuBuilder = new ContextMenuBuilder(webContents);
|
||||
const menu = contextMenuBuilder.buildMenuForElement(info);
|
||||
// show workspace menu to manipulate workspaces if sidebar is not open
|
||||
if (!sidebar) {
|
||||
menu.append(new MenuItem({ type: 'separator' }));
|
||||
const workspaces = await this.workspaceService.getWorkspacesAsList();
|
||||
const services = {
|
||||
native: this.nativeService,
|
||||
view: this.viewService,
|
||||
wiki: this.wikiService,
|
||||
wikiGitWorkspace: this.wikiGitWorkspaceService,
|
||||
window: this.windowService,
|
||||
workspace: this.workspaceService,
|
||||
workspaceView: this.workspaceViewService,
|
||||
};
|
||||
menu.append(
|
||||
new MenuItem({
|
||||
label: i18next.t('Menu.Workspaces'),
|
||||
submenu: workspaces.map((workspace) => {
|
||||
const workspaceContextMenuTemplate = getWorkspaceMenuTemplate(workspace, i18next.t.bind(i18next), services);
|
||||
return {
|
||||
label: workspace.name,
|
||||
submenu: workspaceContextMenuTemplate,
|
||||
};
|
||||
}),
|
||||
}),
|
||||
);
|
||||
}
|
||||
menu.append(
|
||||
new MenuItem({
|
||||
label: i18next.t('ContextMenu.Back'),
|
||||
|
|
|
|||
97
src/services/workspaces/getWorkspaceMenuTemplate.ts
Normal file
97
src/services/workspaces/getWorkspaceMenuTemplate.ts
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
import type { TFunction } from 'i18next';
|
||||
import type { MenuItemConstructorOptions } from 'electron';
|
||||
import { WikiChannel } from '@/constants/channels';
|
||||
import { WindowNames } from '@services/windows/WindowProperties';
|
||||
import type { IWindowService } from '@services/windows/interface';
|
||||
import type { IWorkspaceViewService } from '@services/workspacesView/interface';
|
||||
import type { IWorkspace, IWorkspaceService } from './interface';
|
||||
import type { INativeService } from '@services/native/interface';
|
||||
import type { IViewService } from '@services/view/interface';
|
||||
import type { IWikiService } from '@services/wiki/interface';
|
||||
import type { IWikiGitWorkspaceService } from '@services/wikiGitWorkspace/interface';
|
||||
|
||||
interface IWorkspaceMenuRequiredServices {
|
||||
native: Pick<INativeService, 'open'>;
|
||||
view: Pick<IViewService, 'reloadViewsWebContents'>;
|
||||
wiki: Pick<IWikiService, 'restartWiki' | 'wikiOperation' | 'requestOpenTiddlerInWiki' | 'requestWikiSendActionMessage'>;
|
||||
wikiGitWorkspace: Pick<IWikiGitWorkspaceService, 'removeWorkspace'>;
|
||||
window: Pick<IWindowService, 'open'>;
|
||||
workspace: Pick<IWorkspaceService, 'get' | 'getActiveWorkspace'>;
|
||||
workspaceView: Pick<IWorkspaceViewService, 'wakeUpWorkspaceView' | 'hibernateWorkspaceView' | 'setActiveWorkspaceView'>;
|
||||
}
|
||||
|
||||
export async function openWorkspaceTagTiddler(workspace: IWorkspace, service: IWorkspaceMenuRequiredServices): Promise<void> {
|
||||
const { id, isSubWiki, tagName, mainWikiID } = workspace;
|
||||
let idToActive = id;
|
||||
const activeWorkspace = await service.workspace.getActiveWorkspace();
|
||||
if (isSubWiki) {
|
||||
if (typeof tagName === 'string') {
|
||||
await service.wiki.requestOpenTiddlerInWiki(tagName);
|
||||
}
|
||||
if (mainWikiID === null) {
|
||||
return;
|
||||
}
|
||||
idToActive = mainWikiID;
|
||||
} else {
|
||||
await service.wiki.requestWikiSendActionMessage('tm-home');
|
||||
}
|
||||
if (idToActive !== null && activeWorkspace?.id !== idToActive) {
|
||||
await service.workspaceView.setActiveWorkspaceView(idToActive);
|
||||
}
|
||||
}
|
||||
|
||||
export function getWorkspaceMenuTemplate(workspace: IWorkspace, t: TFunction, service: IWorkspaceMenuRequiredServices): MenuItemConstructorOptions[] {
|
||||
const { active, id, hibernated, tagName, isSubWiki, wikiFolderLocation } = workspace;
|
||||
|
||||
const template = [
|
||||
{
|
||||
label: t('WorkspaceSelector.OpenWorkspaceTagTiddler', { tagName }),
|
||||
click: async () => {
|
||||
await openWorkspaceTagTiddler(workspace, service);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('WorkspaceSelector.EditWorkspace'),
|
||||
click: async () => {
|
||||
await service.window.open(WindowNames.editWorkspace, { workspaceID: id });
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('WorkspaceSelector.RemoveWorkspace'),
|
||||
click: async () => await service.wikiGitWorkspace.removeWorkspace(id),
|
||||
},
|
||||
{
|
||||
label: t('WorkspaceSelector.OpenWorkspaceFolder'),
|
||||
click: async () => await service.native.open(wikiFolderLocation, true),
|
||||
},
|
||||
{
|
||||
label: t('ContextMenu.Reload'),
|
||||
click: async () => await service.view.reloadViewsWebContents(id),
|
||||
},
|
||||
{
|
||||
label: t('ContextMenu.RestartService'),
|
||||
click: async () => {
|
||||
const workspaceToRestart = await service.workspace.get(id);
|
||||
if (workspaceToRestart !== undefined) {
|
||||
await service.wiki.restartWiki(workspaceToRestart);
|
||||
await service.view.reloadViewsWebContents(id);
|
||||
await service.wiki.wikiOperation(WikiChannel.generalNotification, [t('ContextMenu.RestartServiceComplete')]);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
if (!active && !isSubWiki) {
|
||||
template.splice(1, 0, {
|
||||
label: hibernated ? t('WorkspaceSelector.WakeUpWorkspace') : t('WorkspaceSelector.HibernateWorkspace'),
|
||||
click: async () => {
|
||||
if (hibernated) {
|
||||
return await service.workspaceView.wakeUpWorkspaceView(id);
|
||||
}
|
||||
return await service.workspaceView.hibernateWorkspaceView(id);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return template;
|
||||
}
|
||||
|
|
@ -18,7 +18,6 @@ import type { IWorkspaceViewService } from '@services/workspacesView/interface';
|
|||
import type { IWindowService } from '@services/windows/interface';
|
||||
import type { IMenuService } from '@services/menu/interface';
|
||||
import { WindowNames } from '@services/windows/WindowProperties';
|
||||
import type { IAuthenticationService } from '@services/auth/interface';
|
||||
import type { IWikiGitWorkspaceService } from '@services/wikiGitWorkspace/interface';
|
||||
import { SupportedStorageServices } from '@services/types';
|
||||
import { lazyInject } from '@services/container';
|
||||
|
|
@ -40,7 +39,6 @@ export class Workspace implements IWorkspaceService {
|
|||
@lazyInject(serviceIdentifier.WorkspaceView) private readonly workspaceViewService!: IWorkspaceViewService;
|
||||
@lazyInject(serviceIdentifier.WikiGitWorkspace) private readonly wikiGitWorkspaceService!: IWikiGitWorkspaceService;
|
||||
@lazyInject(serviceIdentifier.MenuService) private readonly menuService!: IMenuService;
|
||||
@lazyInject(serviceIdentifier.Authentication) private readonly authenticationService!: IAuthenticationService;
|
||||
|
||||
constructor() {
|
||||
this.workspaces = this.getInitWorkspacesForCache();
|
||||
|
|
|
|||
|
|
@ -34,7 +34,11 @@ export interface IWorkspace {
|
|||
*/
|
||||
lastUrl: string | null;
|
||||
/**
|
||||
* Only useful when isSubWiki === true , this is the wiki repo that this subwiki's folder soft links to
|
||||
* ID of main wiki of the sub-wiki. Only useful when isSubWiki === true
|
||||
*/
|
||||
mainWikiID: string | null;
|
||||
/**
|
||||
* Absolute path of main wiki of the sub-wiki. Only useful when isSubWiki === true , this is the wiki repo that this subwiki's folder soft links to
|
||||
*/
|
||||
mainWikiToLink: string | null;
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue