Изменение окна 'О программе' и улучшение визуала

This commit is contained in:
test 2025-06-23 17:18:07 +05:00
parent f4aae4f3c4
commit 81ad18d75c
15 changed files with 277 additions and 135 deletions

View file

@ -1,13 +1,13 @@
import axios, { AxiosResponse } from "axios"; import axios, { AxiosResponse } from "axios";
const axiosWithoutCredentials = axios.create({ const axiosWithoutCredentials = axios.create({
baseURL: `https://localhost:8001`, baseURL: `http://localhost:8001`,
}) })
export class NetworkService { export class NetworkService {
static createAxiosInstance(ipAddress: string) { static createAxiosInstance(ipAddress: string) {
return axios.create({ return axios.create({
baseURL: `https://${ipAddress}:8001`, baseURL: `http://${ipAddress}:8001`,
}); });
} }

View file

@ -0,0 +1,65 @@
import React from 'react';
import styled from "styled-components";
import {buttonNames} from "../../const/buttons/names";
import {IconComponent} from "../../const/buttons/icons";
const PaginateWrapper = styled.div`
width: 100%;
margin-top: 24px;
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
`
const Page = styled.button`
width: 36px;
height: 36px;
background: ${(props => props.theme.primary)};
color: ${(props => props.theme.textColor)};
border: 1px solid ${(props => props.theme.borderColor)};
font-size: 16px;
cursor: pointer;
border-radius: 4px;
transition: .4s ease;
&:hover {
background: ${(props => props.theme.background)};
}
`
interface PaginationProps {
currentPage: number;
totalPages: number;
onPrevPage: () => void;
onNextPage: () => void;
}
const Pagination = ({currentPage, totalPages, onPrevPage, onNextPage}: PaginationProps) => {
return (
<PaginateWrapper>
<Page
onClick={onPrevPage}
disabled={currentPage === 1}
>
<IconComponent
width="20"
height="20"
name={buttonNames[17]}
/>
</Page>
<Page
onClick={onNextPage}
disabled={currentPage === totalPages}
>
<IconComponent
width="20"
height="20"
name={buttonNames[6]}
/>
</Page>
</PaginateWrapper>
);
};
export default Pagination;

View file

@ -1,4 +1,4 @@
import React from 'react'; import React, {useState} from 'react';
import { DeviceUser } from '../../../store/useDeviceStore'; import { DeviceUser } from '../../../store/useDeviceStore';
interface TableScannerProps { interface TableScannerProps {
@ -9,18 +9,19 @@ import {IconComponent} from "../../../const/buttons/icons";
import {buttonNames} from "../../../const/buttons/names"; import {buttonNames} from "../../../const/buttons/names";
import {ModalMap} from "../../modalwindows/windowsType"; import {ModalMap} from "../../modalwindows/windowsType";
import {useModalContext} from "../../../store"; import {useModalContext} from "../../../store";
import Pagination from "../Pagination";
const TableContainer = styled.div` const TableContainer = styled.div`
width: 100%; width: 100%;
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
background: ${({ theme }) => theme.primary};
margin: 24px 0; margin: 24px 0;
`; `;
const StyledTable = styled.table` const StyledTable = styled.table`
width: 100%; width: 100%;
border-collapse: separate; border-collapse: separate;
border-spacing: 0; border-spacing: 0;
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
background: ${({ theme }) => theme.primary};
`; `;
const TableHeaderCell = styled.th<{ sortable?: boolean }>` const TableHeaderCell = styled.th<{ sortable?: boolean }>`
@ -28,7 +29,7 @@ const TableHeaderCell = styled.th<{ sortable?: boolean }>`
text-align: left; text-align: left;
font-weight: 600; font-weight: 600;
font-size: 14px; font-size: 14px;
color: ${({ theme }) => theme.textSecondary}; color: ${({ theme }) => theme.textColor};
background: ${({ theme }) => theme.primary}; background: ${({ theme }) => theme.primary};
border-bottom: 1px solid ${({ theme }) => theme.borderColor}; border-bottom: 1px solid ${({ theme }) => theme.borderColor};
transition: all 0.2s ease; transition: all 0.2s ease;
@ -47,6 +48,11 @@ const TableCell = styled.td`
color: ${({ theme }) => theme.text}; color: ${({ theme }) => theme.text};
border-bottom: 1px solid ${({ theme }) => theme.borderColor}; border-bottom: 1px solid ${({ theme }) => theme.borderColor};
transition: all 0.2s ease; transition: all 0.2s ease;
button{
background-color: transparent;
border: none;
cursor: pointer;
}
`; `;
const StatusBadge = styled.span<{ status:string }>` const StatusBadge = styled.span<{ status:string }>`
@ -68,7 +74,23 @@ const TableScanner = ({devices}:TableScannerProps) => {
}); });
}; };
return ( // Пагинация
const [currentPage, setCurrentPage] = useState(1);
const [devicesPerPage] = useState(10);
const indexOfLastDevice = currentPage * devicesPerPage;
const indexOfFirstDevice = indexOfLastDevice - devicesPerPage;
const currentDevices = devices.slice(indexOfFirstDevice, indexOfLastDevice);
const totalPages = Math.ceil(devices.length / devicesPerPage);
const handlePrevPage = () => {
if(currentPage > 1) setCurrentPage(currentPage - 1);
}
const handleNextPage = () => {
if(currentPage < totalPages) setCurrentPage(currentPage + 1);
}
return (
<TableContainer> <TableContainer>
<StyledTable> <StyledTable>
<thead> <thead>
@ -84,7 +106,7 @@ const TableScanner = ({devices}:TableScannerProps) => {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{devices.map((item, i) => ( {currentDevices.map((item, i) => (
<TableRow key={i}> <TableRow key={i}>
<TableCell><StatusBadge status={item.status}></StatusBadge></TableCell> <TableCell><StatusBadge status={item.status}></StatusBadge></TableCell>
<TableCell>{item.hostname || item.ip}</TableCell> <TableCell>{item.hostname || item.ip}</TableCell>
@ -94,14 +116,20 @@ const TableScanner = ({devices}:TableScannerProps) => {
<TableCell>{item.last_seen}</TableCell> <TableCell>{item.last_seen}</TableCell>
<TableCell>{item.note || '-'}</TableCell> <TableCell>{item.note || '-'}</TableCell>
<TableCell> <TableCell>
<span onClick={(e)=>openModalNote(e, item)}> <button onClick={(e)=>openModalNote(e, item)}>
<IconComponent name={buttonNames[16]} width="26" height="26" /> <IconComponent name={buttonNames[16]} width="26" height="26" />
</span> </button>
</TableCell> </TableCell>
</TableRow> </TableRow>
))} ))}
</tbody> </tbody>
</StyledTable> </StyledTable>
<Pagination
currentPage={currentPage}
totalPages={totalPages}
onPrevPage={handlePrevPage}
onNextPage={handleNextPage}
/>
</TableContainer> </TableContainer>
); );
}; };

View file

@ -2,8 +2,10 @@
import { MainButton } from "../../../UI/buttons/mainButton" import { MainButton } from "../../../UI/buttons/mainButton"
import { workSpaceNames } from "../../../../const/workspace/names" import { workSpaceNames } from "../../../../const/workspace/names"
import { useWorkSpaceStore } from "../../../../store" import { useWorkSpaceStore } from "../../../../store"
import styled from "styled-components" import styled, {useTheme} from "styled-components"
import ThemeButton from "../../../UI/buttons/toggletheme" import ThemeButton from "../../../UI/buttons/toggletheme"
import {buttonNames} from "../../../../const/buttons/names";
import {IconComponent} from "../../../../const/buttons/icons";
type Props = { type Props = {
from: 'reg' | 'helloWindow' | 'workSpace' from: 'reg' | 'helloWindow' | 'workSpace'
@ -29,23 +31,41 @@ const Content = styled.div`
justify-content: space-between; justify-content: space-between;
height: 100%; height: 100%;
box-sizing: border-box; box-sizing: border-box;
padding: 25px 50px; padding: 40px 50px;
background: ${(props => props.theme.secondary)}; background: ${(props => props.theme.primary)};
border-radius: 18px; border-radius: 18px;
position: relative;
` `
const Listing = styled.div` const Listing = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 15px; background-color: ${(props => props.theme.secondary)};
border-radius: 10px;
padding: 24px 20px;
p{
font-weight: bold;
font-size: 24px;
}
` `
const List = styled.div` const List = styled.ul`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 15px; margin: 10px 0;
margin-left: 10px; padding: 0;
list-style-type: none;
font-size: 18px;
gap: 4px;
& li:before {
color: ${(props => props.theme.accent)};
content: "•";
font-size: 28px;
width: .8em;
display: inline-block;
position: relative;
top: 2px;
}
` `
const Title = styled.div` const Title = styled.div`
@ -55,43 +75,55 @@ const Title = styled.div`
const SubTitle = styled.div` const SubTitle = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 10px; gap: 24px;
background-color:rgba(255, 248, 225, 0.6);
border-left: #ff9800 solid 4px;
border-radius: 0 8px 8px 0;
padding: 20px 12px;
a{
text-decoration: none;
color: ${(props => props.theme.errorColor)};
font-weight: 500;
font-size: 18px;
width: max-content;
}
p{ p{
font-size: 18px; font-size: 18px;
color: ${(props=>props.theme.textColor)};
}
.icon{
width: 32px;
height: 32px;
fill: #ff9800;
} }
` `
const Links = styled.div` const Links = styled.div`
display: flex; display: flex;
flex-direction: column; justify-content: start;
gap: 20px; gap: 20px;
` `
const LinkColumn = styled.div` const LinkBlock = styled.a`
display: flex; text-decoration: none;
flex-direction: column; color: ${(props => props.theme.accent)};;
gap: 10px;
`
const LinkBlock = styled.div`
display: flex;
gap: 5px;
` `
const Copyright = styled.div` const Copyright = styled.div`
width: 100%; width: 100%;
text-align: center; text-align: start;
margin-top: 50px; color: ${(props => props.theme.offlineColor)};
` `
const ButtonContainer = styled.div` const ButtonContainer = styled.div`
position: absolute;
top: 12px;
right: 14px;
`
const AboutLine = styled.hr`
border: ${(props => props.theme.hoverBtn)} 1px solid;
width: 100%; width: 100%;
display: flex;
justifi-content: flex-start;
align-items: center;
` `
const MainTitle = styled.div` const MainTitle = styled.div`
@ -99,24 +131,33 @@ const MainTitle = styled.div`
display: flex; display: flex;
gap: 15px; gap: 15px;
align-items: center; align-items: center;
justify-content: center; justify-content: space-between;
padding-top: 50px; padding-top: 10px;
box-sizing: border-box; box-sizing: border-box;
img{ img{
width: 40px; width: 50px;
height: 40px; height: 50px;
}
.version{
text-wrap: nowrap;
background-color: ${(props => props.theme.hoverBtn)};
color: ${(props => props.theme.borderColor)};
border-radius: 20px;
font-size: 18px;
padding: 10px 18px;
line-height: 1;
}
.title{
display: flex;
justify-content: center;
align-items: center;
gap: 24px;
} }
`
const Text = styled.div`
display: flex;
flex-direction: column;
gap: 30px;
` `
export default function About({ from, onBack }: Props) { export default function About({ from, onBack }: Props) {
const { setWorkModule } = useWorkSpaceStore() const { setWorkModule } = useWorkSpaceStore()
const getBackHandler = () => { const getBackHandler = () => {
switch (from) { switch (from) {
case 'reg': case 'reg':
@ -138,68 +179,63 @@ export default function About({ from, onBack }: Props) {
<Content> <Content>
<MainTitle> <MainTitle>
<img src="./assets/images/gossys.png" alt="" /> <div className={'title'}>
<div style={{width: '100%', display: "flex", justifyContent: 'center'}}><h1>О приложении</h1></div> <img src="./assets/images/gossys.png" alt="" />
<div style={{width: '100%', display: "flex", justifyContent: 'center'}}><h1>О приложении</h1></div>
</div>
<p className={'version'}>v 0.0.3</p>
</MainTitle> </MainTitle>
<AboutLine/>
<Text> <Title>
<p>ГоNets — минимально работоспособный кроссплатформенный продукт (MVP) для демонстрации нашего подхода к управлению настройками ПК в корпоративной среде.</p>
</Title>
<Title> <Listing>
<p>Приложение ГоNets является минимально работоспособным кроссплатформенным продуктом (MVP) для демонстрации нашего подхода к управлению настройками ПК в корпоративной среде.</p> <p>Возможности:</p>
</Title> <List>
<li>Визуализация активных сетевых ресурсов</li>
<li>Настройка параметров локальных и удалённых сетевых ресурсов</li>
<li>Управление взаимодействием ресурсов с Клиентом ГoNets</li>
</List>
</Listing>
<SubTitle>
<svg className="icon" viewBox="0 0 24 24">
<path d="M12 2L1 21h22M12 6l7.53 13H4.47M11 10v4h2v-4m-2 6v2h2v-2"/>
</svg>
<p>Программное обеспечение исключительно для ознакомления и домашнего использования.</p>
<a href={'https://gossys.dev/pages/projects/gonets'}>Перейти на ГоNets-PRO</a>
</SubTitle>
<Listing> <Links>
<p>Данное приложение умеет:</p> <LinkBlock href={'https://gossys.dev/pages/projects/gonets'}>
<List> Домашняя страницa
<p>- Отображать в графическом виде активные сетевые ресурсы</p> </LinkBlock>
<p>- Настраивать сетевые параметры локального и удаленных сетевых ресурсов</p>
<p>- Отображать и изменять взаимодействие сетевых ресурсов с установленным Клиентом ГоNets</p>
</List>
</Listing>
<SubTitle> <LinkBlock href={'https://wiki.gossys.dev/ru/gonets'}>
<p>Программное обеспечение исключительно для ознакомления и домашнего использования.</p> Документация
<p>Для коммерческого использования приобретите версию ГоNets-PRO (Подробная информация на странице продукта)</p> </LinkBlock>
</SubTitle>
<Links> <LinkBlock href={'https://wiki.gossys.dev/ru/lic/GosysPUB'}>
<LinkBlock> Лицензия
<p>Ссылка на домашнюю страницу:</p> </LinkBlock>
<a href="https://gossys.dev/pages/projects/gonets">https://gossys.dev/pages/projects/gonets</a> </Links>
</LinkBlock>
<LinkBlock>
<p>Инструкции и информация:</p>
<a href="https://wiki.gossys.dev/ru/gonets">https://wiki.gossys.dev/ru/gonets</a>
</LinkBlock>
<LinkColumn>
<p>Распространяется под лицензией GosysPUB текущей версии.</p>
<LinkBlock>
<p>Полный текст актуальной лицензии:</p>
<a href="https://wiki.gossys.dev/ru/lic/GosysPUB">https://wiki.gossys.dev/ru/lic/GosysPUB</a>
</LinkBlock>
</LinkColumn>
</Links>
<Copyright>
<p>Разработано и поддерживается ООО «Гибридные Офисные Системы» 2024-2025 г. Все права защищены.</p>
</Copyright>
</Text>
<Copyright>
Разработано и поддерживается ООО «Гибридные Офисные Системы» 2024-2025 г. Все права защищены.
</Copyright>
<ButtonContainer> <ButtonContainer>
{showBackButton && backHandler && ( {showBackButton && backHandler && (
<MainButton <IconComponent
title="Назад" width="36"
height="36"
name={buttonNames[12]}
onClick={backHandler} onClick={backHandler}
style={{ marginRight: '10px' }}
/> />
)} )}
{from == 'reg' && {from == 'reg' &&

View file

@ -1,4 +1,4 @@
import React from 'react'; import React, { useState } from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import DeviceCard from "../../../../../UI/Dropdown/DeviceCard"; import DeviceCard from "../../../../../UI/Dropdown/DeviceCard";
import {DeviceUser} from "../../../../../../store/useDeviceStore"; import {DeviceUser} from "../../../../../../store/useDeviceStore";
@ -28,10 +28,15 @@ const ListUsers = ({loading, handleScan, devices, scanInitiated}: ListUsersProps
const activeDevices = devices.filter(device => device.status === 'online'); const activeDevices = devices.filter(device => device.status === 'online');
const inactiveDevices = devices.filter(device => device.status !== 'online'); const inactiveDevices = devices.filter(device => device.status !== 'online');
// Пагинация
const [currentPage, setCurrentPage] = useState(1);
const [devicesPerPage] = useState(10);
return ( return (
<> <>
<ScanBtn onClick={handleScan} disabled={loading}> <ScanBtn onClick={handleScan} disabled={loading}>
{devices.length > 0 ? 'Обновить список' : 'Сканировать узлы подсети'} {devices.length > 0 ? 'Обновить список' : 'Сканировать узлы'}
</ScanBtn> </ScanBtn>
{devices.length > 0 ? ( {devices.length > 0 ? (
@ -42,7 +47,7 @@ const ListUsers = ({loading, handleScan, devices, scanInitiated}: ListUsersProps
}}> }}>
{/* Колонка активных устройств */} {/* Колонка активных устройств */}
<div style={{ flex: 1 }}> <div style={{ flex: 1 }}>
<h3 style={{ color: '#4CAF50', marginBottom:'12px' }}>Активные устройства ({activeDevices.length})</h3> <h3 style={{ color: '#4CAF50', marginBottom:'12px' }}>Активные узлы ({activeDevices.length})</h3>
{activeDevices.map((device, index) => ( {activeDevices.map((device, index) => (
<DeviceCard <DeviceCard
key={index} key={index}
@ -53,7 +58,7 @@ const ListUsers = ({loading, handleScan, devices, scanInitiated}: ListUsersProps
</div> </div>
{/* Колонка неактивных устройств */} {/* Колонка неактивных устройств */}
<div style={{ flex: 1 }}> <div style={{ flex: 1 }}>
<h3 style={{ color: '#ababab', marginBottom:'12px' }}>Неактивные устройства ({inactiveDevices.length})</h3> <h3 style={{ color: '#ababab', marginBottom:'12px' }}>Неактивные узлы ({inactiveDevices.length})</h3>
{inactiveDevices.map((device, index) => ( {inactiveDevices.map((device, index) => (
<DeviceCard <DeviceCard
key={index} key={index}
@ -64,7 +69,7 @@ const ListUsers = ({loading, handleScan, devices, scanInitiated}: ListUsersProps
</div> </div>
</div> </div>
) : scanInitiated ? ( ) : scanInitiated ? (
<p style={{ marginTop: '20px' }}>Устройства не найдены</p> <p style={{ marginTop: '20px' }}>Узлы не найдены</p>
) : null} ) : null}
</> </>
); );

View file

@ -30,13 +30,13 @@ const ListUsers = ({loading, handleScan, devices, scanInitiated}: ListUsersProps
return ( return (
<> <>
<ScanBtn onClick={handleScan} disabled={loading}> <ScanBtn onClick={handleScan} disabled={loading}>
{devices.length > 0 ? 'Обновить список' : 'Сканировать узлы подсети'} {devices.length > 0 ? 'Обновить список' : 'Сканировать узлы'}
</ScanBtn> </ScanBtn>
{devices.length > 0 ? ( {devices.length > 0 ? (
<TableScanner devices={devices} /> <TableScanner devices={devices} />
) : scanInitiated ? ( ) : scanInitiated ? (
<p style={{ marginTop: '20px' }}>Устройства не найдены</p> <p style={{ marginTop: '20px' }}>Узлы не найдены</p>
) : null} ) : null}
</> </>
); );

View file

@ -77,7 +77,7 @@ const UserLocate = styled.div<{ loading: boolean, scanInitiated: boolean }>`
span { span {
position: absolute; position: absolute;
display: inline-block; display: inline-block;
background: ${(props) => props.theme.accent}; background: ${(props) => props.theme.scannerColor};
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
@ -163,7 +163,7 @@ export default function UserScanner() {
return ( return (
<Wrapper scanInitiated={scanInitiated} loading={loading}> <Wrapper scanInitiated={scanInitiated} loading={loading}>
{(!scanInitiated || loading) && (<TitleWrapper>Сканирование узлов в подсети</TitleWrapper>)} {(!scanInitiated || loading) && (<TitleWrapper>Сканирование узлов подсети</TitleWrapper>)}
<UserLocate loading={loading} scanInitiated={scanInitiated}> <UserLocate loading={loading} scanInitiated={scanInitiated}>
<span className="center"></span> <span className="center"></span>
<span className="ring1"></span> <span className="ring1"></span>
@ -177,7 +177,7 @@ export default function UserScanner() {
{loading ? ( {loading ? (
<LoadingText> <LoadingText>
Сканирование узлов в подсети<ScanningText /> Сканирование узлов <ScanningText />
</LoadingText> </LoadingText>
) : selectedView.value == 1 ? ( ) : selectedView.value == 1 ? (
<TableUsers loading={loading} handleScan={handleScan} devices={devices} scanInitiated={scanInitiated} /> <TableUsers loading={loading} handleScan={handleScan} devices={devices} scanInitiated={scanInitiated} />

View file

@ -136,7 +136,8 @@ const ScanBtn = styled.button<{scanInitiated: boolean}>`
` `
export function WifiScanner() { export function WifiScanner() {
const { ipAddress } = useIpStore(); //const { ipAddress } = useIpStore();
const ipAddress = '192.168.1.147'
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [scanInitiated, setScanInitiated] = useState(false); const [scanInitiated, setScanInitiated] = useState(false);
const { wifiNetworks, setWifiNetworks } = useNetworkStore(); const { wifiNetworks, setWifiNetworks } = useNetworkStore();
@ -161,17 +162,19 @@ export function WifiScanner() {
return ( return (
<Wrapper scanInitiated={scanInitiated} loading={loading}> <Wrapper scanInitiated={scanInitiated} loading={loading}>
<TitleWrapper>Сканирование точек доступа Wi-Fi</TitleWrapper> <TitleWrapper>Сканирование точек доступа Wi-Fi сети</TitleWrapper>
<UserLocate loading={loading} scanInitiated={scanInitiated}> <UserLocate loading={loading} scanInitiated={scanInitiated}>
<span className="center circel"></span> <span className="center circel"></span>
<span className="ring1 circel"></span> <span className="ring1 circel"></span>
<span className="ring2 circel"></span> <span className="ring2 circel"></span>
<span className="ring3 circel"></span> <span className="ring3 circel"></span>
{wifiNetworks.map((network) => ( {wifiNetworks.map((network, index) => (
<WifiDot <WifiDot
key={network.bssid} key={network.bssid}
network={network} network={network}
index={index}
total={wifiNetworks.length}
onSelect={setCurrentNetwork} onSelect={setCurrentNetwork}
/> />
))} ))}

View file

@ -31,43 +31,45 @@ const Dot = styled.div<{ top: string; left: string }>`
} }
`; `;
const WifiDot = ({ network, onSelect }: { network: WifiNetworkScanner, onSelect: (n: WifiNetworkScanner) => void }) => { const getPositionInRing = (index: number, total: number, ringSize: number) => {
const getPositionInRing = (bssid: string, ringSize: number) => { const angle = (index * (2 * Math.PI / total)) + (Math.PI / total * (index % 2));
const hash = bssid.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0); const innerRadius = ringSize * 0.4;
const randomAngle = (hash % 360) * (Math.PI / 180); const outerRadius = ringSize * 0.5;
const innerRadius = ringSize * 0.4; const radius = innerRadius + (outerRadius - innerRadius) * (0.3 + 0.7 * (index % 10) / 10);
const outerRadius = ringSize * 0.5;
const randomValue = (hash % 1000) / 1000;
const randomRadius = Math.sqrt(innerRadius * innerRadius + randomValue * (outerRadius * outerRadius - innerRadius * innerRadius));
return { return {
x: Math.cos(randomAngle) * randomRadius, x: Math.cos(angle) * radius,
y: Math.sin(randomAngle) * randomRadius y: Math.sin(angle) * radius
};
}; };
};
const getPosition = (signal: number, bssid: string) => { const WifiDot = ({ network, index, total, onSelect }: {
network: WifiNetworkScanner,
index: number,
total: number,
onSelect: (n: WifiNetworkScanner) => void
}) => {
const getPosition = (signal: number, index: number, total: number) => {
let strength: 1 | 2 | 3; let strength: 1 | 2 | 3;
if (signal >= -50) { if (signal >= -50) {
strength = 3; strength = 3;
} else if (signal >= -70) { } else if (signal >= -70) {
strength = 2; strength = 2;
} else if (signal >= -90) {
strength = 1;
} else { } else {
strength = 1; strength = 1;
} }
const ringSizes = { 1: 550, 2: 400, 3: 250 }; const ringSizes = { 1: 550, 2: 400, 3: 250 };
const ringSize = ringSizes[strength]; const ringSize = ringSizes[strength];
const offset = getPositionInRing(bssid, ringSize); const offset = getPositionInRing(index, total, ringSize);
return { return {
top: `calc(50% - ${offset.y}px)`, top: `calc(50% + ${offset.y}px)`,
left: `calc(50% - ${offset.x}px)` left: `calc(50% + ${offset.x}px)`
}; };
}; };
const position = getPosition(network.signal, network.bssid); const position = getPosition(network.signal, index, total);
return ( return (
<Dot top={position.top} left={position.left} onClick={() => onSelect(network)}> <Dot top={position.top} left={position.left} onClick={() => onSelect(network)}>

View file

@ -76,7 +76,7 @@ export const NetworkInterfaces = ({ startConnection, ws }: Props) => {
setHasInited(false) setHasInited(false)
initializationAttempt.current = 0; initializationAttempt.current = 0;
const newSocket = new WebSocket(`wss://${ws}:8001/api/v1`); const newSocket = new WebSocket(`ws://${ws}:8001/api/v1`);
let connectionTimeout; let connectionTimeout;
setSocket(newSocket); setSocket(newSocket);

View file

@ -115,7 +115,7 @@ export const DevicesBar = () => {
const checkWebSocketAvailability = async (ip: string): Promise<boolean> => { const checkWebSocketAvailability = async (ip: string): Promise<boolean> => {
return new Promise((resolve) => { return new Promise((resolve) => {
const testSocket = new WebSocket(`wss://${ip}:8001/api/v1`); const testSocket = new WebSocket(`ws://${ip}:8001/api/v1`);
const timeout = setTimeout(() => { const timeout = setTimeout(() => {
testSocket.close(); testSocket.close();
resolve(false); resolve(false);

View file

@ -9,6 +9,7 @@ import settings from '@iconify/icons-ic/baseline-settings';
import info from '@iconify/icons-ic/baseline-info'; import info from '@iconify/icons-ic/baseline-info';
import arrowDown from '@iconify/icons-ic/baseline-keyboard-arrow-down'; import arrowDown from '@iconify/icons-ic/baseline-keyboard-arrow-down';
import arrowRight from '@iconify/icons-ic/baseline-keyboard-arrow-right'; import arrowRight from '@iconify/icons-ic/baseline-keyboard-arrow-right';
import arrowLeft from '@iconify/icons-ic/baseline-keyboard-arrow-left';
import edit from '@iconify/icons-ic/baseline-edit'; import edit from '@iconify/icons-ic/baseline-edit';
import checkCircle from '@iconify/icons-ic/round-check-circle'; import checkCircle from '@iconify/icons-ic/round-check-circle';
import cancel from '@iconify/icons-ic/baseline-cancel'; import cancel from '@iconify/icons-ic/baseline-cancel';
@ -37,6 +38,7 @@ export const ICONS = {
[buttonNames[14]]: userSearch, [buttonNames[14]]: userSearch,
[buttonNames[15]]: wifiFind, [buttonNames[15]]: wifiFind,
[buttonNames[16]]: noteEdit, [buttonNames[16]]: noteEdit,
[buttonNames[17]]: arrowLeft,
} as const; } as const;
type IconName = keyof typeof ICONS; type IconName = keyof typeof ICONS;

View file

@ -16,5 +16,6 @@ export const buttonNames: names ={
13: 'noAdmin', 13: 'noAdmin',
14: 'userSearch', 14: 'userSearch',
15: 'wifiFind', 15: 'wifiFind',
16: 'noteEdit' 16: 'noteEdit',
17: 'arrowLeft',
} }

View file

@ -3,7 +3,7 @@ import { toolBarNames } from "./names"
import { useTheme } from "styled-components" import { useTheme } from "styled-components"
import { Icon } from '@iconify/react'; import { Icon } from '@iconify/react';
import desktop from '@iconify/icons-ic/round-desktop-windows'; import desktop from '@iconify/icons-ic/baseline-menu';
export const ICONS = { export const ICONS = {
[toolBarNames[1]]: desktop, [toolBarNames[1]]: desktop,

View file

@ -24,7 +24,7 @@ export const dark = {
background: '#3A3A3A', background: '#3A3A3A',
textColor: '#FFFFFF', textColor: '#FFFFFF',
borderColor: '#b6b6b6', borderColor: '#b6b6b6',
scannerColor: '#0E9C9D', scannerColor: '#00E5FF',
offlineColor: '#656565', offlineColor: '#656565',
hoverBtn: '#4a4a4a', hoverBtn: '#4a4a4a',
}; };