Update UI Bottom Tool Bar
This commit is contained in:
parent
f04bc0b4c1
commit
31036ff7da
|
|
@ -17,8 +17,8 @@ interface PromptCallback {
|
|||
}
|
||||
|
||||
class APCController {
|
||||
private apc_number?: number
|
||||
private apc_ip: string
|
||||
public apc_number?: number
|
||||
public apc_ip: string
|
||||
private apc_port: number
|
||||
private apc_username: string
|
||||
private apc_password: string
|
||||
|
|
@ -100,7 +100,7 @@ class APCController {
|
|||
this.buffer = ''
|
||||
}
|
||||
}
|
||||
// appendLog(data, 0, 0, this.apc_number || 0)
|
||||
appendLog(data, 0, 0, this.apc_number || 0)
|
||||
}
|
||||
|
||||
private _handleClose(): void {
|
||||
|
|
@ -130,7 +130,7 @@ class APCController {
|
|||
setTimeout(() => {
|
||||
console.log('[ECONNRESET] Trying reconnect apc:', this.apc_ip)
|
||||
this.reconnect()
|
||||
}, 10000)
|
||||
}, 15000)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ export default class LineConnection {
|
|||
})
|
||||
}
|
||||
|
||||
writeCommand(cmd: string, isWrite = false) {
|
||||
writeCommand(cmd: string | Buffer<ArrayBuffer>, isWrite = false) {
|
||||
if (this.client.destroyed) {
|
||||
console.log(`⚠️ Cannot send, line ${this.config.lineNumber} is closed`)
|
||||
return
|
||||
|
|
@ -513,4 +513,17 @@ export default class LineConnection {
|
|||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
// Gửi nhiều ký tự ESC để vào ROMMON
|
||||
breakSpam() {
|
||||
let count = 0
|
||||
const escInterval = setInterval(() => {
|
||||
if (count >= 100) {
|
||||
clearInterval(escInterval)
|
||||
return
|
||||
}
|
||||
this.writeCommand(Buffer.from([0xff, 0xf3])) // Ctrl + Break
|
||||
count++
|
||||
}, 1)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ export default class SwitchController {
|
|||
private _waitFor(prompt: string, timeout = 5000): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timer = setTimeout(() => {
|
||||
reject(new Error(`Timeout waiting for: ${prompt}`))
|
||||
resolve(`Timeout waiting for: ${prompt}`)
|
||||
}, timeout)
|
||||
|
||||
this.promptCallbacks.push({
|
||||
|
|
@ -188,58 +188,74 @@ export default class SwitchController {
|
|||
public async turnPortOff(port: string) {
|
||||
await this.enterEnableMode()
|
||||
this._send(`configure terminal`)
|
||||
await this._waitFor('(config)#')
|
||||
// await this._waitFor('(config)#')
|
||||
await this.sleep(500)
|
||||
this._send(`interface ${port}`)
|
||||
await this._waitFor('(config-if)#')
|
||||
// await this._waitFor('(config-if)#')
|
||||
await this.sleep(500)
|
||||
this._send(`shutdown`)
|
||||
await this._waitFor('(config-if)#')
|
||||
// await this._waitFor('(config-if)#')
|
||||
await this.sleep(500)
|
||||
this._send(`end`)
|
||||
}
|
||||
|
||||
public async turnPortOn(port: string) {
|
||||
await this.enterEnableMode()
|
||||
this._send(`configure terminal`)
|
||||
await this._waitFor('(config)#')
|
||||
// await this._waitFor('(config)#')
|
||||
await this.sleep(500)
|
||||
this._send(`interface ${port}`)
|
||||
await this._waitFor('(config-if)#')
|
||||
// await this._waitFor('(config-if)#')
|
||||
await this.sleep(500)
|
||||
this._send(`no shutdown`)
|
||||
await this._waitFor('(config-if)#')
|
||||
// await this._waitFor('(config-if)#')
|
||||
await this.sleep(500)
|
||||
this._send(`end`)
|
||||
}
|
||||
|
||||
public async restartPort(port: string) {
|
||||
await this.enterEnableMode()
|
||||
this._send(`configure terminal`)
|
||||
await this._waitFor('(config)#')
|
||||
// await this._waitFor('(config)#')
|
||||
await this.sleep(500)
|
||||
this._send(`interface ${port}`)
|
||||
await this._waitFor('(config-if)#')
|
||||
// await this._waitFor('(config-if)#')
|
||||
await this.sleep(500)
|
||||
this._send(`shutdown`)
|
||||
await this._waitFor('(config-if)#')
|
||||
// await this._waitFor('(config-if)#')
|
||||
await this.sleep(500)
|
||||
await this.sleep(2000)
|
||||
this._send(`no shutdown`)
|
||||
await this._waitFor('(config-if)#')
|
||||
// await this._waitFor('(config-if)#')
|
||||
await this.sleep(500)
|
||||
this._send(`end`)
|
||||
}
|
||||
|
||||
public async disablePoE(port: string) {
|
||||
await this.enterEnableMode()
|
||||
this._send(`configure terminal`)
|
||||
await this._waitFor('(config)#')
|
||||
// await this._waitFor('(config)#')
|
||||
await this.sleep(500)
|
||||
this._send(`interface ${port}`)
|
||||
await this._waitFor('(config-if)#')
|
||||
// await this._waitFor('(config-if)#')
|
||||
await this.sleep(500)
|
||||
this._send(`power inline never`)
|
||||
await this._waitFor('(config-if)#')
|
||||
// await this._waitFor('(config-if)#')
|
||||
await this.sleep(500)
|
||||
this._send(`end`)
|
||||
}
|
||||
|
||||
public async enablePoE(port: string) {
|
||||
await this.enterEnableMode()
|
||||
this._send(`configure terminal`)
|
||||
await this._waitFor('(config)#')
|
||||
// await this._waitFor('(config)#')
|
||||
await this.sleep(500)
|
||||
this._send(`interface ${port}`)
|
||||
await this._waitFor('(config-if)#')
|
||||
// await this._waitFor('(config-if)#')
|
||||
await this.sleep(500)
|
||||
this._send(`power inline auto`)
|
||||
await this._waitFor('(config-if)#')
|
||||
// await this._waitFor('(config-if)#')
|
||||
await this.sleep(500)
|
||||
this._send(`end`)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,12 +63,12 @@ export default class SocketIoProvider {
|
|||
|
||||
export class WebSocketIo {
|
||||
intervalMap: { [key: string]: NodeJS.Timeout } = {}
|
||||
stationMap: Map<number, Station> = new Map()
|
||||
lineMap: Map<number, LineConnection> = new Map() // key = lineId
|
||||
userConnecting: Map<number, { userId: number; userName: string }> = new Map()
|
||||
apcsControl: Map<string, APCController> = new Map()
|
||||
switchControl: Map<string, SwitchController> = new Map()
|
||||
lineConnecting: number[] = [] // key = lineId
|
||||
intervalKeepConnect: { [key: string]: NodeJS.Timeout } = {}
|
||||
|
||||
constructor(protected app: ApplicationService) {}
|
||||
|
||||
|
|
@ -115,7 +115,16 @@ export class WebSocketIo {
|
|||
listLineS.forEach((el) => {
|
||||
if (el?.userOpenCLI === userName) {
|
||||
const line = this.lineMap.get(el.id)
|
||||
if (line && line?.userCloseCLI()) line?.userCloseCLI()
|
||||
if (line) {
|
||||
line.config.openCLI = false
|
||||
line.config.userEmailOpenCLI = ''
|
||||
line.config.userOpenCLI = ''
|
||||
io.emit('user_close_cli', {
|
||||
stationId: line.config.stationId,
|
||||
lineId: line.config.id,
|
||||
userEmailOpenCLI: '',
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
setTimeout(() => {
|
||||
|
|
@ -136,7 +145,8 @@ export class WebSocketIo {
|
|||
io,
|
||||
stationId,
|
||||
lineIds,
|
||||
async (line) => line.writeCommand(command, true),
|
||||
async (line) =>
|
||||
command === 'spam_break' ? line.breakSpam() : line.writeCommand(command, true),
|
||||
{ command, timeout: 120000 }
|
||||
)
|
||||
})
|
||||
|
|
@ -159,21 +169,26 @@ export class WebSocketIo {
|
|||
socket.on('open_cli', async (data) => {
|
||||
const { lineId, userEmail, userName: name, stationId } = data
|
||||
const line = this.lineMap.get(lineId)
|
||||
if (line && line?.userOpenCLI) {
|
||||
line?.userOpenCLI({ userEmail, userName: name })
|
||||
if (line) {
|
||||
if (line?.userOpenCLI) line?.userOpenCLI({ userEmail, userName: name })
|
||||
else {
|
||||
line.config.openCLI = true
|
||||
line.config.userEmailOpenCLI = userEmail
|
||||
line.config.userOpenCLI = userName
|
||||
io.emit('user_open_cli', {
|
||||
stationId: line.config.stationId,
|
||||
lineId: line.config.id,
|
||||
userEmailOpenCLI: userEmail,
|
||||
userOpenCLI: userName,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if (this.lineConnecting.includes(lineId)) return
|
||||
const linesData = await Line.findBy('id', lineId)
|
||||
const stationData = await Station.findBy('id', stationId)
|
||||
if (linesData && stationData) {
|
||||
this.lineConnecting.push(lineId)
|
||||
await this.connectLine(
|
||||
io,
|
||||
[linesData],
|
||||
stationData,
|
||||
line?.config?.output || '',
|
||||
line?.config?.commands || []
|
||||
)
|
||||
await this.connectLine(io, [linesData], stationData)
|
||||
const lineReconnect = this.lineMap.get(lineId)
|
||||
if (lineReconnect) {
|
||||
lineReconnect.userOpenCLI({ userEmail, userName: name })
|
||||
|
|
@ -185,21 +200,25 @@ export class WebSocketIo {
|
|||
socket.on('close_cli', async (data) => {
|
||||
const { lineId, stationId } = data
|
||||
const line = this.lineMap.get(lineId)
|
||||
if (line && line?.userCloseCLI) {
|
||||
line?.userCloseCLI()
|
||||
if (line) {
|
||||
if (line?.userCloseCLI) line?.userCloseCLI()
|
||||
else {
|
||||
line.config.openCLI = false
|
||||
line.config.userEmailOpenCLI = ''
|
||||
line.config.userOpenCLI = ''
|
||||
io.emit('user_close_cli', {
|
||||
stationId: line.config.stationId,
|
||||
lineId: line.config.id,
|
||||
userEmailOpenCLI: '',
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if (this.lineConnecting.includes(lineId)) return
|
||||
const linesData = await Line.findBy('id', lineId)
|
||||
const stationData = await Station.findBy('id', stationId)
|
||||
if (linesData && stationData) {
|
||||
this.lineConnecting.push(lineId)
|
||||
await this.connectLine(
|
||||
io,
|
||||
[linesData],
|
||||
stationData,
|
||||
line?.config?.output || '',
|
||||
line?.config?.commands || []
|
||||
)
|
||||
await this.connectLine(io, [linesData], stationData)
|
||||
const lineReconnect = this.lineMap.get(lineId)
|
||||
if (lineReconnect) {
|
||||
lineReconnect.userCloseCLI()
|
||||
|
|
@ -265,7 +284,10 @@ export class WebSocketIo {
|
|||
if (!station) return
|
||||
const apcIp = (station as any)[`${apcName}_ip`] as string
|
||||
const apc = this.apcsControl.get(apcIp)
|
||||
if (apc) await apc.reconnect()
|
||||
if (apc) {
|
||||
await apc.reconnect()
|
||||
this.keepConnectAPC(apcIp, io)
|
||||
} else await this.connectApc(io, apcName, station)
|
||||
} else {
|
||||
for (const outletNumber of outletNumbers) {
|
||||
if (!outletNumber || outletNumber < 0) return
|
||||
|
|
@ -282,7 +304,11 @@ export class WebSocketIo {
|
|||
|
||||
const apcIp = (station as any)[`${apcName}_ip`] as string
|
||||
const apc = this.apcsControl.get(apcIp)
|
||||
if (apc && apc.status === 'CONNECTED') {
|
||||
if (apc && apc.status !== 'CONNECTED') {
|
||||
await apc.reconnect()
|
||||
this.keepConnectAPC(apcIp, io)
|
||||
}
|
||||
if (apc) {
|
||||
switch (action) {
|
||||
case 'on':
|
||||
await apc?.turnOnOutlet(outletNumber)
|
||||
|
|
@ -302,24 +328,6 @@ export class WebSocketIo {
|
|||
setTimeout(() => {
|
||||
apc?.navigateToOutlets()
|
||||
}, 10000)
|
||||
} else if (apc && apc.status !== 'CONNECTED') {
|
||||
await apc.reconnect()
|
||||
switch (action) {
|
||||
case 'on':
|
||||
await apc?.turnOnOutlet(outletNumber)
|
||||
break
|
||||
case 'off':
|
||||
await apc?.turnOffOutlet(outletNumber)
|
||||
break
|
||||
case 'restart':
|
||||
await apc?.restartOutlet(outletNumber)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
setTimeout(() => {
|
||||
apc?.navigateToOutlets()
|
||||
}, 10000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -336,8 +344,11 @@ export class WebSocketIo {
|
|||
data: apc.output,
|
||||
status: apc.status,
|
||||
})
|
||||
this.keepConnectAPC(apcIp, io)
|
||||
} else if (apc && apc.status !== 'CONNECTED') {
|
||||
await apc.reconnect()
|
||||
this.apcsControl.set(apcIp, apc)
|
||||
this.keepConnectAPC(apcIp, io)
|
||||
} else await this.connectApc(io, apcName, station)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
|
|
@ -442,7 +453,6 @@ export class WebSocketIo {
|
|||
commands: string[] = []
|
||||
) {
|
||||
try {
|
||||
this.stationMap.set(station.id, station)
|
||||
for (const line of lines) {
|
||||
const lineConn = new LineConnection(
|
||||
{
|
||||
|
|
@ -584,6 +594,7 @@ export class WebSocketIo {
|
|||
await apc.connect()
|
||||
await apc.login()
|
||||
this.apcsControl.set(ip, apc)
|
||||
this.keepConnectAPC(ip, socket)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
|
|
@ -603,7 +614,7 @@ export class WebSocketIo {
|
|||
status: 'DISCONNECTED',
|
||||
message: `Missing Switch configuration`,
|
||||
})
|
||||
throw new Error(`Missing Switch configuration`)
|
||||
return
|
||||
}
|
||||
|
||||
// Tạo APC Controller instance
|
||||
|
|
@ -633,7 +644,10 @@ export class WebSocketIo {
|
|||
|
||||
private async clearLineBeforeConnect(stationId: number, clearLine: number) {
|
||||
const station = await Station.find(stationId)
|
||||
if (!station) throw new Error(`Station ${stationId} not found`)
|
||||
if (!station) {
|
||||
console.log('[ERROR connect station] Not found!')
|
||||
return
|
||||
}
|
||||
|
||||
// Kết nối tới station qua Telnet / Socket
|
||||
const client = new net.Socket()
|
||||
|
|
@ -679,7 +693,9 @@ export class WebSocketIo {
|
|||
const newMap = new Map<number, LineConnection>()
|
||||
this.lineMap.forEach((line, id) => {
|
||||
if (line && line.config) {
|
||||
newMap.set(id, { config: { ...line.config, status: 'disconnected' } } as LineConnection)
|
||||
newMap.set(id, {
|
||||
config: { ...line.config, status: 'disconnected' },
|
||||
} as LineConnection)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -695,4 +711,19 @@ export class WebSocketIo {
|
|||
const parsed = JSON.parse(raw)
|
||||
this.lineMap = new Map(parsed.lineMap)
|
||||
}
|
||||
|
||||
private keepConnectAPC = (ip: string, io: any) => {
|
||||
if (this.intervalKeepConnect[`${ip}`]) {
|
||||
clearInterval(this.intervalKeepConnect[`${ip}`])
|
||||
delete this.intervalKeepConnect[`${ip}`]
|
||||
}
|
||||
const interval = setInterval(() => {
|
||||
const apcConnect = this.apcsControl.get(ip)
|
||||
if (apcConnect && apcConnect.status === 'CONNECTED') {
|
||||
apcConnect._send('ENTER')
|
||||
}
|
||||
}, 40000)
|
||||
|
||||
this.intervalKeepConnect[`${ip}`] = interval
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,3 +70,10 @@ body {
|
|||
margin: 0.1rem auto 0;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.containerMain {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
height: 88vh;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,22 +27,22 @@ import type {
|
|||
import axios from "axios";
|
||||
import CardLine from "./components/CardLine";
|
||||
import { SocketProvider, useSocket } from "./context/SocketContext";
|
||||
import {
|
||||
// ButtonConnect,
|
||||
ButtonControlApc,
|
||||
ButtonCopy,
|
||||
ButtonDPELP,
|
||||
ButtonScenario,
|
||||
ButtonSelect,
|
||||
} from "./components/ButtonAction";
|
||||
import // ButtonConnect,
|
||||
// ButtonControlApc,
|
||||
// ButtonCopy,
|
||||
// ButtonDPELP,
|
||||
// ButtonScenario,
|
||||
// ButtonSelect,
|
||||
"./components/ButtonAction";
|
||||
import StationSetting from "./components/FormAddEdit";
|
||||
import DrawerScenario from "./components/DrawerScenario";
|
||||
// import DrawerScenario from "./components/DrawerScenario";
|
||||
import { Notifications } from "@mantine/notifications";
|
||||
import ModalTerminal from "./components/ModalTerminal";
|
||||
import PageLogin from "./components/Authentication/LoginPage";
|
||||
import DrawerLogs from "./components/DrawerLogs";
|
||||
// import DrawerLogs from "./components/DrawerLogs";
|
||||
import DraggableTabs from "./components/DragTabs";
|
||||
import { isJsonString } from "./untils/helper";
|
||||
import BottomToolBar from "./components/BottomToolBar";
|
||||
|
||||
const apiUrl = import.meta.env.VITE_BACKEND_URL;
|
||||
|
||||
|
|
@ -67,7 +67,6 @@ function App() {
|
|||
const [stations, setStations] = useState<TStation[]>([]);
|
||||
const [selectedLines, setSelectedLines] = useState<TLine[]>([]);
|
||||
const [activeTab, setActiveTab] = useState("0");
|
||||
const [showBottomShadow, setShowBottomShadow] = useState(false);
|
||||
const [isDisable, setIsDisable] = useState(false);
|
||||
const [isOpenAddStation, setIsOpenAddStation] = useState(false);
|
||||
const [isEditStation, setIsEditStation] = useState(false);
|
||||
|
|
@ -84,6 +83,29 @@ function App() {
|
|||
const [testLogContent, setTestLogContent] = useState("");
|
||||
const [isLogModalOpen, setIsLogModalOpen] = useState(false);
|
||||
|
||||
const connectApcSwitch = (station: TStation) => {
|
||||
if (station?.apc_1_ip && station?.apc_1_port) {
|
||||
socket?.emit("connect_apc", {
|
||||
station: station,
|
||||
apcIp: station?.apc_1_ip,
|
||||
apcName: "apc_1",
|
||||
});
|
||||
}
|
||||
if (station?.apc_2_ip && station?.apc_2_port) {
|
||||
socket?.emit("connect_apc", {
|
||||
station: station,
|
||||
apcIp: station?.apc_2_ip,
|
||||
apcName: "apc_2",
|
||||
});
|
||||
}
|
||||
if (station?.switch_control_ip && station?.switch_control_port) {
|
||||
socket?.emit("connect_switch", {
|
||||
station: station,
|
||||
ip: station?.switch_control_ip,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// function get list station
|
||||
const getStation = async () => {
|
||||
try {
|
||||
|
|
@ -91,6 +113,9 @@ function App() {
|
|||
if (response.status) {
|
||||
if (Array.isArray(response.data)) {
|
||||
setStations(response.data);
|
||||
response.data.forEach((station) => {
|
||||
connectApcSwitch(station);
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
@ -113,9 +138,10 @@ function App() {
|
|||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!socket) return;
|
||||
getStation();
|
||||
getScenarios();
|
||||
}, []);
|
||||
}, [socket]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!socket || !stations?.length) return;
|
||||
|
|
@ -363,16 +389,6 @@ function App() {
|
|||
setSelectedLine(data);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (selectedLine)
|
||||
socket?.emit("close_cli", {
|
||||
lineId: selectedLine?.id,
|
||||
stationId: selectedLine?.station_id,
|
||||
});
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Container w={"100%"} style={{ maxWidth: "100%" }}>
|
||||
<DraggableTabs
|
||||
|
|
@ -389,60 +405,30 @@ function App() {
|
|||
value={station.id.toString()}
|
||||
pt="md"
|
||||
>
|
||||
<Grid>
|
||||
<Grid.Col
|
||||
span={11}
|
||||
style={{
|
||||
boxShadow: showBottomShadow
|
||||
? "inset 0 -12px 10px -10px rgba(0, 0, 0, 0.2)"
|
||||
: "none",
|
||||
borderRadius: 8,
|
||||
}}
|
||||
>
|
||||
<ScrollArea
|
||||
h={"84vh"}
|
||||
onScrollPositionChange={({ y }) => {
|
||||
const el = document.querySelector(
|
||||
".mantine-ScrollArea-viewport"
|
||||
);
|
||||
if (!el) return;
|
||||
const maxScroll = el.scrollHeight - el.clientHeight;
|
||||
setShowBottomShadow(y < maxScroll - 2);
|
||||
<Flex className={classes.containerMain}>
|
||||
<Grid>
|
||||
<Grid.Col
|
||||
span={12}
|
||||
style={{
|
||||
borderRadius: 8,
|
||||
}}
|
||||
>
|
||||
{station.lines.length > 8 ? (
|
||||
<Grid
|
||||
style={{
|
||||
marginLeft: "3%",
|
||||
width: "90%",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<Grid.Col span={6}>
|
||||
<Flex wrap="wrap" gap="sm" justify={"center"}>
|
||||
{station.lines.slice(0, 8).map((line, i) => (
|
||||
<CardLine
|
||||
key={i}
|
||||
socket={socket}
|
||||
stationItem={station}
|
||||
line={line}
|
||||
selectedLines={selectedLines}
|
||||
setSelectedLines={setSelectedLines}
|
||||
openTerminal={openTerminal}
|
||||
loadTerminal={
|
||||
loadingTerminal &&
|
||||
Number(station.id) === Number(activeTab)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Flex>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={6}>
|
||||
<Flex wrap="wrap" gap="sm" justify={"center"}>
|
||||
{station.lines
|
||||
.slice(8, station.lines.length)
|
||||
.map((line, i) => (
|
||||
<ScrollArea h={"63vh"}>
|
||||
{station.lines.length > 8 ? (
|
||||
<Grid
|
||||
style={{
|
||||
marginLeft: "3%",
|
||||
width: "95%",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<Grid.Col
|
||||
span={6}
|
||||
style={{ borderRight: "1px solid #ccc" }}
|
||||
>
|
||||
<Flex wrap="wrap" gap="sm" justify={"center"}>
|
||||
{station.lines.slice(0, 8).map((line, i) => (
|
||||
<CardLine
|
||||
key={i}
|
||||
socket={socket}
|
||||
|
|
@ -457,142 +443,70 @@ function App() {
|
|||
}
|
||||
/>
|
||||
))}
|
||||
</Flex>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
) : station.lines.length <= 8 && station.lines.length > 0 ? (
|
||||
<Flex wrap="wrap" gap="sm" justify={"center"}>
|
||||
{station.lines.map((line, i) => (
|
||||
<CardLine
|
||||
key={i}
|
||||
socket={socket}
|
||||
stationItem={station}
|
||||
line={line}
|
||||
selectedLines={selectedLines}
|
||||
setSelectedLines={setSelectedLines}
|
||||
openTerminal={openTerminal}
|
||||
loadTerminal={
|
||||
loadingTerminal &&
|
||||
Number(station.id) === Number(activeTab)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Flex>
|
||||
) : (
|
||||
<Text ta="center" c="dimmed" mt="lg">
|
||||
No lines configured
|
||||
</Text>
|
||||
)}
|
||||
</ScrollArea>
|
||||
</Grid.Col>
|
||||
<Grid.Col
|
||||
span={1}
|
||||
style={{ backgroundColor: "#f1f1f1", borderRadius: 8 }}
|
||||
>
|
||||
<Flex
|
||||
direction={"column"}
|
||||
justify={"space-between"}
|
||||
align={"center"}
|
||||
h={"100%"}
|
||||
>
|
||||
<Flex
|
||||
direction={"column"}
|
||||
align={"center"}
|
||||
gap={"6px"}
|
||||
wrap={"wrap"}
|
||||
>
|
||||
<ButtonSelect
|
||||
selectedLines={selectedLines}
|
||||
setSelectedLines={setSelectedLines}
|
||||
station={station}
|
||||
/>
|
||||
{/* <ButtonConnect
|
||||
selectedLines={selectedLines}
|
||||
setSelectedLines={setSelectedLines}
|
||||
station={station}
|
||||
socket={socket}
|
||||
/> */}
|
||||
<ButtonControlApc
|
||||
selectedLines={selectedLines}
|
||||
setSelectedLines={setSelectedLines}
|
||||
station={station}
|
||||
socket={socket}
|
||||
/>
|
||||
<ButtonCopy
|
||||
selectedLines={selectedLines}
|
||||
setSelectedLines={setSelectedLines}
|
||||
/>
|
||||
<Flex
|
||||
w={"100%"}
|
||||
direction={"column"}
|
||||
align={"center"}
|
||||
wrap={"wrap"}
|
||||
>
|
||||
<hr style={{ width: "100%" }} />
|
||||
<DrawerScenario
|
||||
scenarios={scenarios}
|
||||
setScenarios={setScenarios}
|
||||
/>
|
||||
</Flex>
|
||||
<ButtonDPELP
|
||||
socket={socket}
|
||||
selectedLines={selectedLines}
|
||||
isDisable={isDisable || selectedLines.length === 0}
|
||||
onClick={() => {
|
||||
setSelectedLines([]);
|
||||
setIsDisable(true);
|
||||
setTimeout(() => {
|
||||
setIsDisable(false);
|
||||
}, 5000);
|
||||
}}
|
||||
/>
|
||||
<ScrollArea h={"60vh"} style={{ paddingBottom: "12px" }}>
|
||||
<Flex
|
||||
w={"100%"}
|
||||
direction={"column"}
|
||||
wrap={"wrap"}
|
||||
gap={"6px"}
|
||||
>
|
||||
{scenarios.map((el, i) => (
|
||||
<ButtonScenario
|
||||
</Flex>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={6}>
|
||||
<Flex wrap="wrap" gap="sm" justify={"center"}>
|
||||
{station.lines
|
||||
.slice(8, station.lines.length)
|
||||
.map((line, i) => (
|
||||
<CardLine
|
||||
key={i}
|
||||
socket={socket}
|
||||
stationItem={station}
|
||||
line={line}
|
||||
selectedLines={selectedLines}
|
||||
setSelectedLines={setSelectedLines}
|
||||
openTerminal={openTerminal}
|
||||
loadTerminal={
|
||||
loadingTerminal &&
|
||||
Number(station.id) === Number(activeTab)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Flex>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
) : station.lines.length <= 8 &&
|
||||
station.lines.length > 0 ? (
|
||||
<Flex wrap="wrap" gap="sm" justify={"center"}>
|
||||
{station.lines.map((line, i) => (
|
||||
<CardLine
|
||||
key={i}
|
||||
socket={socket}
|
||||
selectedLines={selectedLines.filter(
|
||||
(el) =>
|
||||
!el?.userEmailOpenCLI ||
|
||||
el?.userEmailOpenCLI === user?.email
|
||||
)}
|
||||
isDisable={
|
||||
isDisable ||
|
||||
selectedLines.filter(
|
||||
(el) =>
|
||||
!el?.userEmailOpenCLI ||
|
||||
el?.userEmailOpenCLI === user?.email
|
||||
).length === 0
|
||||
stationItem={station}
|
||||
line={line}
|
||||
selectedLines={selectedLines}
|
||||
setSelectedLines={setSelectedLines}
|
||||
openTerminal={openTerminal}
|
||||
loadTerminal={
|
||||
loadingTerminal &&
|
||||
Number(station.id) === Number(activeTab)
|
||||
}
|
||||
onClick={() => {
|
||||
setSelectedLines([]);
|
||||
setIsDisable(true);
|
||||
setTimeout(() => {
|
||||
setIsDisable(false);
|
||||
}, 5000);
|
||||
}}
|
||||
scenario={el}
|
||||
/>
|
||||
))}
|
||||
</Flex>
|
||||
</ScrollArea>
|
||||
</Flex>
|
||||
<DrawerLogs
|
||||
socket={socket}
|
||||
isLogModalOpen={isLogModalOpen}
|
||||
setIsLogModalOpen={setIsLogModalOpen}
|
||||
testLogContent={testLogContent}
|
||||
setTestLogContent={setTestLogContent}
|
||||
/>
|
||||
</Flex>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
) : (
|
||||
<Text ta="center" c="dimmed" mt="lg">
|
||||
No lines configured
|
||||
</Text>
|
||||
)}
|
||||
</ScrollArea>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
<BottomToolBar
|
||||
selectedLines={selectedLines}
|
||||
socket={socket}
|
||||
setSelectedLines={setSelectedLines}
|
||||
isDisable={isDisable}
|
||||
setIsDisable={setIsDisable}
|
||||
station={station}
|
||||
testLogContent={testLogContent}
|
||||
isLogModalOpen={isLogModalOpen}
|
||||
setIsLogModalOpen={setIsLogModalOpen}
|
||||
setTestLogContent={setTestLogContent}
|
||||
/>
|
||||
</Flex>
|
||||
</Tabs.Panel>
|
||||
))}
|
||||
onChange={(id) => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,278 @@
|
|||
import {
|
||||
Box,
|
||||
Button,
|
||||
CloseButton,
|
||||
Flex,
|
||||
Input,
|
||||
ScrollArea,
|
||||
Tabs,
|
||||
Text,
|
||||
} from "@mantine/core";
|
||||
import { useState } from "react";
|
||||
import classes from "./Component.module.css";
|
||||
import type { TLine, TStation } from "../untils/types";
|
||||
import type { Socket } from "socket.io-client";
|
||||
import { ButtonDPELP, ButtonSelect } from "./ButtonAction";
|
||||
import DrawerLogs from "./DrawerLogs";
|
||||
import { DrawerAPCControl, DrawerSwitchControl } from "./DrawerControl";
|
||||
|
||||
interface TabsProps {
|
||||
selectedLines: TLine[];
|
||||
socket: Socket | null;
|
||||
setSelectedLines: (lines: React.SetStateAction<TLine[]>) => void;
|
||||
isDisable: boolean;
|
||||
station: TStation;
|
||||
setIsDisable: (lines: React.SetStateAction<boolean>) => void;
|
||||
testLogContent: string;
|
||||
isLogModalOpen: boolean;
|
||||
setIsLogModalOpen: (lines: React.SetStateAction<boolean>) => void;
|
||||
setTestLogContent: (lines: React.SetStateAction<string>) => void;
|
||||
}
|
||||
|
||||
const BottomToolBar = ({
|
||||
selectedLines,
|
||||
socket,
|
||||
setSelectedLines,
|
||||
isDisable,
|
||||
station,
|
||||
setIsDisable,
|
||||
testLogContent,
|
||||
isLogModalOpen,
|
||||
setIsLogModalOpen,
|
||||
setTestLogContent,
|
||||
}: TabsProps) => {
|
||||
const [valueInput, setValueInput] = useState<string>("");
|
||||
const [activeTabBottom, setActiveBottom] = useState<string>("command");
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
defaultValue="command"
|
||||
orientation="vertical"
|
||||
value={activeTabBottom}
|
||||
onChange={(val) => {
|
||||
setActiveBottom(val || "command");
|
||||
}}
|
||||
className={classes.containerBottom}
|
||||
>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab
|
||||
style={{
|
||||
backgroundColor: activeTabBottom === "command" ? "#c8d9fd" : "",
|
||||
}}
|
||||
value="command"
|
||||
>
|
||||
Command Line
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab
|
||||
style={{
|
||||
backgroundColor: activeTabBottom === "apc" ? "#c8d9fd" : "",
|
||||
}}
|
||||
value="apc"
|
||||
>
|
||||
APC
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab
|
||||
style={{
|
||||
backgroundColor: activeTabBottom === "switch" ? "#c8d9fd" : "",
|
||||
}}
|
||||
value="switch"
|
||||
>
|
||||
Switch
|
||||
</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
|
||||
<Tabs.Panel value="command" p={"xs"}>
|
||||
<Flex justify={"space-between"}>
|
||||
<ScrollArea h={"17vh"}>
|
||||
<Flex wrap={"wrap"} gap={"xs"} w={"400px"}>
|
||||
{selectedLines.map((el) => (
|
||||
<Box
|
||||
key={el.id}
|
||||
style={{
|
||||
paddingLeft: "4px",
|
||||
height: "30px",
|
||||
width: "80px",
|
||||
backgroundColor: "#d4e3ff",
|
||||
borderRadius: "8px",
|
||||
}}
|
||||
>
|
||||
<Flex align={"center"} justify={"center"} gap={"4px"}>
|
||||
<Text fz={"12px"}>Line {el.lineNumber}</Text>
|
||||
<CloseButton
|
||||
style={{ minWidth: "24px" }}
|
||||
aria-label="Clear input"
|
||||
onClick={() =>
|
||||
setSelectedLines(
|
||||
selectedLines.filter((line) => line.id !== el.id)
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Flex>
|
||||
</Box>
|
||||
))}
|
||||
</Flex>
|
||||
</ScrollArea>
|
||||
<Box pl={"md"} pr={"md"}>
|
||||
<Flex justify={"space-between"} mb={"xs"}>
|
||||
<Flex></Flex>
|
||||
<Button
|
||||
disabled={isDisable || selectedLines.length === 0}
|
||||
variant="filled"
|
||||
color="orange"
|
||||
size="xs"
|
||||
radius="md"
|
||||
onClick={() => {
|
||||
const listLine = selectedLines.length
|
||||
? selectedLines
|
||||
: station?.lines;
|
||||
if (listLine.length) {
|
||||
socket?.emit("write_command_line_from_web", {
|
||||
lineIds: listLine.map((line) => line.id),
|
||||
stationId: station.id,
|
||||
command: " \n",
|
||||
});
|
||||
setIsDisable(true);
|
||||
setTimeout(() => {
|
||||
setIsDisable(false);
|
||||
}, 5000);
|
||||
}
|
||||
}}
|
||||
>
|
||||
Send Break
|
||||
</Button>
|
||||
</Flex>
|
||||
<Box>
|
||||
<Input
|
||||
style={{
|
||||
width: "600px",
|
||||
boxShadow: "0px 0px 10px rgba(0, 0, 0, 0.1)",
|
||||
}}
|
||||
placeholder={"Send command to port(s)"}
|
||||
value={valueInput}
|
||||
onChange={(event) => {
|
||||
const newValue = event.currentTarget.value;
|
||||
setValueInput(newValue);
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter") {
|
||||
const listLine = selectedLines.length
|
||||
? selectedLines
|
||||
: station?.lines;
|
||||
if (listLine?.length) {
|
||||
socket?.emit("write_command_line_from_web", {
|
||||
lineIds: listLine.map((line) => line.id),
|
||||
stationId: station.id,
|
||||
command: valueInput + "\n",
|
||||
});
|
||||
setTimeout(() => {
|
||||
socket?.emit("write_command_line_from_web", {
|
||||
lineIds: listLine.map((line) => line.id),
|
||||
stationId: station.id,
|
||||
command: " \n",
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
setValueInput("");
|
||||
}
|
||||
}}
|
||||
rightSectionPointerEvents="all"
|
||||
rightSection={
|
||||
<CloseButton
|
||||
aria-label="Clear input"
|
||||
onClick={() => setValueInput("")}
|
||||
style={{
|
||||
display: valueInput ? undefined : "none",
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box style={{ width: "220px" }}>
|
||||
<Flex align={"center"} wrap={"wrap"} gap={"xs"}>
|
||||
<ButtonSelect
|
||||
selectedLines={selectedLines}
|
||||
setSelectedLines={setSelectedLines}
|
||||
station={station}
|
||||
/>
|
||||
<ButtonDPELP
|
||||
socket={socket}
|
||||
selectedLines={selectedLines}
|
||||
isDisable={isDisable || selectedLines.length === 0}
|
||||
onClick={() => {
|
||||
setSelectedLines([]);
|
||||
setIsDisable(true);
|
||||
setTimeout(() => {
|
||||
setIsDisable(false);
|
||||
}, 5000);
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
disabled={isDisable || selectedLines.length === 0}
|
||||
variant="outline"
|
||||
color="green"
|
||||
style={{ height: "30px", width: "100px" }}
|
||||
onClick={() => {
|
||||
if (selectedLines.length !== station.lines.length)
|
||||
setSelectedLines(station.lines);
|
||||
else setSelectedLines([]);
|
||||
}}
|
||||
>
|
||||
Scenario
|
||||
</Button>
|
||||
{/* <Flex
|
||||
w={"100%"}
|
||||
direction={"column"}
|
||||
wrap={"wrap"}
|
||||
gap={"6px"}
|
||||
>
|
||||
{scenarios.map((el, i) => (
|
||||
<ButtonScenario
|
||||
key={i}
|
||||
socket={socket}
|
||||
selectedLines={selectedLines.filter(
|
||||
(el) =>
|
||||
!el?.userEmailOpenCLI ||
|
||||
el?.userEmailOpenCLI === user?.email
|
||||
)}
|
||||
isDisable={
|
||||
isDisable ||
|
||||
selectedLines.filter(
|
||||
(el) =>
|
||||
!el?.userEmailOpenCLI ||
|
||||
el?.userEmailOpenCLI === user?.email
|
||||
).length === 0
|
||||
}
|
||||
onClick={() => {
|
||||
setSelectedLines([]);
|
||||
setIsDisable(true);
|
||||
setTimeout(() => {
|
||||
setIsDisable(false);
|
||||
}, 5000);
|
||||
}}
|
||||
scenario={el}
|
||||
/>
|
||||
))}
|
||||
</Flex> */}
|
||||
<DrawerLogs
|
||||
socket={socket}
|
||||
isLogModalOpen={isLogModalOpen}
|
||||
setIsLogModalOpen={setIsLogModalOpen}
|
||||
testLogContent={testLogContent}
|
||||
setTestLogContent={setTestLogContent}
|
||||
/>
|
||||
</Flex>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel value="apc" ps={"xs"}>
|
||||
<DrawerAPCControl socket={socket} stationAPI={station} />
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel value="switch" ps={"xs"}>
|
||||
<DrawerSwitchControl socket={socket} stationAPI={station} />
|
||||
</Tabs.Panel>
|
||||
</Tabs>
|
||||
);
|
||||
};
|
||||
|
||||
export default BottomToolBar;
|
||||
|
|
@ -111,3 +111,11 @@
|
|||
.hideScrollBar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.containerBottom {
|
||||
height: 22vh;
|
||||
padding: 8px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 8px;
|
||||
background-color: #f3f3f38c;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,8 @@ import {
|
|||
ActionIcon,
|
||||
Avatar,
|
||||
Box,
|
||||
Button,
|
||||
CloseButton,
|
||||
Flex,
|
||||
Group,
|
||||
Input,
|
||||
Menu,
|
||||
Tabs,
|
||||
Text,
|
||||
|
|
@ -39,7 +36,6 @@ import {
|
|||
import classes from "./Component.module.css";
|
||||
import type { TStation, TUser } from "../untils/types";
|
||||
import type { Socket } from "socket.io-client";
|
||||
import { DrawerAPCControl, DrawerSwitchControl } from "./DrawerControl";
|
||||
|
||||
interface DraggableTabsProps {
|
||||
tabsData: TStation[];
|
||||
|
|
@ -87,6 +83,7 @@ function SortableTab({
|
|||
transition,
|
||||
cursor: "grab",
|
||||
userSelect: "none",
|
||||
backgroundColor: active === tab.id.toString() ? "#deffde" : "",
|
||||
}}
|
||||
color={active === tab.id.toString() ? "green" : ""}
|
||||
fw={600}
|
||||
|
|
@ -116,7 +113,6 @@ export default function DraggableTabs({
|
|||
setStationEdit,
|
||||
active,
|
||||
setActive,
|
||||
onSendCommand,
|
||||
}: DraggableTabsProps) {
|
||||
const user = useMemo(() => {
|
||||
return localStorage.getItem("user") &&
|
||||
|
|
@ -127,12 +123,6 @@ export default function DraggableTabs({
|
|||
const [tabs, setTabs] = useState<TStation[]>(tabsData);
|
||||
const [isChangeTab, setIsChangeTab] = useState<boolean>(false);
|
||||
const [isSetActive, setIsSetActive] = useState<boolean>(false);
|
||||
const [valueInput, setValueInput] = useState<string>("");
|
||||
const [openedAPC, setOpenedAPC] = useState(false);
|
||||
const [openedSwitch, setOpenedSwitch] = useState(false);
|
||||
// const [active, setActive] = useState<string | null>(
|
||||
// tabsData?.length > 0 ? tabsData[0]?.id.toString() : null
|
||||
// );
|
||||
|
||||
const sensors = useSensors(useSensor(PointerSensor));
|
||||
|
||||
|
|
@ -220,29 +210,6 @@ export default function DraggableTabs({
|
|||
};
|
||||
}, []);
|
||||
|
||||
const connectApcSwitch = (station: TStation) => {
|
||||
if (station?.apc_1_ip && station?.apc_1_port) {
|
||||
socket?.emit("connect_apc", {
|
||||
station: station,
|
||||
apcIp: station?.apc_1_ip,
|
||||
apcName: "apc_1",
|
||||
});
|
||||
}
|
||||
if (station?.apc_2_ip && station?.apc_2_port) {
|
||||
socket?.emit("connect_apc", {
|
||||
station: station,
|
||||
apcIp: station?.apc_2_ip,
|
||||
apcName: "apc_2",
|
||||
});
|
||||
}
|
||||
if (station?.switch_control_ip && station?.switch_control_port) {
|
||||
socket?.emit("connect_switch", {
|
||||
station: station,
|
||||
ip: station?.switch_control_ip,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<DndContext
|
||||
sensors={sensors}
|
||||
|
|
@ -259,69 +226,7 @@ export default function DraggableTabs({
|
|||
w={w}
|
||||
>
|
||||
<Flex justify={"space-between"}>
|
||||
<Flex style={{ width: "400px" }} align={"center"}>
|
||||
<Input
|
||||
style={{
|
||||
width: "300px",
|
||||
boxShadow: "0px 0px 10px rgba(0, 0, 0, 0.1)",
|
||||
}}
|
||||
placeholder={"Chat to Port/All"}
|
||||
value={valueInput}
|
||||
onChange={(event) => {
|
||||
const newValue = event.currentTarget.value;
|
||||
setValueInput(newValue);
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter") {
|
||||
onSendCommand(valueInput);
|
||||
setValueInput("");
|
||||
}
|
||||
}}
|
||||
rightSectionPointerEvents="all"
|
||||
rightSection={
|
||||
<CloseButton
|
||||
aria-label="Clear input"
|
||||
onClick={() => setValueInput("")}
|
||||
style={{ display: valueInput ? undefined : "none" }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Flex gap={"xs"} ms={"md"}>
|
||||
<Button
|
||||
miw={"80px"}
|
||||
size="xs"
|
||||
fz={"sm"}
|
||||
variant="filled"
|
||||
onClick={() => {
|
||||
const station = tabs.find(
|
||||
(el) => el.id.toString() === active
|
||||
);
|
||||
if (!station) return;
|
||||
setOpenedAPC(true);
|
||||
connectApcSwitch(station);
|
||||
}}
|
||||
>
|
||||
APC
|
||||
</Button>
|
||||
<Button
|
||||
miw={"80px"}
|
||||
size="xs"
|
||||
fz={"sm"}
|
||||
variant="filled"
|
||||
color="yellow"
|
||||
onClick={() => {
|
||||
const station = tabs.find(
|
||||
(el) => el.id.toString() === active
|
||||
);
|
||||
if (!station) return;
|
||||
setOpenedSwitch(true);
|
||||
connectApcSwitch(station);
|
||||
}}
|
||||
>
|
||||
Switch
|
||||
</Button>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex></Flex>
|
||||
<Tabs.List className={classes.list}>
|
||||
<SortableContext
|
||||
items={tabs}
|
||||
|
|
@ -429,36 +334,6 @@ export default function DraggableTabs({
|
|||
|
||||
{panels}
|
||||
</Tabs>
|
||||
|
||||
{tabs.find((el) => el.id.toString() === active) && (
|
||||
<DrawerAPCControl
|
||||
open={openedAPC}
|
||||
onClose={() => {
|
||||
setOpenedAPC(false);
|
||||
}}
|
||||
socket={socket}
|
||||
stationAPI={tabs.find((el) => el.id.toString() === active) || tabs[0]}
|
||||
openedSwitch={() => {
|
||||
setOpenedAPC(false);
|
||||
setOpenedSwitch(true);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{tabs.find((el) => el.id.toString() === active) && (
|
||||
<DrawerSwitchControl
|
||||
open={openedSwitch}
|
||||
onClose={() => {
|
||||
setOpenedSwitch(false);
|
||||
}}
|
||||
socket={socket}
|
||||
stationAPI={tabs.find((el) => el.id.toString() === active) || tabs[0]}
|
||||
openedAPC={() => {
|
||||
setOpenedSwitch(false);
|
||||
setOpenedAPC(true);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</DndContext>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -177,6 +177,7 @@ function DrawerLogs({
|
|||
</Drawer>
|
||||
|
||||
<Button
|
||||
style={{ height: "30px", width: "100px" }}
|
||||
title="Add Scenario"
|
||||
variant="outline"
|
||||
// color="green"
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@ const TerminalCLI: React.FC<TerminalCLIProps> = ({
|
|||
loadingContent = false,
|
||||
onFocus,
|
||||
onBlur,
|
||||
line,
|
||||
}) => {
|
||||
const xtermRef = useRef<HTMLDivElement>(null);
|
||||
const terminal = useRef<Terminal>(null);
|
||||
|
|
|
|||
Loading…
Reference in New Issue