mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-02 18:39:05 +01:00
aa77b2c259
![image](https://github.com/user-attachments/assets/a4072368-b204-4eed-bb65-8e3884687f9a) This functions very similarly to VSCode's pinned tab feature. To pin a tab, you can right-click on it and select "Pin tab" from the context menu. Once pinned, a tab will be fixed to the left-most edge of the tab bar, in order of pinning. Pinned tabs can be dragged around like any others. If you drag an unpinned tab into the pinned tabs section (any index less than the highest-index pinned tab), it will be pinned. If you drag a pinned tab out of the pinned tab section, it will be unpinned. Pinned tabs' close button is replaced with a persistent pin button, which can be clicked to unpin them. This adds an extra barrier to accidentally closing a pinned tab. They can still be closed from the context menu.
193 lines
6.8 KiB
TypeScript
193 lines
6.8 KiB
TypeScript
// Copyright 2024, Command Line Inc.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
import { App } from "@/app/app";
|
|
import {
|
|
registerControlShiftStateUpdateHandler,
|
|
registerElectronReinjectKeyHandler,
|
|
registerGlobalKeys,
|
|
} from "@/app/store/keymodel";
|
|
import { modalsModel } from "@/app/store/modalmodel";
|
|
import { FileService } from "@/app/store/services";
|
|
import { RpcApi } from "@/app/store/wshclientapi";
|
|
import { initWshrpc, TabRpcClient } from "@/app/store/wshrpcutil";
|
|
import { loadMonaco } from "@/app/view/codeeditor/codeeditor";
|
|
import { getLayoutModelForStaticTab } from "@/layout/index";
|
|
import {
|
|
atoms,
|
|
countersClear,
|
|
countersPrint,
|
|
getApi,
|
|
globalStore,
|
|
initGlobal,
|
|
initGlobalWaveEventSubs,
|
|
loadConnStatus,
|
|
pushFlashError,
|
|
pushNotification,
|
|
removeNotificationById,
|
|
subscribeToConnEvents,
|
|
} from "@/store/global";
|
|
import * as WOS from "@/store/wos";
|
|
import { loadFonts } from "@/util/fontutil";
|
|
import { setKeyUtilPlatform } from "@/util/keyutil";
|
|
import { createElement } from "react";
|
|
import { createRoot } from "react-dom/client";
|
|
|
|
const platform = getApi().getPlatform();
|
|
document.title = `Wave Terminal`;
|
|
let savedInitOpts: WaveInitOpts = null;
|
|
|
|
(window as any).WOS = WOS;
|
|
(window as any).globalStore = globalStore;
|
|
(window as any).globalAtoms = atoms;
|
|
(window as any).RpcApi = RpcApi;
|
|
(window as any).isFullScreen = false;
|
|
(window as any).countersPrint = countersPrint;
|
|
(window as any).countersClear = countersClear;
|
|
(window as any).getLayoutModelForStaticTab = getLayoutModelForStaticTab;
|
|
(window as any).pushFlashError = pushFlashError;
|
|
(window as any).pushNotification = pushNotification;
|
|
(window as any).removeNotificationById = removeNotificationById;
|
|
(window as any).modalsModel = modalsModel;
|
|
|
|
async function initBare() {
|
|
getApi().sendLog("Init Bare");
|
|
document.body.style.visibility = "hidden";
|
|
document.body.style.opacity = "0";
|
|
document.body.classList.add("is-transparent");
|
|
getApi().onWaveInit(initWaveWrap);
|
|
setKeyUtilPlatform(platform);
|
|
loadFonts();
|
|
document.fonts.ready.then(() => {
|
|
console.log("Init Bare Done");
|
|
getApi().setWindowInitStatus("ready");
|
|
});
|
|
}
|
|
|
|
document.addEventListener("DOMContentLoaded", initBare);
|
|
|
|
async function initWaveWrap(initOpts: WaveInitOpts) {
|
|
try {
|
|
if (savedInitOpts) {
|
|
await reinitWave();
|
|
return;
|
|
}
|
|
savedInitOpts = initOpts;
|
|
await initWave(initOpts);
|
|
} catch (e) {
|
|
getApi().sendLog("Error in initWave " + e.message);
|
|
console.error("Error in initWave", e);
|
|
} finally {
|
|
document.body.style.visibility = null;
|
|
document.body.style.opacity = null;
|
|
document.body.classList.remove("is-transparent");
|
|
}
|
|
}
|
|
|
|
async function reinitWave() {
|
|
console.log("Reinit Wave");
|
|
getApi().sendLog("Reinit Wave");
|
|
|
|
// We use this hack to prevent a flicker in the tab bar when switching to a new tab. This class is set in setActiveTab in global.ts. See tab.scss for where this class is used.
|
|
requestAnimationFrame(() => {
|
|
setTimeout(() => {
|
|
document.body.classList.remove("nohover");
|
|
}, 100);
|
|
});
|
|
|
|
const client = await WOS.reloadWaveObject<Client>(WOS.makeORef("client", savedInitOpts.clientId));
|
|
const waveWindow = await WOS.reloadWaveObject<WaveWindow>(WOS.makeORef("window", savedInitOpts.windowId));
|
|
const ws = await WOS.reloadWaveObject<Workspace>(WOS.makeORef("workspace", waveWindow.workspaceid));
|
|
const initialTab = await WOS.reloadWaveObject<Tab>(WOS.makeORef("tab", savedInitOpts.tabId));
|
|
await WOS.reloadWaveObject<LayoutState>(WOS.makeORef("layout", initialTab.layoutstate));
|
|
reloadAllWorkspaceTabs(ws);
|
|
document.title = `Wave Terminal - ${initialTab.name}`; // TODO update with tab name change
|
|
getApi().setWindowInitStatus("wave-ready");
|
|
globalStore.set(atoms.reinitVersion, globalStore.get(atoms.reinitVersion) + 1);
|
|
globalStore.set(atoms.updaterStatusAtom, getApi().getUpdaterStatus());
|
|
}
|
|
|
|
function reloadAllWorkspaceTabs(ws: Workspace) {
|
|
if (ws == null || ws.tabids == null) {
|
|
return;
|
|
}
|
|
ws.tabids.forEach((tabid) => {
|
|
WOS.reloadWaveObject<Tab>(WOS.makeORef("tab", tabid));
|
|
});
|
|
}
|
|
|
|
function loadAllWorkspaceTabs(ws: Workspace) {
|
|
if (ws == null || ws.tabids == null) {
|
|
return;
|
|
}
|
|
ws.tabids.forEach((tabid) => {
|
|
WOS.getObjectValue<Tab>(WOS.makeORef("tab", tabid));
|
|
});
|
|
}
|
|
|
|
async function initWave(initOpts: WaveInitOpts) {
|
|
getApi().sendLog("Init Wave " + JSON.stringify(initOpts));
|
|
console.log(
|
|
"Wave Init",
|
|
"tabid",
|
|
initOpts.tabId,
|
|
"clientid",
|
|
initOpts.clientId,
|
|
"windowid",
|
|
initOpts.windowId,
|
|
"platform",
|
|
platform
|
|
);
|
|
initGlobal({
|
|
tabId: initOpts.tabId,
|
|
clientId: initOpts.clientId,
|
|
windowId: initOpts.windowId,
|
|
platform,
|
|
environment: "renderer",
|
|
});
|
|
(window as any).globalAtoms = atoms;
|
|
|
|
// Init WPS event handlers
|
|
const globalWS = initWshrpc(initOpts.tabId);
|
|
(window as any).globalWS = globalWS;
|
|
(window as any).TabRpcClient = TabRpcClient;
|
|
await loadConnStatus();
|
|
initGlobalWaveEventSubs();
|
|
subscribeToConnEvents();
|
|
|
|
// ensures client/window/workspace are loaded into the cache before rendering
|
|
const [client, waveWindow, initialTab] = await Promise.all([
|
|
WOS.loadAndPinWaveObject<Client>(WOS.makeORef("client", initOpts.clientId)),
|
|
WOS.loadAndPinWaveObject<WaveWindow>(WOS.makeORef("window", initOpts.windowId)),
|
|
WOS.loadAndPinWaveObject<Tab>(WOS.makeORef("tab", initOpts.tabId)),
|
|
]);
|
|
const [ws, layoutState] = await Promise.all([
|
|
WOS.loadAndPinWaveObject<Workspace>(WOS.makeORef("workspace", waveWindow.workspaceid)),
|
|
WOS.reloadWaveObject<LayoutState>(WOS.makeORef("layout", initialTab.layoutstate)),
|
|
]);
|
|
loadAllWorkspaceTabs(ws);
|
|
WOS.wpsSubscribeToObject(WOS.makeORef("workspace", waveWindow.workspaceid));
|
|
|
|
document.title = `Wave Terminal - ${initialTab.name}`; // TODO update with tab name change
|
|
|
|
registerGlobalKeys();
|
|
registerElectronReinjectKeyHandler();
|
|
registerControlShiftStateUpdateHandler();
|
|
setTimeout(loadMonaco, 30);
|
|
const fullConfig = await FileService.GetFullConfig();
|
|
console.log("fullconfig", fullConfig);
|
|
globalStore.set(atoms.fullConfigAtom, fullConfig);
|
|
console.log("Wave First Render");
|
|
let firstRenderResolveFn: () => void = null;
|
|
let firstRenderPromise = new Promise<void>((resolve) => {
|
|
firstRenderResolveFn = resolve;
|
|
});
|
|
const reactElem = createElement(App, { onFirstRender: firstRenderResolveFn }, null);
|
|
const elem = document.getElementById("main");
|
|
const root = createRoot(elem);
|
|
root.render(reactElem);
|
|
await firstRenderPromise;
|
|
console.log("Wave First Render Done");
|
|
getApi().setWindowInitStatus("wave-ready");
|
|
}
|