Добавление переключения DCHP
This commit is contained in:
parent
3d4c59c5e5
commit
e7d8652ac0
13 changed files with 241 additions and 26 deletions
|
|
@ -11,11 +11,11 @@ const PaginateWrapper = styled.div`
|
|||
align-items: center;
|
||||
gap: 10px;
|
||||
`
|
||||
const Page = styled.button`
|
||||
const Page = styled.button<{ active?: boolean }>`
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background: ${(props => props.theme.primary)};
|
||||
color: ${(props => props.theme.textColor)};
|
||||
background: ${(props) => props.active ? props.theme.borderColor : props.theme.primary};
|
||||
color: ${(props) => props.active ? props.theme.primary : props.theme.textColor};
|
||||
border: 1px solid ${(props => props.theme.borderColor)};
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
|
|
@ -23,7 +23,7 @@ const Page = styled.button`
|
|||
|
||||
transition: .4s ease;
|
||||
&:hover {
|
||||
background: ${(props => props.theme.background)};
|
||||
background: ${(props) => props.active ? props.theme.textColor : props.theme.background};;
|
||||
}
|
||||
`
|
||||
|
||||
|
|
@ -32,9 +32,13 @@ interface PaginationProps {
|
|||
totalPages: number;
|
||||
onPrevPage: () => void;
|
||||
onNextPage: () => void;
|
||||
onPageChange: (page: number) => void;
|
||||
}
|
||||
|
||||
const Pagination = ({currentPage, totalPages, onPrevPage, onNextPage}: PaginationProps) => {
|
||||
const Pagination = ({currentPage, totalPages, onPrevPage, onNextPage, onPageChange}: PaginationProps) => {
|
||||
|
||||
const pageNumbers = Array.from({ length: totalPages }, (_, i) => i + 1);
|
||||
|
||||
return (
|
||||
<PaginateWrapper>
|
||||
<Page
|
||||
|
|
@ -47,7 +51,15 @@ const Pagination = ({currentPage, totalPages, onPrevPage, onNextPage}: Paginatio
|
|||
name={buttonNames[17]}
|
||||
/>
|
||||
</Page>
|
||||
|
||||
{pageNumbers.map((page, i) => (
|
||||
<Page
|
||||
key={i}
|
||||
onClick={() => onPageChange(page)}
|
||||
active={currentPage === page}
|
||||
>
|
||||
{page}
|
||||
</Page>
|
||||
))}
|
||||
<Page
|
||||
onClick={onNextPage}
|
||||
disabled={currentPage === totalPages}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,13 @@ import { Handle, Position } from '@xyflow/react';
|
|||
import { Ip } from './style';
|
||||
import { Row, IpTitle, IpContent } from './style';
|
||||
import Input from '../../../../UI/inputs/input';
|
||||
import { useModalContext, usePannableStore } from '../../../../../store';
|
||||
import {useIpStore, useModalContext, usePannableStore} from '../../../../../store';
|
||||
import { ModalMap } from '../../../../modalwindows/windowsType';
|
||||
import { validateIPAddress, validateSameSubnet } from '../../../../../utils/nodeController/validator';
|
||||
import {changeIp} from '../../../../../const/types/types'
|
||||
import { IconComponent } from "../../../../../const/buttons/icons";
|
||||
import { buttonNames } from "../../../../../const/buttons/names";
|
||||
import {NetworkService} from "../../../../../api/request";
|
||||
|
||||
interface IIp {
|
||||
ipType: string
|
||||
|
|
@ -45,6 +46,7 @@ export const IpNode = ({ data }: CustomNodeProps) => {
|
|||
const { toggleEditingMode } = usePannableStore();
|
||||
const [isInput, setIsInput] = useState(false)
|
||||
const { openModal } = useModalContext();
|
||||
const {ipAddress} = useIpStore();
|
||||
|
||||
const [ipData, setIpData] = useState<changeIp>(
|
||||
{
|
||||
|
|
@ -146,7 +148,20 @@ export const IpNode = ({ data }: CustomNodeProps) => {
|
|||
|
||||
setIsInput(false)
|
||||
};
|
||||
|
||||
const switchMethod = async ()=>{
|
||||
const methodDCHP ={
|
||||
"connection_id": ipData.connection,
|
||||
"ipv4_updates": {
|
||||
"ipv4.method": "auto",
|
||||
}
|
||||
}
|
||||
try {
|
||||
await NetworkService.saveIp(ipAddress, methodDCHP);
|
||||
window.location.reload();
|
||||
}catch (err){
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -170,7 +185,10 @@ export const IpNode = ({ data }: CustomNodeProps) => {
|
|||
</Row>
|
||||
|
||||
) : (
|
||||
<IconComponent name={buttonNames[7]} onClick={handleClick} width='18' height='18' setColor='white'/>
|
||||
<Row>
|
||||
{typeMap[data.ipData.ipType] ==='Static' && <IconComponent name={buttonNames[18]} onClick={switchMethod} width='18' height='18' setColor='white'/>}
|
||||
<IconComponent name={buttonNames[7]} onClick={handleClick} width='18' height='18' setColor='white'/>
|
||||
</Row>
|
||||
)}
|
||||
|
||||
</IpTitle>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
import { useSettingsStore } from '../stores/settingsStore';
|
||||
|
||||
export const SettingItem = ({ setting }: { setting: Setting }) => {
|
||||
const { updateSetting } = useSettingsStore();
|
||||
|
||||
const handleChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>
|
||||
) => {
|
||||
const value =
|
||||
setting.type === 'boolean'
|
||||
? (e.target as HTMLInputElement).checked
|
||||
: e.target.value;
|
||||
updateSetting(setting.id, value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<label>{setting.label}</label>
|
||||
|
||||
{setting.type === 'boolean' && (
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={setting.value}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
)}
|
||||
|
||||
{setting.type === 'select' && setting.options && (
|
||||
<select value={setting.value} onChange={handleChange}>
|
||||
{setting.options.map((option) => (
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
)}
|
||||
|
||||
{setting.type === 'text' && (
|
||||
<input
|
||||
type="text"
|
||||
value={setting.value}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
// components/modalContainers/NoteDevice.tsx
|
||||
import { ModalContainer, ModalTitle, ModalContent, ButtonContainer } from "../style";
|
||||
import { MainButton } from "../../UI/buttons/mainButton";
|
||||
import {useEffect, useState} from "react";
|
||||
import styled from "styled-components";
|
||||
import { useSettingsStore } from "../../../store/settingsStore";
|
||||
|
||||
interface Props {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const SectionsSidebar = styled.div`
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
align-items: start;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
width: 20%;
|
||||
|
||||
`
|
||||
const SectionsBTN = styled.button`
|
||||
font-size: 18px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
`
|
||||
const SectionActive = styled.div`
|
||||
width: 80%;
|
||||
background-color: red;
|
||||
`
|
||||
|
||||
const sections = [
|
||||
{id: 'nodesNetwork', label: 'Узлы подсети'},
|
||||
{id: 'wifiNetwork', label: 'Точки доступа'},
|
||||
{id: 'appearance', label: 'Внешний вид'},
|
||||
]
|
||||
|
||||
|
||||
export const Settings = ({onClose}: Props) => {
|
||||
const {activeSection, setActiveSection, initializeSettings} = useSettingsStore();
|
||||
|
||||
useEffect(() => {
|
||||
initializeSettings();
|
||||
}, [initializeSettings]);
|
||||
|
||||
return (
|
||||
<ModalContainer style={{ height: '60vh', width: '50vw'}}>
|
||||
<ModalTitle>
|
||||
<h3>Настройки</h3>
|
||||
</ModalTitle>
|
||||
|
||||
<ModalContent style={{ display: 'flex', height:"100%", gap: '8px' }}>
|
||||
<SectionsSidebar>
|
||||
{sections.map((section) => (
|
||||
<SectionsBTN>{section.label}</SectionsBTN>
|
||||
))}
|
||||
</SectionsSidebar>
|
||||
<SectionActive>
|
||||
{activeSection && <SettingItem setting={} />}
|
||||
</SectionActive>
|
||||
</ModalContent>
|
||||
|
||||
<ButtonContainer>
|
||||
<MainButton
|
||||
type="button"
|
||||
size="small"
|
||||
title='Сохранить'
|
||||
onClick={onClose}
|
||||
/>
|
||||
</ButtonContainer>
|
||||
</ModalContainer>
|
||||
);
|
||||
};
|
||||
|
|
@ -120,7 +120,7 @@ export const IpConfirm = ({ ipData, onClose, smoothClose }: Props) => {
|
|||
);
|
||||
useDevicesStore.setState({ devices: updatedDevices });
|
||||
}
|
||||
|
||||
|
||||
onClose()
|
||||
}
|
||||
} catch (err) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {NoteDevice} from "./modalContainers/NoteDevice";
|
|||
import { NoteWifi } from "./modalContainers/NoteWifi";
|
||||
import {ConnectNetwork} from "./modalContainers/ConnectNetwork";
|
||||
import {DisconnectConfirm} from "./modalContainers/disconnectConfirm";
|
||||
import {Settings} from "./modalContainers/Settings";
|
||||
|
||||
type Props = {
|
||||
isOpen: boolean,
|
||||
|
|
@ -74,6 +75,11 @@ export default function WindowComponent({ isOpen, type, data }: Props) {
|
|||
{type === ModalMap['5'] && (
|
||||
<RightsConfirm onClose={closeLoader} />
|
||||
)}
|
||||
{type === ModalMap['10'] && (
|
||||
<Settings
|
||||
onClose={closeLoader}
|
||||
/>
|
||||
)}
|
||||
</ModalWindow >
|
||||
}
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export const ModalWindow = styled.div`
|
|||
height: 100%;
|
||||
`
|
||||
|
||||
export const ModalContainer = styled.div<{height?: string}>`
|
||||
export const ModalContainer = styled.div<{height?: string, width?:string}>`
|
||||
border-radius: 12px;
|
||||
background: ${(props)=>props.theme.secondary};
|
||||
color: ${(props=>props.theme.textColor)};
|
||||
|
|
@ -25,7 +25,7 @@ export const ModalContainer = styled.div<{height?: string}>`
|
|||
justify-content: space-between;
|
||||
gap: 15px;
|
||||
height: ${(props) => props.height ? props.height : '230px'};
|
||||
width: 520px;
|
||||
width: ${(props) => props.width ? props.width : '520px'};
|
||||
`
|
||||
|
||||
export const ModalTitle = styled.div`
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
import React, {useState} from 'react';
|
||||
import { DeviceUser } from '../../../store/useDeviceStore';
|
||||
import { DeviceUser } from '../../../../../../store/useDeviceStore';
|
||||
|
||||
interface TableScannerProps {
|
||||
devices: DeviceUser[];
|
||||
}
|
||||
import styled from 'styled-components';
|
||||
import {IconComponent} from "../../../const/buttons/icons";
|
||||
import {buttonNames} from "../../../const/buttons/names";
|
||||
import {ModalMap} from "../../modalwindows/windowsType";
|
||||
import {useModalContext} from "../../../store";
|
||||
import Pagination from "../Pagination";
|
||||
import {IconComponent} from "../../../../../../const/buttons/icons";
|
||||
import {buttonNames} from "../../../../../../const/buttons/names";
|
||||
import {ModalMap} from "../../../../../modalwindows/windowsType";
|
||||
import {useModalContext} from "../../../../../../store";
|
||||
import Pagination from "../../../../../UI/Pagination";
|
||||
|
||||
const TableContainer = styled.div`
|
||||
width: 100%;
|
||||
|
|
@ -76,7 +76,7 @@ const TableScanner = ({devices}:TableScannerProps) => {
|
|||
|
||||
// Пагинация
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [devicesPerPage] = useState(10);
|
||||
const [devicesPerPage] = useState(15);
|
||||
|
||||
const indexOfLastDevice = currentPage * devicesPerPage;
|
||||
const indexOfFirstDevice = indexOfLastDevice - devicesPerPage;
|
||||
|
|
@ -89,6 +89,9 @@ const TableScanner = ({devices}:TableScannerProps) => {
|
|||
const handleNextPage = () => {
|
||||
if(currentPage < totalPages) setCurrentPage(currentPage + 1);
|
||||
}
|
||||
const onPageChange = (page: number) => {
|
||||
setCurrentPage(page);
|
||||
}
|
||||
|
||||
return (
|
||||
<TableContainer>
|
||||
|
|
@ -124,12 +127,15 @@ const TableScanner = ({devices}:TableScannerProps) => {
|
|||
))}
|
||||
</tbody>
|
||||
</StyledTable>
|
||||
<Pagination
|
||||
currentPage={currentPage}
|
||||
totalPages={totalPages}
|
||||
onPrevPage={handlePrevPage}
|
||||
onNextPage={handleNextPage}
|
||||
/>
|
||||
{totalPages > 1 && (
|
||||
<Pagination
|
||||
onPageChange={onPageChange}
|
||||
currentPage={currentPage}
|
||||
totalPages={totalPages}
|
||||
onPrevPage={handlePrevPage}
|
||||
onNextPage={handleNextPage}
|
||||
/>
|
||||
)}
|
||||
</TableContainer>
|
||||
);
|
||||
};
|
||||
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
import styled from 'styled-components';
|
||||
import DeviceCard from "../../../../../UI/Dropdown/DeviceCard";
|
||||
import {DeviceUser} from "../../../../../../store/useDeviceStore";
|
||||
import TableScanner from "../../../../../UI/tables/TableScanner";
|
||||
import TableScanner from "./TableScanner";
|
||||
|
||||
const ScanBtn = styled.button`
|
||||
position: relative;
|
||||
|
|
|
|||
|
|
@ -81,6 +81,11 @@ export const ToolBar = () => {
|
|||
/>
|
||||
</IconContainer>
|
||||
</Button>
|
||||
<Button>
|
||||
<IconContainer>
|
||||
<IconComponent name={buttonNames[3]} width="30" height="30" onClick={() => openModal(ModalMap['10'])} />
|
||||
</IconContainer>
|
||||
</Button>
|
||||
</ButtonContainer>
|
||||
</Container>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import refresh from '@iconify/icons-ic/baseline-refresh';
|
|||
import close from '@iconify/icons-ic/round-close';
|
||||
import wifiFind from '@iconify/icons-ic/baseline-wifi-find';
|
||||
import noteEdit from '@iconify/icons-ph/note-pencil';
|
||||
import swapHoriz from '@iconify/icons-ic/baseline-swap-horiz';
|
||||
|
||||
export const ICONS = {
|
||||
[buttonNames[1]]: exitToApp,
|
||||
|
|
@ -39,6 +40,7 @@ export const ICONS = {
|
|||
[buttonNames[15]]: wifiFind,
|
||||
[buttonNames[16]]: noteEdit,
|
||||
[buttonNames[17]]: arrowLeft,
|
||||
[buttonNames[18]]: swapHoriz,
|
||||
} as const;
|
||||
|
||||
type IconName = keyof typeof ICONS;
|
||||
|
|
|
|||
|
|
@ -18,4 +18,5 @@ export const buttonNames: names ={
|
|||
15: 'wifiFind',
|
||||
16: 'noteEdit',
|
||||
17: 'arrowLeft',
|
||||
18: 'swapHoriz',
|
||||
}
|
||||
46
FRONT/DEV/src/store/settingsStore.ts
Normal file
46
FRONT/DEV/src/store/settingsStore.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import { create } from 'zustand';
|
||||
|
||||
export type Setting = {
|
||||
id: string;
|
||||
type: 'boolean' | 'select' | 'text' | 'number';
|
||||
label: string;
|
||||
value: any;
|
||||
options?: { value: any; label: string }[];
|
||||
sectionId: string;
|
||||
};
|
||||
|
||||
type SettingsState = {
|
||||
settings: Setting[];
|
||||
activeSection: string | null;
|
||||
setActiveSection: (sectionId: string | null) => void;
|
||||
updateSetting: (id: string, value: any) => void;
|
||||
initializeSettings: () => void;
|
||||
};
|
||||
|
||||
export const useSettingsStore = create<SettingsState>((set) => ({
|
||||
settings: [],
|
||||
activeSection: null,
|
||||
|
||||
setActiveSection: (sectionId) => set({ activeSection: sectionId }),
|
||||
|
||||
updateSetting: (id, value) =>
|
||||
set((state) => ({
|
||||
settings: state.settings.map((setting) =>
|
||||
setting.id === id ? { ...setting, value } : setting
|
||||
),
|
||||
})),
|
||||
|
||||
initializeSettings: () => {
|
||||
const defaultSettings: Setting[] = [
|
||||
{
|
||||
id: 'rescan-nodes',
|
||||
type: 'number',
|
||||
label: 'nodesNetwork',
|
||||
value: 3000,
|
||||
sectionId: 'appearance',
|
||||
},
|
||||
|
||||
];
|
||||
set({ settings: defaultSettings });
|
||||
},
|
||||
}));
|
||||
Loading…
Add table
Add a link
Reference in a new issue