mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-02 18:39:05 +01:00
connection status overlay (#337)
This commit is contained in:
parent
11e4f6074d
commit
a00dc5682e
@ -287,39 +287,95 @@
|
|||||||
|
|
||||||
.connstatus-overlay {
|
.connstatus-overlay {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: var(--header-height);
|
top: calc(var(--header-height) + 6px);
|
||||||
left: 2px;
|
left: 6px;
|
||||||
right: 2px;
|
right: 6px;
|
||||||
background-color: rgba(0, 0, 0, 0.3);
|
|
||||||
z-index: var(--zindex-block-mask-inner);
|
z-index: var(--zindex-block-mask-inner);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
background: rgba(230, 186, 30, 0.2);
|
||||||
|
backdrop-filter: blur(50px);
|
||||||
|
border-radius: 6px;
|
||||||
|
box-shadow: 0px 13px 16px 0px rgba(0, 0, 0, 0.4);
|
||||||
|
|
||||||
.connstatus-mainelem {
|
.connstatus-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
align-items: center;
|
justify-content: space-between;
|
||||||
justify-content: center;
|
padding: 10px 8px 10px 12px;
|
||||||
padding: 20px;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: rgba(60, 60, 60, 0.65);
|
|
||||||
backdrop-filter: blur(3px);
|
|
||||||
font: var(--base-font);
|
font: var(--base-font);
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
.connstatus-error {
|
.connstatus-status-icon-wrapper {
|
||||||
color: var(--error-color);
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
flex-grow: 1;
|
||||||
|
min-width: 0;
|
||||||
|
|
||||||
|
&.has-error {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
> i {
|
||||||
|
color: #e6ba1e;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connstatus-status {
|
||||||
|
.ellipsis();
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 4px;
|
||||||
|
flex-grow: 1;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.connstatus-status-text {
|
||||||
|
.ellipsis();
|
||||||
|
max-width: 100%;
|
||||||
|
font-size: 11px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 16px;
|
||||||
|
letter-spacing: 0.11px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connstatus-error {
|
||||||
|
.ellipsis();
|
||||||
|
width: 94%;
|
||||||
|
font-size: 11px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 15px;
|
||||||
|
letter-spacing: 0.11px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.connstatus-actions {
|
.connstatus-actions {
|
||||||
margin-top: 10px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 5px;
|
align-items: flex-start;
|
||||||
flex-direction: row;
|
justify-content: center;
|
||||||
flex-wrap: wrap;
|
gap: 6px;
|
||||||
|
|
||||||
|
button {
|
||||||
|
i {
|
||||||
|
font-size: 11px;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:last-child {
|
||||||
|
margin-top: 1.5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright 2024, Command Line Inc.
|
// Copyright 2024, Command Line Inc.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
import { BlockComponentModel } from "@/app/block/blocktypes";
|
||||||
import {
|
import {
|
||||||
blockViewToIcon,
|
blockViewToIcon,
|
||||||
blockViewToName,
|
blockViewToName,
|
||||||
@ -12,6 +13,7 @@ import {
|
|||||||
Input,
|
Input,
|
||||||
} from "@/app/block/blockutil";
|
} from "@/app/block/blockutil";
|
||||||
import { Button } from "@/app/element/button";
|
import { Button } from "@/app/element/button";
|
||||||
|
import { useWidth } from "@/app/hook/useWidth";
|
||||||
import { TypeAheadModal } from "@/app/modals/typeaheadmodal";
|
import { TypeAheadModal } from "@/app/modals/typeaheadmodal";
|
||||||
import { ContextMenuModel } from "@/app/store/contextmenu";
|
import { ContextMenuModel } from "@/app/store/contextmenu";
|
||||||
import {
|
import {
|
||||||
@ -264,52 +266,76 @@ function renderHeaderElements(headerTextUnion: HeaderElem[], preview: boolean):
|
|||||||
|
|
||||||
const ConnStatusOverlay = React.memo(
|
const ConnStatusOverlay = React.memo(
|
||||||
({
|
({
|
||||||
|
blockModel,
|
||||||
nodeModel,
|
nodeModel,
|
||||||
viewModel,
|
viewModel,
|
||||||
changeConnModalAtom,
|
changeConnModalAtom,
|
||||||
}: {
|
}: {
|
||||||
|
blockModel: BlockComponentModel;
|
||||||
nodeModel: NodeModel;
|
nodeModel: NodeModel;
|
||||||
viewModel: ViewModel;
|
viewModel: ViewModel;
|
||||||
changeConnModalAtom: jotai.PrimitiveAtom<boolean>;
|
changeConnModalAtom: jotai.PrimitiveAtom<boolean>;
|
||||||
}) => {
|
}) => {
|
||||||
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", nodeModel.blockId));
|
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", nodeModel.blockId));
|
||||||
const [connModalOpen, setConnModalOpen] = jotai.useAtom(changeConnModalAtom);
|
const [connModalOpen] = jotai.useAtom(changeConnModalAtom);
|
||||||
const connName = blockData.meta?.connection;
|
const connName = blockData.meta?.connection;
|
||||||
const connStatus = jotai.useAtomValue(getConnStatusAtom(connName));
|
const connStatus = jotai.useAtomValue(getConnStatusAtom(connName));
|
||||||
const isLayoutMode = jotai.useAtomValue(atoms.controlShiftDelayAtom);
|
const isLayoutMode = jotai.useAtomValue(atoms.controlShiftDelayAtom);
|
||||||
|
const width = useWidth(blockModel?.blockRef);
|
||||||
|
const [showError, setShowError] = React.useState(false);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (width) {
|
||||||
|
const hasError = !util.isBlank(connStatus.error);
|
||||||
|
const showError = hasError && width >= 250 && connStatus.status != "connecting";
|
||||||
|
setShowError(showError);
|
||||||
|
}
|
||||||
|
}, [width, connStatus, setShowError]);
|
||||||
|
|
||||||
const handleTryReconnect = React.useCallback(() => {
|
const handleTryReconnect = React.useCallback(() => {
|
||||||
const prtn = WshServer.ConnConnectCommand(connName, { timeout: 60000 });
|
const prtn = WshServer.ConnConnectCommand(connName, { timeout: 60000 });
|
||||||
prtn.catch((e) => console.log("error reconnecting", connName, e));
|
prtn.catch((e) => console.log("error reconnecting", connName, e));
|
||||||
}, [connName]);
|
}, [connName]);
|
||||||
const handleSwitchConnection = React.useCallback(() => {
|
|
||||||
setConnModalOpen(true);
|
|
||||||
}, [setConnModalOpen]);
|
|
||||||
if (isLayoutMode || connStatus.status == "connected" || connModalOpen) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
let statusText = `Disconnected from "${connName}"`;
|
let statusText = `Disconnected from "${connName}"`;
|
||||||
let showReconnect = true;
|
let showReconnect = true;
|
||||||
if (connStatus.status == "connecting") {
|
if (connStatus.status == "connecting") {
|
||||||
statusText = `Connecting to "${connName}"...`;
|
statusText = `Connecting to "${connName}"...`;
|
||||||
showReconnect = false;
|
showReconnect = false;
|
||||||
}
|
}
|
||||||
|
let reconDisplay = null;
|
||||||
|
let reconClassName = "outlined";
|
||||||
|
if (width && width < 350) {
|
||||||
|
reconDisplay = <i className="fa-sharp fa-solid fa-rotate-right"></i>;
|
||||||
|
reconClassName = clsx(reconClassName, "font-size-12 vertical-padding-5 horizontal-padding-6");
|
||||||
|
} else {
|
||||||
|
reconDisplay = "Reconnect";
|
||||||
|
reconClassName = clsx(reconClassName, "font-size-11 vertical-padding-3 horizontal-padding-7");
|
||||||
|
}
|
||||||
|
const showIcon = connStatus.status != "connecting";
|
||||||
|
|
||||||
|
if (isLayoutMode || connStatus.status == "connected" || connModalOpen) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="connstatus-overlay">
|
<div className="connstatus-overlay">
|
||||||
<div className="connstatus-mainelem">
|
<div className="connstatus-content">
|
||||||
<div style={{ marginBottom: 5 }}>{statusText}</div>
|
<div className={clsx("connstatus-status-icon-wrapper", { "has-error": showError })}>
|
||||||
{!util.isBlank(connStatus.error) ? (
|
{showIcon && <i className="fa-solid fa-triangle-exclamation"></i>}
|
||||||
<div className="connstatus-error">error: {connStatus.error}</div>
|
<div className="connstatus-status">
|
||||||
) : null}
|
<div className="connstatus-status-text">{statusText}</div>
|
||||||
|
{showError ? <div className="connstatus-error">error: {connStatus.error}</div> : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{showReconnect ? (
|
{showReconnect ? (
|
||||||
<div className="connstatus-actions">
|
<div className="connstatus-actions">
|
||||||
<Button className="secondary" onClick={handleTryReconnect}>
|
<Button className={reconClassName} onClick={handleTryReconnect}>
|
||||||
<i className="fa-sharp fa-solid fa-arrow-right-arrow-left" style={{ marginRight: 5 }} />
|
{reconDisplay}
|
||||||
Reconnect Now
|
|
||||||
</Button>
|
|
||||||
<Button className="secondary" onClick={handleSwitchConnection}>
|
|
||||||
<i className="fa-sharp fa-solid fa-arrow-right-arrow-left" style={{ marginRight: 5 }} />
|
|
||||||
Switch Connection
|
|
||||||
</Button>
|
</Button>
|
||||||
|
{/* <Button className="secondary ghost vertical-padding-5 horizontal-padding-6">
|
||||||
|
<i className="fa-sharp fa-regular fa-xmark-large"></i>
|
||||||
|
</Button> */}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
@ -417,7 +443,12 @@ const BlockFrame_Default_Component = (props: BlockFrameProps) => {
|
|||||||
ref={blockModel?.blockRef}
|
ref={blockModel?.blockRef}
|
||||||
>
|
>
|
||||||
<BlockMask nodeModel={nodeModel} />
|
<BlockMask nodeModel={nodeModel} />
|
||||||
<ConnStatusOverlay nodeModel={nodeModel} viewModel={viewModel} changeConnModalAtom={changeConnModalAtom} />
|
<ConnStatusOverlay
|
||||||
|
blockModel={blockModel}
|
||||||
|
nodeModel={nodeModel}
|
||||||
|
viewModel={viewModel}
|
||||||
|
changeConnModalAtom={changeConnModalAtom}
|
||||||
|
/>
|
||||||
<div className="block-frame-default-inner" style={innerStyle}>
|
<div className="block-frame-default-inner" style={innerStyle}>
|
||||||
<BlockFrame_Header {...props} connBtnRef={connBtnRef} changeConnModalAtom={changeConnModalAtom} />
|
<BlockFrame_Header {...props} connBtnRef={connBtnRef} changeConnModalAtom={changeConnModalAtom} />
|
||||||
{preview ? previewElem : children}
|
{preview ? previewElem : children}
|
||||||
|
@ -17,7 +17,10 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
outline: inherit;
|
outline: inherit;
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 8px 20px;
|
padding-top: 8px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
padding-left: 20px;
|
||||||
|
padding-right: 20px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
@ -79,6 +82,11 @@
|
|||||||
color: var(--error-color);
|
color: var(--error-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.outlined {
|
||||||
|
background: none;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
&.disabled {
|
&.disabled {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
@ -96,6 +104,86 @@
|
|||||||
padding-bottom: 2px;
|
padding-bottom: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vertical-padding-3 {
|
||||||
|
padding-top: 3px;
|
||||||
|
padding-bottom: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-padding-4 {
|
||||||
|
padding-top: 4px;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-padding-5 {
|
||||||
|
padding-top: 5px;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-padding-6 {
|
||||||
|
padding-top: 6px;
|
||||||
|
padding-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-padding-7 {
|
||||||
|
padding-top: 7px;
|
||||||
|
padding-bottom: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-padding-8 {
|
||||||
|
padding-top: 8px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-padding-9 {
|
||||||
|
padding-top: 9px;
|
||||||
|
padding-bottom: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-padding-10 {
|
||||||
|
padding-top: 10px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.horizontal-padding-2 {
|
||||||
|
padding-left: 2px;
|
||||||
|
padding-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.horizontal-padding-3 {
|
||||||
|
padding-left: 3px;
|
||||||
|
padding-right: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.horizontal-padding-4 {
|
||||||
|
padding-left: 4px;
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.horizontal-padding-5 {
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.horizontal-padding-6 {
|
||||||
|
padding-left: 6px;
|
||||||
|
padding-right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.horizontal-padding-7 {
|
||||||
|
padding-left: 7px;
|
||||||
|
padding-right: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.horizontal-padding-8 {
|
||||||
|
padding-left: 8px;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.horizontal-padding-9 {
|
||||||
|
padding-left: 9px;
|
||||||
|
padding-right: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
.horizontal-padding-10 {
|
.horizontal-padding-10 {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
|
Loading…
Reference in New Issue
Block a user