Инициализация в новом репозитории

This commit is contained in:
commit eb1f18f53e
374 changed files with 226678 additions and 0 deletions

View file

@ -0,0 +1,17 @@
import { ToolBar } from "./toolBar/toolBar"
import { ToolSpace } from "./toolSpace/toolSpace"
import styled from "styled-components"
const Container = styled.div`
height: 100%;
display: flex;
`
export const SideBar = ()=>{
return(
<Container>
<ToolBar/>
<ToolSpace/>
</Container>
)
}

View file

@ -0,0 +1,32 @@
import styled from "styled-components"
import { IconComponent as Icon } from "../../../../const/menus/sideBar/icons"
import { useToolBar } from "../../../../hooks/useToolBar"
import { useTheme } from "styled-components"
type Props = {
menuId: string
}
const Button = styled.div`
width: 100%;
cursor: pointer;
`
const IconContainer = styled.div`
padding: 10px;
`
export const ToolBarButton = ({ menuId }: Props) => {
const { isActive, collapseMenu } = useToolBar(menuId);
const theme = useTheme();
const iconColor = isActive ? theme.textColor : theme.active;
return (
<Button onClick={collapseMenu}>
<IconContainer>
<Icon name={menuId} width="30" height="30" setColor={iconColor} />
</IconContainer>
</Button>
)
}

View file

@ -0,0 +1,73 @@
import { useToolBarStore } from "../../../../store"
import { ToolBarButton } from "./toolBar-button"
import styled from "styled-components"
import ThemeButton from "../../../UI/buttons/toggletheme"
import { IconComponent } from "../../../../const/buttons/icons"
import { buttonNames } from "../../../../const/buttons/names"
import { workSpaceNames } from "../../../../const/workspace/names"
import { useModalContext } from "../../../../store"
import { useAdminStore } from "../../../../store/adminStore"
import { ModalMap } from "../../../modalwindows/windowsType"
import { useWorkSpaceStore } from "../../../../store"
const Container = styled.div`
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
background-color: ${(props) => props.theme.primary};
padding: 5px 0;
`
const ButtonContainer = styled.div`
display: flex;
flex-direction: column;
align-items: center;
`
const Button = styled.div`
width: 100%;
cursor: pointer;
`
const IconContainer = styled.div`
padding: 10px;
color: ${props => props.theme.text};
`
export const ToolBar = () => {
const { toolBar } = useToolBarStore()
const toolBarMenu = toolBar?.toolSpace
const { openModal } = useModalContext()
const {isAdmin} = useAdminStore()
const {setWorkModule} = useWorkSpaceStore()
return (
<Container>
<ButtonContainer>
{toolBarMenu && toolBarMenu.map((menu) => (
<ToolBarButton menuId={menu.id} key={menu.id} />
))}
</ButtonContainer>
<ButtonContainer>
<Button>
<IconContainer>
<IconComponent name={isAdmin ? buttonNames[10] : buttonNames[13]} width="30" height="30" onClick={() => openModal(ModalMap['5'])}/>
</IconContainer>
</Button>
<ThemeButton />
<Button>
<IconContainer>
<IconComponent name={buttonNames[4]} width="30" height="30" onClick={()=>setWorkModule(workSpaceNames[2])}/>
</IconContainer>
</Button>
</ButtonContainer>
</Container>
)
}

View file

@ -0,0 +1,246 @@
import styled from "styled-components"
import { useState, useEffect } from "react"
import { useModalContext } from "../../../../store"
import { ModalMap } from "../../../modalwindows/windowsType"
import { NetworkService } from "../../../../api/request"
import { AnimDot } from "../../../UI/animDot"
import { useMenu } from "../../../../hooks/useMenu"
import { useIpStore, useDevicesStore } from "../../../../store"
import { menusNames } from "../../../../const/menus/othersMenus/names"
import { useWorkSpaceStore } from "../../../../store"
import { workSpaceNames } from "../../../../const/workspace/names"
import { IconComponent } from "../../../../const/buttons/icons"
import { buttonNames } from "../../../../const/buttons/names"
const Container = styled.div`
display: flex;
flex-direction: column;
align-items: center;
gap: 15px;
padding: 20px;
p{
margin: 0;
}
`
const Title = styled.div`
padding: 5px 0;
width: 100%;
text-align: center;
border-bottom: 1px solid ${props => props.theme.text};
`
const DeviceBlock = styled.div`
border-radius: 8px;
border: 2px solid ${props => props.theme.accent};
display: flex;
flex-direction: column;
width: 100%;
.paddingP{
padding: 7px 5px;
}
`
const DeviceControl = styled.div`
padding: 5px 8px;
background: ${props => props.theme.accent};
display: flex;
justify-content: space-between;
align-items: center;
color: white;
cursor: pointer;
`
const PlusBlock = styled.div`
font-size: 24px;
cursor: pointer;
border-radius: 8px;
border: 2px dotted ${props => props.theme.accent};
width: 100%;
text-align: center;
padding: 5px 0;
`
const Text = styled.div`
display: flex;
gap: 3px;
align-items: center;
`
const DevicesContainer = styled.div`
width: 100%;
display: flex;
flex-direction: column;
gap: 15px;
`
const DevicesHeader = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
.hControl{
font-size: 20px;
cursor: pointer;
}
`
const DevicesContent = styled.div<{ $isactive: string }>`
${props => props.$isactive === 'true' && `display: flex;`}
${props => props.$isactive === 'false' && `display: none;`}
flex-direction: column;
align-items: center;
gap: 15px;
`
interface CurrentDevice {
hostname: string
address: string
}
export const DevicesBar = () => {
const { openModal } = useModalContext();
const { setIpAddress, ipAddress } = useIpStore();
const { devices, addDevice, deleteDevice } = useDevicesStore()
const { isOpen, collapseMenu } = useMenu(menusNames[1]);
const { setWorkModule } = useWorkSpaceStore()
const [currentDevice, setCurrentDevice] = useState<CurrentDevice>({
address: 'localhost',
hostname: ''
})
const checkWebSocketAvailability = async (ip: string): Promise<boolean> => {
return new Promise((resolve) => {
const testSocket = new WebSocket(`wss://${ip}:8001/api/v1`);
const timeout = setTimeout(() => {
testSocket.close();
resolve(false);
}, 500
);
testSocket.onopen = () => {
clearTimeout(timeout);
testSocket.close();
resolve(true);
};
testSocket.onerror = () => {
clearTimeout(timeout);
testSocket.close();
resolve(false);
};
});
};
useEffect(() => {
const fetchHostame = async () => {
let response = await NetworkService.getHostname();
if (response.status === 200) {
setCurrentDevice(prevData => ({
...prevData,
hostname: response.data.hostname
}))
}
};
fetchHostame();
}, [])
const handleAdd = () => {
openModal(ModalMap['4'], {
onSave: handleAddDeviceComplete,
});
};
const handleAddDeviceComplete = (data: string) => {
addDevice(data)
setIpAddress(data)
};
const handleDelete = (number: number, adress: string) => {
deleteDevice(number)
if(adress == ipAddress){
setIpAddress('localhost')
}
};
const switchWs = async (ip: string) => {
// Проверяем доступность WebSocket
const isAvailable = await checkWebSocketAvailability(ip);
if (!isAvailable) {
openModal(ModalMap['3'], {
message: `Не удалось подключиться к серверу по адресу ${ip}`,
});
return;
}
// Если WebSocket доступен, обновляем IP и переключаем модуль
setIpAddress(ip);
setWorkModule(workSpaceNames[3]);
};
useEffect(() => {
if (devices.length === 0) {
setIpAddress('localhost');
}
}, [devices]);
return (
<Container>
<Title>
<p className="unselectable">Доступные узлы</p>
</Title>
<DeviceBlock>
<DeviceControl className="unselectable" onClick={() => switchWs(currentDevice.address)}>
<p>Текущее устройство</p>
</DeviceControl>
{currentDevice.hostname == '' ? (
<Text className="paddingP">Адрес: Загрузка<AnimDot /></Text>
) : (
<p className="paddingP">Адрес: {currentDevice.hostname}</p>
)}
</DeviceBlock>
<DevicesContainer>
<DevicesHeader className="unselectable" onClick={collapseMenu}>
<p>Дополнительные узлы</p>
<IconComponent name={isOpen ? buttonNames[5] : buttonNames[6]} />
</DevicesHeader>
<DevicesContent $isactive={isOpen.toString()} >
{devices.length > 0 &&
devices.map((device, index) => (
<DeviceBlock key={index}>
<DeviceControl className="unselectable" onClick={() => switchWs(device.address)}>
<p>Узел {device.number}</p>
<IconComponent
width="20"
height="20"
name={buttonNames[2]}
setColor="white"
onClick={(e: any) => {
e.stopPropagation(); // Предотвращаем всплытие события
handleDelete(device.number, device.address);
}}
/>
</DeviceControl>
<p className="paddingP">Адрес: {device.address}</p>
</DeviceBlock>
))
}
<PlusBlock className="unselectable" onClick={handleAdd}>
+
</PlusBlock>
</DevicesContent>
</DevicesContainer>
</Container>
)
}

View file

@ -0,0 +1,27 @@
import { useToolBarStore } from "../../../../store"
import { useToolBar } from "../../../../hooks/useToolBar"
import { Space } from "../../../../const/menus/sideBar/components"
import styled from "styled-components"
const Container = styled.div`
background-color: ${(props) => props.theme.secondary};
width: 250px;
font-size: 14px;
flex: 3;
`
export const ToolSpace = () => {
const { toolBar } = useToolBarStore()
const name = toolBar?.current || ''
const { isActive, isOpen } = useToolBar(name)
if (!isActive || !isOpen) {
return null
}
return (
<Container>
<Space name={name} />
</Container>
)
}