Update nút mở drawer add/edit scenario
This commit is contained in:
parent
df25b5db3f
commit
065900f48b
|
|
@ -583,6 +583,7 @@ function App() {
|
|||
setIsLogModalOpen={setIsLogModalOpen}
|
||||
setTestLogContent={setTestLogContent}
|
||||
scenarios={scenarios}
|
||||
setScenarios={setScenarios}
|
||||
setExpanded={setExpandedBottomBar}
|
||||
activeTabBottom={activeTabBottom}
|
||||
setActiveTabBottom={setActiveTabBottom}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,10 @@ import type { Socket } from "socket.io-client";
|
|||
import { ButtonDPELP, ButtonSelect } from "./ButtonAction";
|
||||
import DrawerLogs from "./DrawerLogs";
|
||||
import { DrawerAPCControl, DrawerSwitchControl } from "./DrawerControl";
|
||||
import DrawerScenario from "./DrawerScenario";
|
||||
import { isJsonString } from "../untils/helper";
|
||||
import { motion } from "motion/react";
|
||||
import { IconCaretDown, IconCaretUp, IconPlayerPlay } from "@tabler/icons-react";
|
||||
import { IconCaretDown, IconCaretUp, IconPlayerPlay, IconPlus } from "@tabler/icons-react";
|
||||
|
||||
interface TabsProps {
|
||||
selectedLines: TLine[];
|
||||
|
|
@ -35,6 +36,7 @@ interface TabsProps {
|
|||
setIsLogModalOpen: (value: React.SetStateAction<boolean>) => void;
|
||||
setTestLogContent: (value: React.SetStateAction<string>) => void;
|
||||
scenarios: IScenario[];
|
||||
setScenarios: (value: React.SetStateAction<IScenario[]>) => void;
|
||||
setExpanded: (value: React.SetStateAction<boolean>) => void;
|
||||
activeTabBottom: string;
|
||||
setActiveTabBottom: (value: React.SetStateAction<string>) => void;
|
||||
|
|
@ -53,6 +55,7 @@ const BottomToolBar = ({
|
|||
setIsLogModalOpen,
|
||||
setTestLogContent,
|
||||
scenarios,
|
||||
setScenarios,
|
||||
setExpanded,
|
||||
setActiveTabBottom,
|
||||
activeTabBottom,
|
||||
|
|
@ -67,6 +70,7 @@ const BottomToolBar = ({
|
|||
const [valueInput, setValueInput] = useState<string>("");
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const [openScenarioModal, setOpenScenarioModal] = useState<boolean>(false);
|
||||
const [openDrawerScenario, setOpenDrawerScenario] = useState<boolean>(false);
|
||||
// const [activeTabBottom, setActiveTabBottom] = useState<string>("command");
|
||||
// const [isExpand, setIsExpand] = useState<boolean>(true);
|
||||
|
||||
|
|
@ -123,10 +127,26 @@ const BottomToolBar = ({
|
|||
<Text fw={700} size="xl">
|
||||
🎯 Select Scenario to Run
|
||||
</Text>
|
||||
<CloseButton
|
||||
size="lg"
|
||||
onClick={() => setOpenScenarioModal(false)}
|
||||
/>
|
||||
<Flex gap="md" align="center">
|
||||
<Button
|
||||
leftSection={<IconPlus size={16} />}
|
||||
variant="light"
|
||||
color="green"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
setOpenScenarioModal(false);
|
||||
setTimeout(() => {
|
||||
setOpenDrawerScenario(true);
|
||||
}, 100);
|
||||
}}
|
||||
>
|
||||
Add/Edit Scenario
|
||||
</Button>
|
||||
<CloseButton
|
||||
size="lg"
|
||||
onClick={() => setOpenScenarioModal(false)}
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
{/* Content */}
|
||||
|
|
@ -542,6 +562,14 @@ const BottomToolBar = ({
|
|||
</Grid>
|
||||
</Box>
|
||||
</motion.div>
|
||||
|
||||
{/* Drawer Scenario để Add/Edit */}
|
||||
<DrawerScenario
|
||||
scenarios={scenarios}
|
||||
setScenarios={setScenarios}
|
||||
externalOpened={openDrawerScenario}
|
||||
onExternalClose={() => setOpenDrawerScenario(false)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,22 +1,21 @@
|
|||
import { useDisclosure } from "@mantine/hooks";
|
||||
import {
|
||||
Drawer,
|
||||
Box,
|
||||
ScrollArea,
|
||||
Table,
|
||||
Grid,
|
||||
TextInput,
|
||||
Button,
|
||||
Checkbox,
|
||||
Text,
|
||||
Flex,
|
||||
CloseButton,
|
||||
} from "@mantine/core";
|
||||
import { IconSettingsPlus } from "@tabler/icons-react";
|
||||
import classes from "./Component.module.css";
|
||||
import TableRows from "./Scenario/TableRows";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useForm } from "@mantine/form";
|
||||
import DialogConfirm from "./DialogConfirm";
|
||||
import type { IBodyScenario, IScenario } from "../untils/types";
|
||||
import classes from "./Component.module.css";
|
||||
import axios from "axios";
|
||||
import { notifications } from "@mantine/notifications";
|
||||
const apiUrl = import.meta.env.VITE_BACKEND_URL;
|
||||
|
|
@ -24,11 +23,26 @@ const apiUrl = import.meta.env.VITE_BACKEND_URL;
|
|||
function DrawerScenario({
|
||||
scenarios,
|
||||
setScenarios,
|
||||
externalOpened,
|
||||
onExternalClose,
|
||||
}: {
|
||||
scenarios: IScenario[];
|
||||
setScenarios: (value: React.SetStateAction<IScenario[]>) => void;
|
||||
externalOpened?: boolean;
|
||||
onExternalClose?: () => void;
|
||||
}) {
|
||||
const [opened, { open, close }] = useDisclosure(false);
|
||||
const [opened, { close }] = useDisclosure(false);
|
||||
|
||||
// Sử dụng external state nếu được provide, nếu không thì dùng internal state
|
||||
const isOpened = externalOpened !== undefined ? externalOpened : opened;
|
||||
|
||||
const handleClose = () => {
|
||||
if (onExternalClose) {
|
||||
onExternalClose();
|
||||
} else {
|
||||
close();
|
||||
}
|
||||
};
|
||||
const [isEdit, setIsEdit] = useState(false);
|
||||
const [openConfirm, setOpenConfirm] = useState<boolean>(false);
|
||||
const [isSubmit, setIsSubmit] = useState<boolean>(false);
|
||||
|
|
@ -178,62 +192,125 @@ function DrawerScenario({
|
|||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!opened) {
|
||||
if (!isOpened) {
|
||||
setIsEdit(false);
|
||||
setIsSubmit(false);
|
||||
setDataScenario(undefined);
|
||||
form.reset();
|
||||
}
|
||||
}, [opened]);
|
||||
}, [isOpened]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Drawer
|
||||
size={"70%"}
|
||||
position="right"
|
||||
style={{ position: "absolute", left: 0 }}
|
||||
offset={8}
|
||||
radius="md"
|
||||
opened={opened}
|
||||
onClose={close}
|
||||
title={isEdit ? "Edit Scenarios" : "Add Scenarios"}
|
||||
>
|
||||
<Grid>
|
||||
<Grid.Col span={2} style={{ borderRight: "1px solid #ccc" }}>
|
||||
{scenarios.map((scenario) => (
|
||||
<Button
|
||||
disabled={isSubmit}
|
||||
className={classes.buttonScenario}
|
||||
key={scenario.id}
|
||||
miw={"100px"}
|
||||
mb={"6px"}
|
||||
style={{ minHeight: "24px" }}
|
||||
mr={"5px"}
|
||||
variant={
|
||||
dataScenario && dataScenario?.id === scenario.id
|
||||
? "filled"
|
||||
: "outline"
|
||||
}
|
||||
onClick={async () => {
|
||||
if (dataScenario?.id === scenario.id) {
|
||||
setIsEdit(false);
|
||||
setDataScenario(undefined);
|
||||
form.reset();
|
||||
} else {
|
||||
setIsEdit(true);
|
||||
setDataScenario(scenario);
|
||||
form.setFieldValue("title", scenario.title);
|
||||
form.setFieldValue("timeout", scenario.timeout.toString());
|
||||
form.setFieldValue("body", JSON.parse(scenario.body));
|
||||
form.setFieldValue("isReboot", scenario.isReboot);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{scenario.title}
|
||||
</Button>
|
||||
))}
|
||||
</Grid.Col>
|
||||
<Grid.Col span={10}>
|
||||
{/* Custom Modal - Giống như Modal Select Scenario */}
|
||||
{isOpened && (
|
||||
<div
|
||||
style={{
|
||||
position: "fixed",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: "rgba(0,0,0,0.6)",
|
||||
zIndex: 100000,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backdropFilter: "blur(3px)",
|
||||
}}
|
||||
onClick={handleClose}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
background: "white",
|
||||
borderRadius: "12px",
|
||||
maxWidth: "90vw",
|
||||
width: "90%",
|
||||
maxHeight: "85vh",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
boxShadow: "0 20px 60px rgba(0,0,0,0.3)",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{/* Header */}
|
||||
<Flex
|
||||
justify="space-between"
|
||||
align="center"
|
||||
p="lg"
|
||||
style={{
|
||||
borderBottom: "1px solid #e9ecef",
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
<Text fw={700} size="xl">
|
||||
{isEdit ? "✏️ Edit Scenarios" : "➕ Add Scenarios"}
|
||||
</Text>
|
||||
<CloseButton size="lg" onClick={handleClose} />
|
||||
</Flex>
|
||||
|
||||
{/* Content */}
|
||||
<div
|
||||
style={{
|
||||
padding: "20px",
|
||||
overflowY: "auto",
|
||||
overflowX: "hidden",
|
||||
flex: 1,
|
||||
}}
|
||||
className={classes.hideScrollBar}
|
||||
>
|
||||
<Flex gap="md" style={{ height: "75vh" }}>
|
||||
{/* Sidebar - List Scenarios */}
|
||||
<Box
|
||||
style={{
|
||||
width: "200px",
|
||||
borderRight: "1px solid #e9ecef",
|
||||
paddingRight: "10px",
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
<ScrollArea h="100%">
|
||||
<Flex direction="column" gap="xs">
|
||||
{scenarios.map((scenario) => (
|
||||
<Button
|
||||
disabled={isSubmit}
|
||||
className={classes.buttonScenario}
|
||||
key={scenario.id}
|
||||
fullWidth
|
||||
style={{ minHeight: "36px" }}
|
||||
variant={
|
||||
dataScenario && dataScenario?.id === scenario.id
|
||||
? "filled"
|
||||
: "outline"
|
||||
}
|
||||
onClick={async () => {
|
||||
if (dataScenario?.id === scenario.id) {
|
||||
setIsEdit(false);
|
||||
setDataScenario(undefined);
|
||||
form.reset();
|
||||
} else {
|
||||
setIsEdit(true);
|
||||
setDataScenario(scenario);
|
||||
form.setFieldValue("title", scenario.title);
|
||||
form.setFieldValue(
|
||||
"timeout",
|
||||
scenario.timeout.toString()
|
||||
);
|
||||
form.setFieldValue("body", JSON.parse(scenario.body));
|
||||
form.setFieldValue("isReboot", scenario.isReboot);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{scenario.title}
|
||||
</Button>
|
||||
))}
|
||||
</Flex>
|
||||
</ScrollArea>
|
||||
</Box>
|
||||
|
||||
{/* Main Content */}
|
||||
<Box style={{ flex: 1, overflow: "hidden" }}>
|
||||
<Box>
|
||||
<Grid>
|
||||
<Grid.Col span={4}>
|
||||
|
|
@ -318,7 +395,10 @@ function DrawerScenario({
|
|||
</Box>
|
||||
<hr style={{ width: "100%" }} />
|
||||
<Box>
|
||||
<ScrollArea h={"70vh"} style={{ marginBottom: "20px" }}>
|
||||
<ScrollArea
|
||||
h={"calc(75vh - 150px)"}
|
||||
style={{ marginBottom: "20px" }}
|
||||
>
|
||||
<Table
|
||||
stickyHeader
|
||||
stickyHeaderOffset={-1}
|
||||
|
|
@ -358,28 +438,12 @@ function DrawerScenario({
|
|||
</Table>
|
||||
</ScrollArea>
|
||||
</Box>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
</Drawer>
|
||||
<Text
|
||||
fw={700}
|
||||
c={"#747474"}
|
||||
style={{
|
||||
fontSize: "14px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "6px",
|
||||
}}
|
||||
>
|
||||
Scenarios
|
||||
<IconSettingsPlus
|
||||
color="green"
|
||||
style={{ cursor: "pointer", width: "18px", height: "18px" }}
|
||||
onClick={() => {
|
||||
open();
|
||||
}}
|
||||
/>
|
||||
</Text>
|
||||
</Box>
|
||||
</Flex>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<DialogConfirm
|
||||
opened={openConfirm}
|
||||
|
|
@ -390,7 +454,7 @@ function DrawerScenario({
|
|||
handle={() => {
|
||||
setOpenConfirm(false);
|
||||
handleDelete();
|
||||
close();
|
||||
handleClose();
|
||||
}}
|
||||
centered={true}
|
||||
/>
|
||||
|
|
|
|||
Loading…
Reference in New Issue