Update run scenario DPELP theo flow mới
This commit is contained in:
parent
7528da2f00
commit
7c7778a0e1
|
|
@ -135,6 +135,7 @@ export default class ScenariosController {
|
||||||
const existedScenarios = await Scenario.query().select('id', 'series')
|
const existedScenarios = await Scenario.query().select('id', 'series')
|
||||||
const duplicatedSeries: string[] = []
|
const duplicatedSeries: string[] = []
|
||||||
for (const sc of existedScenarios) {
|
for (const sc of existedScenarios) {
|
||||||
|
if (sc.id === scenarioId) continue
|
||||||
const scSeries: string[] = JSON.parse(sc.series || '[]').map((s: string) =>
|
const scSeries: string[] = JSON.parse(sc.series || '[]').map((s: string) =>
|
||||||
s.trim().toUpperCase()
|
s.trim().toUpperCase()
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,9 @@ export default class Scenario extends BaseModel {
|
||||||
@column()
|
@column()
|
||||||
declare send_result: boolean
|
declare send_result: boolean
|
||||||
|
|
||||||
|
@column()
|
||||||
|
declare sendResult: boolean
|
||||||
|
|
||||||
@column()
|
@column()
|
||||||
declare brandId: number
|
declare brandId: number
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,14 @@
|
||||||
import fs from 'node:fs'
|
import fs from 'node:fs'
|
||||||
import { textfsmResults } from './../ultils/templates/index.js'
|
import { textfsmResults } from './../ultils/templates/index.js'
|
||||||
import net from 'node:net'
|
import net from 'node:net'
|
||||||
import { appendLog, cleanData, isValidJson, mapToLineFormat, sleep } from '../ultils/helper.js'
|
import {
|
||||||
|
appendLog,
|
||||||
|
cleanData,
|
||||||
|
detectScenarioByModel,
|
||||||
|
isValidJson,
|
||||||
|
mapToLineFormat,
|
||||||
|
sleep,
|
||||||
|
} from '../ultils/helper.js'
|
||||||
import Scenario from '#models/scenario'
|
import Scenario from '#models/scenario'
|
||||||
import Station from '#models/station'
|
import Station from '#models/station'
|
||||||
import APCController from './apc_connection.js'
|
import APCController from './apc_connection.js'
|
||||||
|
|
@ -345,7 +352,8 @@ export default class LineConnection {
|
||||||
lineId: this.config.id,
|
lineId: this.config.id,
|
||||||
title: script?.title,
|
title: script?.title,
|
||||||
})
|
})
|
||||||
if (script?.send_result) this.dataDPELP = ''
|
if (script?.send_result || script?.sendResult) this.dataDPELP = ''
|
||||||
|
|
||||||
if (script?.isReboot) {
|
if (script?.isReboot) {
|
||||||
await sleep(10000)
|
await sleep(10000)
|
||||||
for (let index = 0; index < 30; index++) {
|
for (let index = 0; index < 30; index++) {
|
||||||
|
|
@ -381,6 +389,17 @@ export default class LineConnection {
|
||||||
this.outputBuffer = ''
|
this.outputBuffer = ''
|
||||||
this.outputScenario = ''
|
this.outputScenario = ''
|
||||||
this.config.output += 'Timeout run scenario'
|
this.config.output += 'Timeout run scenario'
|
||||||
|
this.dataDPELP = {
|
||||||
|
line: this.config.lineNumber,
|
||||||
|
pid: '',
|
||||||
|
vid: '',
|
||||||
|
sn: '',
|
||||||
|
ios: '',
|
||||||
|
mac: '',
|
||||||
|
license: [],
|
||||||
|
issues: ['No data'],
|
||||||
|
summary: '',
|
||||||
|
}
|
||||||
this.socketIO.emit('line_output', {
|
this.socketIO.emit('line_output', {
|
||||||
stationId: this.config.stationId,
|
stationId: this.config.stationId,
|
||||||
lineId: this.config.id,
|
lineId: this.config.id,
|
||||||
|
|
@ -426,6 +445,7 @@ export default class LineConnection {
|
||||||
|
|
||||||
const logScenarios = this.outputScenario
|
const logScenarios = this.outputScenario
|
||||||
const data = textfsmResults(logScenarios, '')
|
const data = textfsmResults(logScenarios, '')
|
||||||
|
let pid = ''
|
||||||
try {
|
try {
|
||||||
data.forEach((item) => {
|
data.forEach((item) => {
|
||||||
if (item?.textfsm && isValidJson(item?.textfsm)) {
|
if (item?.textfsm && isValidJson(item?.textfsm)) {
|
||||||
|
|
@ -434,6 +454,7 @@ export default class LineConnection {
|
||||||
) {
|
) {
|
||||||
const dataInventory = JSON.parse(item.textfsm)[0]
|
const dataInventory = JSON.parse(item.textfsm)[0]
|
||||||
this.config.inventory = dataInventory
|
this.config.inventory = dataInventory
|
||||||
|
pid = dataInventory?.pid || ''
|
||||||
this.addHistory(this.config.stationId, this.config.id, {
|
this.addHistory(this.config.stationId, this.config.id, {
|
||||||
id: this.config.id,
|
id: this.config.id,
|
||||||
number: this.config.lineNumber,
|
number: this.config.lineNumber,
|
||||||
|
|
@ -448,6 +469,18 @@ export default class LineConnection {
|
||||||
item.textfsm = JSON.parse(item.textfsm)
|
item.textfsm = JSON.parse(item.textfsm)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
const scenario = await detectScenarioByModel(pid)
|
||||||
|
// console.log(pid, scenario)
|
||||||
|
if (scenario && scenario.id !== script.id) {
|
||||||
|
this.outputScenario = ''
|
||||||
|
// this.runScript(scenario, userName)
|
||||||
|
this.socketIO.emit('confirm_scenario', {
|
||||||
|
scenario: scenario,
|
||||||
|
id: this.config.id,
|
||||||
|
})
|
||||||
|
resolve(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
const detectLog = await this.detectLogWithAI(logScenarios)
|
const detectLog = await this.detectLogWithAI(logScenarios)
|
||||||
const result = mapToLineFormat({
|
const result = mapToLineFormat({
|
||||||
lineNumber: this.config.lineNumber,
|
lineNumber: this.config.lineNumber,
|
||||||
|
|
@ -457,7 +490,7 @@ export default class LineConnection {
|
||||||
},
|
},
|
||||||
data,
|
data,
|
||||||
})
|
})
|
||||||
if (script?.send_result) {
|
if (script?.send_result || script?.sendResult) {
|
||||||
this.dataDPELP = result
|
this.dataDPELP = result
|
||||||
console.log(
|
console.log(
|
||||||
`DPELP DATA line ${this.config.lineNumber} of ${this.config.stationName}:`,
|
`DPELP DATA line ${this.config.lineNumber} of ${this.config.stationName}:`,
|
||||||
|
|
@ -589,102 +622,14 @@ export default class LineConnection {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
async apcControl(action: 'on' | 'off' | 'restart') {
|
|
||||||
try {
|
|
||||||
const station = await Station.find(this.config.stationId)
|
|
||||||
if (!station) throw new Error('Station not found')
|
|
||||||
|
|
||||||
const apcName = this.config.apcName || 'apc_1'
|
|
||||||
const ip = (station as any)[`${apcName}_ip`] as string
|
|
||||||
const port = (station as any)[`${apcName}_port`] as number
|
|
||||||
const username = (station as any)[`${apcName}_username`] as string
|
|
||||||
const password = (station as any)[`${apcName}_password`] as string
|
|
||||||
|
|
||||||
if (!ip || !port || !username || !password)
|
|
||||||
throw new Error(`Missing APC configuration for ${apcName}`)
|
|
||||||
|
|
||||||
// Tạo APC Controller instance
|
|
||||||
const apc = new APCController({
|
|
||||||
host: ip,
|
|
||||||
port,
|
|
||||||
username,
|
|
||||||
password,
|
|
||||||
stationId: this.config.stationId,
|
|
||||||
stationName: this.config.stationName,
|
|
||||||
stationIP: this.config.stationIp,
|
|
||||||
number: this.config.lineNumber,
|
|
||||||
onData: (data: string, status: string) => {
|
|
||||||
this.config.output += data
|
|
||||||
this.socketIO.emit('apc_output', {
|
|
||||||
stationId: this.config.stationId,
|
|
||||||
lineId: this.config.id,
|
|
||||||
apcNumber: apcName === 'apc_1' ? 1 : 2,
|
|
||||||
data,
|
|
||||||
status,
|
|
||||||
})
|
|
||||||
appendLog(
|
|
||||||
cleanData(data),
|
|
||||||
this.config.stationId,
|
|
||||||
this.config.stationName,
|
|
||||||
this.config.stationIp,
|
|
||||||
this.config.lineNumber
|
|
||||||
)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// Connect và login
|
|
||||||
await apc.connect()
|
|
||||||
await apc.login()
|
|
||||||
|
|
||||||
// Thực thi hành động
|
|
||||||
this.socketIO.emit('apc_status', {
|
|
||||||
stationId: this.config.stationId,
|
|
||||||
lineId: this.config.id,
|
|
||||||
action,
|
|
||||||
status: 'running',
|
|
||||||
})
|
|
||||||
|
|
||||||
switch (action) {
|
|
||||||
case 'on':
|
|
||||||
await apc.turnOnOutlet(this.config.outlet)
|
|
||||||
break
|
|
||||||
case 'off':
|
|
||||||
await apc.turnOffOutlet(this.config.outlet)
|
|
||||||
break
|
|
||||||
case 'restart':
|
|
||||||
await apc.restartOutlet(this.config.outlet)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hoàn thành
|
|
||||||
this.socketIO.emit('apc_status', {
|
|
||||||
stationId: this.config.stationId,
|
|
||||||
lineId: this.config.id,
|
|
||||||
action,
|
|
||||||
status: 'done',
|
|
||||||
})
|
|
||||||
|
|
||||||
apc.disconnect()
|
|
||||||
} catch (error) {
|
|
||||||
const msg = (error as Error).message
|
|
||||||
console.error('APC Control error:', msg)
|
|
||||||
this.socketIO.emit('apc_status', {
|
|
||||||
stationId: this.config.stationId,
|
|
||||||
lineId: this.config.id,
|
|
||||||
action,
|
|
||||||
status: 'error',
|
|
||||||
message: msg,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getInventory = () => {
|
getInventory = () => {
|
||||||
const data = textfsmResults(this.outputInventory, 'show inventory')
|
const data = textfsmResults(this.outputInventory, 'show inventory')
|
||||||
try {
|
try {
|
||||||
data.forEach((item) => {
|
data.forEach((item) => {
|
||||||
if (item?.textfsm && isValidJson(item?.textfsm)) {
|
if (item?.textfsm && isValidJson(item?.textfsm)) {
|
||||||
if (['show inventory', 'sh inventory', 'show inv', 'sh inv'].includes(item.command)) {
|
if (['show inventory', 'sh inventory', 'show inv', 'sh inv'].includes(item.command)) {
|
||||||
this.config.inventory = JSON.parse(item.textfsm)[0]
|
const dataInventory = JSON.parse(item.textfsm)[0]
|
||||||
|
this.config.inventory = dataInventory
|
||||||
}
|
}
|
||||||
item.textfsm = JSON.parse(item.textfsm)
|
item.textfsm = JSON.parse(item.textfsm)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import Scenario from '#models/scenario'
|
||||||
import fs from 'node:fs'
|
import fs from 'node:fs'
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
import nodeMailer from 'nodemailer'
|
import nodeMailer from 'nodemailer'
|
||||||
|
|
@ -304,3 +305,30 @@ export function sendMessageToZulip(
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Catch scenario with key longer
|
||||||
|
export const detectScenarioByModel = async (model: string) => {
|
||||||
|
let scenarios = await Scenario.query().preload('brand').preload('category')
|
||||||
|
const normalizedModel = model.trim().toUpperCase()
|
||||||
|
let matched: { scenario: Scenario; score: number } | null = null
|
||||||
|
|
||||||
|
for (const scenario of scenarios) {
|
||||||
|
const seriesList: string[] = Array.isArray(scenario.series)
|
||||||
|
? scenario.series
|
||||||
|
: JSON.parse(scenario.series || '[]')
|
||||||
|
|
||||||
|
for (const s of seriesList) {
|
||||||
|
const pattern = s.trim().toUpperCase()
|
||||||
|
|
||||||
|
if (normalizedModel.startsWith(pattern)) {
|
||||||
|
const score = pattern.length
|
||||||
|
|
||||||
|
if (!matched || score > matched.score) {
|
||||||
|
matched = { scenario, score }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matched?.scenario || null
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import SwitchController from '#services/switch_connection'
|
||||||
import redis from '@adonisjs/redis/services/main'
|
import redis from '@adonisjs/redis/services/main'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import StationConnection from '#services/station_connection'
|
import StationConnection from '#services/station_connection'
|
||||||
|
import Scenario from '#models/scenario'
|
||||||
|
|
||||||
interface HandleOptions {
|
interface HandleOptions {
|
||||||
command?: string
|
command?: string
|
||||||
|
|
@ -573,23 +574,24 @@ export class WebSocketIo {
|
||||||
|
|
||||||
const linkWiki =
|
const linkWiki =
|
||||||
process.env.LINK_WIKI || 'https://logs.danielvu.com/api/wiki/page/insert?title=Dev_test'
|
process.env.LINK_WIKI || 'https://logs.danielvu.com/api/wiki/page/insert?title=Dev_test'
|
||||||
await axios.post(linkWiki, {
|
// await axios.post(linkWiki, {
|
||||||
data: tableHTML,
|
// data: tableHTML,
|
||||||
titleAuto: `[${scenarioName || 'DPELP'}] - ${stationName} - ` + dataFormat,
|
// titleAuto: `[${scenarioName || 'DPELP'}] - ${stationName} - ` + dataFormat,
|
||||||
})
|
// })
|
||||||
await sendMessageToMail(
|
await sendMessageToMail(
|
||||||
'andrew.ng@apactech.io',
|
'andrew.ng@apactech.io',
|
||||||
`[${scenarioName || 'DPELP'}] - ${stationName} - ${dataFormat}`,
|
`[${scenarioName || 'DPELP'}] - ${stationName} - ${dataFormat}`,
|
||||||
tableHTML,
|
tableHTML
|
||||||
['ips@ipsupply.com.au', 'kay@ipsupply.com.au', 'joseph@apactech.io']
|
// ,
|
||||||
)
|
// ['ips@ipsupply.com.au', 'kay@ipsupply.com.au', 'joseph@apactech.io']
|
||||||
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) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ import PageLogin from "./components/Authentication/LoginPage";
|
||||||
import DraggableTabs from "./components/DragTabs";
|
import DraggableTabs from "./components/DragTabs";
|
||||||
import { isJsonString } from "./untils/helper";
|
import { isJsonString } from "./untils/helper";
|
||||||
import BottomToolBar from "./components/BottomToolBar";
|
import BottomToolBar from "./components/BottomToolBar";
|
||||||
|
import ModalConfirmRunScenario from "./components/Modal/ModalConfirmRunScenario";
|
||||||
|
|
||||||
const apiUrl = import.meta.env.VITE_BACKEND_URL;
|
const apiUrl = import.meta.env.VITE_BACKEND_URL;
|
||||||
|
|
||||||
|
|
@ -825,6 +826,12 @@ function App() {
|
||||||
stationItem={stations.find((el) => el.id === Number(activeTab))}
|
stationItem={stations.find((el) => el.id === Number(activeTab))}
|
||||||
scenarios={scenarios}
|
scenarios={scenarios}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<ModalConfirmRunScenario
|
||||||
|
socket={socket}
|
||||||
|
station={stations.find((el) => el.id === Number(activeTab))}
|
||||||
|
scenarios={scenarios}
|
||||||
|
/>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,9 @@ const BottomToolBar = ({
|
||||||
justify={"center"}
|
justify={"center"}
|
||||||
h="100%"
|
h="100%"
|
||||||
>
|
>
|
||||||
<Text fz={"11px"}>Line {el.lineNumber}</Text>
|
<Text fz={"11px"}>
|
||||||
|
Line {el.lineNumber || el.line_number || ""}
|
||||||
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
))}
|
))}
|
||||||
|
|
@ -507,7 +509,9 @@ const BottomToolBar = ({
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Flex align={"center"} justify={"center"} h="100%">
|
<Flex align={"center"} justify={"center"} h="100%">
|
||||||
<Text fz={"10px"}>Line {el.lineNumber}</Text>
|
<Text fz={"10px"}>
|
||||||
|
Line {el.lineNumber || el.line_number || ""}
|
||||||
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
))}
|
))}
|
||||||
|
|
|
||||||
|
|
@ -228,7 +228,7 @@ export const ButtonScenario = ({
|
||||||
apcName: "apc_2",
|
apcName: "apc_2",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (scenario?.send_result)
|
if (scenario?.send_result || scenario?.sendResult)
|
||||||
socket?.emit("run_all_dpelp", {
|
socket?.emit("run_all_dpelp", {
|
||||||
lineIds: selectedLines?.map((el) => el.id),
|
lineIds: selectedLines?.map((el) => el.id),
|
||||||
stationName: station?.name,
|
stationName: station?.name,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,234 @@
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Flex,
|
||||||
|
Modal,
|
||||||
|
ScrollArea,
|
||||||
|
Select,
|
||||||
|
Table,
|
||||||
|
Text,
|
||||||
|
} from "@mantine/core";
|
||||||
|
import type { Socket } from "socket.io-client";
|
||||||
|
import { useEffect, useRef } from "react";
|
||||||
|
import type { IScenario, TLine, TStation } from "../../untils/types";
|
||||||
|
import { useDisclosure } from "@mantine/hooks";
|
||||||
|
|
||||||
|
const ModalConfirmRunScenario = ({
|
||||||
|
socket,
|
||||||
|
station,
|
||||||
|
scenarios,
|
||||||
|
}: {
|
||||||
|
socket: Socket | null;
|
||||||
|
station: TStation | undefined;
|
||||||
|
scenarios: IScenario[];
|
||||||
|
}) => {
|
||||||
|
const [opened, { open, close }] = useDisclosure(false);
|
||||||
|
const listLines = useRef<TLine[]>([]);
|
||||||
|
// const [listChecked, setListChecked] = useState<number[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!socket) return;
|
||||||
|
socket.on("confirm_scenario", (data) => {
|
||||||
|
const line = station?.lines?.find((el) => el.id === data.id);
|
||||||
|
console.log(data, line);
|
||||||
|
if (listLines.current.find((el) => el.id === data.id)) return;
|
||||||
|
listLines.current = [
|
||||||
|
...listLines.current,
|
||||||
|
line ? { ...line, ...data } : data,
|
||||||
|
];
|
||||||
|
// setListChecked([...listChecked, data.id]);
|
||||||
|
if (!opened) open();
|
||||||
|
});
|
||||||
|
// ✅ cleanup on unmount or when socket changes
|
||||||
|
return () => {
|
||||||
|
socket.off("confirm_scenario");
|
||||||
|
};
|
||||||
|
}, [socket, listLines, opened, station]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
style={{ position: "absolute", left: 0 }}
|
||||||
|
opened={opened}
|
||||||
|
closeOnClickOutside={false}
|
||||||
|
closeButtonProps={{ display: "none" }}
|
||||||
|
onClose={() => {
|
||||||
|
// close();
|
||||||
|
// setListChecked([]);
|
||||||
|
// setListLines([]);
|
||||||
|
}}
|
||||||
|
title={
|
||||||
|
<Text fz={"lg"} fw={"bolder"}>
|
||||||
|
Confirm run scenario
|
||||||
|
</Text>
|
||||||
|
}
|
||||||
|
size="xl"
|
||||||
|
>
|
||||||
|
<ScrollArea h={"60vh"} style={{ marginTop: "15px" }}>
|
||||||
|
<Table
|
||||||
|
stickyHeader
|
||||||
|
striped
|
||||||
|
highlightOnHover
|
||||||
|
withRowBorders={true}
|
||||||
|
withTableBorder={true}
|
||||||
|
withColumnBorders={true}
|
||||||
|
>
|
||||||
|
<Table.Thead
|
||||||
|
style={{
|
||||||
|
top: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Table.Tr>
|
||||||
|
<Table.Th
|
||||||
|
style={{
|
||||||
|
width: "70px",
|
||||||
|
textAlign: "center",
|
||||||
|
backgroundColor: "#94c6ff",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Line
|
||||||
|
</Table.Th>
|
||||||
|
<Table.Th
|
||||||
|
style={{
|
||||||
|
width: "140px",
|
||||||
|
textAlign: "center",
|
||||||
|
backgroundColor: "#94c6ff",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Brand
|
||||||
|
</Table.Th>
|
||||||
|
<Table.Th
|
||||||
|
style={{
|
||||||
|
width: "140px ",
|
||||||
|
textAlign: "center",
|
||||||
|
backgroundColor: "#94c6ff",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Category
|
||||||
|
</Table.Th>
|
||||||
|
<Table.Th
|
||||||
|
style={{
|
||||||
|
textAlign: "center",
|
||||||
|
backgroundColor: "#94c6ff",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Scenario
|
||||||
|
</Table.Th>
|
||||||
|
{/* <Table.Th
|
||||||
|
style={{
|
||||||
|
width: "70px",
|
||||||
|
textAlign: "center",
|
||||||
|
backgroundColor: "#94c6ff",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Action
|
||||||
|
</Table.Th> */}
|
||||||
|
</Table.Tr>
|
||||||
|
</Table.Thead>
|
||||||
|
<Table.Tbody>
|
||||||
|
{listLines.current
|
||||||
|
?.sort((a, b) => (a?.id || 0) - (b?.id || 0))
|
||||||
|
?.map((line) => (
|
||||||
|
<Table.Tr key={line.id}>
|
||||||
|
<Table.Td
|
||||||
|
style={{
|
||||||
|
textAlign: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{line.lineNumber || line.line_number || ""}
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td
|
||||||
|
style={{
|
||||||
|
textAlign: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{line?.scenario?.brand?.name || ""}
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td
|
||||||
|
style={{
|
||||||
|
textAlign: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{line?.scenario?.category?.name || ""}
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
<Select
|
||||||
|
placeholder="Select scenario"
|
||||||
|
data={scenarios?.map((el) => ({
|
||||||
|
value: el.id.toString(),
|
||||||
|
label: el.title,
|
||||||
|
}))}
|
||||||
|
value={line.scenario?.id.toString() || null}
|
||||||
|
onChange={(value) => {
|
||||||
|
if (value)
|
||||||
|
listLines.current = listLines.current.map((li) =>
|
||||||
|
li.id === line.id
|
||||||
|
? {
|
||||||
|
...li,
|
||||||
|
scenario: scenarios.find(
|
||||||
|
(el) => el.id.toString() === value
|
||||||
|
),
|
||||||
|
}
|
||||||
|
: li
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Table.Td>
|
||||||
|
{/* <Table.Td
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
height: "50px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
checked={listChecked?.includes(line?.id || 0)}
|
||||||
|
onChange={() => {
|
||||||
|
if (listChecked?.includes(line?.id || 0))
|
||||||
|
setListChecked((pre) =>
|
||||||
|
pre.filter((el) => el !== line?.id)
|
||||||
|
);
|
||||||
|
else setListChecked((pre) => [...pre, line?.id || 0]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Table.Td> */}
|
||||||
|
</Table.Tr>
|
||||||
|
))}
|
||||||
|
</Table.Tbody>
|
||||||
|
</Table>
|
||||||
|
</ScrollArea>
|
||||||
|
<Flex justify={"flex-end"}>
|
||||||
|
<Box>
|
||||||
|
<Button
|
||||||
|
color="green"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => {
|
||||||
|
close();
|
||||||
|
listLines.current.forEach((line) => {
|
||||||
|
const scenario = line.scenario;
|
||||||
|
if (scenario)
|
||||||
|
socket?.emit(
|
||||||
|
"run_scenario",
|
||||||
|
Object.assign(line, {
|
||||||
|
scenario: {
|
||||||
|
...scenario,
|
||||||
|
isReboot:
|
||||||
|
typeof scenario?.isReboot !== "undefined"
|
||||||
|
? scenario?.isReboot
|
||||||
|
: scenario?.is_reboot,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
listLines.current = [];
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Confirm
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Flex>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ModalConfirmRunScenario;
|
||||||
|
|
@ -491,7 +491,10 @@ const ModalRunScenario = ({
|
||||||
apcName: "apc_2",
|
apcName: "apc_2",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (scenario?.send_result)
|
if (
|
||||||
|
scenario?.send_result ||
|
||||||
|
scenario?.sendResult
|
||||||
|
)
|
||||||
socket?.emit("run_all_dpelp", {
|
socket?.emit("run_all_dpelp", {
|
||||||
lineIds: selectedLines?.map((el) => el.id),
|
lineIds: selectedLines?.map((el) => el.id),
|
||||||
stationName: station.name,
|
stationName: station.name,
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,14 @@ function ModalScenario({
|
||||||
if (!value) return "Title is required";
|
if (!value) return "Title is required";
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
brandId: (value) => {
|
||||||
|
if (!value) return "Brand is required";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
categoryId: (value) => {
|
||||||
|
if (!value) return "Category is required";
|
||||||
|
return null;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -131,6 +139,22 @@ function ModalScenario({
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!form.values.brandId) {
|
||||||
|
notifications.show({
|
||||||
|
title: "Error",
|
||||||
|
message: "Brand is required",
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!form.values.categoryId) {
|
||||||
|
notifications.show({
|
||||||
|
title: "Error",
|
||||||
|
message: "Category is required",
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
setIsSubmit(true);
|
setIsSubmit(true);
|
||||||
try {
|
try {
|
||||||
const body = form.values.body.map((el: IBodyScenario) => ({
|
const body = form.values.body.map((el: IBodyScenario) => ({
|
||||||
|
|
@ -345,7 +369,9 @@ function ModalScenario({
|
||||||
);
|
);
|
||||||
form.setFieldValue(
|
form.setFieldValue(
|
||||||
"send_result",
|
"send_result",
|
||||||
scenario.send_result
|
typeof scenario.sendResult !== "undefined"
|
||||||
|
? scenario.sendResult
|
||||||
|
: scenario?.send_result
|
||||||
);
|
);
|
||||||
form.setFieldValue("note", scenario.note);
|
form.setFieldValue("note", scenario.note);
|
||||||
form.setFieldValue(
|
form.setFieldValue(
|
||||||
|
|
@ -486,6 +512,8 @@ function ModalScenario({
|
||||||
onChange={(value) =>
|
onChange={(value) =>
|
||||||
form.setFieldValue("brandId", value || "")
|
form.setFieldValue("brandId", value || "")
|
||||||
}
|
}
|
||||||
|
required
|
||||||
|
error={form.errors.brandId}
|
||||||
/>
|
/>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
<Grid.Col span={2}>
|
<Grid.Col span={2}>
|
||||||
|
|
@ -500,6 +528,8 @@ function ModalScenario({
|
||||||
onChange={(value) =>
|
onChange={(value) =>
|
||||||
form.setFieldValue("categoryId", value || "")
|
form.setFieldValue("categoryId", value || "")
|
||||||
}
|
}
|
||||||
|
required
|
||||||
|
error={form.errors.categoryId}
|
||||||
/>
|
/>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
<Grid.Col span={2}>
|
<Grid.Col span={2}>
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ const TableRows = ({ element, i, form, deleteRow, addRowUnder }: IPayload) => {
|
||||||
</Box> */}
|
</Box> */}
|
||||||
<TextInput
|
<TextInput
|
||||||
style={{ width: "300px" }}
|
style={{ width: "300px" }}
|
||||||
value={element.expect}
|
value={element.expect || ""}
|
||||||
placeholder="Expect previous output"
|
placeholder="Expect previous output"
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const newBody = [...form.values.body];
|
const newBody = [...form.values.body];
|
||||||
|
|
@ -85,7 +85,7 @@ const TableRows = ({ element, i, form, deleteRow, addRowUnder }: IPayload) => {
|
||||||
<Table.Td>
|
<Table.Td>
|
||||||
<TextInput
|
<TextInput
|
||||||
style={{ width: "350px" }}
|
style={{ width: "350px" }}
|
||||||
value={element.send}
|
value={element.send || ""}
|
||||||
placeholder="Command send"
|
placeholder="Command send"
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const newBody = [...form.values.body];
|
const newBody = [...form.values.body];
|
||||||
|
|
@ -101,7 +101,7 @@ const TableRows = ({ element, i, form, deleteRow, addRowUnder }: IPayload) => {
|
||||||
<Table.Td>
|
<Table.Td>
|
||||||
<TextInput
|
<TextInput
|
||||||
style={{ width: "100px" }}
|
style={{ width: "100px" }}
|
||||||
value={element.delay}
|
value={element.delay || ""}
|
||||||
placeholder="Delay send"
|
placeholder="Delay send"
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const value = numberOnly(e.target.value);
|
const value = numberOnly(e.target.value);
|
||||||
|
|
@ -120,7 +120,7 @@ const TableRows = ({ element, i, form, deleteRow, addRowUnder }: IPayload) => {
|
||||||
<Table.Td>
|
<Table.Td>
|
||||||
<TextInput
|
<TextInput
|
||||||
style={{ width: "70px" }}
|
style={{ width: "70px" }}
|
||||||
value={element.repeat}
|
value={element.repeat || ""}
|
||||||
placeholder="Repeat"
|
placeholder="Repeat"
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const value = numberOnly(e.target.value);
|
const value = numberOnly(e.target.value);
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,7 @@ export type TLine = {
|
||||||
tickets?: TDataTicket[];
|
tickets?: TDataTicket[];
|
||||||
connecting?: boolean;
|
connecting?: boolean;
|
||||||
runningScenario?: string;
|
runningScenario?: string;
|
||||||
|
scenario?: IScenario;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TUser = {
|
export type TUser = {
|
||||||
|
|
@ -165,6 +166,7 @@ export type IScenario = {
|
||||||
isReboot: boolean;
|
isReboot: boolean;
|
||||||
is_reboot: boolean;
|
is_reboot: boolean;
|
||||||
send_result: boolean;
|
send_result: boolean;
|
||||||
|
sendResult?: boolean;
|
||||||
brandId: number;
|
brandId: number;
|
||||||
brand_id?: number;
|
brand_id?: number;
|
||||||
brand?: TBrands;
|
brand?: TBrands;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue