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 duplicatedSeries: string[] = []
|
||||
for (const sc of existedScenarios) {
|
||||
if (sc.id === scenarioId) continue
|
||||
const scSeries: string[] = JSON.parse(sc.series || '[]').map((s: string) =>
|
||||
s.trim().toUpperCase()
|
||||
)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ export default class Scenario extends BaseModel {
|
|||
@column()
|
||||
declare send_result: boolean
|
||||
|
||||
@column()
|
||||
declare sendResult: boolean
|
||||
|
||||
@column()
|
||||
declare brandId: number
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,14 @@
|
|||
import fs from 'node:fs'
|
||||
import { textfsmResults } from './../ultils/templates/index.js'
|
||||
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 Station from '#models/station'
|
||||
import APCController from './apc_connection.js'
|
||||
|
|
@ -345,7 +352,8 @@ export default class LineConnection {
|
|||
lineId: this.config.id,
|
||||
title: script?.title,
|
||||
})
|
||||
if (script?.send_result) this.dataDPELP = ''
|
||||
if (script?.send_result || script?.sendResult) this.dataDPELP = ''
|
||||
|
||||
if (script?.isReboot) {
|
||||
await sleep(10000)
|
||||
for (let index = 0; index < 30; index++) {
|
||||
|
|
@ -381,6 +389,17 @@ export default class LineConnection {
|
|||
this.outputBuffer = ''
|
||||
this.outputScenario = ''
|
||||
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', {
|
||||
stationId: this.config.stationId,
|
||||
lineId: this.config.id,
|
||||
|
|
@ -426,6 +445,7 @@ export default class LineConnection {
|
|||
|
||||
const logScenarios = this.outputScenario
|
||||
const data = textfsmResults(logScenarios, '')
|
||||
let pid = ''
|
||||
try {
|
||||
data.forEach((item) => {
|
||||
if (item?.textfsm && isValidJson(item?.textfsm)) {
|
||||
|
|
@ -434,6 +454,7 @@ export default class LineConnection {
|
|||
) {
|
||||
const dataInventory = JSON.parse(item.textfsm)[0]
|
||||
this.config.inventory = dataInventory
|
||||
pid = dataInventory?.pid || ''
|
||||
this.addHistory(this.config.stationId, this.config.id, {
|
||||
id: this.config.id,
|
||||
number: this.config.lineNumber,
|
||||
|
|
@ -448,6 +469,18 @@ export default class LineConnection {
|
|||
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 result = mapToLineFormat({
|
||||
lineNumber: this.config.lineNumber,
|
||||
|
|
@ -457,7 +490,7 @@ export default class LineConnection {
|
|||
},
|
||||
data,
|
||||
})
|
||||
if (script?.send_result) {
|
||||
if (script?.send_result || script?.sendResult) {
|
||||
this.dataDPELP = result
|
||||
console.log(
|
||||
`DPELP DATA line ${this.config.lineNumber} of ${this.config.stationName}:`,
|
||||
|
|
@ -589,102 +622,14 @@ export default class LineConnection {
|
|||
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 = () => {
|
||||
const data = textfsmResults(this.outputInventory, 'show inventory')
|
||||
try {
|
||||
data.forEach((item) => {
|
||||
if (item?.textfsm && isValidJson(item?.textfsm)) {
|
||||
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import Scenario from '#models/scenario'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
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 axios from 'axios'
|
||||
import StationConnection from '#services/station_connection'
|
||||
import Scenario from '#models/scenario'
|
||||
|
||||
interface HandleOptions {
|
||||
command?: string
|
||||
|
|
@ -573,23 +574,24 @@ export class WebSocketIo {
|
|||
|
||||
const linkWiki =
|
||||
process.env.LINK_WIKI || 'https://logs.danielvu.com/api/wiki/page/insert?title=Dev_test'
|
||||
await axios.post(linkWiki, {
|
||||
data: tableHTML,
|
||||
titleAuto: `[${scenarioName || 'DPELP'}] - ${stationName} - ` + dataFormat,
|
||||
})
|
||||
// await axios.post(linkWiki, {
|
||||
// data: tableHTML,
|
||||
// titleAuto: `[${scenarioName || 'DPELP'}] - ${stationName} - ` + dataFormat,
|
||||
// })
|
||||
await sendMessageToMail(
|
||||
'andrew.ng@apactech.io',
|
||||
`[${scenarioName || 'DPELP'}] - ${stationName} - ${dataFormat}`,
|
||||
tableHTML,
|
||||
['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
|
||||
tableHTML
|
||||
// ,
|
||||
// ['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
|
||||
// )
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ import PageLogin from "./components/Authentication/LoginPage";
|
|||
import DraggableTabs from "./components/DragTabs";
|
||||
import { isJsonString } from "./untils/helper";
|
||||
import BottomToolBar from "./components/BottomToolBar";
|
||||
import ModalConfirmRunScenario from "./components/Modal/ModalConfirmRunScenario";
|
||||
|
||||
const apiUrl = import.meta.env.VITE_BACKEND_URL;
|
||||
|
||||
|
|
@ -825,6 +826,12 @@ function App() {
|
|||
stationItem={stations.find((el) => el.id === Number(activeTab))}
|
||||
scenarios={scenarios}
|
||||
/>
|
||||
|
||||
<ModalConfirmRunScenario
|
||||
socket={socket}
|
||||
station={stations.find((el) => el.id === Number(activeTab))}
|
||||
scenarios={scenarios}
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -237,7 +237,9 @@ const BottomToolBar = ({
|
|||
justify={"center"}
|
||||
h="100%"
|
||||
>
|
||||
<Text fz={"11px"}>Line {el.lineNumber}</Text>
|
||||
<Text fz={"11px"}>
|
||||
Line {el.lineNumber || el.line_number || ""}
|
||||
</Text>
|
||||
</Flex>
|
||||
</Box>
|
||||
))}
|
||||
|
|
@ -507,7 +509,9 @@ const BottomToolBar = ({
|
|||
}}
|
||||
/>
|
||||
<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>
|
||||
</Box>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ export const ButtonScenario = ({
|
|||
apcName: "apc_2",
|
||||
});
|
||||
}
|
||||
if (scenario?.send_result)
|
||||
if (scenario?.send_result || scenario?.sendResult)
|
||||
socket?.emit("run_all_dpelp", {
|
||||
lineIds: selectedLines?.map((el) => el.id),
|
||||
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",
|
||||
});
|
||||
}
|
||||
if (scenario?.send_result)
|
||||
if (
|
||||
scenario?.send_result ||
|
||||
scenario?.sendResult
|
||||
)
|
||||
socket?.emit("run_all_dpelp", {
|
||||
lineIds: selectedLines?.map((el) => el.id),
|
||||
stationName: station.name,
|
||||
|
|
|
|||
|
|
@ -94,6 +94,14 @@ function ModalScenario({
|
|||
if (!value) return "Title is required";
|
||||
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;
|
||||
}
|
||||
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);
|
||||
try {
|
||||
const body = form.values.body.map((el: IBodyScenario) => ({
|
||||
|
|
@ -345,7 +369,9 @@ function ModalScenario({
|
|||
);
|
||||
form.setFieldValue(
|
||||
"send_result",
|
||||
scenario.send_result
|
||||
typeof scenario.sendResult !== "undefined"
|
||||
? scenario.sendResult
|
||||
: scenario?.send_result
|
||||
);
|
||||
form.setFieldValue("note", scenario.note);
|
||||
form.setFieldValue(
|
||||
|
|
@ -486,6 +512,8 @@ function ModalScenario({
|
|||
onChange={(value) =>
|
||||
form.setFieldValue("brandId", value || "")
|
||||
}
|
||||
required
|
||||
error={form.errors.brandId}
|
||||
/>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={2}>
|
||||
|
|
@ -500,6 +528,8 @@ function ModalScenario({
|
|||
onChange={(value) =>
|
||||
form.setFieldValue("categoryId", value || "")
|
||||
}
|
||||
required
|
||||
error={form.errors.categoryId}
|
||||
/>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={2}>
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ const TableRows = ({ element, i, form, deleteRow, addRowUnder }: IPayload) => {
|
|||
</Box> */}
|
||||
<TextInput
|
||||
style={{ width: "300px" }}
|
||||
value={element.expect}
|
||||
value={element.expect || ""}
|
||||
placeholder="Expect previous output"
|
||||
onChange={(e) => {
|
||||
const newBody = [...form.values.body];
|
||||
|
|
@ -85,7 +85,7 @@ const TableRows = ({ element, i, form, deleteRow, addRowUnder }: IPayload) => {
|
|||
<Table.Td>
|
||||
<TextInput
|
||||
style={{ width: "350px" }}
|
||||
value={element.send}
|
||||
value={element.send || ""}
|
||||
placeholder="Command send"
|
||||
onChange={(e) => {
|
||||
const newBody = [...form.values.body];
|
||||
|
|
@ -101,7 +101,7 @@ const TableRows = ({ element, i, form, deleteRow, addRowUnder }: IPayload) => {
|
|||
<Table.Td>
|
||||
<TextInput
|
||||
style={{ width: "100px" }}
|
||||
value={element.delay}
|
||||
value={element.delay || ""}
|
||||
placeholder="Delay send"
|
||||
onChange={(e) => {
|
||||
const value = numberOnly(e.target.value);
|
||||
|
|
@ -120,7 +120,7 @@ const TableRows = ({ element, i, form, deleteRow, addRowUnder }: IPayload) => {
|
|||
<Table.Td>
|
||||
<TextInput
|
||||
style={{ width: "70px" }}
|
||||
value={element.repeat}
|
||||
value={element.repeat || ""}
|
||||
placeholder="Repeat"
|
||||
onChange={(e) => {
|
||||
const value = numberOnly(e.target.value);
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ export type TLine = {
|
|||
tickets?: TDataTicket[];
|
||||
connecting?: boolean;
|
||||
runningScenario?: string;
|
||||
scenario?: IScenario;
|
||||
};
|
||||
|
||||
export type TUser = {
|
||||
|
|
@ -165,6 +166,7 @@ export type IScenario = {
|
|||
isReboot: boolean;
|
||||
is_reboot: boolean;
|
||||
send_result: boolean;
|
||||
sendResult?: boolean;
|
||||
brandId: number;
|
||||
brand_id?: number;
|
||||
brand?: TBrands;
|
||||
|
|
|
|||
Loading…
Reference in New Issue