Update flow physical test va confirm skip test
This commit is contained in:
parent
faf37c7136
commit
c032a29cdd
|
|
@ -28,7 +28,7 @@ import path from 'node:path'
|
|||
import axios from 'axios'
|
||||
import redis from '@adonisjs/redis/services/main'
|
||||
import Line from '#models/line'
|
||||
import { ErrorRow, TestResult } from '../ultils/types.js'
|
||||
import { CustomSocket, ErrorRow, TestResult } from '../ultils/types.js'
|
||||
import momentTZ from 'moment-timezone'
|
||||
import { PhysicalPortTest } from './physical_test_service.js'
|
||||
import Station from '#models/station'
|
||||
|
|
@ -79,6 +79,8 @@ interface LineConfig {
|
|||
runningPhysical: boolean
|
||||
listFeatureTested: string[]
|
||||
isReady: boolean
|
||||
isSkipPhysical?: boolean
|
||||
reasonSkipPhysical?: string
|
||||
// history: string
|
||||
}
|
||||
|
||||
|
|
@ -201,6 +203,8 @@ export default class LineConnection {
|
|||
status: 'connected',
|
||||
})
|
||||
this.config.listFeatureTested = []
|
||||
this.config.isSkipPhysical = false
|
||||
this.config.reasonSkipPhysical = ''
|
||||
this.sendFeatureTested()
|
||||
this.checkLog()
|
||||
resolve()
|
||||
|
|
@ -296,6 +300,8 @@ export default class LineConnection {
|
|||
this.config.status = 'disconnected'
|
||||
this.config.output += this.config.output + '[CLEAR_TERMINAL_SCROLL_BACK]'
|
||||
this.config.listFeatureTested = []
|
||||
this.config.isSkipPhysical = false
|
||||
this.config.reasonSkipPhysical = ''
|
||||
this.config.latestScenario = undefined
|
||||
this.physicalTest = new PhysicalPortTest([])
|
||||
this.config.isReady = false
|
||||
|
|
@ -1110,7 +1116,9 @@ ${data.issues?.length ? `- ` + data.issues.join(`\n- `) : ''}
|
|||
*****[Physical]*****
|
||||
Total Ports: ${portPhysical?.length}
|
||||
Ports Tested (Link UP): ${tested.length} (${testedPoE?.length} PoE, ${testedSFP?.length} SFP)
|
||||
Ports Missing/Down: ${missing.length}\n\n`
|
||||
Ports Missing/Down: ${missing.length}
|
||||
${this.config.reasonSkipPhysical ? `***User skip test ports:\n- ${this.config.reasonSkipPhysical}` : ''}
|
||||
\n`
|
||||
await updateNoteToERP(sn, note)
|
||||
}
|
||||
|
||||
|
|
@ -1173,6 +1181,8 @@ Ports Missing/Down: ${missing.length}\n\n`
|
|||
})
|
||||
if (listPorts.length === 0) {
|
||||
this.config.listFeatureTested = [...new Set([...this.config.listFeatureTested, 'PHYSICAL'])]
|
||||
this.config.isSkipPhysical = true
|
||||
this.config.reasonSkipPhysical = ''
|
||||
this.sendFeatureTested()
|
||||
console.log('End physical test')
|
||||
this.endTesting()
|
||||
|
|
@ -1301,15 +1311,28 @@ Ports Missing/Down: ${missing.length}\n\n`
|
|||
/**
|
||||
* Send report after done physical test
|
||||
*/
|
||||
async sendReportPhysicalTest() {
|
||||
async sendReportPhysicalTest(reason?: string) {
|
||||
this.config.listFeatureTested = [...new Set([...this.config.listFeatureTested, 'PHYSICAL'])]
|
||||
if (reason) {
|
||||
this.config.isSkipPhysical = true
|
||||
this.config.reasonSkipPhysical = reason
|
||||
}
|
||||
this.sendFeatureTested()
|
||||
// Set timeout send report
|
||||
this.setTimeoutSendSummaryReport(30000)
|
||||
const formReport = this.physicalTest.getFormReport()
|
||||
if (
|
||||
this.config.listFeatureTested?.includes('PHYSICAL') &&
|
||||
this.config.listFeatureTested?.includes('DPELP')
|
||||
)
|
||||
this.setTimeoutSendSummaryReport(30000)
|
||||
const formReport = this.physicalTest.getFormReport(this.config.inventory)
|
||||
const reasonSkipPhysical = reason
|
||||
? `<b style="color: #ff0000;">User Skip Test Port</b><br/>
|
||||
────────────────────────────────<br/>
|
||||
${reason}`
|
||||
: ''
|
||||
await sendMessageToMail(
|
||||
`[ATC] - [${this.config.stationName} - Line: ${this.config.lineNumber}] - Physical Ports Test`,
|
||||
formReport
|
||||
formReport + reasonSkipPhysical
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -1762,6 +1785,8 @@ ${log}
|
|||
stationId: this.config.stationId,
|
||||
lineId: this.config.id,
|
||||
listFeatureTested: this.config.listFeatureTested,
|
||||
isSkipPhysical: this.config.isSkipPhysical,
|
||||
reasonSkipPhysical: this.config.reasonSkipPhysical,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -1771,6 +1796,7 @@ ${log}
|
|||
sendReportSummary = async (snapshot?: {
|
||||
snapConfig: LineConfig
|
||||
snapPhysical: PhysicalPortTest
|
||||
reason: string
|
||||
}) => {
|
||||
if (this.debounceSendSummaryReport) clearTimeout(this.debounceSendSummaryReport)
|
||||
const physicalTest = snapshot?.snapPhysical ? snapshot?.snapPhysical : this.physicalTest
|
||||
|
|
@ -1797,6 +1823,13 @@ ${log}
|
|||
showLicense?.textfsm && Array.isArray(showLicense?.textfsm) ? showLicense?.textfsm : null
|
||||
const issue = config?.latestScenario?.detectAI?.issue || []
|
||||
const summary = config?.latestScenario?.detectAI?.summary || ''
|
||||
const reasonSkipPhysical =
|
||||
snapshot?.reason || this.config.reasonSkipPhysical
|
||||
? `<br/><b style="color: #ff0000;">User Skip Test Port</b><br/>
|
||||
────────────────────────────────<br/>
|
||||
${snapshot?.reason || this.config.reasonSkipPhysical}`
|
||||
: ''
|
||||
|
||||
const body = `<table cellpadding="6" cellspacing="0" border="1" style="margin-top: 10px; border-collapse: collapse; width: 100%">
|
||||
<tr>
|
||||
<td style="width: 600px; text-align: center;">DPELP</td>
|
||||
|
|
@ -1842,6 +1875,7 @@ ${log}
|
|||
<div style="column-count: 6;">${missingSFP.map((p) => physicalTest.normalizePortName(p.name)).join('<br/>')}</div>`
|
||||
: ''
|
||||
}
|
||||
${reasonSkipPhysical}
|
||||
</td>
|
||||
</tr>
|
||||
</table>`
|
||||
|
|
@ -1883,16 +1917,21 @@ ${log}
|
|||
this.physicalTest = new PhysicalPortTest([])
|
||||
}
|
||||
|
||||
setTimeoutSendSummaryReport(timeout: number) {
|
||||
setTimeoutSendSummaryReport(timeout: number, reason?: string) {
|
||||
// Debounce send summary report
|
||||
if (this.debounceSendSummaryReport) clearTimeout(this.debounceSendSummaryReport)
|
||||
// Snapshot toàn bộ data tại thời điểm này
|
||||
const snapshot = {
|
||||
snapConfig: this.config,
|
||||
snapPhysical: this.physicalTest,
|
||||
reason: reason || '',
|
||||
}
|
||||
this.debounceSendSummaryReport = setTimeout(() => {
|
||||
this.config.listFeatureTested = ['DPELP', 'PHYSICAL']
|
||||
if (!this.config.listFeatureTested?.includes('PHYSICAL')) {
|
||||
this.config.isSkipPhysical = true
|
||||
this.config.reasonSkipPhysical = ''
|
||||
}
|
||||
this.config.listFeatureTested = ['DPELP', 'PHYSICAL', 'SUMMARY']
|
||||
this.sendFeatureTested()
|
||||
this.sendReportSummary(snapshot)
|
||||
}, timeout)
|
||||
|
|
@ -1900,6 +1939,8 @@ ${log}
|
|||
|
||||
resetDPELP() {
|
||||
this.config.listFeatureTested = []
|
||||
this.config.isSkipPhysical = false
|
||||
this.config.reasonSkipPhysical = ''
|
||||
this.dataDPELP = ''
|
||||
this.sendFeatureTested()
|
||||
console.log('Reset DPELP data and features', this.config.id, this.config.listFeatureTested)
|
||||
|
|
|
|||
|
|
@ -127,11 +127,11 @@ export class PhysicalPortTest {
|
|||
console.log('✅ Physical Test DONE')
|
||||
}
|
||||
|
||||
getFormReport() {
|
||||
getFormReport(inventory?: any) {
|
||||
const report: PhysicalTestReport = {
|
||||
device: {
|
||||
model: this?.inventory?.pid || '',
|
||||
serial: this?.inventory?.sn || '',
|
||||
model: this?.inventory?.pid || inventory?.pid || '',
|
||||
serial: this?.inventory?.sn || inventory?.sn || '',
|
||||
},
|
||||
startTime: this.startTime,
|
||||
endTime: new Date(),
|
||||
|
|
|
|||
|
|
@ -611,6 +611,7 @@ export class WebSocketIo {
|
|||
const stationId = data.stationId || ''
|
||||
const scenarioName = data.scenarioName || ''
|
||||
const skipTestPorts = data.skipTestPorts || false
|
||||
const reasonSkipPhysical = data.reasonSkipPhysical || false
|
||||
const station = await Station.find(stationId)
|
||||
// Check station is active
|
||||
const activeStation = await checkStationActive(stationId)
|
||||
|
|
@ -625,6 +626,8 @@ export class WebSocketIo {
|
|||
line.config.listFeatureTested = [
|
||||
...new Set([...line.config.listFeatureTested, 'PHYSICAL']),
|
||||
]
|
||||
line.config.isSkipPhysical = true
|
||||
line.config.reasonSkipPhysical = reasonSkipPhysical
|
||||
} else if (line.config.status === 'connected') {
|
||||
console.log('Reset list feature tested for line', lineId)
|
||||
line.resetDPELP()
|
||||
|
|
@ -653,21 +656,21 @@ export class WebSocketIo {
|
|||
console.error('Error sending wiki message:', error)
|
||||
}
|
||||
try {
|
||||
// await sendMessageToMail(
|
||||
// `[${scenarioName || 'DPELP'}] - ${stationName} - ${dataFormat}`,
|
||||
// tableHTML
|
||||
// )
|
||||
await sendMessageToMail(
|
||||
`[${scenarioName || 'DPELP'}] - ${stationName} - ${dataFormat}`,
|
||||
tableHTML
|
||||
)
|
||||
} catch (error) {
|
||||
console.error('Error sending mail:', error)
|
||||
}
|
||||
try {
|
||||
await sendMessageToZulip(
|
||||
'stream',
|
||||
'ATC_Report',
|
||||
station.name,
|
||||
`\n\n---\n**[${scenarioName || 'DPELP'}] - ${stationName} - ${dataFormat}**\n\n` +
|
||||
zulipMess
|
||||
)
|
||||
// await sendMessageToZulip(
|
||||
// 'stream',
|
||||
// 'ATC_Report',
|
||||
// station.name,
|
||||
// `\n\n---\n**[${scenarioName || 'DPELP'}] - ${stationName} - ${dataFormat}**\n\n` +
|
||||
// zulipMess
|
||||
// )
|
||||
} catch (error) {
|
||||
console.error('Error sending zulip message:', error)
|
||||
}
|
||||
|
|
@ -707,7 +710,7 @@ export class WebSocketIo {
|
|||
})
|
||||
|
||||
socket.on('end_run_physical_test', async (data) => {
|
||||
const { stationId, lineId } = data
|
||||
const { stationId, lineId, reasonSkipPhysical } = data
|
||||
// Check station is active
|
||||
const activeStation = await checkStationActive(stationId)
|
||||
if (!activeStation) return
|
||||
|
|
@ -717,7 +720,7 @@ export class WebSocketIo {
|
|||
stationId,
|
||||
[lineId],
|
||||
async (lineCon) => {
|
||||
await lineCon.sendReportPhysicalTest()
|
||||
await lineCon.sendReportPhysicalTest(reasonSkipPhysical)
|
||||
lineCon.endTesting()
|
||||
},
|
||||
{}
|
||||
|
|
@ -887,7 +890,8 @@ export class WebSocketIo {
|
|||
output = '',
|
||||
inventory: string = '',
|
||||
latestScenario?: any,
|
||||
data?: any
|
||||
data?: any,
|
||||
reasonSkipPhysical?: string
|
||||
) {
|
||||
try {
|
||||
for (const line of lines) {
|
||||
|
|
@ -916,6 +920,8 @@ export class WebSocketIo {
|
|||
latestScenario: latestScenario,
|
||||
listFeatureTested: [],
|
||||
isReady: false,
|
||||
reasonSkipPhysical: reasonSkipPhysical,
|
||||
isSkipPhysical: reasonSkipPhysical ? true : false,
|
||||
},
|
||||
socket,
|
||||
async () => {
|
||||
|
|
@ -1001,7 +1007,8 @@ export class WebSocketIo {
|
|||
line?.config?.output || '',
|
||||
line?.config?.inventory || '',
|
||||
line?.config?.latestScenario || undefined,
|
||||
line?.config?.data || []
|
||||
line?.config?.data || [],
|
||||
line?.config?.reasonSkipPhysical || ''
|
||||
)
|
||||
this.lineConnecting = this.lineConnecting.filter((el) => el !== lineId)
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ import PageLogin from "./components/Authentication/LoginPage";
|
|||
import DraggableTabs from "./components/DragTabs";
|
||||
import { isJsonString } from "./untils/helper";
|
||||
import BottomToolBar from "./components/BottomToolBar";
|
||||
import ModalConfirmSkipTestPort from "./components/Modal/ModalConfirmSkipTestPort";
|
||||
// import ModalConfirmRunScenario from "./components/Modal/ModalConfirmRunScenario";
|
||||
|
||||
const apiUrl = import.meta.env.VITE_BACKEND_URL;
|
||||
|
|
@ -109,6 +110,7 @@ function App() {
|
|||
const [listIos, setListIos] = useState<FileInfo[]>([]);
|
||||
const [listLicense, setListLicense] = useState<FileInfo[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [linesConfirmSkipPort, setLinesConfirmSkipPort] = useState<TLine[]>([]);
|
||||
|
||||
const connectApcSwitch = (station: TStation) => {
|
||||
if (!station?.is_active) return;
|
||||
|
|
@ -468,12 +470,21 @@ function App() {
|
|||
});
|
||||
|
||||
socket?.on("feature_tested", (data) => {
|
||||
if (data?.listFeatureTested)
|
||||
if (data?.listFeatureTested) {
|
||||
updateValueLineStation(
|
||||
data?.lineId,
|
||||
{ listFeatureTested: data?.listFeatureTested },
|
||||
{
|
||||
listFeatureTested: data?.listFeatureTested,
|
||||
isSkipPhysical: data?.isSkipPhysical,
|
||||
reasonSkipPhysical: data?.reasonSkipPhysical,
|
||||
},
|
||||
data?.stationId
|
||||
);
|
||||
if (data?.isSkipPhysical && !data?.reasonSkipPhysical) {
|
||||
const valueLine = findLineByLineId(data?.lineId, data?.stationId);
|
||||
if (valueLine) setLinesConfirmSkipPort((pre) => [...pre, valueLine]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ✅ cleanup on unmount or when socket changes
|
||||
|
|
@ -649,6 +660,13 @@ function App() {
|
|||
}
|
||||
}, [expandedBottomBar]);
|
||||
|
||||
const findLineByLineId = (lineId: number, stationId?: number) => {
|
||||
const valueStation = stations.find((el) => el.id === stationId);
|
||||
if (!valueStation || !stationId) return null;
|
||||
const valueLine = valueStation?.lines?.find((el) => el.id === lineId);
|
||||
return valueLine;
|
||||
};
|
||||
|
||||
return (
|
||||
<Container w={"100%"} style={{ maxWidth: "100%" }}>
|
||||
<DraggableTabs
|
||||
|
|
@ -958,6 +976,8 @@ function App() {
|
|||
setScenarios={setScenarios}
|
||||
listBrands={listBrands}
|
||||
listCategories={listCategories}
|
||||
setLinesConfirmSkipPort={setLinesConfirmSkipPort}
|
||||
linesConfirmSkipPort={linesConfirmSkipPort}
|
||||
/>
|
||||
|
||||
{/* <ModalConfirmRunScenario
|
||||
|
|
@ -965,6 +985,13 @@ function App() {
|
|||
station={stations.find((el) => el.id === Number(activeTab))}
|
||||
scenarios={scenarios}
|
||||
/> */}
|
||||
|
||||
<ModalConfirmSkipTestPort
|
||||
listLines={linesConfirmSkipPort}
|
||||
setListLines={setLinesConfirmSkipPort}
|
||||
socket={socket}
|
||||
station={stations.find((el) => el.id === Number(activeTab))}
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import {
|
|||
CloseButton,
|
||||
Flex,
|
||||
Grid,
|
||||
Menu,
|
||||
ScrollArea,
|
||||
Tabs,
|
||||
Text,
|
||||
|
|
@ -26,11 +25,7 @@ import { DrawerAPCControl, DrawerSwitchControl } from "./Drawer/DrawerControl";
|
|||
import DrawerScenario from "./Modal/ModalScenario";
|
||||
import { isJsonString } from "../untils/helper";
|
||||
import { motion } from "motion/react";
|
||||
import {
|
||||
IconCaretDown,
|
||||
IconCaretRight,
|
||||
IconCaretUp,
|
||||
} from "@tabler/icons-react";
|
||||
import { IconCaretDown, IconCaretUp } from "@tabler/icons-react";
|
||||
import InputHistory from "./InputHistory";
|
||||
import ModalRunScenario from "./Modal/ModalRunScenario";
|
||||
|
||||
|
|
@ -365,94 +360,27 @@ const BottomToolBar = ({
|
|||
gap={"xs"}
|
||||
wrap={"wrap"}
|
||||
>
|
||||
<Menu
|
||||
trigger="hover"
|
||||
withArrow
|
||||
shadow="md"
|
||||
position="top"
|
||||
>
|
||||
<Menu.Target>
|
||||
<Button
|
||||
fw={400}
|
||||
mr={"5px"}
|
||||
disabled={
|
||||
isDisable || selectedLines.length === 0
|
||||
}
|
||||
variant="outline"
|
||||
color="green"
|
||||
style={{ height: "30px", width: "100px" }}
|
||||
onClick={() => {}}
|
||||
>
|
||||
DPELP <IconCaretRight size={"14px"} />
|
||||
</Button>
|
||||
</Menu.Target>
|
||||
<Menu.Dropdown>
|
||||
<Flex direction={"column"} gap={"8px"}>
|
||||
<ButtonDPELP
|
||||
socket={socket}
|
||||
selectedLines={selectedLines}
|
||||
isDisable={
|
||||
isDisable || selectedLines.length === 0
|
||||
}
|
||||
dataDPELP={scenarios?.find(
|
||||
(el) => el.title.toUpperCase() === "DPELP"
|
||||
)}
|
||||
onClick={() => {
|
||||
if (
|
||||
selectedLines.length > 0
|
||||
// &&
|
||||
// selectedLines.length === station?.lines?.length
|
||||
) {
|
||||
socket?.emit("run_all_dpelp", {
|
||||
lineIds: selectedLines.map(
|
||||
(line) => line.id
|
||||
),
|
||||
stationName: station.name,
|
||||
stationId: station.id,
|
||||
});
|
||||
}
|
||||
setIsDisable(true);
|
||||
setTimeout(() => {
|
||||
setIsDisable(false);
|
||||
}, 5000);
|
||||
}}
|
||||
text="Run Test Ports after DPELP"
|
||||
/>
|
||||
<ButtonDPELP
|
||||
socket={socket}
|
||||
selectedLines={selectedLines}
|
||||
isDisable={
|
||||
isDisable || selectedLines.length === 0
|
||||
}
|
||||
dataDPELP={scenarios?.find(
|
||||
(el) => el.title.toUpperCase() === "DPELP"
|
||||
)}
|
||||
onClick={() => {
|
||||
if (
|
||||
selectedLines.length > 0
|
||||
// &&
|
||||
// selectedLines.length === station?.lines?.length
|
||||
) {
|
||||
socket?.emit("run_all_dpelp", {
|
||||
lineIds: selectedLines.map(
|
||||
(line) => line.id
|
||||
),
|
||||
stationName: station.name,
|
||||
stationId: station.id,
|
||||
skipTestPorts: true,
|
||||
});
|
||||
}
|
||||
setIsDisable(true);
|
||||
setTimeout(() => {
|
||||
setIsDisable(false);
|
||||
}, 5000);
|
||||
}}
|
||||
text="Skip Test Ports"
|
||||
color="yellow"
|
||||
/>
|
||||
</Flex>
|
||||
</Menu.Dropdown>
|
||||
</Menu>
|
||||
<ButtonDPELP
|
||||
socket={socket}
|
||||
selectedLines={selectedLines}
|
||||
isDisable={isDisable || selectedLines.length === 0}
|
||||
dataDPELP={scenarios?.find(
|
||||
(el) => el.title.toUpperCase() === "DPELP"
|
||||
)}
|
||||
onClick={() => {
|
||||
if (selectedLines.length > 0) {
|
||||
socket?.emit("run_all_dpelp", {
|
||||
lineIds: selectedLines.map((line) => line.id),
|
||||
stationName: station.name,
|
||||
stationId: station.id,
|
||||
});
|
||||
}
|
||||
setIsDisable(true);
|
||||
setTimeout(() => {
|
||||
setIsDisable(false);
|
||||
}, 5000);
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
fw={400}
|
||||
disabled={isDisable || selectedLines.length === 0}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,13 @@
|
|||
import { Card, Text, Box, Flex, Menu, Button, Input } from "@mantine/core";
|
||||
import {
|
||||
Card,
|
||||
Text,
|
||||
Box,
|
||||
Flex,
|
||||
Menu,
|
||||
Button,
|
||||
Input,
|
||||
Tooltip,
|
||||
} from "@mantine/core";
|
||||
import type { IScenario, TLine, TStation } from "../untils/types";
|
||||
import classes from "./Component.module.css";
|
||||
import TerminalCLI from "./TerminalXTerm";
|
||||
|
|
@ -399,19 +408,48 @@ const CardLine = ({
|
|||
""
|
||||
)}
|
||||
{line?.listFeatureTested?.includes("PHYSICAL") ? (
|
||||
<Text
|
||||
style={{
|
||||
border: "1px solid #ccc",
|
||||
borderRadius: "16px",
|
||||
paddingLeft: "4px",
|
||||
paddingRight: "4px",
|
||||
backgroundColor: "#69da53",
|
||||
}}
|
||||
fz={"9px"}
|
||||
c={"dark"}
|
||||
>
|
||||
Physical
|
||||
</Text>
|
||||
line?.isSkipPhysical ? (
|
||||
<Tooltip
|
||||
label={
|
||||
line?.reasonSkipPhysical ||
|
||||
"User skip physical test"
|
||||
}
|
||||
>
|
||||
<motion.div
|
||||
style={{
|
||||
border: "1px solid #ccc",
|
||||
borderRadius: "16px",
|
||||
paddingLeft: "4px",
|
||||
paddingRight: "4px",
|
||||
fontSize: "9px",
|
||||
backgroundColor: "red",
|
||||
color: "white",
|
||||
}}
|
||||
animate={{ opacity: [0.2, 1, 0.2] }}
|
||||
transition={{
|
||||
duration: 1.2,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut",
|
||||
}}
|
||||
>
|
||||
Physical
|
||||
</motion.div>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Text
|
||||
style={{
|
||||
border: "1px solid #ccc",
|
||||
borderRadius: "16px",
|
||||
paddingLeft: "4px",
|
||||
paddingRight: "4px",
|
||||
backgroundColor: "#69da53",
|
||||
}}
|
||||
fz={"9px"}
|
||||
c={"dark"}
|
||||
>
|
||||
Physical
|
||||
</Text>
|
||||
)
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,161 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
Modal,
|
||||
Box,
|
||||
Text,
|
||||
Flex,
|
||||
TextInput,
|
||||
Button,
|
||||
ScrollArea,
|
||||
} from "@mantine/core";
|
||||
import type { TLine, TStation } from "../../untils/types";
|
||||
import type { Socket } from "socket.io-client";
|
||||
|
||||
interface Props {
|
||||
listLines: TLine[];
|
||||
setListLines: (lines: React.SetStateAction<TLine[]>) => void;
|
||||
socket: Socket | null;
|
||||
station: TStation | undefined;
|
||||
}
|
||||
|
||||
interface PropsLines {
|
||||
id: number | undefined;
|
||||
note: string;
|
||||
pid?: string;
|
||||
sn?: string;
|
||||
vid?: string;
|
||||
lineNumber?: number;
|
||||
isError?: boolean;
|
||||
}
|
||||
|
||||
export default function ModalConfirmSkipTestPort({
|
||||
listLines,
|
||||
setListLines,
|
||||
socket,
|
||||
station,
|
||||
}: Props) {
|
||||
const [dataLines, setDataLines] = useState<PropsLines[]>([]);
|
||||
const [isDisabled, setIsDisabled] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (listLines) {
|
||||
setDataLines((prev) =>
|
||||
listLines
|
||||
.filter((line) => line.id)
|
||||
.map((line) => ({
|
||||
id: line.id,
|
||||
lineNumber: line?.lineNumber,
|
||||
pid: line?.inventory?.pid,
|
||||
sn: line?.inventory?.sn,
|
||||
vid: line?.inventory?.vid,
|
||||
note: prev?.find((el) => el.id === line.id)
|
||||
? prev?.find((el) => el.id === line.id)?.note || ""
|
||||
: "",
|
||||
}))
|
||||
);
|
||||
}
|
||||
}, [listLines]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
size={"xl"}
|
||||
style={{ position: "absolute", left: 0 }}
|
||||
opened={dataLines.length > 0}
|
||||
onClose={() => {}}
|
||||
closeOnClickOutside={false}
|
||||
closeOnEscape={false}
|
||||
withCloseButton={false}
|
||||
title="Confirm Skip Test Ports"
|
||||
>
|
||||
<Box>
|
||||
<ScrollArea h={"66vh"}>
|
||||
{dataLines.map((line, i) => (
|
||||
<Box
|
||||
key={i}
|
||||
style={{ borderBottom: "1px #ccc solid" }}
|
||||
pb="sm"
|
||||
mb="sm"
|
||||
>
|
||||
<Flex
|
||||
p={"xs"}
|
||||
style={{
|
||||
backgroundColor: "#e9ecef",
|
||||
fontWeight: 600,
|
||||
}}
|
||||
gap={"lg"}
|
||||
>
|
||||
<Text size="sm" fw={600}>
|
||||
Line: {line.lineNumber}
|
||||
</Text>
|
||||
<Text size="sm" fw={600}>
|
||||
PID: {line.pid || ""}
|
||||
</Text>
|
||||
<Text size="sm" fw={600}>
|
||||
SN: {line.sn || ""}
|
||||
</Text>
|
||||
<Text size="sm" fw={600}>
|
||||
VID: {line.vid || ""}
|
||||
</Text>
|
||||
</Flex>
|
||||
<Box>
|
||||
<TextInput
|
||||
required
|
||||
placeholder="Enter the reason for skip test ports"
|
||||
mt="4px"
|
||||
mb="4px"
|
||||
value={line.note}
|
||||
onChange={(e) =>
|
||||
setDataLines(
|
||||
dataLines.map((el) =>
|
||||
el.id === line.id
|
||||
? {
|
||||
...el,
|
||||
note: e.target.value,
|
||||
isError: false,
|
||||
}
|
||||
: el
|
||||
)
|
||||
)
|
||||
}
|
||||
error={
|
||||
line.isError
|
||||
? "Please enter the reason for skip test ports"
|
||||
: ""
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
<Flex justify={"end"}>
|
||||
<Button
|
||||
disabled={isDisabled}
|
||||
color={"green"}
|
||||
size="xs"
|
||||
onClick={() => {
|
||||
if (!line.note)
|
||||
setDataLines(
|
||||
dataLines.map((el) => ({ ...el, isError: true }))
|
||||
);
|
||||
else {
|
||||
socket?.emit("end_run_physical_test", {
|
||||
lineId: line?.id,
|
||||
stationId: Number(station?.id),
|
||||
reasonSkipPhysical: line?.note,
|
||||
});
|
||||
setDataLines(dataLines.filter((el) => el.id !== line.id));
|
||||
setListLines(listLines.filter((el) => el.id !== line.id));
|
||||
}
|
||||
setIsDisabled(true);
|
||||
setTimeout(() => {
|
||||
setIsDisabled(false);
|
||||
}, 1000);
|
||||
}}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</Flex>
|
||||
</Box>
|
||||
))}
|
||||
</ScrollArea>
|
||||
</Box>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
|
@ -81,6 +81,8 @@ const ModalTerminal = ({
|
|||
listBrands,
|
||||
listCategories,
|
||||
setScenarios,
|
||||
setLinesConfirmSkipPort,
|
||||
linesConfirmSkipPort,
|
||||
}: {
|
||||
opened: boolean;
|
||||
onClose: () => void;
|
||||
|
|
@ -96,6 +98,8 @@ const ModalTerminal = ({
|
|||
listBrands: TBrands[];
|
||||
listCategories: TCategories[];
|
||||
setScenarios: (value: React.SetStateAction<IScenario[]>) => void;
|
||||
setLinesConfirmSkipPort: (value: React.SetStateAction<TLine[]>) => void;
|
||||
linesConfirmSkipPort: TLine[];
|
||||
}) => {
|
||||
const user = useMemo(() => {
|
||||
return localStorage.getItem("user") &&
|
||||
|
|
@ -134,6 +138,12 @@ const ModalTerminal = ({
|
|||
line?.listFeatureTested?.includes("DPELP")
|
||||
)
|
||||
setActiveStep(2);
|
||||
if (
|
||||
line?.listFeatureTested?.includes("PHYSICAL") &&
|
||||
line?.listFeatureTested?.includes("DPELP") &&
|
||||
line?.listFeatureTested?.includes("SUMMARY")
|
||||
)
|
||||
setActiveStep(3);
|
||||
} else setActiveStep(0);
|
||||
}, [opened, line?.listFeatureTested]);
|
||||
|
||||
|
|
@ -537,6 +547,7 @@ const ModalTerminal = ({
|
|||
return;
|
||||
}
|
||||
if (openSelectIos) return;
|
||||
if (linesConfirmSkipPort.length) return;
|
||||
onClose();
|
||||
if (
|
||||
line?.userOpenCLI === user?.userName &&
|
||||
|
|
@ -685,7 +696,31 @@ const ModalTerminal = ({
|
|||
></Stepper.Step>
|
||||
<Stepper.Step
|
||||
disabled={isDisable}
|
||||
label="Physical Test"
|
||||
label={
|
||||
line?.isSkipPhysical ? (
|
||||
<Tooltip
|
||||
label={
|
||||
line?.reasonSkipPhysical || "User skip physical test"
|
||||
}
|
||||
>
|
||||
<motion.div
|
||||
style={{
|
||||
color: "red",
|
||||
}}
|
||||
animate={{ opacity: [0.2, 1, 0.2] }}
|
||||
transition={{
|
||||
duration: 1.2,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut",
|
||||
}}
|
||||
>
|
||||
Physical Test
|
||||
</motion.div>
|
||||
</Tooltip>
|
||||
) : (
|
||||
"Physical Test"
|
||||
)
|
||||
}
|
||||
description="Test physical ports"
|
||||
></Stepper.Step>
|
||||
<Stepper.Step
|
||||
|
|
@ -1209,16 +1244,17 @@ const ModalTerminal = ({
|
|||
<SimpleGrid cols={5} spacing={"xs"}>
|
||||
{isPhysicalTest && line?.ports
|
||||
? line.ports.map((port, i) => (
|
||||
<Text
|
||||
fz={"15px"}
|
||||
key={i}
|
||||
c={
|
||||
line?.listPortsPhysical?.includes(port)
|
||||
? "#014a1a"
|
||||
: "#dedede"
|
||||
}
|
||||
>
|
||||
{normalizePortName(port)}
|
||||
<Box key={i}>
|
||||
<Text
|
||||
fz={"15px"}
|
||||
c={
|
||||
line?.listPortsPhysical?.includes(port)
|
||||
? "#014a1a"
|
||||
: "#dedede"
|
||||
}
|
||||
>
|
||||
{normalizePortName(port)}
|
||||
</Text>
|
||||
{port?.includes("SFP") ? (
|
||||
<Text
|
||||
mt={-4}
|
||||
|
|
@ -1235,7 +1271,7 @@ const ModalTerminal = ({
|
|||
) : (
|
||||
""
|
||||
)}
|
||||
</Text>
|
||||
</Box>
|
||||
))
|
||||
: null}
|
||||
</SimpleGrid>
|
||||
|
|
@ -1265,31 +1301,58 @@ const ModalTerminal = ({
|
|||
Reset
|
||||
</Button>
|
||||
{isPhysicalTest ? (
|
||||
<Button
|
||||
fw={400}
|
||||
disabled={isDisable}
|
||||
variant="filled"
|
||||
color="green"
|
||||
size="xs"
|
||||
fz={"xs"}
|
||||
mt={"8px"}
|
||||
onClick={() => {
|
||||
socket?.emit("end_run_physical_test", {
|
||||
lineId: line?.id,
|
||||
stationId: Number(stationItem?.id),
|
||||
});
|
||||
// setListPortsPhysical([]);
|
||||
setIsDisable(true);
|
||||
setTimeout(() => {
|
||||
setIsDisable(false);
|
||||
}, 5000);
|
||||
}}
|
||||
>
|
||||
Done/End
|
||||
</Button>
|
||||
<Flex gap={"sm"}>
|
||||
<Button
|
||||
fw={400}
|
||||
disabled={isDisable}
|
||||
variant="outline"
|
||||
color="red"
|
||||
size="xs"
|
||||
fz={"xs"}
|
||||
mt={"8px"}
|
||||
onClick={() => {
|
||||
if (line)
|
||||
setLinesConfirmSkipPort((pre) => [...pre, line]);
|
||||
setIsDisable(true);
|
||||
setTimeout(() => {
|
||||
setIsDisable(false);
|
||||
}, 5000);
|
||||
}}
|
||||
>
|
||||
Skip test ports
|
||||
</Button>
|
||||
<Button
|
||||
fw={400}
|
||||
disabled={isDisable}
|
||||
variant="filled"
|
||||
color="green"
|
||||
size="xs"
|
||||
fz={"xs"}
|
||||
mt={"8px"}
|
||||
onClick={() => {
|
||||
socket?.emit("end_run_physical_test", {
|
||||
lineId: line?.id,
|
||||
stationId: Number(stationItem?.id),
|
||||
});
|
||||
// setListPortsPhysical([]);
|
||||
setIsDisable(true);
|
||||
setTimeout(() => {
|
||||
setIsDisable(false);
|
||||
}, 5000);
|
||||
}}
|
||||
>
|
||||
Done/End
|
||||
</Button>
|
||||
</Flex>
|
||||
) : (
|
||||
<Button
|
||||
disabled={isDisable}
|
||||
disabled={
|
||||
isDisable ||
|
||||
(line?.runningScenario &&
|
||||
line?.runningScenario?.length > 0
|
||||
? true
|
||||
: false)
|
||||
}
|
||||
fw={400}
|
||||
variant="filled"
|
||||
// color="green"
|
||||
|
|
@ -1395,67 +1458,30 @@ const ModalTerminal = ({
|
|||
</Flex>
|
||||
</Menu.Dropdown>
|
||||
</Menu>
|
||||
<Menu trigger="hover" withArrow shadow="md" position="top">
|
||||
<Menu.Target>
|
||||
<Button
|
||||
fw={400}
|
||||
mr={"5px"}
|
||||
disabled={isDisable}
|
||||
variant="outline"
|
||||
color="green"
|
||||
style={{ height: "30px", width: "100px" }}
|
||||
onClick={() => {}}
|
||||
>
|
||||
DPELP <IconCaretRight size={"14px"} />
|
||||
</Button>
|
||||
</Menu.Target>
|
||||
<Menu.Dropdown>
|
||||
<Flex direction={"column"} gap={"8px"}>
|
||||
<ButtonDPELP
|
||||
socket={socket}
|
||||
selectedLines={line ? [line] : []}
|
||||
isDisable={isDisable}
|
||||
dataDPELP={scenarios?.find(
|
||||
(el) => el.title.toUpperCase() === "DPELP"
|
||||
)}
|
||||
onClick={() => {
|
||||
socket?.emit("run_all_dpelp", {
|
||||
lineIds: [line?.id],
|
||||
stationName: stationItem?.name,
|
||||
stationId: Number(stationItem?.id),
|
||||
});
|
||||
setIsDisable(true);
|
||||
setTimeout(() => {
|
||||
setIsDisable(false);
|
||||
}, 10000);
|
||||
}}
|
||||
text="Run Test Ports after DPELP"
|
||||
/>
|
||||
<ButtonDPELP
|
||||
socket={socket}
|
||||
selectedLines={line ? [line] : []}
|
||||
isDisable={isDisable}
|
||||
dataDPELP={scenarios?.find(
|
||||
(el) => el.title.toUpperCase() === "DPELP"
|
||||
)}
|
||||
onClick={() => {
|
||||
socket?.emit("run_all_dpelp", {
|
||||
lineIds: [line?.id],
|
||||
stationName: stationItem?.name,
|
||||
stationId: Number(stationItem?.id),
|
||||
skipTestPorts: true,
|
||||
});
|
||||
setIsDisable(true);
|
||||
setTimeout(() => {
|
||||
setIsDisable(false);
|
||||
}, 10000);
|
||||
}}
|
||||
text="Skip Test Ports"
|
||||
color="yellow"
|
||||
/>
|
||||
</Flex>
|
||||
</Menu.Dropdown>
|
||||
</Menu>
|
||||
<ButtonDPELP
|
||||
socket={socket}
|
||||
selectedLines={line ? [line] : []}
|
||||
isDisable={
|
||||
isDisable ||
|
||||
(line?.runningScenario && line?.runningScenario?.length > 0
|
||||
? true
|
||||
: false)
|
||||
}
|
||||
onClick={() => {
|
||||
socket?.emit("run_all_dpelp", {
|
||||
lineIds: [line?.id],
|
||||
stationName: stationItem?.name,
|
||||
stationId: Number(stationItem?.id),
|
||||
});
|
||||
setIsDisable(true);
|
||||
setTimeout(() => {
|
||||
setIsDisable(false);
|
||||
}, 10000);
|
||||
}}
|
||||
dataDPELP={scenarios?.find(
|
||||
(el) => el.title.toUpperCase() === "DPELP"
|
||||
)}
|
||||
/>
|
||||
<Button
|
||||
fw={400}
|
||||
disabled={isDisable}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,8 @@ export type TLine = {
|
|||
listPortsPhysical?: string[];
|
||||
listFeatureTested?: string[];
|
||||
isReady?: boolean;
|
||||
isSkipPhysical?: boolean;
|
||||
reasonSkipPhysical?: string;
|
||||
};
|
||||
|
||||
export type TUser = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue