Merge pull request 'Refactor log handling and improve output buffering' (#5) from that into main
Reviewed-on: #5
This commit is contained in:
commit
55954d0bda
|
|
@ -17,6 +17,8 @@ interface LineConfig {
|
||||||
lineNumber: number
|
lineNumber: number
|
||||||
ip: string
|
ip: string
|
||||||
stationId: number
|
stationId: number
|
||||||
|
stationName: string
|
||||||
|
stationIp: string
|
||||||
apcName?: string
|
apcName?: string
|
||||||
outlet: number
|
outlet: number
|
||||||
output: string
|
output: string
|
||||||
|
|
@ -36,8 +38,17 @@ interface LineConfig {
|
||||||
textfsm: string
|
textfsm: string
|
||||||
}[]
|
}[]
|
||||||
commands: string[]
|
commands: string[]
|
||||||
|
// history: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** HISTORY
|
||||||
|
* PID
|
||||||
|
* SN
|
||||||
|
* VID
|
||||||
|
* Timestamp
|
||||||
|
* Scenario
|
||||||
|
*/
|
||||||
|
|
||||||
interface User {
|
interface User {
|
||||||
userEmail: string
|
userEmail: string
|
||||||
userName: string
|
userName: string
|
||||||
|
|
@ -81,7 +92,7 @@ export default class LineConnection {
|
||||||
if (resolvedOrRejected) return
|
if (resolvedOrRejected) return
|
||||||
resolvedOrRejected = true
|
resolvedOrRejected = true
|
||||||
|
|
||||||
console.log(`✅ Connected to line ${lineNumber} (${ip}:${port})`)
|
console.log(`[${Date.now()}] ✅ Connected to line ${lineNumber} (${ip}:${port})`)
|
||||||
this.connecting = true
|
this.connecting = true
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.config.status = 'connected'
|
this.config.status = 'connected'
|
||||||
|
|
@ -135,8 +146,9 @@ export default class LineConnection {
|
||||||
appendLog(
|
appendLog(
|
||||||
cleanData(message),
|
cleanData(message),
|
||||||
this.config.stationId,
|
this.config.stationId,
|
||||||
this.config.lineNumber,
|
this.config.stationName,
|
||||||
this.config.port
|
this.config.stationIp,
|
||||||
|
this.config.lineNumber
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -154,7 +166,7 @@ export default class LineConnection {
|
||||||
})
|
})
|
||||||
|
|
||||||
this.client.on('close', () => {
|
this.client.on('close', () => {
|
||||||
console.log(`🔌 Line ${lineNumber} disconnected`)
|
console.log(`[${Date.now()}] 🔌 Line ${lineNumber} disconnected`)
|
||||||
this.config.status = 'disconnected'
|
this.config.status = 'disconnected'
|
||||||
// this.config.inventory = undefined
|
// this.config.inventory = undefined
|
||||||
this.socketIO.emit('line_disconnected', {
|
this.socketIO.emit('line_disconnected', {
|
||||||
|
|
@ -178,8 +190,9 @@ export default class LineConnection {
|
||||||
appendLog(
|
appendLog(
|
||||||
cleanData(message),
|
cleanData(message),
|
||||||
this.config.stationId,
|
this.config.stationId,
|
||||||
this.config.lineNumber,
|
this.config.stationName,
|
||||||
this.config.port
|
this.config.stationIp,
|
||||||
|
this.config.lineNumber
|
||||||
)
|
)
|
||||||
console.log(`⏳ Connection timeout line ${lineNumber}`)
|
console.log(`⏳ Connection timeout line ${lineNumber}`)
|
||||||
this.client.destroy()
|
this.client.destroy()
|
||||||
|
|
@ -257,8 +270,9 @@ export default class LineConnection {
|
||||||
appendLog(
|
appendLog(
|
||||||
`\n\n---start-scenarios---${now}---${userName}---\n---scenario---${script?.title}---${now}---\n`,
|
`\n\n---start-scenarios---${now}---${userName}---\n---scenario---${script?.title}---${now}---\n`,
|
||||||
this.config.stationId,
|
this.config.stationId,
|
||||||
this.config.lineNumber,
|
this.config.stationName,
|
||||||
this.config.port
|
this.config.stationIp,
|
||||||
|
this.config.lineNumber
|
||||||
)
|
)
|
||||||
this.config.latestScenario = {
|
this.config.latestScenario = {
|
||||||
name: script?.title,
|
name: script?.title,
|
||||||
|
|
@ -282,8 +296,9 @@ export default class LineConnection {
|
||||||
appendLog(
|
appendLog(
|
||||||
`\n---end-scenarios---${now}---${userName}---\n`,
|
`\n---end-scenarios---${now}---${userName}---\n`,
|
||||||
this.config.stationId,
|
this.config.stationId,
|
||||||
this.config.lineNumber,
|
this.config.stationName,
|
||||||
this.config.port
|
this.config.stationIp,
|
||||||
|
this.config.lineNumber
|
||||||
)
|
)
|
||||||
// reject(new Error('Script timeout'))
|
// reject(new Error('Script timeout'))
|
||||||
}, script.timeout || 300000)
|
}, script.timeout || 300000)
|
||||||
|
|
@ -303,8 +318,9 @@ export default class LineConnection {
|
||||||
appendLog(
|
appendLog(
|
||||||
`\n---end-scenarios---${now}---${userName}---\n`,
|
`\n---end-scenarios---${now}---${userName}---\n`,
|
||||||
this.config.stationId,
|
this.config.stationId,
|
||||||
this.config.lineNumber,
|
this.config.stationName,
|
||||||
this.config.port
|
this.config.stationIp,
|
||||||
|
this.config.lineNumber
|
||||||
)
|
)
|
||||||
|
|
||||||
const logScenarios = getLogWithTimeScenario(this.outputScenario, now) || ''
|
const logScenarios = getLogWithTimeScenario(this.outputScenario, now) || ''
|
||||||
|
|
@ -342,8 +358,9 @@ export default class LineConnection {
|
||||||
appendLog(
|
appendLog(
|
||||||
`\n---send-command---"${step?.send ?? ''}"---${now}---\n`,
|
`\n---send-command---"${step?.send ?? ''}"---${now}---\n`,
|
||||||
this.config.stationId,
|
this.config.stationId,
|
||||||
this.config.lineNumber,
|
this.config.stationName,
|
||||||
this.config.port
|
this.config.stationIp,
|
||||||
|
this.config.lineNumber
|
||||||
)
|
)
|
||||||
let repeatCount = Number(step.repeat) || 1
|
let repeatCount = Number(step.repeat) || 1
|
||||||
const sendCommand = async () => {
|
const sendCommand = async () => {
|
||||||
|
|
@ -396,8 +413,9 @@ export default class LineConnection {
|
||||||
appendLog(
|
appendLog(
|
||||||
`\n-------${user.userName}-------\n`,
|
`\n-------${user.userName}-------\n`,
|
||||||
this.config.stationId,
|
this.config.stationId,
|
||||||
this.config.lineNumber,
|
this.config.stationName,
|
||||||
this.config.port
|
this.config.stationIp,
|
||||||
|
this.config.lineNumber
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -457,8 +475,9 @@ export default class LineConnection {
|
||||||
appendLog(
|
appendLog(
|
||||||
cleanData(data),
|
cleanData(data),
|
||||||
this.config.stationId,
|
this.config.stationId,
|
||||||
this.config.lineNumber,
|
this.config.stationName,
|
||||||
this.config.port
|
this.config.stationIp,
|
||||||
|
this.config.lineNumber
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ export default class SwitchController {
|
||||||
public ports: PortInfo[]
|
public ports: PortInfo[]
|
||||||
public portGroups: PortInfo[][]
|
public portGroups: PortInfo[][]
|
||||||
private isEnable: boolean
|
private isEnable: boolean
|
||||||
|
private retryConnect: number
|
||||||
|
|
||||||
constructor({ host, port = 23, username, password, onData }: SwitchControllerOptions) {
|
constructor({ host, port = 23, username, password, onData }: SwitchControllerOptions) {
|
||||||
this.host = host
|
this.host = host
|
||||||
|
|
@ -47,6 +48,7 @@ export default class SwitchController {
|
||||||
this.ports = []
|
this.ports = []
|
||||||
this.portGroups = []
|
this.portGroups = []
|
||||||
this.isEnable = false
|
this.isEnable = false
|
||||||
|
this.retryConnect = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
private sleep(ms: number) {
|
private sleep(ms: number) {
|
||||||
|
|
@ -65,10 +67,17 @@ export default class SwitchController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleClose() {
|
private async _handleClose(err: boolean) {
|
||||||
|
console.log('[SWITCH CONNECTION CLOSE]', err)
|
||||||
this.status = 'DISCONNECTED'
|
this.status = 'DISCONNECTED'
|
||||||
this.isEnable = false
|
this.isEnable = false
|
||||||
this.onData(this.portGroups, this.status)
|
this.onData(this.portGroups, this.status)
|
||||||
|
if (this.retryConnect <= 5) {
|
||||||
|
await this.sleep(15000)
|
||||||
|
console.log('Retry connect times', this.retryConnect)
|
||||||
|
this.retryConnect += 1
|
||||||
|
await this.reconnect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleError(err: Error & { code?: string }) {
|
private _handleError(err: Error & { code?: string }) {
|
||||||
|
|
@ -113,8 +122,8 @@ export default class SwitchController {
|
||||||
this.socket.on('data', (data) => this._handleData(data.toString()))
|
this.socket.on('data', (data) => this._handleData(data.toString()))
|
||||||
resolve()
|
resolve()
|
||||||
})
|
})
|
||||||
this.socket.on('close', () => {
|
this.socket.on('close', (e) => {
|
||||||
this._handleClose()
|
this._handleClose(e)
|
||||||
resolve()
|
resolve()
|
||||||
})
|
})
|
||||||
this.socket.on('error', (err) => {
|
this.socket.on('error', (err) => {
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,20 @@ export function sleep(ms: number) {
|
||||||
return new Promise((resolve) => setTimeout(resolve, ms))
|
return new Promise((resolve) => setTimeout(resolve, ms))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function appendLog(output: string, stationId: number, lineNumber: number, port: number) {
|
// 20250527-AUTO-Session.Station_1-13-192.168.171.9-2.log
|
||||||
|
// {DATE}-AUTO-Session.{Station name}-{Station ID}-{Station IP}-{Line number}.log
|
||||||
|
export function appendLog(
|
||||||
|
output: string,
|
||||||
|
stationId: number,
|
||||||
|
stationName: string,
|
||||||
|
stationIP: string,
|
||||||
|
lineNumber: number
|
||||||
|
) {
|
||||||
const date = new Date().toISOString().slice(0, 10).replace(/-/g, '') // YYYYMMDD
|
const date = new Date().toISOString().slice(0, 10).replace(/-/g, '') // YYYYMMDD
|
||||||
const logDir = path.join('storage', 'system_logs')
|
const logDir = path.join('storage', 'system_logs')
|
||||||
const logFile = path.join(logDir, `${date}-Station_${stationId}-Line_${lineNumber}_${port}.log`)
|
const logFile = path
|
||||||
|
.join(logDir, `${date}-AUTO-Session.${stationName}-${stationId}-${stationIP}-${lineNumber}.log`)
|
||||||
|
.replaceAll(' ', '_')
|
||||||
|
|
||||||
// Ensure folder exists
|
// Ensure folder exists
|
||||||
if (!fs.existsSync(logDir)) {
|
if (!fs.existsSync(logDir)) {
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ export class WebSocketIo {
|
||||||
lineIds,
|
lineIds,
|
||||||
async (line) =>
|
async (line) =>
|
||||||
command === 'spam_break' ? line.breakSpam() : line.writeCommand(command, userName),
|
command === 'spam_break' ? line.breakSpam() : line.writeCommand(command, userName),
|
||||||
{ command, timeout: 120000 }
|
{ command }
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -162,7 +162,6 @@ export class WebSocketIo {
|
||||||
async (line) => line.runScript(scenario, userName),
|
async (line) => line.runScript(scenario, userName),
|
||||||
{
|
{
|
||||||
scenario,
|
scenario,
|
||||||
timeout: scenario?.timeout ? Number(scenario.timeout) + 120000 : 300000,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
@ -203,7 +202,7 @@ export class WebSocketIo {
|
||||||
stationId,
|
stationId,
|
||||||
[lineId],
|
[lineId],
|
||||||
async (lineCon) => lineCon.writeCommand('\r\n', userName),
|
async (lineCon) => lineCon.writeCommand('\r\n', userName),
|
||||||
{ command: '\r\n', timeout: 120000 }
|
{ command: '\r\n' }
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
if (this.lineConnecting.includes(lineId)) return
|
if (this.lineConnecting.includes(lineId)) return
|
||||||
|
|
@ -322,7 +321,7 @@ export class WebSocketIo {
|
||||||
.andWhere('outlet', outletNumber)
|
.andWhere('outlet', outletNumber)
|
||||||
if (lines.length > 0) {
|
if (lines.length > 0) {
|
||||||
const line = this.lineMap.get(lines[0].id)
|
const line = this.lineMap.get(lines[0].id)
|
||||||
if (line) this.setTimeoutConnect(lines[0].id, line, 300000)
|
if (line) this.setTimeoutConnect(lines[0].id, line)
|
||||||
}
|
}
|
||||||
|
|
||||||
const apcIp = (station as any)[`${apcName}_ip`] as string
|
const apcIp = (station as any)[`${apcName}_ip`] as string
|
||||||
|
|
@ -508,6 +507,8 @@ export class WebSocketIo {
|
||||||
ip: station.ip,
|
ip: station.ip,
|
||||||
lineNumber: line.lineNumber,
|
lineNumber: line.lineNumber,
|
||||||
stationId: station.id,
|
stationId: station.id,
|
||||||
|
stationName: station.name,
|
||||||
|
stationIp: station.ip,
|
||||||
apcName: line.apcName,
|
apcName: line.apcName,
|
||||||
outlet: line.outlet,
|
outlet: line.outlet,
|
||||||
baud: line.baud,
|
baud: line.baud,
|
||||||
|
|
@ -542,7 +543,7 @@ export class WebSocketIo {
|
||||||
private setTimeoutConnect = (
|
private setTimeoutConnect = (
|
||||||
lineId: number,
|
lineId: number,
|
||||||
lineConn: LineConnection | SwitchController,
|
lineConn: LineConnection | SwitchController,
|
||||||
timeout = 120000
|
timeout = 28800000 // 8h = 8*60*60*1000
|
||||||
) => {
|
) => {
|
||||||
if (this.intervalMap[`${lineId}`]) {
|
if (this.intervalMap[`${lineId}`]) {
|
||||||
clearInterval(this.intervalMap[`${lineId}`])
|
clearInterval(this.intervalMap[`${lineId}`])
|
||||||
|
|
@ -576,7 +577,7 @@ export class WebSocketIo {
|
||||||
// console.log(line?.config)
|
// console.log(line?.config)
|
||||||
if (line && line.config.status === 'connected') {
|
if (line && line.config.status === 'connected') {
|
||||||
this.lineConnecting = this.lineConnecting.filter((el) => el !== lineId)
|
this.lineConnecting = this.lineConnecting.filter((el) => el !== lineId)
|
||||||
this.setTimeoutConnect(lineId, line, options.timeout)
|
this.setTimeoutConnect(lineId, line)
|
||||||
// await sleep(500)
|
// await sleep(500)
|
||||||
await action(line, options)
|
await action(line, options)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -598,7 +599,7 @@ export class WebSocketIo {
|
||||||
|
|
||||||
const lineReconnect = this.lineMap.get(lineId)
|
const lineReconnect = this.lineMap.get(lineId)
|
||||||
if (lineReconnect) {
|
if (lineReconnect) {
|
||||||
this.setTimeoutConnect(lineId, lineReconnect, options.timeout)
|
this.setTimeoutConnect(lineId, lineReconnect)
|
||||||
await sleep(100)
|
await sleep(100)
|
||||||
await action(lineReconnect, options)
|
await action(lineReconnect, options)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,14 @@ import "@mantine/notifications/styles.css";
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
import classes from "./App.module.css";
|
import classes from "./App.module.css";
|
||||||
|
|
||||||
import { Suspense, useCallback, useEffect, useMemo, useState } from "react";
|
import {
|
||||||
|
Suspense,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
import {
|
import {
|
||||||
Tabs,
|
Tabs,
|
||||||
Text,
|
Text,
|
||||||
|
|
@ -79,6 +86,8 @@ function App() {
|
||||||
const [isLogModalOpen, setIsLogModalOpen] = useState(false);
|
const [isLogModalOpen, setIsLogModalOpen] = useState(false);
|
||||||
const [expandedBottomBar, setExpandedBottomBar] = useState(true);
|
const [expandedBottomBar, setExpandedBottomBar] = useState(true);
|
||||||
const [activeTabBottom, setActiveTabBottom] = useState<string>("command");
|
const [activeTabBottom, setActiveTabBottom] = useState<string>("command");
|
||||||
|
const lineBuffersRef = useRef(new Map<number, string>());
|
||||||
|
const flushScheduledRef = useRef(false);
|
||||||
|
|
||||||
const connectApcSwitch = (station: TStation) => {
|
const connectApcSwitch = (station: TStation) => {
|
||||||
if (station?.apc_1_ip && station?.apc_1_port) {
|
if (station?.apc_1_ip && station?.apc_1_port) {
|
||||||
|
|
@ -165,11 +174,20 @@ function App() {
|
||||||
);
|
);
|
||||||
|
|
||||||
socket?.on("line_output", (data) => {
|
socket?.on("line_output", (data) => {
|
||||||
updateValueLineStation(
|
const { lineId, data: text } = data;
|
||||||
data?.lineId,
|
// updateValueLineStation(
|
||||||
{ netOutput: data.data, commands: data.commands || [] },
|
// data?.lineId,
|
||||||
data?.stationId
|
// { netOutput: data.data, commands: data.commands || [] },
|
||||||
);
|
// data?.stationId
|
||||||
|
// );
|
||||||
|
|
||||||
|
const buf = lineBuffersRef.current.get(lineId) || "";
|
||||||
|
lineBuffersRef.current.set(lineId, buf + text);
|
||||||
|
|
||||||
|
if (!flushScheduledRef.current) {
|
||||||
|
flushScheduledRef.current = true;
|
||||||
|
setTimeout(() => flushBuffers(), 50);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket?.on("line_error", (data) => {
|
socket?.on("line_error", (data) => {
|
||||||
|
|
@ -323,6 +341,28 @@ function App() {
|
||||||
};
|
};
|
||||||
}, [socket, stations, selectedLine]);
|
}, [socket, stations, selectedLine]);
|
||||||
|
|
||||||
|
const flushBuffers = useCallback(() => {
|
||||||
|
setStations((prev) =>
|
||||||
|
prev.map((station) => ({
|
||||||
|
...station,
|
||||||
|
lines: station.lines.map((line) => {
|
||||||
|
const buffered = lineBuffersRef.current.get(line.id || 0);
|
||||||
|
if (!buffered) return line; // không có update
|
||||||
|
updateValueSelectedLine(line?.id || 0, { netOutput: buffered });
|
||||||
|
return {
|
||||||
|
...line,
|
||||||
|
netOutput: (line.netOutput || "") + buffered,
|
||||||
|
output: buffered,
|
||||||
|
loadingOutput: line.loadingOutput ? false : true,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
// clear
|
||||||
|
lineBuffersRef.current.clear();
|
||||||
|
flushScheduledRef.current = false;
|
||||||
|
}, []);
|
||||||
|
|
||||||
const updateValueLineStation = useCallback(
|
const updateValueLineStation = useCallback(
|
||||||
(lineId: number, updates: Partial<TLine>, stationId?: number) => {
|
(lineId: number, updates: Partial<TLine>, stationId?: number) => {
|
||||||
setStations((prevStations) =>
|
setStations((prevStations) =>
|
||||||
|
|
@ -374,6 +414,29 @@ function App() {
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const updateValueSelectedLine = useCallback(
|
||||||
|
(lineId: number, updates: Partial<TLine>) => {
|
||||||
|
// Update selectedLine nếu nó đang được chọn
|
||||||
|
setSelectedLine((prevSelected) => {
|
||||||
|
if (!prevSelected || prevSelected.id !== lineId) return prevSelected;
|
||||||
|
|
||||||
|
const isNetOutput = typeof updates?.netOutput !== "undefined";
|
||||||
|
|
||||||
|
return {
|
||||||
|
...prevSelected,
|
||||||
|
...updates,
|
||||||
|
...(isNetOutput && {
|
||||||
|
netOutput:
|
||||||
|
(prevSelected.netOutput || "") + (updates.netOutput || ""),
|
||||||
|
output: updates.netOutput,
|
||||||
|
loadingOutput: prevSelected.loadingOutput ? false : true,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
// const getLine = (lineId: number, stationId: number) => {
|
// const getLine = (lineId: number, stationId: number) => {
|
||||||
// const station = stations?.find((sta) => sta.id === stationId);
|
// const station = stations?.find((sta) => sta.id === stationId);
|
||||||
// if (station) {
|
// if (station) {
|
||||||
|
|
@ -530,7 +593,6 @@ function App() {
|
||||||
onChange={(id) => {
|
onChange={(id) => {
|
||||||
if (selectedLines.length > 0) {
|
if (selectedLines.length > 0) {
|
||||||
selectedLines.forEach((el) => {
|
selectedLines.forEach((el) => {
|
||||||
console.log(el?.userOpenCLI, user?.userName);
|
|
||||||
if (el?.userOpenCLI === user?.userName)
|
if (el?.userOpenCLI === user?.userName)
|
||||||
socket?.emit("close_cli", {
|
socket?.emit("close_cli", {
|
||||||
lineId: el?.id,
|
lineId: el?.id,
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,8 @@ function DrawerLogs({
|
||||||
<div>
|
<div>
|
||||||
Format:
|
Format:
|
||||||
<i style={{ marginLeft: "4px" }}>
|
<i style={{ marginLeft: "4px" }}>
|
||||||
YYYYMMDD-Station_{`{id}`}-Line_{`{number}`}_{`{port}`}
|
YYYYMMDD-AUTO-Session.{`{Station name}`}-{`{Station ID}`}-
|
||||||
|
{`{Station IP}`}-{`{Line number}`}
|
||||||
.log
|
.log
|
||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -146,8 +146,6 @@ const TerminalCLI: React.FC<TerminalCLIProps> = ({
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}, 500);
|
}, 500);
|
||||||
if (fitRef.current) fitRef.current?.fit();
|
if (fitRef.current) fitRef.current?.fit();
|
||||||
} else {
|
|
||||||
setIsInit(false);
|
|
||||||
}
|
}
|
||||||
}, [cliOpened]);
|
}, [cliOpened]);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue