Upgrade UI Modal Terminal
This commit is contained in:
parent
9fac74ccc0
commit
53d8f184d0
|
|
@ -0,0 +1,32 @@
|
|||
import { Box, Flex, Text } from "@mantine/core";
|
||||
|
||||
interface GroupButtonProps {
|
||||
title: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function GroupButtonTerminal({
|
||||
title,
|
||||
children,
|
||||
}: GroupButtonProps) {
|
||||
return (
|
||||
<Box
|
||||
p="xs"
|
||||
style={{
|
||||
border: "1px solid var(--mantine-color-gray-3)",
|
||||
borderRadius: "8px",
|
||||
backgroundColor: "var(--mantine-color-gray-0)",
|
||||
}}
|
||||
>
|
||||
<Flex justify="space-between" align="center" gap="md">
|
||||
<Text fz={12} c="dimmed">
|
||||
{title}
|
||||
</Text>
|
||||
|
||||
<Flex gap="sm" wrap="wrap">
|
||||
{children}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ import {
|
|||
ActionIcon,
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
CloseButton,
|
||||
Flex,
|
||||
Grid,
|
||||
|
|
@ -58,6 +59,7 @@ import ModalLineHistory from "./ModalLineHistory";
|
|||
import AutoProgress from "../Components/AutoProgress";
|
||||
import LoaderOverlay from "../Components/LoaderOverlay";
|
||||
import { bodyDPELP, convertFromKilobytesString } from "../../untils/helper";
|
||||
import GroupButtonTerminal from "../Components/GroupButtonTerminal";
|
||||
const apiUrl = import.meta.env.VITE_BACKEND_URL;
|
||||
|
||||
const INIT_TICKET = {
|
||||
|
|
@ -69,6 +71,83 @@ const INIT_TICKET = {
|
|||
status: "open",
|
||||
};
|
||||
|
||||
// Sub-component: Switch Connection Status
|
||||
interface SwitchConnectionStatusProps {
|
||||
line: TLine | undefined;
|
||||
findSwitchPort: (portName: string) => SwitchPortsProps | null;
|
||||
normalizePortName: (port: string) => string;
|
||||
}
|
||||
|
||||
const SwitchConnectionStatus = ({
|
||||
line,
|
||||
findSwitchPort,
|
||||
normalizePortName,
|
||||
}: SwitchConnectionStatusProps) => {
|
||||
const port = line?.interface ? findSwitchPort(line.interface) : null;
|
||||
const isConnected = port?.status === "ON";
|
||||
const portName = line?.interface ? normalizePortName(line.interface) : "";
|
||||
|
||||
return (
|
||||
<Flex justify="center" mb="sm">
|
||||
<IconCircleDot size={18} color={isConnected ? "green" : "red"} />
|
||||
<Flex ml="xs" gap="xs">
|
||||
<Text size="sm">Internet</Text>
|
||||
{line?.interface ? (
|
||||
<Text size="sm" c={isConnected ? "green" : "red"}>
|
||||
{isConnected ? "Connected" : "Not Connected"} ({portName})
|
||||
</Text>
|
||||
) : (
|
||||
<Text size="sm" c="red">
|
||||
Not config
|
||||
</Text>
|
||||
)}
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
// Sub-component: Switch Control Buttons
|
||||
interface SwitchControlButtonsProps {
|
||||
isDisable: boolean;
|
||||
hasInterface: boolean;
|
||||
onSwitchOn: () => void;
|
||||
onSwitchOff: () => void;
|
||||
onSwitchRestart: () => void;
|
||||
}
|
||||
|
||||
const SwitchControlButtons = ({
|
||||
isDisable,
|
||||
hasInterface,
|
||||
onSwitchOn,
|
||||
onSwitchOff,
|
||||
onSwitchRestart,
|
||||
}: SwitchControlButtonsProps) => {
|
||||
const SWITCH_ACTIONS = [
|
||||
{ label: "ON", color: "green", handler: onSwitchOn },
|
||||
{ label: "OFF", color: "red", handler: onSwitchOff },
|
||||
{ label: "Restart", color: "orange", handler: onSwitchRestart },
|
||||
] as const;
|
||||
|
||||
return (
|
||||
<Flex justify="space-around" gap="xs">
|
||||
{SWITCH_ACTIONS.map(({ label, color, handler }) => (
|
||||
<Button
|
||||
key={label}
|
||||
className={classes.buttonControl}
|
||||
disabled={isDisable || !hasInterface}
|
||||
fw={400}
|
||||
variant="outline"
|
||||
color={color}
|
||||
size="xs"
|
||||
onClick={handler}
|
||||
>
|
||||
{label}
|
||||
</Button>
|
||||
))}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
const ModalTerminal = ({
|
||||
opened,
|
||||
onClose,
|
||||
|
|
@ -817,6 +896,13 @@ const ModalTerminal = ({
|
|||
<IconCircleCheckFilled color="green" fontSize={"18px"} />
|
||||
)}
|
||||
</Flex>
|
||||
<Card
|
||||
shadow="sm"
|
||||
p="sm"
|
||||
radius="md"
|
||||
withBorder
|
||||
h={"fit-content"}
|
||||
>
|
||||
<Flex
|
||||
mt="4px"
|
||||
align="center"
|
||||
|
|
@ -958,7 +1044,9 @@ const ModalTerminal = ({
|
|||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (!line?.inventory?.sn) return;
|
||||
navigator.clipboard.writeText(line.inventory?.sn || "");
|
||||
navigator.clipboard.writeText(
|
||||
line.inventory?.sn || "",
|
||||
);
|
||||
}}
|
||||
>
|
||||
{line?.inventory?.sn || ""}
|
||||
|
|
@ -988,12 +1076,22 @@ const ModalTerminal = ({
|
|||
copiedColor="violet"
|
||||
/>
|
||||
</Flex>
|
||||
</Card>
|
||||
</Box>
|
||||
<Tabs.Panel value="general" h={"95%"}>
|
||||
<Flex
|
||||
justify={"space-between"}
|
||||
direction={"column"}
|
||||
h={"95%"}
|
||||
>
|
||||
<ScrollArea h={"95%"}>
|
||||
<Card
|
||||
shadow="sm"
|
||||
p="sm"
|
||||
radius="md"
|
||||
withBorder
|
||||
h={"fit-content"}
|
||||
mt={"4px"}
|
||||
>
|
||||
<Flex>
|
||||
<Text size="md" mr={"6px"} fw={"bold"}>
|
||||
|
|
@ -1082,7 +1180,15 @@ const ModalTerminal = ({
|
|||
</Text>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Box>
|
||||
</Card>
|
||||
<Card
|
||||
shadow="sm"
|
||||
p="sm"
|
||||
radius="md"
|
||||
withBorder
|
||||
h={"fit-content"}
|
||||
mt={"4px"}
|
||||
>
|
||||
<Flex justify={"space-between"} align={"center"}>
|
||||
<Text size="md" mr={"sm"} fw={"bold"}>
|
||||
Warning from test report: AI
|
||||
|
|
@ -1118,7 +1224,7 @@ const ModalTerminal = ({
|
|||
<Box>
|
||||
<Textarea
|
||||
disabled={isDisable}
|
||||
rows={5}
|
||||
rows={4}
|
||||
size="sm"
|
||||
placeholder="Report from AI"
|
||||
value={valueIssue}
|
||||
|
|
@ -1128,107 +1234,53 @@ const ModalTerminal = ({
|
|||
/>
|
||||
</Box>
|
||||
</LoaderOverlay>
|
||||
</Box>
|
||||
<Box
|
||||
</Card>
|
||||
<Card
|
||||
shadow="sm"
|
||||
p="sm"
|
||||
radius="md"
|
||||
withBorder
|
||||
h={"fit-content"}
|
||||
mt={"4px"}
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<fieldset
|
||||
style={{
|
||||
width: "280px",
|
||||
}}
|
||||
<Box
|
||||
component="fieldset"
|
||||
w={280}
|
||||
style={{ border: "none", padding: 0 }}
|
||||
>
|
||||
<Flex justify={"center"}>
|
||||
<IconCircleDot
|
||||
color={
|
||||
line?.interface &&
|
||||
findSwitchPort(line?.interface)?.status === "ON"
|
||||
? "green"
|
||||
: "red"
|
||||
}
|
||||
<SwitchConnectionStatus
|
||||
line={line}
|
||||
findSwitchPort={findSwitchPort}
|
||||
normalizePortName={normalizePortName}
|
||||
/>
|
||||
<SwitchControlButtons
|
||||
isDisable={isDisable}
|
||||
hasInterface={!!line?.interface}
|
||||
onSwitchOn={() => controlSwitch("on")}
|
||||
onSwitchOff={() => controlSwitch("off")}
|
||||
onSwitchRestart={() => controlSwitch("restart")}
|
||||
/>
|
||||
<Flex>
|
||||
<Text size="sm" ml={"sm"}>
|
||||
Internet
|
||||
</Text>
|
||||
{line?.interface ? (
|
||||
findSwitchPort(line?.interface)?.status ===
|
||||
"ON" ? (
|
||||
<Text size="sm" ml={"4px"} c={"green"}>
|
||||
Connected (
|
||||
{normalizePortName(line?.interface)})
|
||||
</Text>
|
||||
) : (
|
||||
<Text size="sm" ml={"4px"} c={"red"}>
|
||||
Not Connected (
|
||||
{normalizePortName(line?.interface)})
|
||||
</Text>
|
||||
)
|
||||
) : (
|
||||
<Text c={"red"} size="sm" ml={"4px"}>
|
||||
Not config
|
||||
</Text>
|
||||
)}
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex justify={"space-around"} mt={"4px"}>
|
||||
<Button
|
||||
className={classes.buttonControl}
|
||||
disabled={isDisable || !line?.interface}
|
||||
fw={400}
|
||||
variant="outline"
|
||||
color="green"
|
||||
size="xs"
|
||||
onClick={() => {
|
||||
controlSwitch("on");
|
||||
}}
|
||||
>
|
||||
ON
|
||||
</Button>
|
||||
<Button
|
||||
className={classes.buttonControl}
|
||||
disabled={isDisable || !line?.interface}
|
||||
fw={400}
|
||||
variant="outline"
|
||||
color="red"
|
||||
size="xs"
|
||||
onClick={() => {
|
||||
controlSwitch("off");
|
||||
}}
|
||||
>
|
||||
OFF
|
||||
</Button>
|
||||
<Button
|
||||
className={classes.buttonControl}
|
||||
disabled={isDisable || !line?.interface}
|
||||
fw={400}
|
||||
variant="outline"
|
||||
color="orange"
|
||||
size="xs"
|
||||
onClick={() => {
|
||||
controlSwitch("restart");
|
||||
}}
|
||||
>
|
||||
Restart
|
||||
</Button>
|
||||
</Flex>
|
||||
</fieldset>
|
||||
</Box>
|
||||
<Flex
|
||||
justify={"center"}
|
||||
style={{
|
||||
borderTop: "1px solid #ccc",
|
||||
borderBottom: "1px solid #ccc",
|
||||
paddingTop: "12px",
|
||||
paddingBottom: "12px",
|
||||
marginTop: "8px",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
disabled={isDisable}
|
||||
fw={400}
|
||||
w={"120px"}
|
||||
w={"200px"}
|
||||
variant="outline"
|
||||
color="red"
|
||||
size="xs"
|
||||
|
|
@ -1254,6 +1306,8 @@ const ModalTerminal = ({
|
|||
Clear line
|
||||
</Button>
|
||||
</Flex>
|
||||
</Card>
|
||||
</ScrollArea>
|
||||
</Flex>
|
||||
</Tabs.Panel>
|
||||
|
||||
|
|
@ -1438,7 +1492,8 @@ const ModalTerminal = ({
|
|||
loadingClearTerminal={line?.loadingClearTerminal}
|
||||
isClearKeepScrollBack={isClearKeepScrollBack}
|
||||
/>
|
||||
<Flex justify={"space-around"} mt={"md"} pt={"md"} pb={"md"}>
|
||||
<Flex justify={"space-around"} mt={"xs"} pt={"xs"}>
|
||||
<GroupButtonTerminal title="CONSOLE">
|
||||
<Menu trigger="hover" withArrow shadow="md" position="right">
|
||||
<Menu.Target>
|
||||
<Button
|
||||
|
|
@ -1494,6 +1549,28 @@ const ModalTerminal = ({
|
|||
</Flex>
|
||||
</Menu.Dropdown>
|
||||
</Menu>
|
||||
<Button
|
||||
fw={400}
|
||||
disabled={isDisable}
|
||||
variant="filled"
|
||||
color="orange"
|
||||
size="xs"
|
||||
onClick={() => {
|
||||
socket?.emit("write_command_line_from_web", {
|
||||
lineIds: [line?.id],
|
||||
stationId: stationItem?.id,
|
||||
command: "spam_break",
|
||||
});
|
||||
setIsDisable(true);
|
||||
setTimeout(() => {
|
||||
setIsDisable(false);
|
||||
}, 5000);
|
||||
}}
|
||||
>
|
||||
Send Break
|
||||
</Button>
|
||||
</GroupButtonTerminal>
|
||||
<GroupButtonTerminal title="TEST">
|
||||
<ButtonDPELP
|
||||
socket={socket}
|
||||
selectedLines={line ? [line] : []}
|
||||
|
|
@ -1540,6 +1617,8 @@ const ModalTerminal = ({
|
|||
>
|
||||
Scenario
|
||||
</Button>
|
||||
</GroupButtonTerminal>
|
||||
<GroupButtonTerminal title="CONFIG">
|
||||
<Button
|
||||
disabled={
|
||||
isDisable ||
|
||||
|
|
@ -1576,26 +1655,8 @@ const ModalTerminal = ({
|
|||
>
|
||||
Select License
|
||||
</Button>
|
||||
<Button
|
||||
fw={400}
|
||||
disabled={isDisable}
|
||||
variant="filled"
|
||||
color="orange"
|
||||
size="xs"
|
||||
onClick={() => {
|
||||
socket?.emit("write_command_line_from_web", {
|
||||
lineIds: [line?.id],
|
||||
stationId: stationItem?.id,
|
||||
command: "spam_break",
|
||||
});
|
||||
setIsDisable(true);
|
||||
setTimeout(() => {
|
||||
setIsDisable(false);
|
||||
}, 5000);
|
||||
}}
|
||||
>
|
||||
Send Break
|
||||
</Button>
|
||||
</GroupButtonTerminal>
|
||||
<GroupButtonTerminal title="DEVICE">
|
||||
<Menu trigger="hover" withArrow shadow="md" position="top">
|
||||
<Menu.Target>
|
||||
<Button
|
||||
|
|
@ -1651,6 +1712,7 @@ const ModalTerminal = ({
|
|||
</Flex>
|
||||
</Menu.Dropdown>
|
||||
</Menu>
|
||||
</GroupButtonTerminal>
|
||||
</Flex>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={3} display={"none"}>
|
||||
|
|
|
|||
|
|
@ -295,6 +295,7 @@ const TerminalCLI: React.FC<TerminalCLIProps> = ({
|
|||
backgroundColor: "black",
|
||||
paddingBottom: customStyle.paddingBottom ?? "10px",
|
||||
maxHeight: customStyle.maxHeight ?? "70vh",
|
||||
borderRadius: "8px",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
|
|
|
|||
Loading…
Reference in New Issue