mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-16 09:36:17 +08:00
@@ -18,7 +18,6 @@ import { useI18n } from '@affine/i18n';
|
||||
import {
|
||||
DeleteIcon,
|
||||
DeletePermanentlyIcon,
|
||||
DualLinkIcon,
|
||||
DuplicateIcon,
|
||||
EditIcon,
|
||||
FavoritedIcon,
|
||||
@@ -27,6 +26,7 @@ import {
|
||||
FilterMinusIcon,
|
||||
InformationIcon,
|
||||
MoreVerticalIcon,
|
||||
OpenInNewIcon,
|
||||
PlusIcon,
|
||||
ResetIcon,
|
||||
SplitViewIcon,
|
||||
@@ -39,7 +39,6 @@ import {
|
||||
WorkspaceService,
|
||||
} from '@toeverything/infra';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import type { CollectionService } from '../../modules/collection';
|
||||
import { InfoModal } from '../affine/page-properties';
|
||||
@@ -49,7 +48,7 @@ import * as styles from './list.css';
|
||||
import { DisablePublicSharing, MoveToTrash } from './operation-menu-items';
|
||||
import { CreateOrEditTag } from './tags/create-tag';
|
||||
import type { TagMeta } from './types';
|
||||
import { ColWrapper, stopPropagationWithoutPrevent } from './utils';
|
||||
import { ColWrapper } from './utils';
|
||||
import { useEditCollection, useEditCollectionName } from './view';
|
||||
|
||||
const tooltipSideTop = { side: 'top' as const };
|
||||
@@ -100,6 +99,10 @@ export const PageOperationCell = ({
|
||||
workbench.openDoc(page.id, { at: 'tail' });
|
||||
}, [page.id, workbench]);
|
||||
|
||||
const onOpenInNewTab = useCallback(() => {
|
||||
workbench.openDoc(page.id, { at: 'new-tab' });
|
||||
}, [page.id, workbench]);
|
||||
|
||||
const onToggleFavoritePage = useCallback(() => {
|
||||
const status = favAdapter.isFavorite(page.id, 'doc');
|
||||
favAdapter.toggle(page.id, 'doc');
|
||||
@@ -173,6 +176,17 @@ export const PageOperationCell = ({
|
||||
</MenuItem>
|
||||
) : null}
|
||||
|
||||
<MenuItem
|
||||
onClick={onOpenInNewTab}
|
||||
preFix={
|
||||
<MenuIcon>
|
||||
<OpenInNewIcon />
|
||||
</MenuIcon>
|
||||
}
|
||||
>
|
||||
{t['com.affine.workbench.tab.page-menu-open']()}
|
||||
</MenuItem>
|
||||
|
||||
{environment.isDesktop && appSettings.enableMultiView ? (
|
||||
<MenuItem
|
||||
onClick={onOpenInSplitView}
|
||||
@@ -186,27 +200,6 @@ export const PageOperationCell = ({
|
||||
</MenuItem>
|
||||
) : null}
|
||||
|
||||
{!environment.isDesktop && (
|
||||
<Link
|
||||
className={styles.clearLinkStyle}
|
||||
onClick={stopPropagationWithoutPrevent}
|
||||
to={`/workspace/${currentWorkspace.id}/${page.id}`}
|
||||
target={'_blank'}
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<MenuItem
|
||||
style={{ marginBottom: 4 }}
|
||||
preFix={
|
||||
<MenuIcon>
|
||||
<DualLinkIcon />
|
||||
</MenuIcon>
|
||||
}
|
||||
>
|
||||
{t['com.affine.openPageOperation.newTab']()}
|
||||
</MenuItem>
|
||||
</Link>
|
||||
)}
|
||||
|
||||
<MenuItem
|
||||
preFix={
|
||||
<MenuIcon>
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
FavoritedIcon,
|
||||
FavoriteIcon,
|
||||
FilterIcon,
|
||||
OpenInNewIcon,
|
||||
PlusIcon,
|
||||
SplitViewIcon,
|
||||
} from '@blocksuite/icons/rc';
|
||||
@@ -79,6 +80,10 @@ export const CollectionOperations = ({
|
||||
workbench.openCollection(collection.id, { at: 'tail' });
|
||||
}, [collection.id, workbench]);
|
||||
|
||||
const openCollectionNewTab = useCallback(() => {
|
||||
workbench.openCollection(collection.id, { at: 'new-tab' });
|
||||
}, [collection.id, workbench]);
|
||||
|
||||
const favAdapter = useService(CompatibleFavoriteItemsAdapter);
|
||||
|
||||
const onToggleFavoritePage = useCallback(() => {
|
||||
@@ -153,6 +158,15 @@ export const CollectionOperations = ({
|
||||
: t['com.affine.favoritePageOperation.add'](),
|
||||
click: onToggleFavoritePage,
|
||||
},
|
||||
{
|
||||
icon: (
|
||||
<MenuIcon>
|
||||
<OpenInNewIcon />
|
||||
</MenuIcon>
|
||||
),
|
||||
name: t['com.affine.workbench.tab.page-menu-open'](),
|
||||
click: openCollectionNewTab,
|
||||
},
|
||||
...(appSettings.enableMultiView
|
||||
? [
|
||||
{
|
||||
@@ -189,6 +203,7 @@ export const CollectionOperations = ({
|
||||
onAddDocToCollection,
|
||||
favorite,
|
||||
onToggleFavoritePage,
|
||||
openCollectionNewTab,
|
||||
appSettings.enableMultiView,
|
||||
openCollectionSplitView,
|
||||
service,
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
FavoritedIcon,
|
||||
FavoriteIcon,
|
||||
FilterIcon,
|
||||
OpenInNewIcon,
|
||||
PlusIcon,
|
||||
SplitViewIcon,
|
||||
} from '@blocksuite/icons/rc';
|
||||
@@ -110,6 +111,15 @@ export const useExplorerCollectionNodeOperations = (
|
||||
});
|
||||
}, [collectionId, workbenchService.workbench]);
|
||||
|
||||
const handleOpenInNewTab = useCallback(() => {
|
||||
workbenchService.workbench.openCollection(collectionId, { at: 'new-tab' });
|
||||
mixpanel.track('OpenInNewTab', {
|
||||
page: 'sidebar',
|
||||
module: 'collection',
|
||||
control: 'open in new tab button',
|
||||
});
|
||||
}, [collectionId, workbenchService.workbench]);
|
||||
|
||||
const handleDeleteCollection = useCallback(() => {
|
||||
collectionService.deleteCollection(deleteInfo, collectionId);
|
||||
mixpanel.track('CollectionDeleted', {
|
||||
@@ -187,6 +197,21 @@ export const useExplorerCollectionNodeOperations = (
|
||||
</MenuItem>
|
||||
),
|
||||
},
|
||||
{
|
||||
index: 99,
|
||||
view: (
|
||||
<MenuItem
|
||||
preFix={
|
||||
<MenuIcon>
|
||||
<OpenInNewIcon />
|
||||
</MenuIcon>
|
||||
}
|
||||
onClick={handleOpenInNewTab}
|
||||
>
|
||||
{t['com.affine.workbench.tab.page-menu-open']()}
|
||||
</MenuItem>
|
||||
),
|
||||
},
|
||||
...(appSettings.enableMultiView
|
||||
? [
|
||||
{
|
||||
@@ -232,6 +257,7 @@ export const useExplorerCollectionNodeOperations = (
|
||||
favorite,
|
||||
handleAddDocToCollection,
|
||||
handleDeleteCollection,
|
||||
handleOpenInNewTab,
|
||||
handleOpenInSplitView,
|
||||
handleShowEdit,
|
||||
handleToggleFavoriteCollection,
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
FavoriteIcon,
|
||||
InformationIcon,
|
||||
LinkedPageIcon,
|
||||
OpenInNewIcon,
|
||||
SplitViewIcon,
|
||||
} from '@blocksuite/icons/rc';
|
||||
import { DocsService, useLiveData, useServices } from '@toeverything/infra';
|
||||
@@ -75,6 +76,17 @@ export const useExplorerDocNodeOperations = (
|
||||
});
|
||||
}, [docRecord, openConfirmModal, t]);
|
||||
|
||||
const handleOpenInNewTab = useCallback(() => {
|
||||
workbenchService.workbench.openDoc(docId, {
|
||||
at: 'new-tab',
|
||||
});
|
||||
mixpanel.track('OpenInNewTab', {
|
||||
page: 'sidebar',
|
||||
module: 'doc',
|
||||
control: 'open in new tab button',
|
||||
});
|
||||
}, [docId, workbenchService]);
|
||||
|
||||
const handleOpenInSplitView = useCallback(() => {
|
||||
workbenchService.workbench.openDoc(docId, {
|
||||
at: 'beside',
|
||||
@@ -151,6 +163,21 @@ export const useExplorerDocNodeOperations = (
|
||||
</MenuItem>
|
||||
),
|
||||
},
|
||||
{
|
||||
index: 99,
|
||||
view: (
|
||||
<MenuItem
|
||||
preFix={
|
||||
<MenuIcon>
|
||||
<OpenInNewIcon />
|
||||
</MenuIcon>
|
||||
}
|
||||
onClick={handleOpenInNewTab}
|
||||
>
|
||||
{t['com.affine.workbench.tab.page-menu-open']()}
|
||||
</MenuItem>
|
||||
),
|
||||
},
|
||||
...(appSettings.enableMultiView
|
||||
? [
|
||||
{
|
||||
@@ -219,6 +246,7 @@ export const useExplorerDocNodeOperations = (
|
||||
favorite,
|
||||
handleAddLinkedPage,
|
||||
handleMoveToTrash,
|
||||
handleOpenInNewTab,
|
||||
handleOpenInSplitView,
|
||||
handleToggleFavoriteDoc,
|
||||
options.openInfoModal,
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
DeleteIcon,
|
||||
FavoritedIcon,
|
||||
FavoriteIcon,
|
||||
OpenInNewIcon,
|
||||
PlusIcon,
|
||||
SplitViewIcon,
|
||||
} from '@blocksuite/icons/rc';
|
||||
@@ -97,6 +98,17 @@ export const useExplorerTagNodeOperations = (
|
||||
});
|
||||
}, [favoriteService, tagId]);
|
||||
|
||||
const handleOpenInNewTab = useCallback(() => {
|
||||
workbenchService.workbench.openTag(tagId, {
|
||||
at: 'new-tab',
|
||||
});
|
||||
mixpanel.track('OpenInNewTab', {
|
||||
page: 'sidebar',
|
||||
module: 'tag',
|
||||
control: 'open in new tab button',
|
||||
});
|
||||
}, [tagId, workbenchService]);
|
||||
|
||||
return useMemo(
|
||||
() => [
|
||||
{
|
||||
@@ -108,6 +120,21 @@ export const useExplorerTagNodeOperations = (
|
||||
</IconButton>
|
||||
),
|
||||
},
|
||||
{
|
||||
index: 50,
|
||||
view: (
|
||||
<MenuItem
|
||||
preFix={
|
||||
<MenuIcon>
|
||||
<OpenInNewIcon />
|
||||
</MenuIcon>
|
||||
}
|
||||
onClick={handleOpenInNewTab}
|
||||
>
|
||||
{t['com.affine.workbench.tab.page-menu-open']()}
|
||||
</MenuItem>
|
||||
),
|
||||
},
|
||||
...(appSettings.enableMultiView
|
||||
? [
|
||||
{
|
||||
@@ -180,6 +207,7 @@ export const useExplorerTagNodeOperations = (
|
||||
favorite,
|
||||
handleMoveToTrash,
|
||||
handleNewDoc,
|
||||
handleOpenInNewTab,
|
||||
handleOpenInSplitView,
|
||||
handleToggleFavoriteTag,
|
||||
t,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
app,
|
||||
type CookiesSetDetails,
|
||||
globalShortcut,
|
||||
Menu,
|
||||
type View,
|
||||
type WebContents,
|
||||
WebContentsView,
|
||||
@@ -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 =
|
||||
@@ -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;
|
||||
@@ -384,23 +386,19 @@ export class WebContentViewsManager {
|
||||
}
|
||||
};
|
||||
|
||||
addTab = async (option?: AddTabOption) => {
|
||||
if (!option) {
|
||||
const activeWorkbench = this.activeWorkbenchMeta;
|
||||
const basename = activeWorkbench?.basename ?? '/';
|
||||
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,
|
||||
};
|
||||
|
||||
option = {
|
||||
basename,
|
||||
view: {
|
||||
title: 'New Tab',
|
||||
path: basename.startsWith('/workspace')
|
||||
? {
|
||||
pathname: '/all',
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
};
|
||||
}
|
||||
const workbenches = this.tabViewsMeta.workbenches;
|
||||
const newKey = this.generateViewId('app');
|
||||
const views = (
|
||||
@@ -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,
|
||||
@@ -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,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -25,7 +25,8 @@ test('click btn bew page and open in tab', async ({ page, workspace }) => {
|
||||
page.getByRole('menuitem', { name: 'Open in new tab' }).click(),
|
||||
]);
|
||||
|
||||
expect(newTabPage.url()).toBe(newPageUrl);
|
||||
await expect(newTabPage).toHaveURL(newPageUrl, { timeout: 15000 });
|
||||
|
||||
const currentWorkspace = await workspace.current();
|
||||
|
||||
expect(currentWorkspace.meta.flavour).toContain('local');
|
||||
|
||||
Reference in New Issue
Block a user