Thên button edit scenarios ở ngoài (góc trái trên)
This commit is contained in:
parent
237a514ae1
commit
ef57da0154
|
|
@ -505,6 +505,8 @@ function App() {
|
||||||
setIsOpenAddStation={setIsOpenAddStation}
|
setIsOpenAddStation={setIsOpenAddStation}
|
||||||
setStationEdit={setStationEdit}
|
setStationEdit={setStationEdit}
|
||||||
tabsData={stations}
|
tabsData={stations}
|
||||||
|
scenarios={scenarios}
|
||||||
|
setScenarios={setScenarios}
|
||||||
panels={stations.map((station) => (
|
panels={stations.map((station) => (
|
||||||
<Tabs.Panel
|
<Tabs.Panel
|
||||||
className={classes.content}
|
className={classes.content}
|
||||||
|
|
|
||||||
|
|
@ -1,379 +1,335 @@
|
||||||
import {
|
import { ActionIcon, Avatar, Box, Button, Flex, Group, Menu, Tabs, Text, Tooltip, UnstyledButton } from "@mantine/core";
|
||||||
ActionIcon,
|
import { DndContext, useSensor, useSensors, PointerSensor, closestCenter, type DragEndEvent } from "@dnd-kit/core";
|
||||||
Avatar,
|
import { arrayMove, SortableContext, useSortable, horizontalListSortingStrategy } from "@dnd-kit/sortable";
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
Flex,
|
|
||||||
Group,
|
|
||||||
Menu,
|
|
||||||
Tabs,
|
|
||||||
Text,
|
|
||||||
Tooltip,
|
|
||||||
UnstyledButton,
|
|
||||||
} from "@mantine/core";
|
|
||||||
import {
|
|
||||||
DndContext,
|
|
||||||
useSensor,
|
|
||||||
useSensors,
|
|
||||||
PointerSensor,
|
|
||||||
closestCenter,
|
|
||||||
type DragEndEvent,
|
|
||||||
} from "@dnd-kit/core";
|
|
||||||
import {
|
|
||||||
arrayMove,
|
|
||||||
SortableContext,
|
|
||||||
useSortable,
|
|
||||||
horizontalListSortingStrategy,
|
|
||||||
} from "@dnd-kit/sortable";
|
|
||||||
import { CSS } from "@dnd-kit/utilities";
|
import { CSS } from "@dnd-kit/utilities";
|
||||||
import { useEffect, useMemo, useState, type JSX } from "react";
|
import { useEffect, useMemo, useState, type JSX } from "react";
|
||||||
import {
|
import { IconChevronRight, IconEdit, IconLogout, IconSettings, IconSettingsPlus, IconListDetails, IconUsersGroup } from "@tabler/icons-react";
|
||||||
IconChevronRight,
|
|
||||||
IconEdit,
|
|
||||||
IconLogout,
|
|
||||||
IconSettings,
|
|
||||||
IconSettingsPlus,
|
|
||||||
IconUsersGroup,
|
|
||||||
} from "@tabler/icons-react";
|
|
||||||
import classes from "./Component.module.css";
|
import classes from "./Component.module.css";
|
||||||
import type { TStation, TUser } from "../untils/types";
|
import type { IScenario, TStation, TUser } from "../untils/types";
|
||||||
import type { Socket } from "socket.io-client";
|
import type { Socket } from "socket.io-client";
|
||||||
import ModalHistory from "./ModalHistory";
|
import ModalHistory from "./ModalHistory";
|
||||||
import ModalConfig from "./ModalConfig";
|
import ModalConfig from "./ModalConfig";
|
||||||
|
import DrawerScenario from "./DrawerScenario";
|
||||||
|
|
||||||
interface DraggableTabsProps {
|
interface DraggableTabsProps {
|
||||||
tabsData: TStation[];
|
tabsData: TStation[];
|
||||||
panels: JSX.Element[];
|
panels: JSX.Element[];
|
||||||
storageKey?: string;
|
storageKey?: string;
|
||||||
onChange: (activeTabId: string | null) => void;
|
onChange: (activeTabId: string | null) => void;
|
||||||
w?: string | number;
|
w?: string | number;
|
||||||
isStationSettings?: boolean;
|
isStationSettings?: boolean;
|
||||||
socket: Socket | null;
|
socket: Socket | null;
|
||||||
usersConnecting: TUser[];
|
usersConnecting: TUser[];
|
||||||
setIsEditStation: (value: React.SetStateAction<boolean>) => void;
|
setIsEditStation: (value: React.SetStateAction<boolean>) => void;
|
||||||
setIsOpenAddStation: (value: React.SetStateAction<boolean>) => void;
|
setIsOpenAddStation: (value: React.SetStateAction<boolean>) => void;
|
||||||
setStationEdit: (value: React.SetStateAction<TStation | undefined>) => void;
|
setStationEdit: (value: React.SetStateAction<TStation | undefined>) => void;
|
||||||
active: string;
|
active: string;
|
||||||
setActive: (value: React.SetStateAction<string>) => void;
|
setActive: (value: React.SetStateAction<string>) => void;
|
||||||
onSendCommand: (value: string) => void;
|
onSendCommand: (value: string) => void;
|
||||||
|
scenarios: IScenario[];
|
||||||
|
setScenarios: (value: React.SetStateAction<IScenario[]>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function SortableTab({
|
function SortableTab({
|
||||||
tab,
|
tab,
|
||||||
active,
|
active,
|
||||||
onChange,
|
onChange,
|
||||||
}: {
|
}: {
|
||||||
tab: TStation;
|
tab: TStation;
|
||||||
active: string | null;
|
active: string | null;
|
||||||
onChange: (id: string) => void;
|
onChange: (id: string) => void;
|
||||||
isStationSettings?: boolean;
|
isStationSettings?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const { attributes, listeners, setNodeRef, transform, transition } =
|
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id: tab.id.toString() });
|
||||||
useSortable({ id: tab.id.toString() });
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs.Tab
|
<Tabs.Tab
|
||||||
className={classes.tab}
|
className={classes.tab}
|
||||||
ref={setNodeRef}
|
ref={setNodeRef}
|
||||||
{...attributes}
|
{...attributes}
|
||||||
{...listeners}
|
{...listeners}
|
||||||
onPointerDown={(e) => {
|
onPointerDown={(e) => {
|
||||||
listeners?.onPointerDown?.(e);
|
listeners?.onPointerDown?.(e);
|
||||||
onChange(tab.id.toString());
|
onChange(tab.id.toString());
|
||||||
}}
|
}}
|
||||||
value={tab.id.toString()}
|
value={tab.id.toString()}
|
||||||
style={{
|
style={{
|
||||||
transform: CSS.Transform.toString(transform),
|
transform: CSS.Transform.toString(transform),
|
||||||
transition,
|
transition,
|
||||||
cursor: "grab",
|
cursor: "grab",
|
||||||
userSelect: "none",
|
userSelect: "none",
|
||||||
backgroundColor: active === tab.id.toString() ? "#deffde" : "",
|
backgroundColor: active === tab.id.toString() ? "#deffde" : "",
|
||||||
}}
|
}}
|
||||||
color={active === tab.id.toString() ? "green" : ""}
|
color={active === tab.id.toString() ? "green" : ""}
|
||||||
fw={600}
|
fw={600}
|
||||||
fz="md"
|
fz="md"
|
||||||
c="#747474"
|
c="#747474">
|
||||||
>
|
<Box className={classes.stationName}>
|
||||||
<Box className={classes.stationName}>
|
<Text fw={600} fz="md" className={classes.stationText}>
|
||||||
<Text fw={600} fz="md" className={classes.stationText}>
|
{tab.name}
|
||||||
{tab.name}
|
</Text>
|
||||||
</Text>
|
</Box>
|
||||||
</Box>
|
</Tabs.Tab>
|
||||||
</Tabs.Tab>
|
);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function DraggableTabs({
|
export default function DraggableTabs({
|
||||||
tabsData,
|
tabsData,
|
||||||
panels,
|
panels,
|
||||||
storageKey = "draggable-tabs-order",
|
storageKey = "draggable-tabs-order",
|
||||||
onChange,
|
onChange,
|
||||||
w,
|
w,
|
||||||
isStationSettings = false,
|
isStationSettings = false,
|
||||||
socket,
|
socket,
|
||||||
usersConnecting,
|
usersConnecting,
|
||||||
setIsEditStation,
|
setIsEditStation,
|
||||||
setIsOpenAddStation,
|
setIsOpenAddStation,
|
||||||
setStationEdit,
|
setStationEdit,
|
||||||
active,
|
active,
|
||||||
setActive,
|
setActive,
|
||||||
|
scenarios,
|
||||||
|
setScenarios,
|
||||||
}: DraggableTabsProps) {
|
}: DraggableTabsProps) {
|
||||||
const user = useMemo(() => {
|
const user = useMemo(() => {
|
||||||
return localStorage.getItem("user") &&
|
return localStorage.getItem("user") && typeof localStorage.getItem("user") === "string" ? JSON.parse(localStorage.getItem("user") || "") : null;
|
||||||
typeof localStorage.getItem("user") === "string"
|
}, []);
|
||||||
? JSON.parse(localStorage.getItem("user") || "")
|
const [tabs, setTabs] = useState<TStation[]>(tabsData);
|
||||||
: null;
|
const [isChangeTab, setIsChangeTab] = useState<boolean>(false);
|
||||||
}, []);
|
const [isSetActive, setIsSetActive] = useState<boolean>(false);
|
||||||
const [tabs, setTabs] = useState<TStation[]>(tabsData);
|
const [isHistoryModalOpen, setIsHistoryModalOpen] = useState<boolean>(false);
|
||||||
const [isChangeTab, setIsChangeTab] = useState<boolean>(false);
|
const [openConfig, setOpenConfig] = useState<boolean>(false);
|
||||||
const [isSetActive, setIsSetActive] = useState<boolean>(false);
|
const [openDrawerScenario, setOpenDrawerScenario] = useState<boolean>(false);
|
||||||
const [isHistoryModalOpen, setIsHistoryModalOpen] = useState<boolean>(false);
|
|
||||||
const [openConfig, setOpenConfig] = useState<boolean>(false);
|
|
||||||
|
|
||||||
const sensors = useSensors(useSensor(PointerSensor));
|
const sensors = useSensors(useSensor(PointerSensor));
|
||||||
|
|
||||||
// Load saved order from localStorage
|
// Load saved order from localStorage
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isChangeTab) {
|
if (isChangeTab) {
|
||||||
setTabs((pre) =>
|
setTabs((pre) =>
|
||||||
pre
|
pre
|
||||||
.map((t) => {
|
.map((t) => {
|
||||||
const updatedTab = tabsData.find((td) => td.id === t.id);
|
const updatedTab = tabsData.find((td) => td.id === t.id);
|
||||||
return updatedTab ? updatedTab : t;
|
return updatedTab ? updatedTab : t;
|
||||||
})
|
})
|
||||||
.filter((t) => (tabsData.find((td) => td.id === t.id) ? true : false))
|
.filter((t) => (tabsData.find((td) => td.id === t.id) ? true : false))
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const saved = localStorage.getItem(storageKey);
|
const saved = localStorage.getItem(storageKey);
|
||||||
let tabSelected =
|
let tabSelected = tabsData?.length > 0 ? tabsData[0]?.id.toString() : null;
|
||||||
tabsData?.length > 0 ? tabsData[0]?.id.toString() : null;
|
if (saved) {
|
||||||
if (saved) {
|
try {
|
||||||
try {
|
const order = JSON.parse(saved) as { id: string; index: number }[];
|
||||||
const order = JSON.parse(saved) as { id: string; index: number }[];
|
|
||||||
|
|
||||||
// Find the max index in saved order
|
// Find the max index in saved order
|
||||||
const maxIndex = Math.max(...order.map((o) => o.index), 0);
|
const maxIndex = Math.max(...order.map((o) => o.index), 0);
|
||||||
|
|
||||||
const sorted = [...tabsData].sort((a, b) => {
|
const sorted = [...tabsData].sort((a, b) => {
|
||||||
const aOrder = order.find(
|
const aOrder = order.find((o) => o.id.toString() === a.id.toString())?.index;
|
||||||
(o) => o.id.toString() === a.id.toString()
|
const bOrder = order.find((o) => o.id.toString() === b.id.toString())?.index;
|
||||||
)?.index;
|
|
||||||
const bOrder = order.find(
|
|
||||||
(o) => o.id.toString() === b.id.toString()
|
|
||||||
)?.index;
|
|
||||||
|
|
||||||
// If not found, assign index after all existing ones
|
// If not found, assign index after all existing ones
|
||||||
const aIndex = aOrder !== undefined ? aOrder : maxIndex + 1;
|
const aIndex = aOrder !== undefined ? aOrder : maxIndex + 1;
|
||||||
const bIndex = bOrder !== undefined ? bOrder : maxIndex + 1;
|
const bIndex = bOrder !== undefined ? bOrder : maxIndex + 1;
|
||||||
|
|
||||||
return aIndex - bIndex;
|
return aIndex - bIndex;
|
||||||
});
|
});
|
||||||
|
|
||||||
tabSelected = sorted?.length > 0 ? sorted[0]?.id.toString() : null;
|
tabSelected = sorted?.length > 0 ? sorted[0]?.id.toString() : null;
|
||||||
setTabs(sorted);
|
setTabs(sorted);
|
||||||
} catch {
|
} catch {
|
||||||
setTabs(tabsData);
|
setTabs(tabsData);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setTabs(tabsData);
|
setTabs(tabsData);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isSetActive && tabSelected) {
|
if (!isSetActive && tabSelected) {
|
||||||
setActive(tabSelected);
|
setActive(tabSelected);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
onChange(tabSelected);
|
onChange(tabSelected);
|
||||||
}, 100);
|
}, 100);
|
||||||
setIsSetActive(true);
|
setIsSetActive(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [tabsData, storageKey]);
|
}, [tabsData, storageKey]);
|
||||||
|
|
||||||
// Handle reorder
|
// Handle reorder
|
||||||
const handleDragEnd = (event: DragEndEvent) => {
|
const handleDragEnd = (event: DragEndEvent) => {
|
||||||
const { active: dragActive, over } = event;
|
const { active: dragActive, over } = event;
|
||||||
if (dragActive.id !== over?.id && over?.id) {
|
if (dragActive.id !== over?.id && over?.id) {
|
||||||
const oldIndex = tabs.findIndex(
|
const oldIndex = tabs.findIndex((t) => t.id.toString() === dragActive.id.toString());
|
||||||
(t) => t.id.toString() === dragActive.id.toString()
|
const newIndex = tabs.findIndex((t) => t.id.toString() === over?.id.toString());
|
||||||
);
|
const newTabs = arrayMove(tabs, oldIndex, newIndex);
|
||||||
const newIndex = tabs.findIndex(
|
setTabs(newTabs);
|
||||||
(t) => t.id.toString() === over?.id.toString()
|
|
||||||
);
|
|
||||||
const newTabs = arrayMove(tabs, oldIndex, newIndex);
|
|
||||||
setTabs(newTabs);
|
|
||||||
|
|
||||||
const order = newTabs.map((t, i) => ({ id: t.id, index: i }));
|
const order = newTabs.map((t, i) => ({ id: t.id, index: i }));
|
||||||
localStorage.setItem(storageKey, JSON.stringify(order));
|
localStorage.setItem(storageKey, JSON.stringify(order));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
setIsChangeTab(false);
|
setIsChangeTab(false);
|
||||||
setIsSetActive(false);
|
setIsSetActive(false);
|
||||||
setTabs([]);
|
setTabs([]);
|
||||||
setActive("0");
|
setActive("0");
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DndContext
|
<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
|
||||||
sensors={sensors}
|
<Tabs
|
||||||
collisionDetection={closestCenter}
|
value={active}
|
||||||
onDragEnd={handleDragEnd}
|
onChange={(val) => {
|
||||||
>
|
setIsChangeTab(true);
|
||||||
<Tabs
|
onChange(val);
|
||||||
value={active}
|
setActive(val || "0");
|
||||||
onChange={(val) => {
|
}}
|
||||||
setIsChangeTab(true);
|
w={w}>
|
||||||
onChange(val);
|
<Flex justify={"space-between"}>
|
||||||
setActive(val || "0");
|
<Flex style={{ marginTop: "8px" }} gap="xs" align="center">
|
||||||
}}
|
<ActionIcon title="Setting" variant="outline" onClick={() => setOpenConfig(true)}>
|
||||||
w={w}
|
<IconSettings />
|
||||||
>
|
</ActionIcon>
|
||||||
<Flex justify={"space-between"}>
|
<Button
|
||||||
<Flex style={{ marginTop: "8px" }}>
|
color="yellow"
|
||||||
<ActionIcon
|
variant="filled"
|
||||||
title="Setting"
|
size="xs"
|
||||||
variant="outline"
|
leftSection={<IconListDetails size={16} />}
|
||||||
onClick={() => setOpenConfig(true)}
|
onClick={() => setOpenDrawerScenario(true)}>
|
||||||
>
|
Scenario
|
||||||
<IconSettings />
|
</Button>
|
||||||
</ActionIcon>
|
</Flex>
|
||||||
</Flex>
|
<Tabs.List className={classes.list}>
|
||||||
<Tabs.List className={classes.list}>
|
<SortableContext items={tabs} strategy={horizontalListSortingStrategy}>
|
||||||
<SortableContext
|
{tabs.map((tab) => (
|
||||||
items={tabs}
|
<SortableTab
|
||||||
strategy={horizontalListSortingStrategy}
|
key={tab.id}
|
||||||
>
|
tab={tab}
|
||||||
{tabs.map((tab) => (
|
active={active}
|
||||||
<SortableTab
|
onChange={(id) => {
|
||||||
key={tab.id}
|
setIsChangeTab(true);
|
||||||
tab={tab}
|
onChange(id);
|
||||||
active={active}
|
setActive(id);
|
||||||
onChange={(id) => {
|
}}
|
||||||
setIsChangeTab(true);
|
isStationSettings={isStationSettings}
|
||||||
onChange(id);
|
/>
|
||||||
setActive(id);
|
))}
|
||||||
}}
|
</SortableContext>
|
||||||
isStationSettings={isStationSettings}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</SortableContext>
|
|
||||||
|
|
||||||
<Flex gap={"md"} ms={"xs"} align={"center"}>
|
<Flex gap={"md"} ms={"xs"} align={"center"}>
|
||||||
{Number(active) ? (
|
{Number(active) ? (
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
title="Edit Station"
|
title="Edit Station"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setStationEdit(
|
setStationEdit(tabsData.find((el) => el.id === Number(active)));
|
||||||
tabsData.find((el) => el.id === Number(active))
|
setIsOpenAddStation(true);
|
||||||
);
|
setIsEditStation(true);
|
||||||
setIsOpenAddStation(true);
|
}}>
|
||||||
setIsEditStation(true);
|
<IconEdit />
|
||||||
}}
|
</ActionIcon>
|
||||||
>
|
) : (
|
||||||
<IconEdit />
|
""
|
||||||
</ActionIcon>
|
)}
|
||||||
) : (
|
<ActionIcon
|
||||||
""
|
title="Add Station"
|
||||||
)}
|
variant="outline"
|
||||||
<ActionIcon
|
color="green"
|
||||||
title="Add Station"
|
onClick={() => {
|
||||||
variant="outline"
|
setIsOpenAddStation(true);
|
||||||
color="green"
|
setIsEditStation(false);
|
||||||
onClick={() => {
|
setStationEdit(undefined);
|
||||||
setIsOpenAddStation(true);
|
}}>
|
||||||
setIsEditStation(false);
|
<IconSettingsPlus />
|
||||||
setStationEdit(undefined);
|
</ActionIcon>
|
||||||
}}
|
</Flex>
|
||||||
>
|
</Tabs.List>
|
||||||
<IconSettingsPlus />
|
<Flex align={"center"}>
|
||||||
</ActionIcon>
|
<Button
|
||||||
</Flex>
|
variant="outline"
|
||||||
</Tabs.List>
|
style={{ height: "26px", width: "80px", marginRight: "20px" }}
|
||||||
<Flex align={"center"}>
|
size="xs"
|
||||||
<Button
|
onClick={() => {
|
||||||
variant="outline"
|
setIsHistoryModalOpen(true);
|
||||||
style={{ height: "26px", width: "80px", marginRight: "20px" }}
|
}}>
|
||||||
size="xs"
|
History
|
||||||
onClick={() => {
|
</Button>
|
||||||
setIsHistoryModalOpen(true);
|
<Tooltip
|
||||||
}}
|
withArrow
|
||||||
>
|
label={usersConnecting.map((el) => (
|
||||||
History
|
<Text key={el.userId || el.id}>{el.userName}</Text>
|
||||||
</Button>
|
))}>
|
||||||
<Tooltip
|
<Avatar radius="xl" me={"sm"}>
|
||||||
withArrow
|
<IconUsersGroup color="green" />
|
||||||
label={usersConnecting.map((el) => (
|
</Avatar>
|
||||||
<Text key={el.userId || el.id}>{el.userName}</Text>
|
</Tooltip>
|
||||||
))}
|
<Menu withArrow>
|
||||||
>
|
<Menu.Target>
|
||||||
<Avatar radius="xl" me={"sm"}>
|
<UnstyledButton
|
||||||
<IconUsersGroup color="green" />
|
style={{
|
||||||
</Avatar>
|
padding: "var(--mantine-spacing-md)",
|
||||||
</Tooltip>
|
color: "var(--mantine-color-text)",
|
||||||
<Menu withArrow>
|
borderRadius: "var(--mantine-radius-sm)",
|
||||||
<Menu.Target>
|
}}>
|
||||||
<UnstyledButton
|
<Group>
|
||||||
style={{
|
<div style={{ flex: 1 }}>
|
||||||
padding: "var(--mantine-spacing-md)",
|
<Text size="sm" fw={500}>
|
||||||
color: "var(--mantine-color-text)",
|
{user?.userName || user?.user_name || ""}
|
||||||
borderRadius: "var(--mantine-radius-sm)",
|
</Text>
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Group>
|
|
||||||
<div style={{ flex: 1 }}>
|
|
||||||
<Text size="sm" fw={500}>
|
|
||||||
{user?.userName || user?.user_name || ""}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Text c="dimmed" size="xs">
|
<Text c="dimmed" size="xs">
|
||||||
{user?.email}
|
{user?.email}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<IconChevronRight size={16} />
|
<IconChevronRight size={16} />
|
||||||
</Group>
|
</Group>
|
||||||
</UnstyledButton>
|
</UnstyledButton>
|
||||||
</Menu.Target>
|
</Menu.Target>
|
||||||
<Menu.Dropdown>
|
<Menu.Dropdown>
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
style={{ width: "150px" }}
|
style={{ width: "150px" }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
localStorage.removeItem("user");
|
localStorage.removeItem("user");
|
||||||
window.location.href = "/";
|
window.location.href = "/";
|
||||||
socket?.disconnect();
|
socket?.disconnect();
|
||||||
}}
|
}}
|
||||||
color="red"
|
color="red"
|
||||||
leftSection={<IconLogout size={16} stroke={1.5} />}
|
leftSection={<IconLogout size={16} stroke={1.5} />}>
|
||||||
>
|
Logout
|
||||||
Logout
|
</Menu.Item>
|
||||||
</Menu.Item>
|
</Menu.Dropdown>
|
||||||
</Menu.Dropdown>
|
</Menu>
|
||||||
</Menu>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
|
||||||
|
|
||||||
{panels}
|
{panels}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
<ModalHistory
|
<ModalHistory
|
||||||
opened={isHistoryModalOpen}
|
opened={isHistoryModalOpen}
|
||||||
onClose={() => setIsHistoryModalOpen(false)}
|
onClose={() => setIsHistoryModalOpen(false)}
|
||||||
socket={socket}
|
socket={socket}
|
||||||
stationIds={tabs.map((el) => el.id)}
|
stationIds={tabs.map((el) => el.id)}
|
||||||
tabs={tabs}
|
tabs={tabs}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ModalConfig
|
<ModalConfig
|
||||||
opened={openConfig}
|
opened={openConfig}
|
||||||
onClose={() => setOpenConfig(false)}
|
onClose={() => setOpenConfig(false)}
|
||||||
onSave={() => {
|
onSave={() => {
|
||||||
onChange(active);
|
onChange(active);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</DndContext>
|
|
||||||
);
|
<DrawerScenario
|
||||||
|
scenarios={scenarios}
|
||||||
|
setScenarios={setScenarios}
|
||||||
|
externalOpened={openDrawerScenario}
|
||||||
|
onExternalClose={() => setOpenDrawerScenario(false)}
|
||||||
|
/>
|
||||||
|
</DndContext>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue