connmodal updates. connection colors, conn status in modal (#335)

This commit is contained in:
Mike Sawka
2024-09-05 23:09:30 -07:00
committed by GitHub
parent 975b77e728
commit acae25f6e3
8 changed files with 71 additions and 20 deletions
+27 -8
View File
@@ -4,6 +4,7 @@
import {
blockViewToIcon,
blockViewToName,
computeConnColorNum,
ConnectionButton,
ControllerStatusIcon,
getBlockHeaderIcon,
@@ -20,6 +21,7 @@ import {
getHostName,
getUserName,
globalStore,
refocusNode,
useBlockAtom,
useSettingsKeyAtom,
WOS,
@@ -35,6 +37,8 @@ import * as jotai from "jotai";
import * as React from "react";
import { BlockFrameProps } from "./blocktypes";
const NumActiveConnColors = 8;
function handleHeaderContextMenu(
e: React.MouseEvent<HTMLDivElement>,
blockData: Block,
@@ -354,6 +358,8 @@ const BlockFrame_Default_Component = (props: BlockFrameProps) => {
const changeConnModalAtom = useBlockAtom(nodeModel.blockId, "changeConn", () => {
return jotai.atom(false);
}) as jotai.PrimitiveAtom<boolean>;
const connModalOpen = jotai.useAtomValue(changeConnModalAtom);
const connBtnRef = React.useRef<HTMLDivElement>();
React.useEffect(() => {
if (!manageConnection) {
@@ -416,7 +422,7 @@ const BlockFrame_Default_Component = (props: BlockFrameProps) => {
<BlockFrame_Header {...props} connBtnRef={connBtnRef} changeConnModalAtom={changeConnModalAtom} />
{preview ? previewElem : children}
</div>
{preview ? null : (
{preview || !connModalOpen ? null : (
<ChangeConnectionBlockModal
blockId={nodeModel.blockId}
nodeModel={nodeModel}
@@ -454,7 +460,15 @@ const ChangeConnectionBlockModal = React.memo(
const connStatusAtom = getConnStatusAtom(connection);
const connStatus = jotai.useAtomValue(connStatusAtom);
const [connList, setConnList] = React.useState<Array<string>>([]);
const allConnStatus = jotai.useAtomValue(atoms.allConnStatus);
const connStatusMap = new Map<string, ConnStatus>();
let maxActiveConnNum = 1;
for (const conn of allConnStatus) {
if (conn.activeconnnum > maxActiveConnNum) {
maxActiveConnNum = conn.activeconnnum;
}
connStatusMap.set(conn.connection, conn);
}
React.useEffect(() => {
if (!changeConnModalOpen) {
setConnList([]);
@@ -533,7 +547,7 @@ const ChangeConnectionBlockModal = React.memo(
const reconnectSuggestion: SuggestionConnectionItem = {
status: "connected",
icon: "arrow-right-arrow-left",
iconColor: "var(--conn-icon-color)",
iconColor: "var(--grey-text-color)",
label: `Reconnect to ${connStatus.connection}`,
value: "",
onSelect: async (_: string) => {
@@ -565,7 +579,6 @@ const ChangeConnectionBlockModal = React.memo(
iconColor: "var(--grey-text-color)",
value: "",
label: localName,
// TODO: need to specify user name and host name
onSelect: (_: string) => {
changeConnection("");
globalStore.set(changeConnModalAtom, false);
@@ -573,10 +586,15 @@ const ChangeConnectionBlockModal = React.memo(
});
}
const remoteItems = filteredList.map((connName) => {
const connStatus = connStatusMap.get(connName);
const connColorNum = computeConnColorNum(connStatus);
const item: SuggestionConnectionItem = {
status: "connected",
icon: "arrow-right-arrow-left",
iconColor: "var(--conn-icon-color)",
iconColor:
connStatus?.status == "connected"
? `var(--conn-icon-color-${connColorNum})`
: "var(--grey-text-color)",
value: connName,
label: connName,
};
@@ -604,18 +622,19 @@ const ChangeConnectionBlockModal = React.memo(
changeConnection(connSelected);
globalStore.set(changeConnModalAtom, false);
setConnSelected("");
refocusNode(blockId);
return true;
}
if (keyutil.checkKeyPressed(waveEvent, "Escape")) {
globalStore.set(changeConnModalAtom, false);
setConnSelected("");
viewModel.giveFocus();
refocusNode(blockId);
return true;
}
},
[changeConnModalAtom, viewModel, blockId, connSelected]
);
// this check was also moved to BlockFrame to prevent all the above code from running unnecessarily
if (!changeConnModalOpen) {
return null;
}
@@ -654,4 +673,4 @@ const BlockFrame = React.memo((props: BlockFrameProps) => {
return <FrameElem {...props} numBlocksInTab={numBlocks} />;
});
export { BlockFrame };
export { BlockFrame, NumActiveConnColors };
+12 -1
View File
@@ -1,6 +1,7 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import { NumActiveConnColors } from "@/app/block/blockframe";
import { useLongClick } from "@/app/hook/useLongClick";
import { getConnStatusAtom, waveEventSubscribe, WOS } from "@/app/store/global";
import * as services from "@/app/store/services";
@@ -199,6 +200,15 @@ export const ControllerStatusIcon = React.memo(({ blockId }: { blockId: string }
return controllerStatusElem;
});
export function computeConnColorNum(connStatus: ConnStatus): number {
// activeconnnum is 1-indexed, so we need to adjust for when mod is 0
const connColorNum = (connStatus?.activeconnnum ?? 1) % NumActiveConnColors;
if (connColorNum == 0) {
return NumActiveConnColors;
}
return connColorNum;
}
export const ConnectionButton = React.memo(
React.forwardRef<HTMLDivElement, ConnectionButtonProps>(
({ connection, changeConnModalAtom }: ConnectionButtonProps, ref) => {
@@ -208,7 +218,8 @@ export const ConnectionButton = React.memo(
const connStatus = jotai.useAtomValue(connStatusAtom);
let showDisconnectedSlash = false;
let connIconElem: React.ReactNode = null;
let color = "var(--conn-icon-color)";
const connColorNum = computeConnColorNum(connStatus);
let color = `var(--conn-icon-color-${connColorNum})`;
const clickHandler = function () {
setConnModalOpen(true);
};
+5
View File
@@ -127,6 +127,10 @@ function initGlobalAtoms(initOpts: GlobalInitOptions) {
const reducedMotionPreferenceAtom = jotai.atom((get) => get(settingsAtom)?.["window:reducedmotion"]);
const typeAheadModalAtom = jotai.atom({});
const modalOpen = jotai.atom(false);
const allConnStatusAtom = jotai.atom<ConnStatus[]>((get) => {
const connStatuses = Array.from(ConnStatusMap.values()).map((atom) => get(atom));
return connStatuses;
});
atoms = {
// initialized in wave.ts (will not be null inside of application)
windowId: windowIdAtom,
@@ -145,6 +149,7 @@ function initGlobalAtoms(initOpts: GlobalInitOptions) {
reducedMotionPreferenceAtom,
typeAheadModalAtom,
modalOpen,
allConnStatus: allConnStatusAtom,
};
}
+8 -1
View File
@@ -92,6 +92,13 @@
--form-element-secondary-color: rgba(255, 255, 255, 0.2);
--form-element-error-color: var(--error-color);
/* temporary conn icon color - will be replaced with individual colors */
--conn-icon-color: #53b4ea;
--conn-icon-color-1: #53b4ea;
--conn-icon-color-2: #aa67ff;
--conn-icon-color-3: #fda7fd;
--conn-icon-color-4: #ef476f;
--conn-icon-color-5: #497bf8;
--conn-icon-color-6: #ffa24e;
--conn-icon-color-7: #dbde52;
--conn-icon-color-8: #58c142;
}
+1
View File
@@ -22,6 +22,7 @@ declare global {
updaterStatusAtom: jotai.PrimitiveAtom<UpdaterStatus>;
typeAheadModalAtom: jotai.PrimitiveAtom<TypeAheadModalType>;
modalOpen: jotai.PrimitiveAtom<boolean>;
allConnStatus: jotai.Atom<ConnStatus[]>;
};
type WritableWaveObjectAtom<T extends WaveObj> = jotai.WritableAtom<T, [value: T], void>;
+1
View File
@@ -159,6 +159,7 @@ declare global {
connection: string;
connected: boolean;
hasconnected: boolean;
activeconnnum: number;
error?: string;
};
+11 -5
View File
@@ -43,6 +43,7 @@ const DefaultConnectionTimeout = 60 * time.Second
var globalLock = &sync.Mutex{}
var clientControllerMap = make(map[remote.SSHOpts]*SSHConn)
var activeConnCounter = &atomic.Int32{}
type SSHConn struct {
Lock *sync.Mutex
@@ -55,6 +56,7 @@ type SSHConn struct {
Error string
HasWaiter *atomic.Bool
LastConnectTime int64
ActiveConnNum int
}
func GetAllConnStatus() []wshrpc.ConnStatus {
@@ -72,11 +74,12 @@ func (conn *SSHConn) DeriveConnStatus() wshrpc.ConnStatus {
conn.Lock.Lock()
defer conn.Lock.Unlock()
return wshrpc.ConnStatus{
Status: conn.Status,
Connected: conn.Status == Status_Connected,
Connection: conn.Opts.String(),
HasConnected: (conn.LastConnectTime > 0),
Error: conn.Error,
Status: conn.Status,
Connected: conn.Status == Status_Connected,
Connection: conn.Opts.String(),
HasConnected: (conn.LastConnectTime > 0),
ActiveConnNum: conn.ActiveConnNum,
Error: conn.Error,
}
}
@@ -395,6 +398,9 @@ func (conn *SSHConn) Connect(ctx context.Context) error {
} else {
conn.Status = Status_Connected
conn.LastConnectTime = time.Now().UnixMilli()
if conn.ActiveConnNum == 0 {
conn.ActiveConnNum = int(activeConnCounter.Add(1))
}
}
})
conn.FireConnChangeEvent()
+6 -5
View File
@@ -364,9 +364,10 @@ type TimeSeriesData struct {
}
type ConnStatus struct {
Status string `json:"status"`
Connection string `json:"connection"`
Connected bool `json:"connected"`
HasConnected bool `json:"hasconnected"` // true if it has *ever* connected successfully
Error string `json:"error,omitempty"`
Status string `json:"status"`
Connection string `json:"connection"`
Connected bool `json:"connected"`
HasConnected bool `json:"hasconnected"` // true if it has *ever* connected successfully
ActiveConnNum int `json:"activeconnnum"`
Error string `json:"error,omitempty"`
}