Инициализация в новом репозитории
This commit is contained in:
commit
eb1f18f53e
374 changed files with 226678 additions and 0 deletions
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue