mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-21 16:38:23 +01:00
closeTab fix (#1403)
fixes bug with closeTab when the tab didn't exist in the waveWindow cache. also adds Cmd-Shift-W to close a tab (doesn't work for pinned tabs). and restores Cmd-W for killing blocks on pinned tabs
This commit is contained in:
parent
7a61f25331
commit
5744f4b06f
@ -108,7 +108,7 @@ export class WaveTabView extends WebContentsView {
|
|||||||
// TODO: circuitous
|
// TODO: circuitous
|
||||||
const waveWindow = waveWindowMap.get(this.waveWindowId);
|
const waveWindow = waveWindowMap.get(this.waveWindowId);
|
||||||
if (waveWindow) {
|
if (waveWindow) {
|
||||||
waveWindow.allTabViews.delete(this.waveTabId);
|
waveWindow.allLoadedTabViews.delete(this.waveTabId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ export class WaveBrowserWindow extends BaseWindow {
|
|||||||
waveWindowId: string;
|
waveWindowId: string;
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
waveReadyPromise: Promise<void>;
|
waveReadyPromise: Promise<void>;
|
||||||
allTabViews: Map<string, WaveTabView>;
|
allLoadedTabViews: Map<string, WaveTabView>;
|
||||||
activeTabView: WaveTabView;
|
activeTabView: WaveTabView;
|
||||||
private canClose: boolean;
|
private canClose: boolean;
|
||||||
private deleteAllowed: boolean;
|
private deleteAllowed: boolean;
|
||||||
@ -108,7 +108,7 @@ export class WaveBrowserWindow extends BaseWindow {
|
|||||||
this.tabSwitchQueue = [];
|
this.tabSwitchQueue = [];
|
||||||
this.waveWindowId = waveWindow.oid;
|
this.waveWindowId = waveWindow.oid;
|
||||||
this.workspaceId = waveWindow.workspaceid;
|
this.workspaceId = waveWindow.workspaceid;
|
||||||
this.allTabViews = new Map<string, WaveTabView>();
|
this.allLoadedTabViews = new Map<string, WaveTabView>();
|
||||||
const winBoundsPoller = setInterval(() => {
|
const winBoundsPoller = setInterval(() => {
|
||||||
if (this.isDestroyed()) {
|
if (this.isDestroyed()) {
|
||||||
clearInterval(winBoundsPoller);
|
clearInterval(winBoundsPoller);
|
||||||
@ -237,7 +237,7 @@ export class WaveBrowserWindow extends BaseWindow {
|
|||||||
console.log("win removing window from backend DB", this.waveWindowId);
|
console.log("win removing window from backend DB", this.waveWindowId);
|
||||||
fireAndForget(() => WindowService.CloseWindow(this.waveWindowId, true));
|
fireAndForget(() => WindowService.CloseWindow(this.waveWindowId, true));
|
||||||
}
|
}
|
||||||
for (const tabView of this.allTabViews.values()) {
|
for (const tabView of this.allLoadedTabViews.values()) {
|
||||||
tabView?.destroy();
|
tabView?.destroy();
|
||||||
}
|
}
|
||||||
waveWindowMap.delete(this.waveWindowId);
|
waveWindowMap.delete(this.waveWindowId);
|
||||||
@ -278,15 +278,15 @@ export class WaveBrowserWindow extends BaseWindow {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("switchWorkspace newWs", newWs);
|
console.log("switchWorkspace newWs", newWs);
|
||||||
if (this.allTabViews.size) {
|
if (this.allLoadedTabViews.size) {
|
||||||
for (const tab of this.allTabViews.values()) {
|
for (const tab of this.allLoadedTabViews.values()) {
|
||||||
this.contentView.removeChildView(tab);
|
this.contentView.removeChildView(tab);
|
||||||
tab?.destroy();
|
tab?.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log("destroyed all tabs", this.waveWindowId);
|
console.log("destroyed all tabs", this.waveWindowId);
|
||||||
this.workspaceId = workspaceId;
|
this.workspaceId = workspaceId;
|
||||||
this.allTabViews = new Map();
|
this.allLoadedTabViews = new Map();
|
||||||
await this.setActiveTab(newWs.activetabid, false);
|
await this.setActiveTab(newWs.activetabid, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,17 +306,22 @@ export class WaveBrowserWindow extends BaseWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async closeTab(tabId: string) {
|
async closeTab(tabId: string) {
|
||||||
console.log("closeTab", tabId, this.waveWindowId, this.workspaceId);
|
console.log(`closeTab tabid=${tabId} ws=${this.workspaceId} window=${this.waveWindowId}`);
|
||||||
const tabView = this.allTabViews.get(tabId);
|
const rtn = await WorkspaceService.CloseTab(this.workspaceId, tabId, true);
|
||||||
if (tabView) {
|
if (rtn == null) {
|
||||||
const rtn = await WorkspaceService.CloseTab(this.workspaceId, tabId, true);
|
console.log("[error] closeTab: no return value", tabId, this.workspaceId, this.waveWindowId);
|
||||||
if (rtn?.closewindow) {
|
return;
|
||||||
this.close();
|
|
||||||
} else if (rtn?.newactivetabid) {
|
|
||||||
await this.setActiveTab(rtn.newactivetabid, false);
|
|
||||||
}
|
|
||||||
this.allTabViews.delete(tabId);
|
|
||||||
}
|
}
|
||||||
|
if (rtn.closewindow) {
|
||||||
|
this.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!rtn.newactivetabid) {
|
||||||
|
console.log("[error] closeTab, no new active tab", tabId, this.workspaceId, this.waveWindowId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.setActiveTab(rtn.newactivetabid, false);
|
||||||
|
this.allLoadedTabViews.delete(tabId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setTabViewIntoWindow(tabView: WaveTabView, tabInitialized: boolean) {
|
async setTabViewIntoWindow(tabView: WaveTabView, tabInitialized: boolean) {
|
||||||
@ -330,7 +335,7 @@ export class WaveBrowserWindow extends BaseWindow {
|
|||||||
oldActiveView.isActiveTab = false;
|
oldActiveView.isActiveTab = false;
|
||||||
}
|
}
|
||||||
this.activeTabView = tabView;
|
this.activeTabView = tabView;
|
||||||
this.allTabViews.set(tabView.waveTabId, tabView);
|
this.allLoadedTabViews.set(tabView.waveTabId, tabView);
|
||||||
if (!tabInitialized) {
|
if (!tabInitialized) {
|
||||||
console.log("initializing a new tab");
|
console.log("initializing a new tab");
|
||||||
await tabView.initPromise;
|
await tabView.initPromise;
|
||||||
@ -407,7 +412,7 @@ export class WaveBrowserWindow extends BaseWindow {
|
|||||||
}
|
}
|
||||||
const curBounds = this.getContentBounds();
|
const curBounds = this.getContentBounds();
|
||||||
this.activeTabView?.positionTabOnScreen(curBounds);
|
this.activeTabView?.positionTabOnScreen(curBounds);
|
||||||
for (const tabView of this.allTabViews.values()) {
|
for (const tabView of this.allLoadedTabViews.values()) {
|
||||||
if (tabView == this.activeTabView) {
|
if (tabView == this.activeTabView) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -465,7 +470,7 @@ export class WaveBrowserWindow extends BaseWindow {
|
|||||||
|
|
||||||
export function getWaveWindowByTabId(tabId: string): WaveBrowserWindow {
|
export function getWaveWindowByTabId(tabId: string): WaveBrowserWindow {
|
||||||
for (const ww of waveWindowMap.values()) {
|
for (const ww of waveWindowMap.values()) {
|
||||||
if (ww.allTabViews.has(tabId)) {
|
if (ww.allLoadedTabViews.has(tabId)) {
|
||||||
return ww;
|
return ww;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -530,17 +535,22 @@ ipcMain.on("set-active-tab", async (event, tabId) => {
|
|||||||
ipcMain.on("create-tab", async (event, opts) => {
|
ipcMain.on("create-tab", async (event, opts) => {
|
||||||
const senderWc = event.sender;
|
const senderWc = event.sender;
|
||||||
const ww = getWaveWindowByWebContentsId(senderWc.id);
|
const ww = getWaveWindowByWebContentsId(senderWc.id);
|
||||||
if (!ww) {
|
if (ww != null) {
|
||||||
return;
|
await ww.createTab();
|
||||||
}
|
}
|
||||||
await ww.createTab();
|
|
||||||
event.returnValue = true;
|
event.returnValue = true;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on("close-tab", async (event, tabId) => {
|
ipcMain.on("close-tab", async (event, workspaceId, tabId) => {
|
||||||
const ww = getWaveWindowByTabId(tabId);
|
const ww = getWaveWindowByWorkspaceId(workspaceId);
|
||||||
await ww.closeTab(tabId);
|
if (ww == null) {
|
||||||
|
console.log(`close-tab: no window found for workspace ws=${workspaceId} tab=${tabId}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ww != null) {
|
||||||
|
await ww.closeTab(tabId);
|
||||||
|
}
|
||||||
event.returnValue = true;
|
event.returnValue = true;
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
@ -44,7 +44,7 @@ contextBridge.exposeInMainWorld("api", {
|
|||||||
deleteWorkspace: (workspaceId) => ipcRenderer.send("delete-workspace", workspaceId),
|
deleteWorkspace: (workspaceId) => ipcRenderer.send("delete-workspace", workspaceId),
|
||||||
setActiveTab: (tabId) => ipcRenderer.send("set-active-tab", tabId),
|
setActiveTab: (tabId) => ipcRenderer.send("set-active-tab", tabId),
|
||||||
createTab: () => ipcRenderer.send("create-tab"),
|
createTab: () => ipcRenderer.send("create-tab"),
|
||||||
closeTab: (tabId) => ipcRenderer.send("close-tab", tabId),
|
closeTab: (workspaceId, tabId) => ipcRenderer.send("close-tab", workspaceId, tabId),
|
||||||
setWindowInitStatus: (status) => ipcRenderer.send("set-window-init-status", status),
|
setWindowInitStatus: (status) => ipcRenderer.send("set-window-init-status", status),
|
||||||
onWaveInit: (callback) => ipcRenderer.on("wave-init", (_event, initOpts) => callback(initOpts)),
|
onWaveInit: (callback) => ipcRenderer.on("wave-init", (_event, initOpts) => callback(initOpts)),
|
||||||
sendLog: (log) => ipcRenderer.send("fe-log", log),
|
sendLog: (log) => ipcRenderer.send("fe-log", log),
|
||||||
|
@ -112,7 +112,7 @@ export class Updater {
|
|||||||
private set status(value: UpdaterStatus) {
|
private set status(value: UpdaterStatus) {
|
||||||
this._status = value;
|
this._status = value;
|
||||||
getAllWaveWindows().forEach((window) => {
|
getAllWaveWindows().forEach((window) => {
|
||||||
const allTabs = Array.from(window.allTabViews.values());
|
const allTabs = Array.from(window.allLoadedTabViews.values());
|
||||||
allTabs.forEach((tab) => {
|
allTabs.forEach((tab) => {
|
||||||
tab.webContents.send("app-update-status", value);
|
tab.webContents.send("app-update-status", value);
|
||||||
});
|
});
|
||||||
|
@ -71,15 +71,20 @@ function shouldDispatchToBlock(e: WaveKeyboardEvent): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function genericClose(tabId: string) {
|
function genericClose(tabId: string) {
|
||||||
|
const ws = globalStore.get(atoms.workspace);
|
||||||
const tabORef = WOS.makeORef("tab", tabId);
|
const tabORef = WOS.makeORef("tab", tabId);
|
||||||
const tabAtom = WOS.getWaveObjectAtom<Tab>(tabORef);
|
const tabAtom = WOS.getWaveObjectAtom<Tab>(tabORef);
|
||||||
const tabData = globalStore.get(tabAtom);
|
const tabData = globalStore.get(tabAtom);
|
||||||
if (tabData == null) {
|
if (tabData == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (ws.pinnedtabids?.includes(tabId) && tabData.blockids?.length == 1) {
|
||||||
|
// don't allow closing the last block in a pinned tab
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (tabData.blockids == null || tabData.blockids.length == 0) {
|
if (tabData.blockids == null || tabData.blockids.length == 0) {
|
||||||
// close tab
|
// close tab
|
||||||
getApi().closeTab(tabId);
|
getApi().closeTab(ws.oid, tabId);
|
||||||
deleteLayoutModelForTab(tabId);
|
deleteLayoutModelForTab(tabId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -246,11 +251,21 @@ function registerGlobalKeys() {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
globalKeyMap.set("Cmd:w", () => {
|
globalKeyMap.set("Cmd:w", () => {
|
||||||
|
const tabId = globalStore.get(atoms.staticTabId);
|
||||||
|
genericClose(tabId);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
globalKeyMap.set("Cmd:Shift:w", () => {
|
||||||
const tabId = globalStore.get(atoms.staticTabId);
|
const tabId = globalStore.get(atoms.staticTabId);
|
||||||
const ws = globalStore.get(atoms.workspace);
|
const ws = globalStore.get(atoms.workspace);
|
||||||
if (!ws.pinnedtabids?.includes(tabId)) {
|
if (ws.pinnedtabids?.includes(tabId)) {
|
||||||
genericClose(tabId);
|
// switch to first unpinned tab if it exists (for close spamming)
|
||||||
|
if (ws.tabids != null && ws.tabids.length > 0) {
|
||||||
|
getApi().setActiveTab(ws.tabids[0]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
getApi().closeTab(ws.oid, tabId);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
globalKeyMap.set("Cmd:m", () => {
|
globalKeyMap.set("Cmd:m", () => {
|
||||||
|
@ -5,7 +5,7 @@ import { Button } from "@/app/element/button";
|
|||||||
import { modalsModel } from "@/app/store/modalmodel";
|
import { modalsModel } from "@/app/store/modalmodel";
|
||||||
import { WindowDrag } from "@/element/windowdrag";
|
import { WindowDrag } from "@/element/windowdrag";
|
||||||
import { deleteLayoutModelForTab } from "@/layout/index";
|
import { deleteLayoutModelForTab } from "@/layout/index";
|
||||||
import { atoms, createTab, getApi, isDev, PLATFORM, setActiveTab } from "@/store/global";
|
import { atoms, createTab, getApi, globalStore, isDev, PLATFORM, setActiveTab } from "@/store/global";
|
||||||
import { fireAndForget } from "@/util/util";
|
import { fireAndForget } from "@/util/util";
|
||||||
import { useAtomValue } from "jotai";
|
import { useAtomValue } from "jotai";
|
||||||
import { OverlayScrollbars } from "overlayscrollbars";
|
import { OverlayScrollbars } from "overlayscrollbars";
|
||||||
@ -570,7 +570,8 @@ const TabBar = memo(({ workspace }: TabBarProps) => {
|
|||||||
|
|
||||||
const handleCloseTab = (event: React.MouseEvent<HTMLButtonElement, MouseEvent> | null, tabId: string) => {
|
const handleCloseTab = (event: React.MouseEvent<HTMLButtonElement, MouseEvent> | null, tabId: string) => {
|
||||||
event?.stopPropagation();
|
event?.stopPropagation();
|
||||||
getApi().closeTab(tabId);
|
const ws = globalStore.get(atoms.workspace);
|
||||||
|
getApi().closeTab(ws.oid, tabId);
|
||||||
tabsWrapperRef.current.style.setProperty("--tabs-wrapper-transition", "width 0.3s ease");
|
tabsWrapperRef.current.style.setProperty("--tabs-wrapper-transition", "width 0.3s ease");
|
||||||
deleteLayoutModelForTab(tabId);
|
deleteLayoutModelForTab(tabId);
|
||||||
};
|
};
|
||||||
|
2
frontend/types/custom.d.ts
vendored
2
frontend/types/custom.d.ts
vendored
@ -93,7 +93,7 @@ declare global {
|
|||||||
deleteWorkspace: (workspaceId: string) => void;
|
deleteWorkspace: (workspaceId: string) => void;
|
||||||
setActiveTab: (tabId: string) => void;
|
setActiveTab: (tabId: string) => void;
|
||||||
createTab: () => void;
|
createTab: () => void;
|
||||||
closeTab: (tabId: string) => void;
|
closeTab: (workspaceId: string, tabId: string) => void;
|
||||||
setWindowInitStatus: (status: "ready" | "wave-ready") => void;
|
setWindowInitStatus: (status: "ready" | "wave-ready") => void;
|
||||||
onWaveInit: (callback: (initOpts: WaveInitOpts) => void) => void;
|
onWaveInit: (callback: (initOpts: WaveInitOpts) => void) => void;
|
||||||
sendLog: (log: string) => void;
|
sendLog: (log: string) => void;
|
||||||
|
Loading…
Reference in New Issue
Block a user