Update confirm before run Physical

This commit is contained in:
nguyentrungthat 2026-04-01 13:31:23 +07:00
parent b715c0773a
commit 2ecb153118
7 changed files with 95 additions and 20 deletions

View File

@ -1908,6 +1908,12 @@ ${log}
`[ATC] - [${config.stationName} - Line: ${config.lineNumber}] - Summary of Testing Results`,
body
)
this.socketIO.emit('summary_tested', {
stationId: this.config.stationId,
lineId: this.config.id,
body: body,
title: `[${config.stationName} - Line: ${config.lineNumber}] - Summary of Testing Results`,
})
}
/**

View File

@ -162,7 +162,7 @@ export class PhysicalPortTest {
const missingPoE = missing.filter((p) => !p.name.includes('SFP'))
const missingSFP = missing.filter((p) => p.name.includes('SFP'))
const status = missing.length === 0 ? 'PASS' : 'WARNING'
const status = missing.length === 0 && tested.length > 0 ? 'PASS' : 'WARNING'
return `
<b>Physical Ports Test Report</b><br/>
@ -181,29 +181,32 @@ export class PhysicalPortTest {
</tr>
</table>
<br/>
${missing.length
? `
${
missing.length
? `
<br/>
<b style="color: #ff0000;">Missing Ports</b><br/>
<table cellpadding="6" cellspacing="0" border="1" style="margin-top: 10px; border-collapse: collapse; width: 100%">
<tr>
${missingPoE?.length
? `<td>
${
missingPoE?.length
? `<td>
<div style="column-count: 12;">${missingPoE.map((p) => this.normalizePortName(p.name)).join('<br/>')}</div>
</td>`
: ''
}
${missingSFP?.length
? `<td>
: ''
}
${
missingSFP?.length
? `<td>
<div style="column-count: 4;">${missingSFP.map((p) => this.normalizePortName(p.name)).join('<br/>')}</div>
</td>`
: ''
}
: ''
}
</tr>
</table>
`
: ''
}
: ''
}
<br/>
<br/>
`.trim()

View File

@ -26,6 +26,7 @@ import {
Box,
} from "@mantine/core";
import type {
DataSummaryTested,
FileInfo,
IScenario,
ReceivedFile,
@ -57,6 +58,7 @@ import { isJsonString } from "./untils/helper";
import BottomToolBar from "./components/BottomToolBar";
import ModalConfirmSkipTestPort from "./components/Modal/ModalConfirmSkipTestPort";
import ModalConfirmRunPhysical from "./components/Modal/ModalConfirmRunPhysicalTest";
import ModalSummaryTested from "./components/Modal/ModalSummaryTested";
// import ModalConfirmRunScenario from "./components/Modal/ModalConfirmRunScenario";
const apiUrl = import.meta.env.VITE_BACKEND_URL;
@ -115,6 +117,8 @@ function App() {
const [linesConfirmRunPhysical, setLinesConfirmRunPhysical] = useState<
TLine[]
>([]);
const [dataSummaryTested, setDataSummaryTested] =
useState<DataSummaryTested | null>(null);
const connectApcSwitch = (station: TStation) => {
if (!station?.is_active) return;
@ -499,6 +503,15 @@ function App() {
}
});
socket?.on("summary_tested", (data) => {
if (data?.body) {
setDataSummaryTested({
body: data?.body || "",
title: data?.title || "",
});
}
});
// ✅ cleanup on unmount or when socket changes
return () => {
socket.off("init");
@ -518,6 +531,7 @@ function App() {
socket.off("user_clear_terminal");
socket.off("test_port_physical");
socket.off("feature_tested");
socket.off("summary_tested");
};
}, [socket, stations, selectedLine]);
@ -990,6 +1004,7 @@ function App() {
listCategories={listCategories}
setLinesConfirmSkipPort={setLinesConfirmSkipPort}
linesConfirmSkipPort={linesConfirmSkipPort}
dataSummaryTested={dataSummaryTested}
/>
{/* <ModalConfirmRunScenario
@ -1011,6 +1026,11 @@ function App() {
socket={socket}
station={stations.find((el) => el.id === Number(activeTab))}
/>
<ModalSummaryTested
data={dataSummaryTested}
setData={setDataSummaryTested}
/>
</Container>
);
}

View File

@ -65,7 +65,7 @@ export default function ModalConfirmRunPhysical({
title="Confirm Run Test Ports"
>
<Box>
<ScrollArea h={"66vh"}>
<ScrollArea h={"50vh"}>
{dataLines.map((line, i) => (
<Box
key={i}
@ -81,6 +81,7 @@ export default function ModalConfirmRunPhysical({
>
<Flex
p={"xs"}
align={"center"}
style={{
fontWeight: 600,
}}
@ -101,16 +102,16 @@ export default function ModalConfirmRunPhysical({
)
}
/>
<Text size="sm" fw={600}>
<Text size="lg" fw={600}>
Line: {line.lineNumber}
</Text>
<Text size="sm" fw={600}>
<Text size="lg" fw={600}>
PID: {line.pid || ""}
</Text>
<Text size="sm" fw={600}>
<Text size="lg" fw={600}>
SN: {line.sn || ""}
</Text>
<Text size="sm" fw={600}>
<Text size="lg" fw={600}>
VID: {line.vid || ""}
</Text>
</Flex>

View File

@ -0,0 +1,32 @@
import { Modal, Box, Text } from "@mantine/core";
import type { DataSummaryTested } from "../../untils/types";
interface Props {
data: DataSummaryTested | null;
setData: (value: React.SetStateAction<DataSummaryTested | null>) => void;
}
export default function ModalSummaryTested({ data, setData }: Props) {
return (
<Modal
size={"70%"}
style={{ position: "absolute", left: 0 }}
opened={data && data?.body ? true : false}
onClose={() => {
setData(null);
}}
title="Summary"
>
<Box>
<Box p={"md"} pt={0}>
<Text fw={"bold"} fz={18}>
{data?.title}
</Text>
</Box>
<Box pt={0} p={"md"}>
<span dangerouslySetInnerHTML={{ __html: data?.body || "" }} />
</Box>
</Box>
</Modal>
);
}

View File

@ -17,6 +17,7 @@ import {
Tooltip,
} from "@mantine/core";
import type {
DataSummaryTested,
FileInfo,
IScenario,
SwitchPortsProps,
@ -83,6 +84,7 @@ const ModalTerminal = ({
setScenarios,
setLinesConfirmSkipPort,
linesConfirmSkipPort,
dataSummaryTested,
}: {
opened: boolean;
onClose: () => void;
@ -100,6 +102,7 @@ const ModalTerminal = ({
setScenarios: (value: React.SetStateAction<IScenario[]>) => void;
setLinesConfirmSkipPort: (value: React.SetStateAction<TLine[]>) => void;
linesConfirmSkipPort: TLine[];
dataSummaryTested: DataSummaryTested | null;
}) => {
const user = useMemo(() => {
return localStorage.getItem("user") &&
@ -547,8 +550,13 @@ const ModalTerminal = ({
setOpenScenarioModal(false);
return;
}
if (openSelectIos) return;
if (linesConfirmSkipPort.length) return;
if (
openSelectIos ||
linesConfirmSkipPort.length > 0 ||
(dataSummaryTested && dataSummaryTested?.body)
)
return;
onClose();
if (
line?.userOpenCLI === user?.userName &&

View File

@ -300,3 +300,8 @@ export type Keywords = {
match_type: string;
is_active: boolean;
};
export type DataSummaryTested = {
body: string;
title: string;
};