ATC_SIMPLE/FRONTEND/src/components/DrawerControl.tsx

1418 lines
48 KiB
TypeScript

import {
Box,
Button,
Card,
Flex,
Grid,
Group,
Loader,
Radio,
ScrollArea,
Text,
} from "@mantine/core";
import { IconRepeat } from "@tabler/icons-react";
import { useEffect, useState } from "react";
import classes from "./Component.module.css";
import type { APCProps, SwitchPortsProps, TStation } from "../untils/types";
import type { Socket } from "socket.io-client";
interface DrawerProps {
stationAPI: TStation;
socket: Socket | null;
}
type TSelectedOutlet = {
number?: number;
name: string;
status: string;
apc: number;
};
export const DrawerAPCControl: React.FC<DrawerProps> = ({
stationAPI,
socket,
}) => {
const findLineByOutlet = (outlet: TSelectedOutlet) => {
return stationAPI.lines.find(
(line) =>
line.outlet === outlet.number && line.apcName === `apc_${outlet.apc}`
);
};
const [listOutlet, setListOutlet] = useState<TSelectedOutlet[]>(
Array.from({ length: 16 })
.map((_, index) => ({
number: index / 8 < 1 ? index + 1 : index - 7, // Outlet numbers 1-8 for APC 1, 1-8 for APC 2
name: `Outlet ${(index % 8) + 1}`,
status: "OFF",
apc: index / 8 < 1 ? 1 : 2, // Assuming two APCs, alternating outlets
}))
.map((el) => {
const line = findLineByOutlet(el);
if (!line) return el;
return {
...el,
name: "Line " + line.lineNumber || el.name,
};
})
);
const [dataStation, setDataStation] = useState<TStation>(stationAPI);
const [listOutletSelected, setListOutletSelected] = useState<
TSelectedOutlet[]
>([]);
const [isSubmit, setIsSubmit] = useState(true);
const detectOutlet = (
apc: APCProps,
lines: string[],
result: TSelectedOutlet[],
i: number
) => {
let insideDeviceManager = false;
let currentBlock: string[] = [];
let lastDeviceManagerBlock: string[] = [];
for (const line of lines) {
// Detect start of any section
const isSectionHeader = line.match(/^-{5,}.*-{5,}$/);
// If it's the Device Manager section, start capturing
if (line.includes("------- Device Manager")) {
insideDeviceManager = true;
currentBlock = [];
continue;
}
// If a new section starts and we were inside Device Manager, save it
if (
insideDeviceManager &&
isSectionHeader &&
!line.includes("Device Manager")
) {
insideDeviceManager = false;
if (currentBlock.length > 0) {
lastDeviceManagerBlock = [...currentBlock];
}
continue;
}
// If inside, accumulate
if (insideDeviceManager) {
currentBlock.push(line);
}
}
// Edge case: block was still open till end of file
if (insideDeviceManager && currentBlock.length > 0) {
lastDeviceManagerBlock = [...currentBlock];
}
// Parse outlets from the lastDeviceManagerBlock
let indexOutlet = 1;
lastDeviceManagerBlock.forEach((line) => {
const match = line.match(
/^\s*\d+-\s+((?:Outlet|Port)\s+\d+)\s+(ON|OFF)/i
);
if (match) {
const [, , status] = match;
result.push({
number: indexOutlet,
name: "Outlet " + indexOutlet,
status: status.toUpperCase(),
apc: i + 1,
});
indexOutlet++;
}
});
if (result.length > 0 && apc?.status === "CONNECTED") apc.outlets = result;
else {
Array.from({ length: 8 }).forEach((_, index) => {
result.push({
number: index + 1,
name: `Outlet ${index + 1}`,
status: "OFF",
apc: i + 1,
});
});
apc.outlets = result;
}
};
useEffect(() => {
socket?.on("apc_output", (data) => {
if (data.stationId !== stationAPI.id) return;
const outlets: TSelectedOutlet[] = [];
const apc1 =
data.apcNumber === 1
? { output: data.data, status: data.status }
: dataStation?.apc1;
const apc2 =
data.apcNumber === 2
? { output: data.data, status: data.status }
: dataStation?.apc2;
setDataStation((prev) => ({ ...prev, apc1: apc1, apc2: apc2 }));
[apc1, apc2].forEach((apc, i) => {
if (!apc) return;
const result: TSelectedOutlet[] = [];
const lines = apc?.output?.split("\n") || [];
detectOutlet(apc, lines, result, i);
outlets.push(...result);
});
setTimeout(() => {
if (apc1 || apc2) setIsSubmit(false);
if (outlets.length > 0)
setListOutlet(
listOutlet.map((el) =>
outlets.find((o) => o.number === el.number && o.apc === el.apc)
? {
...el,
...outlets.find(
(o) => o.number === el.number && o.apc === el.apc
),
}
: el
)
);
}, 1000);
});
return () => {
socket?.off("apc_output");
};
}, [socket, dataStation, stationAPI]);
const toggleSelect = (outlet: TSelectedOutlet, number: number) => {
setListOutletSelected((prev) =>
prev.find((pid) => pid.name === outlet.name && pid.apc === outlet.apc)
? prev.filter(
(pid) => pid.name !== outlet.name || pid.apc !== outlet.apc
)
: [...prev, { ...outlet, number }]
);
};
const RenderAPCStatus = (apc: APCProps) => {
switch (apc?.status) {
case "CONNECTED":
return (
<>
<Text fw={800} c="green" fz={"12px"}>
{apc?.status}
</Text>
</>
);
case "DISCONNECTED":
return (
<>
<Text fw={800} c="red" fz={"12px"}>
{apc?.status}
</Text>
</>
);
case "TIMEOUT":
return (
<>
<Text fw={800} c="yellow" fz={"12px"}>
{apc?.status}
</Text>
</>
);
default:
return (
<>
<Text fw={800} c="red" fz={"12px"}>
DISCONNECTED
</Text>
</>
);
}
};
useEffect(() => {
setTimeout(() => {
setIsSubmit(false);
}, 15000);
}, []);
return (
<Grid>
<Grid.Col span={6}>
<fieldset style={{ padding: "4px 6px" }}>
<legend>
<div className={classes.titleAPC}>
<Text fw={700} c={"#514d4d"} fz={"xs"}>
APC 1
</Text>
{dataStation?.apc_1_ip ? (
RenderAPCStatus(dataStation?.apc1)
) : (
<Text fw={800} c="red" fz={"12px"}>
APC not available
</Text>
)}
{dataStation?.apc1?.status !== "CONNECTED" ? (
<Button
style={{ height: "24px" }}
size="xs"
disabled={isSubmit || !dataStation?.apc_1_ip}
variant="filled"
color="yellow"
onClick={() => {
socket?.emit("control_apc", {
outletNumbers: [],
station: { ...stationAPI, lines: [] },
action: "reconnect",
apcName: "apc_1",
});
setListOutletSelected([]); // Clear selected outlets
setIsSubmit(true);
setTimeout(() => {
setIsSubmit(false);
}, 5000);
}}
>
<IconRepeat size={14} />
</Button>
) : (
<div style={{ height: "24px" }}></div>
)}
<Button
disabled={
isSubmit ||
!dataStation?.apc_1_ip ||
dataStation?.apc1?.status !== "CONNECTED"
}
title={
listOutletSelected.filter((el) => el.apc === 1).length ===
listOutlet.length
? "Deselect All"
: "Select All"
}
// mt={'xs'}
className={classes.buttonMenuTool}
variant="filled"
onClick={() => {
if (
listOutletSelected.filter((el) => el.apc === 1).length ===
listOutlet.filter((el) => el.apc === 1).length
) {
setListOutletSelected([]);
} else {
setListOutletSelected(
listOutlet
.filter((el) => el.apc === 1)
.map((el) => ({ ...el, apc: 1 }))
);
}
}}
>
{listOutletSelected.filter((el) => el.apc === 1).length ===
listOutlet.filter((el) => el.apc === 1).length
? "Deselect"
: "Select All"}
</Button>
<Button
className={classes.buttonMenuTool}
disabled={
isSubmit ||
listOutlet.filter((el) => el.apc === 1).length === 0 ||
listOutletSelected.filter((el) => el.apc === 1).length ===
0 ||
dataStation?.apc1?.status === "DISCONNECTED" ||
dataStation?.apc1?.status === "TIMEOUT"
}
title={"Restart"}
variant="filled"
color="yellow"
onClick={() => {
socket?.emit("control_apc", {
outletNumbers: listOutletSelected
.filter((el) => el.apc === 1)
.map((el) => el.number),
station: { ...stationAPI, lines: [] },
action: "restart",
apcName: "apc_1",
});
setListOutletSelected([]);
setIsSubmit(true);
setTimeout(() => {
setIsSubmit(false);
}, 5000);
}}
>
Restart
</Button>
<Button
disabled={
isSubmit ||
listOutlet.filter((el) => el.apc === 1).length === 0 ||
listOutletSelected.filter((el) => el.apc === 1).length ===
0 ||
dataStation?.apc1?.status === "DISCONNECTED" ||
dataStation?.apc1?.status === "TIMEOUT"
}
title={"Turn On"}
// mt={'xs'}
className={classes.buttonMenuTool}
variant="filled"
color="green"
onClick={() => {
socket?.emit("control_apc", {
outletNumbers: listOutletSelected
.filter((el) => el.apc === 1)
.map((el) => el.number),
station: { ...stationAPI, lines: [] },
action: "on",
apcName: "apc_1",
});
setListOutletSelected([]);
setIsSubmit(true);
setTimeout(() => {
setIsSubmit(false);
}, 5000);
}}
>
Turn On
</Button>
<Button
disabled={
isSubmit ||
listOutlet.filter((el) => el.apc === 1).length === 0 ||
listOutletSelected.filter((el) => el.apc === 1).length ===
0 ||
dataStation?.apc1?.status === "DISCONNECTED" ||
dataStation?.apc1?.status === "TIMEOUT"
}
title={"Turn Off"}
// mt={'xs'}
className={classes.buttonMenuTool}
variant="filled"
color="red"
onClick={() => {
socket?.emit("control_apc", {
outletNumbers: listOutletSelected
.filter((el) => el.apc === 1)
.map((el) => el.number),
station: { ...stationAPI, lines: [] },
action: "off",
apcName: "apc_1",
});
setListOutletSelected([]);
setIsSubmit(true);
setTimeout(() => {
setIsSubmit(false);
}, 5000);
}}
>
Turn Off
</Button>
</div>
</legend>
<Box>
<Box
style={{
display: "flex",
flexWrap: "wrap",
gap: "10px",
paddingTop: "8px",
paddingBottom: "8px",
}}
>
{listOutlet
.filter((el) => el.apc === 1)
.map((outlet, i) => (
<Card
key={i}
shadow="sm"
padding="xs"
radius="md"
withBorder
className={`${
isSubmit || !dataStation?.apc_1_ip
? classes.isDisabled
: ""
}`}
style={{
paddingLeft: 0,
paddingRight: 0,
width: "65px",
position: "relative",
cursor: "pointer",
textAlign: "center",
border: listOutletSelected.find(
(el) => el.name === outlet.name && el.apc === outlet.apc
)?.name
? "1px solid #0018ff"
: "",
}}
onClick={() => {
toggleSelect(outlet, i + 1);
}}
>
<Text
fw={500}
fz={"12px"}
style={{
color: outlet.status === "ON" ? "#40c057" : "#f03e3e",
}}
>
{findLineByOutlet(outlet)
? "Line " + findLineByOutlet(outlet)?.lineNumber
: outlet.name}
</Text>
</Card>
))}
</Box>
</Box>
</fieldset>
</Grid.Col>
<Grid.Col span={6}>
<fieldset style={{ padding: "4px 6px" }}>
<legend>
<div className={classes.titleAPC}>
<Text fw={700} c={"#514d4d"} fz={"xs"}>
APC 2
</Text>
{dataStation?.apc_2_ip ? (
RenderAPCStatus(dataStation?.apc2)
) : (
<Text fw={800} c="red" fz={"12px"}>
APC not available
</Text>
)}
{dataStation?.apc2?.status !== "CONNECTED" ? (
<Button
style={{ height: "24px" }}
size="xs"
disabled={isSubmit || !dataStation?.apc_2_ip}
variant="filled"
color="yellow"
onClick={() => {
socket?.emit("control_apc", {
outletNumbers: [],
station: { ...stationAPI, lines: [] },
action: "reconnect",
apcName: "apc_2",
});
setListOutletSelected([]);
setIsSubmit(true);
setTimeout(() => {
setIsSubmit(false);
}, 5000);
}}
>
<IconRepeat size={14} />
</Button>
) : (
<div style={{ height: "24px" }}></div>
)}
<Button
disabled={
isSubmit ||
!dataStation?.apc_2_ip ||
dataStation?.apc2?.status !== "CONNECTED"
}
title={
listOutletSelected.filter((el) => el.apc === 2).length ===
listOutlet.length
? "Deselect All"
: "Select All"
}
className={classes.buttonMenuTool}
variant="filled"
onClick={() => {
if (
listOutletSelected.filter((el) => el.apc === 2).length ===
listOutlet.filter((el) => el.apc === 2).length
) {
setListOutletSelected([]);
} else {
setListOutletSelected(
listOutlet
.filter((el) => el.apc === 2)
.map((el) => ({ ...el }))
);
}
}}
>
{listOutletSelected.filter((el) => el.apc === 2).length ===
listOutlet.filter((el) => el.apc === 2).length
? "Deselect"
: "Select All"}
</Button>
<Button
disabled={
isSubmit ||
listOutlet.filter((el) => el.apc === 2).length === 0 ||
listOutletSelected.filter((el) => el.apc === 2).length ===
0 ||
dataStation?.apc2?.status === "DISCONNECTED" ||
dataStation?.apc2?.status === "TIMEOUT"
}
title={"Restart"}
className={classes.buttonMenuTool}
variant="filled"
color="yellow"
onClick={() => {
socket?.emit("control_apc", {
outletNumbers: listOutletSelected
.filter((el) => el.apc === 2)
.map((el) => el.number),
station: { ...stationAPI, lines: [] },
action: "restart",
apcName: "apc_2",
});
setListOutletSelected([]);
setIsSubmit(true);
setTimeout(() => {
setIsSubmit(false);
}, 5000);
}}
>
Restart
</Button>
<Button
disabled={
isSubmit ||
listOutlet.filter((el) => el.apc === 2).length === 0 ||
listOutletSelected.filter((el) => el.apc === 2).length ===
0 ||
dataStation?.apc2?.status === "DISCONNECTED" ||
dataStation?.apc2?.status === "TIMEOUT"
}
title={"Turn On All"}
className={classes.buttonMenuTool}
variant="filled"
color="green"
onClick={() => {
socket?.emit("control_apc", {
outletNumbers: listOutletSelected
.filter((el) => el.apc === 2)
.map((el) => el.number),
station: { ...stationAPI, lines: [] },
action: "on",
apcName: "apc_2",
});
setListOutletSelected([]);
setIsSubmit(true);
setTimeout(() => {
setIsSubmit(false);
}, 5000);
}}
>
Turn On
</Button>
<Button
disabled={
isSubmit ||
listOutlet.filter((el) => el.apc === 2).length === 0 ||
listOutletSelected.filter((el) => el.apc === 2).length ===
0 ||
dataStation?.apc2?.status === "DISCONNECTED" ||
dataStation?.apc2?.status === "TIMEOUT"
}
className={classes.buttonMenuTool}
title={"Turn Off"}
// mt={'xs'}
miw={"80px"}
size="xs"
fz={"xs"}
variant="filled"
color="red"
onClick={() => {
socket?.emit("control_apc", {
outletNumbers: listOutletSelected
.filter((el) => el.apc === 2)
.map((el) => el.number),
station: { ...stationAPI, lines: [] },
action: "off",
apcName: "apc_2",
});
setListOutletSelected([]);
setIsSubmit(true);
setTimeout(() => {
setIsSubmit(false);
}, 5000);
}}
>
Turn Off
</Button>
</div>
</legend>
<Box>
<Box
style={{
display: "flex",
flexWrap: "wrap",
gap: "10px",
paddingTop: "8px",
paddingBottom: "8px",
}}
>
{listOutlet
.filter((el) => el.apc === 2)
.map((outlet, i) => (
<Card
key={i}
shadow="sm"
padding="xs"
radius="md"
withBorder
className={`${
isSubmit || !dataStation?.apc_2_ip
? classes.isDisabled
: ""
}`}
style={{
paddingLeft: 0,
paddingRight: 0,
width: "65px",
position: "relative",
cursor: "pointer",
textAlign: "center",
border: listOutletSelected.find(
(el) => el.name === outlet.name && el.apc === outlet.apc
)?.name
? "1px solid #0018ff"
: "",
}}
onClick={() => {
toggleSelect(outlet, i + 1);
}}
>
<Text
fw={500}
fz={"12px"}
style={{
color: outlet.status === "ON" ? "#40c057" : "#f03e3e",
}}
>
{findLineByOutlet(outlet)
? "Line " + findLineByOutlet(outlet)?.lineNumber
: outlet.name}
</Text>
</Card>
))}
</Box>
</Box>
</fieldset>
</Grid.Col>
</Grid>
);
};
export const DrawerSwitchControl: React.FC<DrawerProps> = ({
stationAPI,
socket,
}) => {
const [listPorts, setListPorts] = useState<SwitchPortsProps[][]>([]);
const [dataStation, setDataStation] = useState<TStation>(stationAPI);
const [listPortsSelected, setListPortsSelected] = useState<
SwitchPortsProps[]
>([]);
const [isSubmit, setIsSubmit] = useState(false);
const [loading, setLoading] = useState(true);
const [checkedActive, setCheckedActive] = useState("all");
useEffect(() => {
if (!open) {
setListPortsSelected([]);
setLoading(true);
}
}, [open]);
useEffect(() => {
const value = localStorage.getItem("show-switch-port");
if (value) {
setCheckedActive(value);
}
}, []);
useEffect(() => {
if (loading)
setTimeout(() => {
setLoading(false);
}, 15000);
}, [loading]);
useEffect(() => {
socket?.on("switch_output", (data) => {
if (data.stationId !== stationAPI.id) return;
if (data?.portGroups && data?.portGroups.length > 0)
setListPorts(data?.portGroups || []);
setLoading(false);
setDataStation({ ...dataStation, switch: { status: data.status } });
});
return () => {
socket?.off("switch_output");
};
}, [socket, dataStation, stationAPI]);
const toggleSelect = (port: SwitchPortsProps) => {
setListPortsSelected((prev) =>
prev.find((pid) => pid.name === port.name)
? prev.filter((pid) => pid.name !== port.name)
: [...prev, { ...port }]
);
};
const RenderAPCStatus = (apc: APCProps) => {
switch (apc.status) {
case "CONNECTED":
return (
<>
<Text size="sm" fw={800} c="green">
{apc.status}
</Text>
</>
);
case "DISCONNECTED":
return (
<>
<Text size="sm" fw={800} c="red">
{apc.status}
</Text>
</>
);
case "TIMEOUT":
return (
<>
<Text size="sm" fw={800} c="yellow">
{apc.status}
</Text>
</>
);
default:
return (
<>
{/* <Text size="sm" fw={800} c="blue">
{line.status}
</Text> */}
</>
);
}
};
const sortedPorts = (ports: SwitchPortsProps[]) => {
return ports.sort((a: SwitchPortsProps, b: SwitchPortsProps) => {
const splitNameA = a.name.split("/");
const splitNameB = b.name.split("/");
const numA = parseInt(splitNameA[splitNameA.length - 1], 10);
const numB = parseInt(splitNameB[splitNameB.length - 1], 10);
const isOddA = numA % 2 !== 0;
const isOddB = numB % 2 !== 0;
// if (numA / 48 > 1) return 0;
// Ưu tiên số lẻ lên trước
if (isOddA && !isOddB) return -1;
if (!isOddA && isOddB) return 1;
// Cùng là chẵn hoặc cùng là lẻ -> sắp theo thứ tự tăng dần
return numA - numB;
});
};
const normalizePortName = (port: string): string => {
if (!port) return "";
// Example inputs: "Fa0/1", "Gi0/0/1", "Fa0/0/2"
const match = port.match(/^([A-Za-z]+)([\d/]+)$/);
if (!match) return port;
// const type = match[1]; // Fa, Gi, Te, etc.
const numbers = match[2]; // "0/1" / "0/0/1" / "0/0/2"
// Get the last part after slash
const parts = numbers.split("/");
const last = parts[parts.length - 1];
return `${last}`;
};
const convertPortName = (port: string): string => {
if (!port) return "";
// Example inputs: "Fa0/1", "Gi0/0/1", "Fa0/0/2"
const match = port.match(/^([A-Za-z]+)([\d/]+)$/);
if (!match) return port;
const type = match[1]; // Fa, Gi, Te, etc.
const numbers = match[2]; // "0/1" / "0/0/1" / "0/0/2"
// Get the last part after slash
const parts = numbers.split("/");
const last = parts[parts.length - 1];
return `${type?.slice(0, 2)}${last}`;
};
const changeShowPort = (status: string) => {
localStorage.setItem("show-switch-port", status);
setCheckedActive(status);
};
const checkFilterPort = (status: string, portName: string) => {
if (checkedActive === "all") return true;
if (checkedActive === "on") return status === "ON";
if (checkedActive === "off") return status === "OFF";
if (checkedActive === "config") {
const listInterface = stationAPI?.lines
?.filter((el) => el.interface)
.map((el) => convertPortName(el.interface || ""));
return listInterface?.includes(convertPortName(portName));
}
};
return loading ? (
<Box
style={{
height: "10vh",
width: "100%",
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<Loader color="blue" />
</Box>
) : (
<Grid>
<div
style={{
display: "flex",
justifyContent: "space-between",
marginTop: "6px",
minWidth: "98%",
}}
>
<div
style={{
display: "flex",
justifyContent: "left",
marginTop: "6px",
marginBottom: "10px",
gap: "20px",
}}
>
<Box ps={"8px"} pt={"4px"}>
{dataStation?.switch_control_ip ? (
dataStation?.switch ? (
RenderAPCStatus(dataStation?.switch)
) : (
<Text fw={800} c="red" fz={"12px"}>
DISCONNECTED
</Text>
)
) : (
<Text fw={800} c="red" fz={"12px"}>
Switch not available
</Text>
)}
</Box>
{dataStation?.switch?.status !== "CONNECTED" ? (
<Button
size="xs"
disabled={isSubmit || !dataStation?.switch_control_ip}
variant="filled"
color="yellow"
onClick={() => {
socket?.emit("control_switch", {
ports: [],
command: "reconnect",
station: { ...stationAPI, lines: [] },
ip: stationAPI?.switch_control_ip,
});
setIsSubmit(true);
setTimeout(() => {
setIsSubmit(false);
}, 10000);
}}
>
<IconRepeat size={14} />
</Button>
) : (
""
)}
<Button
className={classes.buttonMenuTool}
disabled={isSubmit || !dataStation?.switch_control_ip}
title={
listPortsSelected.length === listPorts.flat().length &&
listPorts.flat().length > 0
? "Deselect All"
: "Select All"
}
miw={"80px"}
size="xs"
fz={"xs"}
variant="filled"
onClick={() => {
if (listPortsSelected.length === listPorts.flat().length) {
setListPortsSelected([]);
} else {
setListPortsSelected(listPorts.flat());
}
}}
>
{listPortsSelected.length === listPorts.flat().length &&
listPorts.flat().length > 0
? "Clear All"
: "Select All"}
</Button>
<Button
className={classes.buttonMenuTool}
disabled={
isSubmit ||
listPorts.flat().length === 0 ||
listPortsSelected.length === 0 ||
(dataStation?.switch &&
(dataStation?.switch?.status === "DISCONNECTED" ||
dataStation?.switch?.status === "TIMEOUT"))
}
title={
listPortsSelected.length === 0 ||
listPortsSelected.length === listPorts.flat().length
? "Restart All"
: "Restart Selected"
}
// mt={'xs'}
miw={"80px"}
size="xs"
fz={"xs"}
variant="filled"
color="yellow"
onClick={() => {
const listPortsRestart =
listPortsSelected?.length > 0
? listPortsSelected
: listPorts.flat();
if (listPortsRestart.filter((el) => el.poe !== "ON").length > 0)
socket?.emit("control_switch", {
ports: listPortsRestart
.filter((el) => el.poe !== "ON")
.map((el) => el.name),
command: "restart",
station: { ...stationAPI, lines: [] },
ip: stationAPI?.switch_control_ip,
});
if (listPortsRestart.filter((el) => el.poe === "ON").length > 0)
socket?.emit("control_switch", {
ports: listPortsRestart
.filter((el) => el.poe === "ON")
.map((el) => el.name),
command: "restart-poe",
station: { ...stationAPI, lines: [] },
ip: stationAPI?.switch_control_ip,
});
setListPortsSelected([]);
setIsSubmit(true);
setTimeout(() => {
setIsSubmit(false);
}, 15000);
}}
>
{listPortsSelected.length === 0 ||
listPortsSelected.length === listPorts.flat().length
? "Restart All"
: "Restart Selected"}
</Button>
<Button
className={classes.buttonMenuTool}
disabled={
isSubmit ||
listPorts.flat().length === 0 ||
listPortsSelected.length === 0 ||
(dataStation?.switch &&
(dataStation?.switch?.status === "DISCONNECTED" ||
dataStation?.switch?.status === "TIMEOUT"))
}
title={
listPortsSelected.length === 0 ||
listPortsSelected.length === listPorts.flat().length
? "Turn On All"
: "Turn On Selected"
}
// mt={'xs'}
miw={"80px"}
size="xs"
fz={"xs"}
variant="filled"
color="green"
onClick={() => {
const listPortsRestart =
listPortsSelected?.length > 0
? listPortsSelected
: listPorts.flat();
if (listPortsRestart.filter((el) => el.poe !== "ON").length > 0)
socket?.emit("control_switch", {
ports: listPortsRestart
.filter((el) => el.poe !== "ON")
.map((el) => el.name),
command: "on",
station: { ...stationAPI, lines: [] },
ip: stationAPI?.switch_control_ip,
});
if (listPortsRestart.filter((el) => el.poe === "ON").length > 0)
socket?.emit("control_switch", {
ports: listPortsRestart
.filter((el) => el.poe === "ON")
.map((el) => el.name),
command: "on-poe",
station: { ...stationAPI, lines: [] },
ip: stationAPI?.switch_control_ip,
});
setListPortsSelected([]);
setIsSubmit(true);
setTimeout(() => {
setIsSubmit(false);
}, 10000);
}}
>
{listPortsSelected.length === 0 ||
listPortsSelected.length === listPorts.flat().length
? "Turn On All"
: "Turn On Selected"}
</Button>
<Button
className={classes.buttonMenuTool}
disabled={
isSubmit ||
listPorts.flat().length === 0 ||
listPortsSelected.length === 0 ||
(dataStation?.switch &&
(dataStation?.switch?.status === "DISCONNECTED" ||
dataStation?.switch?.status === "TIMEOUT"))
}
title={
listPortsSelected.length === 0 ||
listPortsSelected.length === listPorts.flat().length
? "Turn Off All"
: "Turn Off Selected"
}
// mt={'xs'}
miw={"80px"}
size="xs"
fz={"xs"}
variant="filled"
color="red"
onClick={() => {
const listPortsRestart =
listPortsSelected?.length > 0
? listPortsSelected
: listPorts.flat();
if (listPortsRestart.filter((el) => el.poe !== "ON").length > 0)
socket?.emit("control_switch", {
ports: listPortsRestart
.filter((el) => el.poe !== "ON")
.map((el) => el.name),
command: "off",
station: { ...stationAPI, lines: [] },
ip: stationAPI?.switch_control_ip,
});
if (listPortsRestart.filter((el) => el.poe === "ON").length > 0)
socket?.emit("control_switch", {
ports: listPortsRestart
.filter((el) => el.poe === "ON")
.map((el) => el.name),
command: "off-poe",
station: { ...stationAPI, lines: [] },
ip: stationAPI?.switch_control_ip,
});
setListPortsSelected([]);
setIsSubmit(true);
setTimeout(() => {
setIsSubmit(false);
}, 10000);
}}
>
{listPortsSelected.length === 0 ||
listPortsSelected.length === listPorts.flat().length
? "Turn Off All"
: "Turn Off Selected"}
</Button>
<Group ms="xs" style={{ display: "flex", gap: "8px" }}>
<Radio
value="all"
label="All"
checked={checkedActive === "all"}
onChange={() => changeShowPort("all")}
/>
<Radio
value="on"
label="On"
checked={checkedActive === "on"}
onChange={() => changeShowPort("on")}
/>
<Radio
value="off"
label="Off"
checked={checkedActive === "off"}
onChange={() => changeShowPort("off")}
/>
<Radio
value="config"
label="Config interface"
checked={checkedActive === "config"}
onChange={() => changeShowPort("config")}
/>
</Group>
</div>
</div>
<Grid.Col span={12} pt={"4px"}>
{listPorts?.length > 0 && (
<Box>
<Grid>
{listPorts?.map((group, key) => {
const isMini = group?.length > 0 && group?.length < 4;
const isLarge = group?.length > 20;
return (
<Grid.Col
pt={0}
key={key}
span={isLarge ? 11 : isMini ? 1 : 12}
>
{isLarge ? (
<fieldset
style={{
padding: "0px 4px",
}}
>
<legend>
<Text fw={700} c={"#514d4d"} fz={"xs"}>
{group[0]?.name.substring(0, 2) || ""}
</Text>
</legend>
<ScrollArea h={"11vh"} w={"67vw"}>
<Flex gap={"8px"} wrap={"nowrap"}>
{sortedPorts(group)
.slice(0, sortedPorts(group).length / 2)
.filter((el) =>
checkFilterPort(el.status, el.name)
)
?.map((port, i) => (
<Card
key={i}
shadow="sm"
padding="xs"
radius="md"
withBorder
style={{
flex: "0 0 auto",
position: "relative",
width: "50px",
height: "40px",
backgroundColor:
port.poe === "ON"
? "#f2dcf8"
: port.status === "ON"
? "#d4f1d3"
: "#f5f5f5",
cursor: "pointer",
border: listPortsSelected.find(
(el) => el.name === port.name
)?.name
? "1px solid #0018ff"
: "",
}}
className={`${
isSubmit ? classes.isDisabled : ""
}`}
onClick={() => {
toggleSelect(port);
}}
>
<Box
style={{
display: "flex",
alignItems: "center",
gap: "2px",
flexDirection: "column",
flexWrap: "wrap",
}}
>
<Text fw={500} fz={"11px"}>
{normalizePortName(port.name)}
</Text>
</Box>
<Box
style={{
display:
port.poe === "ON" ? "block" : "none",
position: "absolute",
bottom: "2px",
right: "2px",
zIndex: 10,
}}
>
<Text size="10px" fs={"italic"}>
poe
</Text>
</Box>
</Card>
))}
</Flex>
<Flex gap={"8px"} wrap={"nowrap"} mt={"8px"}>
{sortedPorts(group)
.slice(
sortedPorts(group).length / 2,
sortedPorts(group).length
)
.filter((el) =>
checkFilterPort(el.status, el.name)
)
?.map((port, i) => (
<Card
key={i}
shadow="sm"
padding="xs"
radius="md"
withBorder
style={{
flex: "0 0 auto",
position: "relative",
width: "50px",
height: "40px",
backgroundColor:
port.poe === "ON"
? "#f2dcf8"
: port.status === "ON"
? "#d4f1d3"
: "#f5f5f5",
cursor: "pointer",
border: listPortsSelected.find(
(el) => el.name === port.name
)?.name
? "1px solid #0018ff"
: "",
}}
className={`${
isSubmit ? classes.isDisabled : ""
}`}
onClick={() => {
toggleSelect(port);
}}
>
<Box
style={{
display: "flex",
alignItems: "center",
gap: "2px",
flexDirection: "column",
flexWrap: "wrap",
}}
>
<Text fw={500} fz={"11px"}>
{normalizePortName(port.name)}
</Text>
</Box>
</Card>
))}
</Flex>
</ScrollArea>
</fieldset>
) : (
<fieldset
style={{
padding: "0px 4px",
}}
>
<legend>
<Text fw={700} c={"#514d4d"} fz={"xs"}>
{group[0]?.name.substring(0, 2) || ""}
</Text>
</legend>
<Box
style={{
display: "flex",
flexDirection: "column",
// flexWrap: "wrap",
// justifyContent: "center",
alignItems: "center",
gap: "8px",
overflow: "auto",
height: "11vh",
maxWidth: "70vw",
}}
>
{sortedPorts(group)
?.filter((el) =>
checkFilterPort(el.status, el.name)
)
?.map((port, i) => (
<Card
key={i}
shadow="sm"
padding="xs"
radius="md"
withBorder
style={{
position: "relative",
width: "50px",
height: "40px",
backgroundColor:
port.poe === "ON"
? "#f2dcf8"
: port.status === "ON"
? "#d4f1d3"
: "#f5f5f5",
cursor: "pointer",
border: listPortsSelected.find(
(el) => el.name === port.name
)?.name
? "1px solid #0018ff"
: "",
}}
className={`${
isSubmit ? classes.isDisabled : ""
}`}
onClick={() => {
toggleSelect(port);
}}
>
<Box
style={{
display: "flex",
alignItems: "center",
gap: "2px",
flexDirection: "column",
flexWrap: "wrap",
}}
>
{/* <IconSection
size={"12px"}
color={
port.poe === "ON"
? "#b722d4"
: port.status === "ON"
? "#40c057"
: "#b8b8b8"
}
/> */}
<Text fw={500} fz={"11px"}>
{normalizePortName(port.name)}
</Text>
</Box>
</Card>
))}
</Box>
</fieldset>
)}
</Grid.Col>
);
})}
</Grid>
</Box>
)}
</Grid.Col>
</Grid>
);
};