diff --git a/BACKEND/app/services/line_connection.ts b/BACKEND/app/services/line_connection.ts
index 40cad37..fe1c529 100644
--- a/BACKEND/app/services/line_connection.ts
+++ b/BACKEND/app/services/line_connection.ts
@@ -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`,
+ })
}
/**
diff --git a/BACKEND/app/services/physical_test_service.ts b/BACKEND/app/services/physical_test_service.ts
index 22bbfde..d3ab5c6 100644
--- a/BACKEND/app/services/physical_test_service.ts
+++ b/BACKEND/app/services/physical_test_service.ts
@@ -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 `
Physical Ports Test Report
@@ -181,29 +181,32 @@ export class PhysicalPortTest {
- ${missing.length
- ? `
+ ${
+ missing.length
+ ? `
────────────────────────────────
Missing Ports
- ${missingPoE?.length
- ? `|
+ ${
+ missingPoE?.length
+ ? ` |
${missingPoE.map((p) => this.normalizePortName(p.name)).join(' ')}
| `
- : ''
- }
- ${missingSFP?.length
- ? `
+ : ''
+ }
+ ${
+ missingSFP?.length
+ ? ` |
${missingSFP.map((p) => this.normalizePortName(p.name)).join(' ')}
| `
- : ''
- }
+ : ''
+ }
`
- : ''
- }
+ : ''
+ }
`.trim()
diff --git a/FRONTEND/src/App.tsx b/FRONTEND/src/App.tsx
index 3e5b644..87f9bfa 100644
--- a/FRONTEND/src/App.tsx
+++ b/FRONTEND/src/App.tsx
@@ -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(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}
/>
{/* el.id === Number(activeTab))}
/>
+
+
);
}
diff --git a/FRONTEND/src/components/Modal/ModalConfirmRunPhysicalTest.tsx b/FRONTEND/src/components/Modal/ModalConfirmRunPhysicalTest.tsx
index e34228d..f65c33d 100644
--- a/FRONTEND/src/components/Modal/ModalConfirmRunPhysicalTest.tsx
+++ b/FRONTEND/src/components/Modal/ModalConfirmRunPhysicalTest.tsx
@@ -65,7 +65,7 @@ export default function ModalConfirmRunPhysical({
title="Confirm Run Test Ports"
>
-
+
{dataLines.map((line, i) => (
-
+
Line: {line.lineNumber}
-
+
PID: {line.pid || ""}
-
+
SN: {line.sn || ""}
-
+
VID: {line.vid || ""}
diff --git a/FRONTEND/src/components/Modal/ModalSummaryTested.tsx b/FRONTEND/src/components/Modal/ModalSummaryTested.tsx
new file mode 100644
index 0000000..c7630bd
--- /dev/null
+++ b/FRONTEND/src/components/Modal/ModalSummaryTested.tsx
@@ -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) => void;
+}
+
+export default function ModalSummaryTested({ data, setData }: Props) {
+ return (
+ {
+ setData(null);
+ }}
+ title="Summary"
+ >
+
+
+
+ {data?.title}
+
+
+
+
+
+
+
+ );
+}
diff --git a/FRONTEND/src/components/Modal/ModalTerminal.tsx b/FRONTEND/src/components/Modal/ModalTerminal.tsx
index 60a38d7..8ee94e7 100644
--- a/FRONTEND/src/components/Modal/ModalTerminal.tsx
+++ b/FRONTEND/src/components/Modal/ModalTerminal.tsx
@@ -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) => void;
setLinesConfirmSkipPort: (value: React.SetStateAction) => 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 &&
diff --git a/FRONTEND/src/untils/types.ts b/FRONTEND/src/untils/types.ts
index d660a6f..e1ef1fe 100644
--- a/FRONTEND/src/untils/types.ts
+++ b/FRONTEND/src/untils/types.ts
@@ -300,3 +300,8 @@ export type Keywords = {
match_type: string;
is_active: boolean;
};
+
+export type DataSummaryTested = {
+ body: string;
+ title: string;
+};