Добавление заметок

This commit is contained in:
test 2025-06-12 15:24:50 +05:00
parent ea56d17ea7
commit e61ffd793c
20 changed files with 274 additions and 118 deletions

View file

@ -95,7 +95,35 @@ export class NetworkService {
static async scanWifi(ipAddress: string): Promise<AxiosResponse> {
try {
const axiosInstance = this.createAxiosInstance(ipAddress);
return await axiosInstance.get('/subnet/user');
return await axiosInstance.get('/subnet/wifi');
} catch (error: any) {
return error.response;
}
}
static async addNote(ipAddress: string, mac:string, note: string): Promise<AxiosResponse> {
try {
const axiosInstance = this.createAxiosInstance(ipAddress);
return await axiosInstance.post(`/subnet/devices/${mac}/note`, {
note: note
});
} catch (error: any) {
return error.response;
}
}
static async editNote(ipAddress: string, mac:string, note: string): Promise<AxiosResponse> {
try {
const axiosInstance = this.createAxiosInstance(ipAddress);
return await axiosInstance.put(`/subnet/devices/${mac}/note`, {
note: note
});
} catch (error: any) {
return error.response;
}
}
static async deleteNote(ipAddress: string, mac:string): Promise<AxiosResponse> {
try {
const axiosInstance = this.createAxiosInstance(ipAddress);
return await axiosInstance.delete(`/subnet/devices/${mac}/note`);
} catch (error: any) {
return error.response;
}

View file

@ -1,6 +1,10 @@
import React from 'react';
import React, {useState} from 'react';
import styled, { css } from 'styled-components';
import { DeviceUser } from "../../../store/useDeviceStore";
import {buttonNames} from "../../../const/buttons/names";
import {ModalMap} from "../../modalwindows/windowsType";
import {IconComponent} from "../../../const/buttons/icons";
import {useModalContext} from "../../../store";
interface DeviceCardProps {
device: DeviceUser;
@ -24,7 +28,7 @@ const CardWrapper = styled.div<{ status: 'online' | 'offline' }>`
const CardHeader = styled.div<{ status: 'online' | 'offline' }>`
background: ${({ status, theme }) =>
status === 'online' ? theme.successColor : theme.errorColor};
status === 'online' ? theme.successColor : theme.offlineColor};
color: white;
padding: 16px;
font-size: 18px;
@ -67,9 +71,19 @@ const Value = styled.span`
color: #333;
`;
const DeviceCard: React.FC<DeviceCardProps> = ({ device, status }) => {
const [isExpanded, setIsExpanded] = React.useState(false);
const [isExpanded, setIsExpanded] = useState(false);
const toggleExpanded = () => setIsExpanded(!isExpanded);
const { openModal } = useModalContext();
const openModalNote = (e: React.MouseEvent) => {
e.stopPropagation();
openModal(ModalMap['6'], {
mac: device.mac,
currentNote: device.note || ''
});
};
return (
@ -78,6 +92,9 @@ const DeviceCard: React.FC<DeviceCardProps> = ({ device, status }) => {
<p>
MAC: {device.mac}
</p>
<span onClick={openModalNote}>
<IconComponent name={buttonNames[7]} width="24" height="24" setColor={'white'} />
</span>
</CardHeader>
<CardContent isExpanded={isExpanded}>
@ -107,6 +124,11 @@ const DeviceCard: React.FC<DeviceCardProps> = ({ device, status }) => {
<Label>Последняя активность:</Label>
<Value>{device.last_seen}</Value>
</InfoRow>
<InfoRow>
<Label>Заметка:</Label>
<Value>{device.note || '-'}</Value>
</InfoRow>
</CardContent>
</CardWrapper>
);

View file

@ -68,6 +68,7 @@ const DropdownRow = styled.button`
font-size: 16px;
border: none;
width: 100%;
color: ${({theme}) => theme.textColor};
transition: all .3s ease;
cursor: pointer;

View file

@ -9,15 +9,15 @@ const Button = styled.button.withConfig({
border: none;
padding: ${(props) =>
props.size === "small"
? "4px 8px"
? "10px 28px"
: props.size === "big"
? "10px 20px"
: "6px 10px"}; // По умолчанию
: "12px 20px"}; // По умолчанию
border-radius: 8px;
color: white;
font-size: ${(props) =>
props.size === "small"
? "12px"
? "14px"
: props.size === "big"
? "16px"
: "14px"}; // По умолчанию
@ -30,7 +30,7 @@ const Button = styled.button.withConfig({
? 'row-reverse'
: 'row'};
gap: 10px;
transition: all .3s ease;
&:hover{
background-color: ${(props) => props.$hoverсolor};
}

View file

@ -5,7 +5,7 @@ type Props = {
placeholderText: string;
id: string;
value?: string;
onChange?: (identifier: string, value: string) => void;
onChange?: (value: string) => void;
onFileChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
type?: string;
multiple?: boolean;
@ -24,7 +24,7 @@ const InputContainer = styled.div`
`;
const StyledInput = styled.input`
padding: 8px 10px;
padding: 12px 10px;
color: black;
border-radius: 8px;
border: 1px solid #A1A1A1;
@ -41,7 +41,7 @@ const Input = React.forwardRef<HTMLInputElement, Props>(({ placeholderText, id,
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { value } = e.target;
if (onChange) {
onChange(id, value);
onChange(value);
}
};

View file

@ -5,6 +5,10 @@ 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";
const TableContainer = styled.div`
width: 100%;
@ -48,12 +52,21 @@ const TableCell = styled.td`
const StatusBadge = styled.span<{ status:string }>`
width: 10px;
height: 30px;
background-color: ${({theme, status}) => (status==='online' ? theme.successColor : theme.errorColor)};
background-color: ${({theme, status}) => (status==='online' ? theme.successColor : theme.offlineColor)};
display: inline-block;
border-radius:4px;
`
const TableScanner = ({devices}:TableScannerProps) => {
const { openModal } = useModalContext();
const openModalNote = (e: React.MouseEvent, device:DeviceUser ) => {
e.stopPropagation();
openModal(ModalMap['6'], {
mac: device.mac,
currentNote: device.note || ''
});
};
return (
<TableContainer>
@ -66,6 +79,8 @@ const TableScanner = ({devices}:TableScannerProps) => {
<TableHeaderCell>IP адрес</TableHeaderCell>
<TableHeaderCell>Открытые порты</TableHeaderCell>
<TableHeaderCell>Последняя активность</TableHeaderCell>
<TableHeaderCell>Заметка</TableHeaderCell>
<TableHeaderCell></TableHeaderCell>
</tr>
</thead>
<tbody>
@ -77,6 +92,12 @@ const TableScanner = ({devices}:TableScannerProps) => {
<TableCell>{item.ip}</TableCell>
<TableCell>{item.open_ports.join(', ') || '-'}</TableCell>
<TableCell>{item.last_seen}</TableCell>
<TableCell>{item.note || '-'}</TableCell>
<TableCell>
<span onClick={(e)=>openModalNote(e, item)}>
<IconComponent name={buttonNames[7]} width="24" height="24" />
</span>
</TableCell>
</TableRow>
))}
</tbody>

View file

@ -0,0 +1,81 @@
// components/modalContainers/NoteDevice.tsx
import { ModalContainer, ModalTitle, ModalContent, ButtonContainer } from "../style";
import { MainButton } from "../../UI/buttons/mainButton";
import Input from "../../UI/inputs/input";
import { useState } from "react";
import {useIpStore} from "../../../store";
import {NetworkService} from "../../../api/request";
import useNetworkStore from "../../../store/useDeviceStore";
interface Props {
mac: string;
onClose: () => void;
currentNote?: string;
}
export const NoteDevice = ({ mac, onClose, currentNote}: Props) => {
const [note, setNote] = useState(currentNote || '');
const { ipAddress } = useIpStore();
const { devices, setDevices } = useNetworkStore();
const handleSave = async () => {
try {
if (!currentNote && note.trim() !== '') {
await NetworkService.addNote(ipAddress, mac, note);
}else if (currentNote && note.trim() !== '' && note !== currentNote) {
await NetworkService.editNote(ipAddress, mac, note);
}else if (currentNote && note.trim() === '') {
await NetworkService.deleteNote(ipAddress, mac);
}else {
onClose();
return;
}
const updatedDevices = devices.map(device =>
device.mac === mac
? { ...device, note: note.trim() }
: device
);
setDevices(updatedDevices);
onClose();
} catch (error) {
console.error('Error saving note:', error);
}
};
return (
<ModalContainer style={{ height: '250px' }}>
<ModalTitle>
<h3>{currentNote ? 'Редактирование заметки' : 'Добавление заметки'}</h3>
</ModalTitle>
<ModalContent style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
<Input
type="text"
placeholderText='Введите заметку...'
value={note}
id='deviceNote'
onChange={(value) => setNote(value)}
/>
</ModalContent>
<ButtonContainer>
<MainButton
type="button"
size="small"
title="Отмена"
onClick={onClose}
/>
<MainButton
type="button"
size="small"
title='Сохранить'
onClick={handleSave}
/>
</ButtonContainer>
</ModalContainer>
);
};

View file

@ -3,6 +3,7 @@ import { IpConfirm, ConnectionError, AddDevice, RightsConfirm } from "./modalCon
import { ModalMap } from "./windowsType";
import Loader from "../UI/loader";
import { ModalWindow } from "./style";
import {NoteDevice} from "./modalContainers/NoteDevice";
type Props = {
isOpen: boolean,
@ -35,6 +36,13 @@ export default function WindowComponent({ isOpen, type, data }: Props) {
message={data.message}
/>
}
{type === ModalMap['6'] && (
<NoteDevice
mac={data.mac}
currentNote={data.currentNote}
onClose={closeLoader}
/>
)}
{type === ModalMap['4'] && (
<AddDevice onSave={data?.onSave} onClose={closeLoader} />

View file

@ -24,7 +24,7 @@ export const ModalContainer = styled.div<{height?: string}>`
flex-direction: column;
justify-content: space-between;
gap: 15px;
height: ${(props) => props.height ? props.height : '200px'};
height: ${(props) => props.height ? props.height : '230px'};
width: 520px;
`

View file

@ -5,5 +5,6 @@ export const ModalMap: ModalType = {
'2': 'loader',
'3': 'connectionError',
'4': 'addDevice',
'5': 'sudo'
'5': 'sudo',
'6': 'noteDevice',
}

View file

@ -25,8 +25,6 @@ interface ListUsersProps {
}
const ListUsers = ({loading, handleScan, devices, scanInitiated}: ListUsersProps) => {
// Фильтр по статусу
const activeDevices = devices.filter(device => device.status === 'online');
const inactiveDevices = devices.filter(device => device.status !== 'online');
@ -55,7 +53,7 @@ const ListUsers = ({loading, handleScan, devices, scanInitiated}: ListUsersProps
</div>
{/* Колонка неактивных устройств */}
<div style={{ flex: 1 }}>
<h3 style={{ color: '#F44336', marginBottom:'12px' }}>Неактивные устройства ({inactiveDevices.length})</h3>
<h3 style={{ color: '#ababab', marginBottom:'12px' }}>Неактивные устройства ({inactiveDevices.length})</h3>
{inactiveDevices.map((device, index) => (
<DeviceCard
key={index}

View file

@ -14,21 +14,21 @@ type Option ={
// Анимации
const ring1 = keyframes`
0% { width: 250px; height: 250px; }
50% { width: 280px; height: 280px; }
100% { width: 250px; height: 250px; }
0% { transform: translate(-50%, -50%) scale(1); opacity: 0.12; }
50% { transform: translate(-50%, -50%) scale(1.1); opacity: 0.2; }
100% { transform: translate(-50%, -50%) scale(1); opacity: 0.12; }
`;
const ring2 = keyframes`
0% { width: 400px; height: 400px; }
50% { width: 430px; height: 430px; }
100% { width: 400px; height: 400px; }
0% { transform: translate(-50%, -50%) scale(1); opacity: 0.08; }
50% { transform: translate(-50%, -50%) scale(1.1); opacity: 0.15; }
100% { transform: translate(-50%, -50%) scale(1); opacity: 0.08; }
`;
const ring3 = keyframes`
0% { width: 550px; height: 550px; }
50% { width: 580px; height: 580px; }
100% { width: 550px; height: 550px; }
0% { transform: translate(-50%, -50%) scale(1); opacity: 0.04; }
50% { transform: translate(-50%, -50%) scale(1.1); opacity: 0.1; }
100% { transform: translate(-50%, -50%) scale(1); opacity: 0.04; }
`;
const dotAnimation = keyframes`
0% { content: '.'; }
@ -36,6 +36,11 @@ const dotAnimation = keyframes`
66% { content: '...'; }
100% { content: '.'; }
`;
const pulse = keyframes`
0% { transform: translate(-50%, -50%) scale(1); }
50% { transform: translate(-50%, -50%) scale(1.1); }
100% { transform: translate(-50%, -50%) scale(1); }
`;
// Стили
const Wrapper = styled.div<{ scanInitiated: boolean, loading: boolean}>`
@ -60,8 +65,8 @@ const TitleWrapper = styled.h2`
left: 50%;
transform: translateX(-50%);
font-size: 32px;
width: max-content;
`
const UserLocate = styled.div<{ loading: boolean, scanInitiated: boolean }>`
width: 60px;
height: 60px;
@ -77,10 +82,10 @@ const UserLocate = styled.div<{ loading: boolean, scanInitiated: boolean }>`
left: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
&.center{
&.center {
width: 60px;
height: 60px;
animation: ${({ loading }) => (loading ? pulse : "none")} 2s ease infinite;
}
&.ring1 {
opacity: 0.12;
@ -94,6 +99,7 @@ const UserLocate = styled.div<{ loading: boolean, scanInitiated: boolean }>`
width: 400px;
height: 400px;
animation: ${({ loading }) => (loading ? ring2 : "none")} 4s linear infinite;
animation-delay: ${({ loading }) => (loading ? "0.1s" : "0")};
}
&.ring3 {
@ -101,9 +107,9 @@ const UserLocate = styled.div<{ loading: boolean, scanInitiated: boolean }>`
width: 550px;
height: 550px;
animation: ${({ loading }) => (loading ? ring3 : "none")} 4s linear infinite;
animation-delay: ${({ loading }) => (loading ? "0.2s" : "0")};
}
}
`;
const LoadingText = styled.div`

View file

@ -15,21 +15,19 @@ type Option ={
// Анимации
const ring1 = keyframes`
0% { width: 250px; height: 250px; }
50% { width: 280px; height: 280px; }
100% { width: 250px; height: 250px; }
0% { transform: translate(-50%, -50%) scale(1); opacity: 0.12; }
50% { transform: translate(-50%, -50%) scale(1.1); opacity: 0.2; }
100% { transform: translate(-50%, -50%) scale(1); opacity: 0.12; }
`;
const ring2 = keyframes`
0% { width: 400px; height: 400px; }
50% { width: 430px; height: 430px; }
100% { width: 400px; height: 400px; }
0% { transform: translate(-50%, -50%) scale(1); opacity: 0.08; }
50% { transform: translate(-50%, -50%) scale(1.1); opacity: 0.15; }
100% { transform: translate(-50%, -50%) scale(1); opacity: 0.08; }
`;
const ring3 = keyframes`
0% { width: 550px; height: 550px; }
50% { width: 580px; height: 580px; }
100% { width: 550px; height: 550px; }
0% { transform: translate(-50%, -50%) scale(1); opacity: 0.04; }
50% { transform: translate(-50%, -50%) scale(1.1); opacity: 0.1; }
100% { transform: translate(-50%, -50%) scale(1); opacity: 0.04; }
`;
const dotAnimation = keyframes`
0% { content: '.'; }
@ -37,13 +35,18 @@ const dotAnimation = keyframes`
66% { content: '...'; }
100% { content: '.'; }
`;
const pulse = keyframes`
0% { transform: translate(-50%, -50%) scale(1); }
50% { transform: translate(-50%, -50%) scale(1.1); }
100% { transform: translate(-50%, -50%) scale(1); }
`;
// Стили
const Wrapper = styled.div<{ scanInitiated: boolean, loading: boolean}>`
display: flex;
flex-direction: column;
align-items: center;
justify-content:${({scanInitiated, loading})=>(scanInitiated && !loading ? 'start' : 'center')};
justify-content:center ;
height: 100%;
width: 100%;
position: relative;
@ -69,7 +72,7 @@ const UserLocate = styled.div<{ loading: boolean, scanInitiated: boolean }>`
border-radius: 50%;
position: relative;
transition: .4s ease;
transform: ${({scanInitiated,loading})=>(scanInitiated && !loading ? 'scale(0)' : 'scale(1)')};
transform: scale(1);
span {
position: absolute;
display: inline-block;
@ -78,10 +81,10 @@ const UserLocate = styled.div<{ loading: boolean, scanInitiated: boolean }>`
left: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
&.center{
&.center {
width: 60px;
height: 60px;
animation: ${({ loading }) => (loading ? pulse : "none")} 2s ease infinite;
}
&.ring1 {
opacity: 0.12;
@ -95,6 +98,7 @@ const UserLocate = styled.div<{ loading: boolean, scanInitiated: boolean }>`
width: 400px;
height: 400px;
animation: ${({ loading }) => (loading ? ring2 : "none")} 4s linear infinite;
animation-delay: ${({ loading }) => (loading ? "0.1s" : "0")};
}
&.ring3 {
@ -102,11 +106,12 @@ const UserLocate = styled.div<{ loading: boolean, scanInitiated: boolean }>`
width: 550px;
height: 550px;
animation: ${({ loading }) => (loading ? ring3 : "none")} 4s linear infinite;
animation-delay: ${({ loading }) => (loading ? "0.2s" : "0")};
}
}
`;
const LoadingText = styled.div`
position: relative;
padding: 14px 22px;
@ -122,7 +127,7 @@ const ScanningText = styled.span`
animation: ${dotAnimation} 1.5s infinite;
}
`;
const ScanBtn = styled.button<{loading: boolean}>`
const ScanBtn = styled.button<{scanInitiated: boolean}>`
position: relative;
padding: 14px 22px;
background-color: #4CAF50;
@ -130,57 +135,25 @@ const ScanBtn = styled.button<{loading: boolean}>`
border: none;
border-radius: 12px;
font-size: 18px;
transition: .4s ease;
transform: ${({loading}) => (!loading ? "translateY(240px)" : "translateY(0)")};
transition: transform .4s ease;
transform: ${({scanInitiated}) => (scanInitiated ? "translateY(240px)" : "translateY(0)")};
&:hover{
transform: ${({loading}) => (!loading ? "translateY(240px)" : "translateY(0)")} scale(1.03);
transform: ${({scanInitiated}) => (scanInitiated ? "translateY(240px)" : "translateY(0)")} scale(1.03);
}
`
const data = [
{
ssid: "Huawei",
bssid: "wef",
channel: 0,
signal:2,
encryption: "wef",
frequency: "ewf",
vendor: "striwefwng",
hidden: false
},
{
ssid: "Gu-2",
bssid: "grgerger",
channel: 0,
signal: 2,
encryption: "weergref",
frequency: "eergewf",
vendor: "grgregerge",
hidden: false
},
{
ssid: "Huawei_wifi2",
bssid: "wqdqw",
channel: 2,
signal: 3,
encryption: "wefwe",
frequency: "wef",
vendor: "fwefw",
hidden: false
},
];
export function WifiScanner() {
const {ipAddress} = useIpStore();
const ipAddress = '192.168.1.147';
const [loading, setLoading] = useState(false);
const [scanInitiated, setScanInitiated] = useState(false);
const {wifiNetworks, setWifiNetworks} = useNetworkStore();
const [currentNetwork, setCurrentNetwork] = useState<WifiNetworkScanner | null>(null);
const handleScan = async () => {
try {
setWifiNetworks([]);
setLoading(true);
setScanInitiated(true);
try {
const res = await NetworkService.scanWifi(ipAddress);
const networks = res.data.access_points || [];
setWifiNetworks(networks);
@ -194,16 +167,14 @@ export function WifiScanner() {
return (
<Wrapper scanInitiated={scanInitiated} loading={loading}>
{(!scanInitiated || loading) && (
<TitleWrapper>Сканирование Wi-Fi сети</TitleWrapper>
)}
<UserLocate loading={loading} scanInitiated={scanInitiated}>
<span className="center"></span>
<span className="ring1"></span>
<span className="ring2"></span>
<span className="ring3"></span>
{data.map((network) => (
{wifiNetworks.map((network) => (
<WifiDot
key={network.bssid}
network={network}
@ -224,7 +195,7 @@ export function WifiScanner() {
Сканирование сети <ScanningText/>
</LoadingText>
) : (
<ScanBtn onClick={handleScan} disabled={loading} loading={loading}>
<ScanBtn onClick={handleScan} disabled={loading} scanInitiated={scanInitiated}>
{wifiNetworks.length > 0 ? 'Обновить список' : 'Сканировать сеть'}
</ScanBtn>
)}

View file

@ -25,7 +25,7 @@ const CloseBtn = styled.div`
top: -20px;
right: -20px;
cursor: pointer;
background-color: white;
background-color: ${(props) => props.theme.primary};
border-radius: 50%;
display: flex;
justify-content: center;
@ -37,7 +37,7 @@ const CloseBtn = styled.div`
visibility: visible;
&:hover {
background-color: #d6d6d6;
background-color: ${(props) => props.theme.hoverBtn};
}
`
const ModalTitle = styled.div`
@ -100,9 +100,9 @@ const ModalWifiScaner = ({ network,onClose }: { network: WifiNetworkScanner, onC
<ModalTitle>
<h4>{network.ssid}</h4>
<SignalBarsWrapper>
<SignalBar active={network.signal >= 1} />
<SignalBar active={network.signal >= 2} />
<SignalBar active={network.signal >= 3} />
<SignalBar active={network.signal >= -120} />
<SignalBar active={network.signal >= -70} />
<SignalBar active={network.signal >= -50} />
</SignalBarsWrapper>
</ModalTitle>
<ModalContent>

View file

@ -46,15 +46,24 @@ const WifiDot = ({ network, onSelect }: { network: WifiNetworkScanner, onSelect:
};
const getPosition = (signal: number, bssid: string) => {
const strength = Math.min(3, Math.max(1, signal));
let strength: 1 | 2 | 3;
if (signal >= -50) {
strength = 3;
} else if (signal >= -70) {
strength = 2;
} else if (signal >= -90) {
strength = 1;
} else {
strength = 1;
}
const ringSizes = { 1: 550, 2: 400, 3: 250 };
const ringSize = ringSizes[strength as 1 | 2 | 3];
const ringSize = ringSizes[strength];
const offset = getPositionInRing(bssid, ringSize);
return {
top: `calc(50% - ${offset.y}px)`,
left: `calc(50% - ${offset.x}px)`
}
};
};
const position = getPosition(network.signal, network.bssid);

View file

@ -57,7 +57,7 @@ export const ToolBar = () => {
</Button>
<Button>
<IconContainer>
<IconComponent name={buttonNames[14]} width="30" height="30" onClick={() => setWorkModule(workSpaceNames[6])} />
<IconComponent name={buttonNames[15]} width="30" height="30" onClick={() => setWorkModule(workSpaceNames[6])} />
</IconContainer>
</Button>
</ButtonContainer>

View file

@ -17,6 +17,7 @@ import admin from '@iconify/icons-ic/baseline-admin-panel-settings';
import noAdmin from '@iconify/icons-ic/baseline-remove-moderator'
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';
export const ICONS = {
[buttonNames[1]]: exitToApp,
@ -33,6 +34,7 @@ export const ICONS = {
[buttonNames[12]]: close,
[buttonNames[13]]: noAdmin,
[buttonNames[14]]: userSearch,
[buttonNames[15]]: wifiFind,
} as const;
type IconName = keyof typeof ICONS;

View file

@ -14,5 +14,6 @@ export const buttonNames: names ={
11: 'reset',
12: 'close',
13: 'noAdmin',
14: 'userSearch'
14: 'userSearch',
15: 'wifiFind',
}

View file

@ -11,7 +11,10 @@ export const light = {
secondary: '#EDEDED',
background: '#E8E8E8',
textColor: '#000000',
borderColor: '#404040',
scannerColor: '#007ACC',
offlineColor: '#ababab',
hoverBtn: '#d6d6d6',
};
export const dark = {
@ -20,5 +23,8 @@ export const dark = {
secondary: '#252525',
background: '#3A3A3A',
textColor: '#FFFFFF',
borderColor: '#b6b6b6',
scannerColor: '#0E9C9D',
offlineColor: '#656565',
hoverBtn: '#4a4a4a',
};

View file

@ -8,6 +8,7 @@ export interface DeviceUser {
open_ports: string[];
status: string;
last_seen: string;
note: string;
}
export interface WifiNetworkScanner {