Skip to content

Commit

Permalink
feat(electron): new tab/split view entries
Browse files Browse the repository at this point in the history
  • Loading branch information
pengx17 committed Aug 2, 2024
1 parent 44309f3 commit c045c4a
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 134 deletions.
48 changes: 30 additions & 18 deletions packages/frontend/core/src/modules/navigation/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,42 @@ export const resolveRouteLinkMeta = (href: string) => {
return null;
}

const hash = url.hash;
const pathname = url.pathname;

// http://---/workspace/{workspaceid}/xxx/yyy
// http://---/workspace/{workspaceid}/xxx
const [_, workspaceId, moduleName, subModuleName] =
pathname.match(/\/workspace\/([^/]+)\/([^/]+)(?:\/([^/]+))?/) || [];
url.pathname.match(/\/workspace\/([^/]+)\/([^/]+)(?:\/([^/]+))?/) || [];

if (isRouteModulePath(moduleName)) {
return {
workspaceId,
moduleName,
subModuleName,
};
} else if (moduleName) {
// for now we assume all other cases are doc links
return {
workspaceId,
moduleName: 'doc' as const,
docId: moduleName,
blockId: hash.slice(1),
if (workspaceId) {
const basename = `/workspace/${workspaceId}`;
const pathname = url.pathname.replace(basename, '');
const search = url.search;
const hash = url.hash;
const location = {
pathname,
search,
hash,
};
if (isRouteModulePath(moduleName)) {
return {
location,
basename,
workspaceId,
moduleName,
subModuleName,
};
} else if (moduleName) {
// for now we assume all other cases are doc links
return {
location,
basename,
workspaceId,
moduleName: 'doc' as const,
docId: moduleName,
blockId: hash.slice(1),
};
}
}
return;
return null;
} catch {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ export class DesktopStateSynchronizer extends Service {
event.type === 'open-in-split-view' &&
event.payload.tabId === appInfo?.viewId
) {
const activeView = workbench.activeView$.value;
if (activeView) {
workbench.open(activeView.location$.value, {
at: 'beside',
});
}
const to =
event.payload.view?.path ??
workbench.activeView$.value?.location$.value;

workbench.open(to, {
at: 'beside',
});
}

if (
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/electron/src/main/ui/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ import {
pingAppLayoutReady,
showDevTools,
showTab,
showTabContextMenu,
updateWorkbenchMeta,
updateWorkbenchViewMeta,
} from '../windows-manager';
import { showTabContextMenu } from '../windows-manager/context-menu';
import { getChallengeResponse } from './challenge';
import { uiSubjects } from './subject';

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { Menu } from 'electron';

import { logger } from '../logger';
import {
addTab,
closeTab,
reloadView,
WebContentViewsManager,
} from './tab-views';

export const showTabContextMenu = async (tabId: string, viewIndex: number) => {
const workbenches = WebContentViewsManager.instance.tabViewsMeta.workbenches;
const unpinned = workbenches.filter(w => !w.pinned);
const tabMeta = workbenches.find(w => w.id === tabId);
if (!tabMeta) {
return;
}

const template: Parameters<typeof Menu.buildFromTemplate>[0] = [
tabMeta.pinned
? {
label: 'Unpin tab',
click: () => {
WebContentViewsManager.instance.pinTab(tabId, false);
},
}
: {
label: 'Pin tab',
click: () => {
WebContentViewsManager.instance.pinTab(tabId, true);
},
},
{
label: 'Refresh tab',
click: () => {
reloadView().catch(logger.error);
},
},
{
label: 'Duplicate tab',
click: () => {
addTab({
basename: tabMeta.basename,
view: tabMeta.views,
show: false,
}).catch(logger.error);
},
},

{ type: 'separator' },

tabMeta.views.length > 1
? {
label: 'Separate tabs',
click: () => {
WebContentViewsManager.instance.separateView(tabId, viewIndex);
},
}
: {
label: 'Open in split view',
click: () => {
WebContentViewsManager.instance.openInSplitView({ tabId });
},
},

...(unpinned.length > 0
? ([
{ type: 'separator' },
{
label: 'Close tab',
click: () => {
closeTab(tabId).catch(logger.error);
},
},
{
label: 'Close other tabs',
click: () => {
const tabsToRetain =
WebContentViewsManager.instance.tabViewsMeta.workbenches.filter(
w => w.id === tabId || w.pinned
);

WebContentViewsManager.instance.patchTabViewsMeta({
workbenches: tabsToRetain,
activeWorkbenchId: tabId,
});
},
},
] as const)
: []),
];
const menu = Menu.buildFromTemplate(template);
menu.popup();
};
134 changes: 25 additions & 109 deletions packages/frontend/electron/src/main/windows-manager/tab-views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
app,
type CookiesSetDetails,
globalShortcut,
Menu,
type View,
type WebContents,
WebContentsView,
Expand Down Expand Up @@ -103,7 +102,10 @@ type SeparateViewAction = {

type OpenInSplitViewAction = {
type: 'open-in-split-view';
payload: { tabId: string };
payload: {
tabId: string;
view?: Omit<WorkbenchViewMeta, 'id'>;
};
};

type TabAction =
Expand All @@ -114,7 +116,7 @@ type TabAction =
| SeparateViewAction
| OpenInSplitViewAction;

type AddTabOption = {
export type AddTabOption = {
basename?: string;
view?: Omit<WorkbenchViewMeta, 'id'> | Array<Omit<WorkbenchViewMeta, 'id'>>;
target?: string;
Expand Down Expand Up @@ -384,23 +386,19 @@ export class WebContentViewsManager {
}
};

addTab = async (option?: AddTabOption) => {
if (!option) {
const activeWorkbench = this.activeWorkbenchMeta;
const basename = activeWorkbench?.basename ?? '/';

option = {
basename,
view: {
title: 'New Tab',
path: basename.startsWith('/workspace')
? {
pathname: '/all',
}
: undefined,
},
};
}
addTab = async (option: AddTabOption = {}) => {
const activeWorkbench = this.activeWorkbenchMeta;

option.basename ??= activeWorkbench?.basename ?? '/';
option.view ??= {
title: 'New Tab',
path: option.basename?.startsWith('/workspace')
? {
pathname: '/all',
}
: undefined,
};

const workbenches = this.tabViewsMeta.workbenches;
const newKey = this.generateViewId('app');
const views = (
Expand All @@ -420,7 +418,7 @@ export class WebContentViewsManager {
(option.edge === 'left' ? 0 : 1);

const workbench: WorkbenchMeta = {
basename: option.basename ?? this.activeWorkbenchMeta?.basename ?? '/',
basename: option.basename,
activeViewIndex: 0,
views: views,
id: newKey,
Expand Down Expand Up @@ -588,14 +586,16 @@ export class WebContentViewsManager {
addTab(newTabMeta).catch(logger.error);
};

openInSplitView = (tabId: string) => {
const tabMeta = this.tabViewsMeta.workbenches.find(w => w.id === tabId);
openInSplitView = (payload: OpenInSplitViewAction['payload']) => {
const tabMeta = this.tabViewsMeta.workbenches.find(
w => w.id === payload.tabId
);
if (!tabMeta) {
return;
}
this.tabAction$.next({
type: 'open-in-split-view',
payload: { tabId },
payload: payload,
});
};

Expand Down Expand Up @@ -954,6 +954,7 @@ export const closeTab = WebContentViewsManager.instance.closeTab;
export const undoCloseTab = WebContentViewsManager.instance.undoCloseTab;
export const activateView = WebContentViewsManager.instance.activateView;
export const moveTab = WebContentViewsManager.instance.moveTab;
export const openInSplitView = WebContentViewsManager.instance.openInSplitView;

export const reloadView = async () => {
const id = WebContentViewsManager.instance.activeWorkbenchId;
Expand Down Expand Up @@ -993,88 +994,3 @@ export const pingAppLayoutReady = (wc: WebContents) => {
WebContentViewsManager.instance.setTabUIReady(viewId);
}
};

export const showTabContextMenu = async (tabId: string, viewIndex: number) => {
const workbenches = WebContentViewsManager.instance.tabViewsMeta.workbenches;
const unpinned = workbenches.filter(w => !w.pinned);
const tabMeta = workbenches.find(w => w.id === tabId);
if (!tabMeta) {
return;
}

const template: Parameters<typeof Menu.buildFromTemplate>[0] = [
tabMeta.pinned
? {
label: 'Unpin tab',
click: () => {
WebContentViewsManager.instance.pinTab(tabId, false);
},
}
: {
label: 'Pin tab',
click: () => {
WebContentViewsManager.instance.pinTab(tabId, true);
},
},
{
label: 'Refresh tab',
click: () => {
reloadView().catch(logger.error);
},
},
{
label: 'Duplicate tab',
click: () => {
addTab({
basename: tabMeta.basename,
view: tabMeta.views,
show: false,
}).catch(logger.error);
},
},

{ type: 'separator' },

tabMeta.views.length > 1
? {
label: 'Separate tabs',
click: () => {
WebContentViewsManager.instance.separateView(tabId, viewIndex);
},
}
: {
label: 'Open in split view',
click: () => {
WebContentViewsManager.instance.openInSplitView(tabId);
},
},

...(unpinned.length > 0
? ([
{ type: 'separator' },
{
label: 'Close tab',
click: () => {
closeTab(tabId).catch(logger.error);
},
},
{
label: 'Close other tabs',
click: () => {
const tabsToRetain =
WebContentViewsManager.instance.tabViewsMeta.workbenches.filter(
w => w.id === tabId || w.pinned
);

WebContentViewsManager.instance.patchTabViewsMeta({
workbenches: tabsToRetain,
activeWorkbenchId: tabId,
});
},
},
] as const)
: []),
];
const menu = Menu.buildFromTemplate(template);
menu.popup();
};

0 comments on commit c045c4a

Please sign in to comment.