mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-02 18:39:05 +01:00
move connection switching to blockheader (#276)
This commit is contained in:
parent
f28bdccb5d
commit
c2fe3b18e1
@ -148,7 +148,7 @@
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: var(--main-text-color);
|
color: var(--main-text-color);
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
padding-right: 6px;
|
padding-right: 2px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--highlight-bg-color);
|
background-color: var(--highlight-bg-color);
|
||||||
@ -162,6 +162,7 @@
|
|||||||
.connection-name {
|
.connection-name {
|
||||||
flex: 1 100 auto;
|
flex: 1 100 auto;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
padding-right: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,6 +116,7 @@ const BlockFull = React.memo(({ nodeModel, viewModel }: FullBlockProps) => {
|
|||||||
counterInc("render-BlockFull");
|
counterInc("render-BlockFull");
|
||||||
const focusElemRef = React.useRef<HTMLInputElement>(null);
|
const focusElemRef = React.useRef<HTMLInputElement>(null);
|
||||||
const blockRef = React.useRef<HTMLDivElement>(null);
|
const blockRef = React.useRef<HTMLDivElement>(null);
|
||||||
|
const contentRef = React.useRef<HTMLDivElement>(null);
|
||||||
const [blockClicked, setBlockClicked] = React.useState(false);
|
const [blockClicked, setBlockClicked] = React.useState(false);
|
||||||
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", nodeModel.blockId));
|
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", nodeModel.blockId));
|
||||||
const [focusedChild, setFocusedChild] = React.useState(null);
|
const [focusedChild, setFocusedChild] = React.useState(null);
|
||||||
@ -202,6 +203,7 @@ const BlockFull = React.memo(({ nodeModel, viewModel }: FullBlockProps) => {
|
|||||||
width: addlProps?.transform?.width,
|
width: addlProps?.transform?.width,
|
||||||
height: addlProps?.transform?.height,
|
height: addlProps?.transform?.height,
|
||||||
}}
|
}}
|
||||||
|
ref={contentRef}
|
||||||
>
|
>
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<React.Suspense fallback={<CenteredDiv>Loading...</CenteredDiv>}>{viewElem}</React.Suspense>
|
<React.Suspense fallback={<CenteredDiv>Loading...</CenteredDiv>}>{viewElem}</React.Suspense>
|
||||||
|
@ -10,11 +10,14 @@ import {
|
|||||||
Input,
|
Input,
|
||||||
} from "@/app/block/blockutil";
|
} from "@/app/block/blockutil";
|
||||||
import { Button } from "@/app/element/button";
|
import { Button } from "@/app/element/button";
|
||||||
|
import { TypeAheadModal } from "@/app/modals/typeaheadmodal";
|
||||||
import { ContextMenuModel } from "@/app/store/contextmenu";
|
import { ContextMenuModel } from "@/app/store/contextmenu";
|
||||||
import { atoms, globalStore, WOS } from "@/app/store/global";
|
import { atoms, globalStore, WOS } from "@/app/store/global";
|
||||||
import * as services from "@/app/store/services";
|
import * as services from "@/app/store/services";
|
||||||
|
import { WshServer } from "@/app/store/wshserver";
|
||||||
import { MagnifyIcon } from "@/element/magnify";
|
import { MagnifyIcon } from "@/element/magnify";
|
||||||
import { NodeModel } from "@/layout/index";
|
import { NodeModel } from "@/layout/index";
|
||||||
|
import * as keyutil from "@/util/keyutil";
|
||||||
import { checkKeyPressed, keydownWrapper } from "@/util/keyutil";
|
import { checkKeyPressed, keydownWrapper } from "@/util/keyutil";
|
||||||
import * as util from "@/util/util";
|
import * as util from "@/util/util";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
@ -129,6 +132,7 @@ const BlockFrame_Header = ({ nodeModel, viewModel, preview }: BlockFrameProps) =
|
|||||||
const preIconButton = util.useAtomValueSafe(viewModel.preIconButton);
|
const preIconButton = util.useAtomValueSafe(viewModel.preIconButton);
|
||||||
const headerTextUnion = util.useAtomValueSafe(viewModel.viewText);
|
const headerTextUnion = util.useAtomValueSafe(viewModel.viewText);
|
||||||
const magnified = jotai.useAtomValue(nodeModel.isMagnified);
|
const magnified = jotai.useAtomValue(nodeModel.isMagnified);
|
||||||
|
const manageConnection = jotai.useAtomValue(viewModel.manageConnection);
|
||||||
const dragHandleRef = preview ? null : nodeModel.dragHandleRef;
|
const dragHandleRef = preview ? null : nodeModel.dragHandleRef;
|
||||||
|
|
||||||
const onContextMenu = React.useCallback(
|
const onContextMenu = React.useCallback(
|
||||||
@ -163,6 +167,16 @@ const BlockFrame_Header = ({ nodeModel, viewModel, preview }: BlockFrameProps) =
|
|||||||
} else if (Array.isArray(headerTextUnion)) {
|
} else if (Array.isArray(headerTextUnion)) {
|
||||||
headerTextElems.push(...renderHeaderElements(headerTextUnion, preview));
|
headerTextElems.push(...renderHeaderElements(headerTextUnion, preview));
|
||||||
}
|
}
|
||||||
|
if (manageConnection) {
|
||||||
|
const connButtonElem = (
|
||||||
|
<ConnectionButton
|
||||||
|
key={nodeModel.blockId}
|
||||||
|
blockId={nodeModel.blockId}
|
||||||
|
connection={blockData?.meta?.connection}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
headerTextElems.unshift(connButtonElem);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="block-frame-default-header" ref={dragHandleRef} onContextMenu={onContextMenu}>
|
<div className="block-frame-default-header" ref={dragHandleRef} onContextMenu={onContextMenu}>
|
||||||
@ -174,6 +188,7 @@ const BlockFrame_Header = ({ nodeModel, viewModel, preview }: BlockFrameProps) =
|
|||||||
<div className="block-frame-blockid">[{nodeModel.blockId.substring(0, 8)}]</div>
|
<div className="block-frame-blockid">[{nodeModel.blockId.substring(0, 8)}]</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="block-frame-textelems-wrapper">{headerTextElems}</div>
|
<div className="block-frame-textelems-wrapper">{headerTextElems}</div>
|
||||||
<div className="block-frame-end-icons">{endIconsElem}</div>
|
<div className="block-frame-end-icons">{endIconsElem}</div>
|
||||||
</div>
|
</div>
|
||||||
@ -193,8 +208,6 @@ const HeaderTextElem = React.memo(({ elem, preview }: { elem: HeaderElem; previe
|
|||||||
{elem.text}
|
{elem.text}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
} else if (elem.elemtype == "connectionbutton") {
|
|
||||||
return <ConnectionButton decl={elem} />;
|
|
||||||
} else if (elem.elemtype == "div") {
|
} else if (elem.elemtype == "div") {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -294,6 +307,13 @@ const BlockFrame_Default_Component = (props: BlockFrameProps) => {
|
|||||||
onKeyDown={keydownWrapper(handleKeyDown)}
|
onKeyDown={keydownWrapper(handleKeyDown)}
|
||||||
>
|
>
|
||||||
<BlockMask nodeModel={nodeModel} />
|
<BlockMask nodeModel={nodeModel} />
|
||||||
|
{preview ? null : (
|
||||||
|
<ChangeConnectionBlockModal
|
||||||
|
blockId={nodeModel.blockId}
|
||||||
|
viewModel={viewModel}
|
||||||
|
blockRef={blockModel?.blockRef}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div className="block-frame-default-inner" style={innerStyle}>
|
<div className="block-frame-default-inner" style={innerStyle}>
|
||||||
<BlockFrame_Header {...props} />
|
<BlockFrame_Header {...props} />
|
||||||
{preview ? previewElem : children}
|
{preview ? previewElem : children}
|
||||||
@ -302,6 +322,70 @@ const BlockFrame_Default_Component = (props: BlockFrameProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ChangeConnectionBlockModal = React.memo(
|
||||||
|
({
|
||||||
|
blockId,
|
||||||
|
viewModel,
|
||||||
|
blockRef,
|
||||||
|
}: {
|
||||||
|
blockId: string;
|
||||||
|
viewModel: ViewModel;
|
||||||
|
blockRef: React.RefObject<HTMLDivElement>;
|
||||||
|
}) => {
|
||||||
|
const typeAhead = jotai.useAtomValue(atoms.typeAheadModalAtom);
|
||||||
|
const [connSelected, setConnSelected] = React.useState("");
|
||||||
|
const changeConnection = React.useCallback(
|
||||||
|
async (connName: string) => {
|
||||||
|
await WshServer.SetMetaCommand({
|
||||||
|
oref: WOS.makeORef("block", blockId),
|
||||||
|
meta: { connection: connName },
|
||||||
|
});
|
||||||
|
await WshServer.ControllerRestartCommand({ blockid: blockId });
|
||||||
|
},
|
||||||
|
[blockId]
|
||||||
|
);
|
||||||
|
const handleTypeAheadKeyDown = React.useCallback(
|
||||||
|
(waveEvent: WaveKeyboardEvent): boolean => {
|
||||||
|
if (keyutil.checkKeyPressed(waveEvent, "Enter")) {
|
||||||
|
changeConnection(connSelected);
|
||||||
|
globalStore.set(atoms.typeAheadModalAtom, {
|
||||||
|
...(typeAhead as TypeAheadModalType),
|
||||||
|
[blockId]: false,
|
||||||
|
});
|
||||||
|
setConnSelected("");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (keyutil.checkKeyPressed(waveEvent, "Escape")) {
|
||||||
|
globalStore.set(atoms.typeAheadModalAtom, {
|
||||||
|
...(typeAhead as TypeAheadModalType),
|
||||||
|
[blockId]: false,
|
||||||
|
});
|
||||||
|
setConnSelected("");
|
||||||
|
viewModel.giveFocus();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[typeAhead, viewModel, blockId, connSelected]
|
||||||
|
);
|
||||||
|
if (!typeAhead[blockId]) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<TypeAheadModal
|
||||||
|
anchor={blockRef}
|
||||||
|
suggestions={[]}
|
||||||
|
onSelect={(selected: string) => {
|
||||||
|
changeConnection(selected);
|
||||||
|
}}
|
||||||
|
onKeyDown={(e) => keyutil.keydownWrapper(handleTypeAheadKeyDown)(e)}
|
||||||
|
onChange={(current: string) => setConnSelected(current)}
|
||||||
|
value={connSelected}
|
||||||
|
label="Switch Connection"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const BlockFrame_Default = React.memo(BlockFrame_Default_Component) as typeof BlockFrame_Default_Component;
|
const BlockFrame_Default = React.memo(BlockFrame_Default_Component) as typeof BlockFrame_Default_Component;
|
||||||
|
|
||||||
const BlockFrame = React.memo((props: BlockFrameProps) => {
|
const BlockFrame = React.memo((props: BlockFrameProps) => {
|
||||||
|
@ -2,8 +2,10 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
import { useLongClick } from "@/app/hook/useLongClick";
|
import { useLongClick } from "@/app/hook/useLongClick";
|
||||||
|
import { atoms, getConnStatusAtom } from "@/app/store/global";
|
||||||
import * as util from "@/util/util";
|
import * as util from "@/util/util";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
import * as jotai from "jotai";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
export const colorRegex = /^((#[0-9a-f]{6,8})|([a-z]+))$/;
|
export const colorRegex = /^((#[0-9a-f]{6,8})|([a-z]+))$/;
|
||||||
@ -168,30 +170,60 @@ export const IconButton = React.memo(({ decl, className }: { decl: HeaderIconBut
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ConnectionButton = React.memo(({ decl }: { decl: ConnectionButton }) => {
|
export const ConnectionButton = React.memo(({ blockId, connection }: { blockId: string; connection: string }) => {
|
||||||
|
const [typeAhead, setTypeAhead] = jotai.useAtom(atoms.typeAheadModalAtom);
|
||||||
const buttonRef = React.useRef<HTMLDivElement>(null);
|
const buttonRef = React.useRef<HTMLDivElement>(null);
|
||||||
|
const isLocal = connection == "" || connection == "local";
|
||||||
|
const connStatusAtom = getConnStatusAtom(connection);
|
||||||
|
const connStatus = jotai.useAtomValue(connStatusAtom);
|
||||||
|
const showDisconnectedSlash = !isLocal && !connStatus?.connected;
|
||||||
|
let connIconElem: React.ReactNode = null;
|
||||||
|
let color = "#53b4ea";
|
||||||
|
const clickHandler = function () {
|
||||||
|
setTypeAhead({
|
||||||
|
...typeAhead,
|
||||||
|
[blockId]: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
let titleText = null;
|
||||||
|
if (isLocal) {
|
||||||
|
color = "var(--grey-text-color)";
|
||||||
|
titleText = "Connected to Local Machine";
|
||||||
|
connIconElem = (
|
||||||
|
<i
|
||||||
|
className={clsx(util.makeIconClass("laptop", false), "fa-stack-1x")}
|
||||||
|
style={{ color: color, marginRight: 2 }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
titleText = "Connected to " + connection;
|
||||||
|
if (!connStatus?.connected) {
|
||||||
|
color = "var(--grey-text-color)";
|
||||||
|
titleText = "Disconnected from " + connection;
|
||||||
|
}
|
||||||
|
connIconElem = (
|
||||||
|
<i
|
||||||
|
className={clsx(util.makeIconClass("arrow-right-arrow-left", false), "fa-stack-1x")}
|
||||||
|
style={{ color: color, marginRight: 2 }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={buttonRef} className={clsx("connection-button")} onClick={decl.onClick}>
|
<div ref={buttonRef} className={clsx("connection-button")} onClick={clickHandler} title={titleText}>
|
||||||
<span className="fa-stack connection-icon-box">
|
<span className="fa-stack connection-icon-box">
|
||||||
{typeof decl.icon === "string" ? (
|
{connIconElem}
|
||||||
<i
|
|
||||||
className={clsx(util.makeIconClass(decl.icon, true), "fa-stack-1x")}
|
|
||||||
style={{ color: decl.iconColor, marginRight: "2px" }}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
decl.icon
|
|
||||||
)}
|
|
||||||
<i
|
<i
|
||||||
className="fa-slash fa-solid fa-stack-1x"
|
className="fa-slash fa-solid fa-stack-1x"
|
||||||
style={{
|
style={{
|
||||||
color: decl.iconColor,
|
color: color,
|
||||||
marginRight: "2px",
|
marginRight: "2px",
|
||||||
textShadow: "0 1px black, 0 1.5px black",
|
textShadow: "0 1px black, 0 1.5px black",
|
||||||
opacity: decl.connected ? 0 : 1,
|
opacity: showDisconnectedSlash ? 1 : 0,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<div className="connection-name">{decl.text}</div>
|
{isLocal ? null : <div className="connection-name">{connection}</div>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,18 +1,9 @@
|
|||||||
// Copyright 2024, Command Line Inc.
|
// Copyright 2024, Command Line Inc.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
import { TypeAheadModal } from "@/app/modals/typeaheadmodal";
|
|
||||||
import { WshServer } from "@/app/store/wshserver";
|
import { WshServer } from "@/app/store/wshserver";
|
||||||
import { VDomView } from "@/app/view/term/vdom";
|
import { VDomView } from "@/app/view/term/vdom";
|
||||||
import {
|
import { WOS, atoms, getEventORefSubject, globalStore, useBlockAtom, useSettingsAtom } from "@/store/global";
|
||||||
WOS,
|
|
||||||
atoms,
|
|
||||||
getConnStatusAtom,
|
|
||||||
getEventORefSubject,
|
|
||||||
globalStore,
|
|
||||||
useBlockAtom,
|
|
||||||
useSettingsAtom,
|
|
||||||
} from "@/store/global";
|
|
||||||
import * as services from "@/store/services";
|
import * as services from "@/store/services";
|
||||||
import * as keyutil from "@/util/keyutil";
|
import * as keyutil from "@/util/keyutil";
|
||||||
import * as util from "@/util/util";
|
import * as util from "@/util/util";
|
||||||
@ -110,27 +101,18 @@ class TermViewModel {
|
|||||||
termRef: React.RefObject<TermWrap>;
|
termRef: React.RefObject<TermWrap>;
|
||||||
blockAtom: jotai.Atom<Block>;
|
blockAtom: jotai.Atom<Block>;
|
||||||
termMode: jotai.Atom<string>;
|
termMode: jotai.Atom<string>;
|
||||||
connectedAtom: jotai.Atom<boolean>;
|
|
||||||
typeahead: boolean;
|
|
||||||
htmlElemFocusRef: React.RefObject<HTMLInputElement>;
|
htmlElemFocusRef: React.RefObject<HTMLInputElement>;
|
||||||
blockId: string;
|
blockId: string;
|
||||||
viewIcon: jotai.Atom<string>;
|
viewIcon: jotai.Atom<string>;
|
||||||
viewText: jotai.Atom<HeaderElem[]>;
|
viewText: jotai.Atom<HeaderElem[]>;
|
||||||
viewName: jotai.Atom<string>;
|
viewName: jotai.Atom<string>;
|
||||||
blockBg: jotai.Atom<MetaType>;
|
blockBg: jotai.Atom<MetaType>;
|
||||||
|
manageConnection: jotai.Atom<boolean>;
|
||||||
|
|
||||||
constructor(blockId: string) {
|
constructor(blockId: string) {
|
||||||
this.viewType = "term";
|
this.viewType = "term";
|
||||||
this.blockId = blockId;
|
this.blockId = blockId;
|
||||||
this.blockAtom = WOS.getWaveObjectAtom<Block>(`block:${blockId}`);
|
this.blockAtom = WOS.getWaveObjectAtom<Block>(`block:${blockId}`);
|
||||||
this.connectedAtom = jotai.atom((get) => {
|
|
||||||
const connectionName = get(this.blockAtom).meta?.connection || "";
|
|
||||||
if (connectionName == "") {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const status = get(getConnStatusAtom(connectionName));
|
|
||||||
return status.connected;
|
|
||||||
});
|
|
||||||
this.termMode = jotai.atom((get) => {
|
this.termMode = jotai.atom((get) => {
|
||||||
const blockData = get(this.blockAtom);
|
const blockData = get(this.blockAtom);
|
||||||
return blockData?.meta?.["term:mode"] ?? "term";
|
return blockData?.meta?.["term:mode"] ?? "term";
|
||||||
@ -145,32 +127,11 @@ class TermViewModel {
|
|||||||
}
|
}
|
||||||
return "Terminal";
|
return "Terminal";
|
||||||
});
|
});
|
||||||
|
this.manageConnection = jotai.atom(true);
|
||||||
this.viewText = jotai.atom((get) => {
|
this.viewText = jotai.atom((get) => {
|
||||||
const blockData = get(this.blockAtom);
|
const blockData = get(this.blockAtom);
|
||||||
const titleText: HeaderText = { elemtype: "text", text: blockData?.meta?.title ?? "" };
|
const titleText: HeaderText = { elemtype: "text", text: blockData?.meta?.title ?? "" };
|
||||||
const typeAhead = get(atoms.typeAheadModalAtom);
|
return [titleText] as HeaderElem[];
|
||||||
const connectionName = blockData?.meta?.connection || "";
|
|
||||||
const isConnected = get(this.connectedAtom);
|
|
||||||
let iconColor: string;
|
|
||||||
if (connectionName != "") {
|
|
||||||
iconColor = "#53b4ea";
|
|
||||||
} else {
|
|
||||||
iconColor = "var(--grey-text-color)";
|
|
||||||
}
|
|
||||||
const connButton: ConnectionButton = {
|
|
||||||
elemtype: "connectionbutton",
|
|
||||||
icon: "arrow-right-arrow-left",
|
|
||||||
iconColor: iconColor,
|
|
||||||
text: connectionName,
|
|
||||||
connected: isConnected,
|
|
||||||
onClick: () => {
|
|
||||||
globalStore.set(atoms.typeAheadModalAtom, {
|
|
||||||
...(typeAhead as TypeAheadModalType),
|
|
||||||
[blockId]: true,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
return [connButton, titleText] as HeaderElem[];
|
|
||||||
});
|
});
|
||||||
this.blockBg = jotai.atom((get) => {
|
this.blockBg = jotai.atom((get) => {
|
||||||
const blockData = get(this.blockAtom);
|
const blockData = get(this.blockAtom);
|
||||||
@ -231,9 +192,7 @@ interface TerminalViewProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
||||||
const typeAhead = jotai.useAtomValue(atoms.typeAheadModalAtom);
|
|
||||||
const viewRef = React.createRef<HTMLDivElement>();
|
const viewRef = React.createRef<HTMLDivElement>();
|
||||||
const [connSelected, setConnSelected] = React.useState("");
|
|
||||||
const connectElemRef = React.useRef<HTMLDivElement>(null);
|
const connectElemRef = React.useRef<HTMLDivElement>(null);
|
||||||
const termRef = React.useRef<TermWrap>(null);
|
const termRef = React.useRef<TermWrap>(null);
|
||||||
model.termRef = termRef;
|
model.termRef = termRef;
|
||||||
@ -398,45 +357,8 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
|||||||
[blockId]
|
[blockId]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleTypeAheadKeyDown = React.useCallback(
|
|
||||||
(waveEvent: WaveKeyboardEvent): boolean => {
|
|
||||||
if (keyutil.checkKeyPressed(waveEvent, "Enter")) {
|
|
||||||
changeConnection(connSelected);
|
|
||||||
globalStore.set(atoms.typeAheadModalAtom, {
|
|
||||||
...(typeAhead as TypeAheadModalType),
|
|
||||||
[blockId]: false,
|
|
||||||
});
|
|
||||||
setConnSelected("");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (keyutil.checkKeyPressed(waveEvent, "Escape")) {
|
|
||||||
globalStore.set(atoms.typeAheadModalAtom, {
|
|
||||||
...(typeAhead as TypeAheadModalType),
|
|
||||||
[blockId]: false,
|
|
||||||
});
|
|
||||||
setConnSelected("");
|
|
||||||
model.giveFocus();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[typeAhead, model, blockId, connSelected]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx("view-term", "term-mode-" + termMode)} onKeyDown={handleKeyDown} ref={viewRef}>
|
<div className={clsx("view-term", "term-mode-" + termMode)} onKeyDown={handleKeyDown} ref={viewRef}>
|
||||||
{typeAhead[blockId] && (
|
|
||||||
<TypeAheadModal
|
|
||||||
anchor={viewRef}
|
|
||||||
suggestions={[]}
|
|
||||||
onSelect={(selected: string) => {
|
|
||||||
changeConnection(selected);
|
|
||||||
}}
|
|
||||||
onKeyDown={(e) => keyutil.keydownWrapper(handleTypeAheadKeyDown)(e)}
|
|
||||||
onChange={(current: string) => setConnSelected(current)}
|
|
||||||
value={connSelected}
|
|
||||||
label="Switch Connection"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<TermThemeUpdater blockId={blockId} termRef={termRef} />
|
<TermThemeUpdater blockId={blockId} termRef={termRef} />
|
||||||
<TermStickers config={stickerConfig} />
|
<TermStickers config={stickerConfig} />
|
||||||
<div key="conntectElem" className="term-connectelem" ref={connectElemRef}></div>
|
<div key="conntectElem" className="term-connectelem" ref={connectElemRef}></div>
|
||||||
|
3
frontend/types/custom.d.ts
vendored
3
frontend/types/custom.d.ts
vendored
@ -19,7 +19,7 @@ declare global {
|
|||||||
controlShiftDelayAtom: jotai.PrimitiveAtom<boolean>;
|
controlShiftDelayAtom: jotai.PrimitiveAtom<boolean>;
|
||||||
reducedMotionPreferenceAtom: jotai.Atom<boolean>;
|
reducedMotionPreferenceAtom: jotai.Atom<boolean>;
|
||||||
updaterStatusAtom: jotai.PrimitiveAtom<UpdaterStatus>;
|
updaterStatusAtom: jotai.PrimitiveAtom<UpdaterStatus>;
|
||||||
typeAheadModalAtom: jotai.Primitive<TypeAheadModalType>;
|
typeAheadModalAtom: jotai.PrimitiveAtom<TypeAheadModalType>;
|
||||||
};
|
};
|
||||||
|
|
||||||
type WritableWaveObjectAtom<T extends WaveObj> = jotai.WritableAtom<T, [value: T], void>;
|
type WritableWaveObjectAtom<T extends WaveObj> = jotai.WritableAtom<T, [value: T], void>;
|
||||||
@ -201,6 +201,7 @@ declare global {
|
|||||||
preIconButton?: jotai.Atom<HeaderIconButton>;
|
preIconButton?: jotai.Atom<HeaderIconButton>;
|
||||||
endIconButtons?: jotai.Atom<HeaderIconButton[]>;
|
endIconButtons?: jotai.Atom<HeaderIconButton[]>;
|
||||||
blockBg?: jotai.Atom<MetaType>;
|
blockBg?: jotai.Atom<MetaType>;
|
||||||
|
manageConnection?: jotai.Atom<boolean>;
|
||||||
|
|
||||||
onBack?: () => void;
|
onBack?: () => void;
|
||||||
onForward?: () => void;
|
onForward?: () => void;
|
||||||
|
@ -69,8 +69,8 @@ func (conn *SSHConn) DeriveConnStatus() wshrpc.ConnStatus {
|
|||||||
defer conn.Lock.Unlock()
|
defer conn.Lock.Unlock()
|
||||||
return wshrpc.ConnStatus{
|
return wshrpc.ConnStatus{
|
||||||
Status: conn.Status,
|
Status: conn.Status,
|
||||||
|
Connected: conn.Status == Status_Connected,
|
||||||
Connection: conn.Opts.String(),
|
Connection: conn.Opts.String(),
|
||||||
Connected: conn.Client != nil,
|
|
||||||
Error: conn.Error,
|
Error: conn.Error,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user