Merge pull request 'Enhance port filtering and UI in DrawerControl' (#1) from that into main
Reviewed-on: #1
This commit is contained in:
commit
55e2115fdf
|
|
@ -411,7 +411,7 @@ function App() {
|
|||
borderRadius: 8,
|
||||
}}
|
||||
>
|
||||
<ScrollArea h={expandedBottomBar ? "70vh" : "85vh"}>
|
||||
<ScrollArea h={expandedBottomBar ? "68vh" : "85vh"}>
|
||||
{station.lines.length > 8 ? (
|
||||
<Grid
|
||||
style={{
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ const BottomToolBar = ({
|
|||
<motion.div
|
||||
initial={false}
|
||||
animate={{
|
||||
height: isExpand ? "18vh" : 0,
|
||||
height: isExpand ? "20vh" : 0,
|
||||
y: 0, // đẩy xuống khi thu nhỏ
|
||||
}}
|
||||
transition={{ type: "spring", stiffness: 180, damping: 20 }}
|
||||
|
|
@ -115,7 +115,7 @@ const BottomToolBar = ({
|
|||
setActiveTabBottom(val || "command");
|
||||
}}
|
||||
className={classes.containerBottom}
|
||||
style={{ height: "18vh" }}
|
||||
style={{ height: "20vh" }}
|
||||
>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab
|
||||
|
|
@ -157,7 +157,7 @@ const BottomToolBar = ({
|
|||
|
||||
<Tabs.Panel value="command" p={"xs"}>
|
||||
<Flex justify={"space-between"}>
|
||||
<ScrollArea h={"13vh"}>
|
||||
<ScrollArea h={"15vh"}>
|
||||
<Flex wrap={"wrap"} gap={"xs"} w={"400px"}>
|
||||
{selectedLines.map((el) => (
|
||||
<Box
|
||||
|
|
|
|||
|
|
@ -792,19 +792,14 @@ export const DrawerSwitchControl: React.FC<DrawerProps> = ({
|
|||
const normalizePortName = (port: string): string => {
|
||||
if (!port) return "";
|
||||
|
||||
// Example inputs: "Fa0/1", "Gi0/0/1", "Fa0/0/2"
|
||||
// Match interface type + numeric hierarchy (e.g. "Gi" + "1/0/24")
|
||||
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"
|
||||
const numbers = match[2]; // e.g. "1/0/24"
|
||||
|
||||
// Get the last part after slash
|
||||
const parts = numbers.split("/");
|
||||
const last = parts[parts.length - 1];
|
||||
|
||||
return `${type}${last}`;
|
||||
return numbers;
|
||||
};
|
||||
|
||||
const changeShowPort = (status: string) => {
|
||||
|
|
@ -812,6 +807,18 @@ export const DrawerSwitchControl: React.FC<DrawerProps> = ({
|
|||
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) => el.interface);
|
||||
return listInterface?.includes(portName);
|
||||
}
|
||||
};
|
||||
|
||||
return loading ? (
|
||||
<Box
|
||||
style={{
|
||||
|
|
@ -830,7 +837,6 @@ export const DrawerSwitchControl: React.FC<DrawerProps> = ({
|
|||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
borderTop: "1px #ccc solid",
|
||||
marginTop: "6px",
|
||||
minWidth: "98%",
|
||||
}}
|
||||
|
|
@ -878,6 +884,7 @@ export const DrawerSwitchControl: React.FC<DrawerProps> = ({
|
|||
""
|
||||
)}
|
||||
<Button
|
||||
className={classes.buttonMenuTool}
|
||||
disabled={isSubmit}
|
||||
title={
|
||||
listPortsSelected.length === listPorts.flat().length
|
||||
|
|
@ -902,6 +909,7 @@ export const DrawerSwitchControl: React.FC<DrawerProps> = ({
|
|||
{"(" + listPorts.flat().length + ")"}
|
||||
</Button>
|
||||
<Button
|
||||
className={classes.buttonMenuTool}
|
||||
disabled={
|
||||
isSubmit ||
|
||||
listPorts.flat().length === 0 ||
|
||||
|
|
@ -958,6 +966,7 @@ export const DrawerSwitchControl: React.FC<DrawerProps> = ({
|
|||
: "Restart Selected"}
|
||||
</Button>
|
||||
<Button
|
||||
className={classes.buttonMenuTool}
|
||||
disabled={
|
||||
isSubmit ||
|
||||
listPorts.flat().length === 0 ||
|
||||
|
|
@ -1014,6 +1023,7 @@ export const DrawerSwitchControl: React.FC<DrawerProps> = ({
|
|||
: "Turn On Selected"}
|
||||
</Button>
|
||||
<Button
|
||||
className={classes.buttonMenuTool}
|
||||
disabled={
|
||||
isSubmit ||
|
||||
listPorts.flat().length === 0 ||
|
||||
|
|
@ -1088,6 +1098,12 @@ export const DrawerSwitchControl: React.FC<DrawerProps> = ({
|
|||
checked={checkedActive === "off"}
|
||||
onChange={() => changeShowPort("off")}
|
||||
/>
|
||||
<Radio
|
||||
value="config"
|
||||
label="Config interface"
|
||||
checked={checkedActive === "config"}
|
||||
onChange={() => changeShowPort("config")}
|
||||
/>
|
||||
</Group>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1106,186 +1122,197 @@ export const DrawerSwitchControl: React.FC<DrawerProps> = ({
|
|||
span={isLarge ? 11 : isMini ? 1 : 12}
|
||||
>
|
||||
{isLarge ? (
|
||||
<ScrollArea h={"12vh"} w={"68vw"}>
|
||||
<Flex gap={"8px"} wrap={"nowrap"}>
|
||||
{sortedPorts(group)
|
||||
.slice(0, sortedPorts(group).length / 2)
|
||||
.filter((el) => {
|
||||
if (checkedActive === "all") return true;
|
||||
if (checkedActive === "on")
|
||||
return el.status === "ON";
|
||||
if (checkedActive === "off")
|
||||
return el.status === "OFF";
|
||||
})
|
||||
?.map((port, i) => (
|
||||
<Card
|
||||
key={i}
|
||||
shadow="sm"
|
||||
padding="xs"
|
||||
radius="md"
|
||||
withBorder
|
||||
style={{
|
||||
flex: "0 0 auto",
|
||||
position: "relative",
|
||||
width: "50px",
|
||||
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>
|
||||
<Flex gap={"8px"} wrap={"nowrap"} mt={"8px"} pb={"xs"}>
|
||||
{sortedPorts(group)
|
||||
.slice(
|
||||
sortedPorts(group).length / 2,
|
||||
sortedPorts(group).length
|
||||
)
|
||||
.filter((el) => {
|
||||
if (checkedActive === "all") return true;
|
||||
if (checkedActive === "on")
|
||||
return el.status === "ON";
|
||||
if (checkedActive === "off")
|
||||
return el.status === "OFF";
|
||||
})
|
||||
?.map((port, i) => (
|
||||
<Card
|
||||
key={i}
|
||||
shadow="sm"
|
||||
padding="xs"
|
||||
radius="md"
|
||||
withBorder
|
||||
style={{
|
||||
flex: "0 0 auto",
|
||||
position: "relative",
|
||||
width: "50px",
|
||||
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>
|
||||
) : (
|
||||
<Box
|
||||
<fieldset
|
||||
style={{
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
justifyContent: "center",
|
||||
gap: "10px",
|
||||
overflow: "auto",
|
||||
maxHeight: "12vh",
|
||||
maxWidth: "70vw",
|
||||
borderLeft: "1px solid #dedede",
|
||||
padding: "0px 4px",
|
||||
}}
|
||||
>
|
||||
{sortedPorts(group)
|
||||
?.filter((el) => {
|
||||
if (checkedActive === "all") return true;
|
||||
if (checkedActive === "on")
|
||||
return el.status === "ON";
|
||||
if (checkedActive === "off")
|
||||
return el.status === "OFF";
|
||||
})
|
||||
?.map((port, i) => (
|
||||
<Card
|
||||
key={i}
|
||||
shadow="sm"
|
||||
padding="xs"
|
||||
radius="md"
|
||||
withBorder
|
||||
style={{
|
||||
position: "relative",
|
||||
width: "50px",
|
||||
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
|
||||
<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>
|
||||
</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",
|
||||
flexWrap: "wrap",
|
||||
justifyContent: "center",
|
||||
gap: "10px",
|
||||
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={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "2px",
|
||||
flexDirection: "column",
|
||||
flexWrap: "wrap",
|
||||
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);
|
||||
}}
|
||||
>
|
||||
{/* <IconSection
|
||||
<Box
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "2px",
|
||||
flexDirection: "column",
|
||||
flexWrap: "wrap",
|
||||
}}
|
||||
>
|
||||
{/* <IconSection
|
||||
size={"12px"}
|
||||
color={
|
||||
port.poe === "ON"
|
||||
|
|
@ -1295,13 +1322,14 @@ export const DrawerSwitchControl: React.FC<DrawerProps> = ({
|
|||
: "#b8b8b8"
|
||||
}
|
||||
/> */}
|
||||
<Text fw={500} fz={"11px"}>
|
||||
{normalizePortName(port.name)}
|
||||
</Text>
|
||||
</Box>
|
||||
</Card>
|
||||
))}
|
||||
</Box>
|
||||
<Text fw={500} fz={"11px"}>
|
||||
{normalizePortName(port.name)}
|
||||
</Text>
|
||||
</Box>
|
||||
</Card>
|
||||
))}
|
||||
</Box>
|
||||
</fieldset>
|
||||
)}
|
||||
</Grid.Col>
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in New Issue