add: frontend update

This commit is contained in:
Domingo Dirutigliano
2024-10-13 01:50:52 +02:00
parent fffc9e3b89
commit cbf2c5a43d
53 changed files with 778 additions and 1255 deletions

View File

@@ -108,7 +108,7 @@ function AddNewRegex({ opened, onClose, service }:{ opened:boolean, onClose:()=>
<Alert variant="light" color="yellow" radius="lg" title="You are using whitelists" icon={<AiFillWarning />}>
Using whitelist means that EVERY packet that doesn't match the regex will be DROPPED... In most cases this cause the service interruption.
</Alert></>:null}
<Group position="right" mt="md">
<Group align="right" mt="md">
<Button loading={submitLoading} type="submit">Add Filter</Button>
</Group>

View File

@@ -1,5 +1,4 @@
import { Box, Center, SegmentedControl } from "@mantine/core";
import React from "react";
import { FaListAlt } from "react-icons/fa";
import { TiCancel } from "react-icons/ti";

View File

@@ -1,8 +0,0 @@
@use "../../vars" as *;
@use "../../index.scss" as *;
.footer{
margin-top: 50px;
background-color: $primary_color;
@extend .center-flex;
}

View File

@@ -1,13 +0,0 @@
import { Footer, Space } from '@mantine/core';
import image from "./pwnzer0tt1.svg"
import style from "./index.module.scss";
import { Link } from 'react-router-dom';
function FooterPage() {
return <Footer id="footer" height={70} className={style.footer}>
<img src={image} width={25} height={25} /> <Space w="xs" />Made by <div style={{marginLeft:"5px"}} /> <Link to="https://pwnzer0tt1.it">Pwnzer0tt1</Link> <Space w="xs" /> <img src={image} width={25} height={25} />
</Footer>
}
export default FooterPage;

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 139 KiB

View File

@@ -47,7 +47,7 @@ function ResetModal({ opened, onClose }:{ opened: boolean, onClose: () => void }
{...form.getInputProps('delete_data', { type: 'checkbox' })}
/>
<Space h="md" />
<Group position="right" mt="md">
<Group align="right" mt="md">
<Button loading={loadingBtn} onClick={close} >Cancel</Button>
<Button loading={loadingBtn} type="submit" color="red">Reset</Button>
</Group>

View File

@@ -46,7 +46,7 @@ function ResetPasswordModal({ opened, onClose }:{ opened: boolean, onClose: () =
{...form.getInputProps('expire', { type: 'checkbox' })}
/>
<Space h="md" />
<Group position="right" mt="md">
<Group align="right" mt="md">
<Button loading={loadingBtn} type="submit">Change Password</Button>
</Group>
</form>

View File

@@ -1,24 +0,0 @@
@use "../../vars" as *;
@use "../../index.scss" as *;
.header{
width: 100%;
background-color: $primary_color;
display: flex;
align-items: center;
justify-content: center;
}
.divlogo{
width: 110px;
height: 100%;
cursor: pointer;
@extend .center-flex;
}
.navbtn{
@extend .center-flex;
width: 30px;
margin:0;
}

View File

@@ -1,7 +1,6 @@
import React, { useState } from 'react';
import { ActionIcon, Divider, Image, Menu, Tooltip, Burger, Space, Header, Button, ThemeIcon } from '@mantine/core';
import style from "./index.module.scss";
import { errorNotify, getmainpath, isLargeScreen, logout } from '../../js/utils';
import { ActionIcon, Divider, Image, Menu, Tooltip, Burger, Space, AppShell, Box, Title } from '@mantine/core';
import { errorNotify, getMainPath, isLargeScreen, logout } from '../../js/utils';
import { AiFillHome } from "react-icons/ai"
import { useNavigate } from 'react-router-dom';
import { FaLock } from 'react-icons/fa';
@@ -10,11 +9,13 @@ import { ImExit } from 'react-icons/im';
import ResetPasswordModal from './ResetPasswordModal';
import ResetModal from './ResetModal';
import { MenuDropDownWithButton } from '../MainLayout';
import { useNavbarStore } from '../../js/store';
function HeaderPage({navOpen, setNav, ...other}: { navOpen: boolean, setNav:React.Dispatch<React.SetStateAction<boolean>>}) {
function HeaderPage(props: any) {
const navigator = useNavigate()
const { navOpened, toggleNav } = useNavbarStore()
const logout_action = () => {
logout().then(r => {
@@ -25,40 +26,42 @@ function HeaderPage({navOpen, setNav, ...other}: { navOpen: boolean, setNav:Reac
}
const go_to_home = () => {
navigator(`/${getmainpath()}`)
navigator(`/${getMainPath()}`)
}
const [changePasswordModal, setChangePasswordModal] = useState(false);
const [resetFiregexModal, setResetFiregexModal] = useState(false);
const [tooltipHomeOpened, setTooltipHomeOpened] = useState(false);
const [tooltipLogoutOpened,setTooltipLogoutOpened] = useState(false);
const isLarge = isLargeScreen()
console.log(isLarge)
return <Header height={100} className={style.header} {...other}>
<Space w="lg" />
{isLarge?null:<div>
<Burger
opened={navOpen}
className={style.navbtn}
onClick={() => setNav((o) => !o)}
size="sm"
mr="xl"
/>
</div>}
<div className={style.divlogo}>
<Tooltip zIndex={0} label="Home" openDelay={1000}color="dark" position="right" >
<Image src="/header-logo.png" alt="Firegex logo" onClick={()=>navigator("/")}/>
</Tooltip>
</div>
return <AppShell.Header className="firegex__header__header" {...props}>
<Burger
hiddenFrom='md'
ml="lg"
opened={navOpened}
className="firegex__header__navbtn"
onClick={toggleNav}
size="sm"
/>
<Box style={{ display: "flex", justifyContent: "center", alignItems: "center"}} ml={5}>
<Box className="firegex__header__divlogo">
<Tooltip zIndex={0} label="Home" openDelay={1000} color="dark" position="right" >
<Image src="/header-logo.png" alt="Firegex logo" w={50} onClick={()=>navigator("/")}/>
</Tooltip>
</Box>
<Box display="flex" style={{ flexDirection: "column" }} visibleFrom='xs'>
<Title order={2} >[Fi]*regex</Title>
<p style={{margin: 0, fontSize: "70%"}}>By <a href="https://pwnzer0tt1.it">Pwnzer0tt1</a></p>
</Box>
</Box>
<div className="flex-spacer" />
<Box className="flex-spacer" />
<MenuDropDownWithButton>
<Menu.Label>Firewall Access</Menu.Label>
<Menu.Item icon={<FaLock size={14} />} onClick={() => setChangePasswordModal(true)}>Change Password</Menu.Item>
<Menu.Item leftSection={<FaLock size={14} />} onClick={() => setChangePasswordModal(true)}>Change Password</Menu.Item>
<Divider />
<Menu.Label>Actions</Menu.Label>
<Menu.Item color="red" icon={<MdOutlineSettingsBackupRestore size={18} />} onClick={() => setResetFiregexModal(true)}>Reset Firegex</Menu.Item>
<Menu.Item color="red" leftSection={<MdOutlineSettingsBackupRestore size={18} />} onClick={() => setResetFiregexModal(true)}>Reset Firegex</Menu.Item>
</MenuDropDownWithButton>
<Space w="md" />
<Tooltip label="Home" position='bottom' color="teal" opened={tooltipHomeOpened}>
@@ -78,7 +81,7 @@ function HeaderPage({navOpen, setNav, ...other}: { navOpen: boolean, setNav:Reac
<ResetPasswordModal opened={changePasswordModal} onClose={() => setChangePasswordModal(false)} />
<ResetModal opened={resetFiregexModal} onClose={() => setResetFiregexModal(false)} />
<Space w="xl" />
</Header>
</AppShell.Header>
}
export default HeaderPage;

View File

@@ -1,55 +1,119 @@
import { AutocompleteItem, Select, SelectProps } from "@mantine/core";
import React, { useState } from "react";
import { Combobox, TextInput, useCombobox } from "@mantine/core";
import { useState } from "react";
import { ipInterfacesQuery } from "../js/utils";
const AutoCompleteItem = React.forwardRef<HTMLDivElement, ItemProps>(
({ netint, value, ...props }: ItemProps, ref) => <div ref={ref} {...props}>
( <b>{netint}</b> ) -{">"} <b>{value}</b>
</div>
);
interface ItemProps extends AutocompleteItem {
interface ItemProps{
value: string
netint: string;
}
interface InterfaceInputProps extends Omit<SelectProps, "data">{
initialCustomInterfaces?:AutocompleteItem[],
includeInterfaceNames?:boolean
interface InterfaceInputProps{
initialCustomInterfaces?:ItemProps[],
includeInterfaceNames?:boolean,
onChange?: (value:string) => void,
value?:string,
defaultValue?:string
}
export const InterfaceInput = ({ initialCustomInterfaces, includeInterfaceNames, ...props }:InterfaceInputProps) => {
export const InterfaceInput = ({ initialCustomInterfaces, includeInterfaceNames, onChange, value, defaultValue }:InterfaceInputProps) => {
const [customIpInterfaces, setCustomIpInterfaces] = useState<AutocompleteItem[]>(initialCustomInterfaces??[]);
const [customIpInterfaces, setCustomIpInterfaces] = useState<ItemProps[]>(initialCustomInterfaces??[]);
const interfacesQuery = ipInterfacesQuery()
const getInterfaces = () => {
if (interfacesQuery.isLoading || !interfacesQuery.data) return []
if(includeInterfaceNames){
const result = interfacesQuery.data.map(item => ({netint:"IP", value:item.addr, label:item.addr})) as AutocompleteItem[]
interfacesQuery.data.map(item => item.name).filter((item, index, arr) => arr.indexOf(item) === index).forEach(item => result.push({netint:"INT", value:item, label:item}))
const result = interfacesQuery.data.map(item => ({netint:"IP", value:item.addr})) as ItemProps[]
interfacesQuery.data.map(item => item.name).filter((item, index, arr) => arr.indexOf(item) === index).forEach(item => result.push({netint:"INT", value:item}))
return result
}
return (interfacesQuery.data.map(item => ({netint:item.name, value:item.addr, label:item.addr})) as AutocompleteItem[])
return (interfacesQuery.data.map(item => ({netint:item.name, value:item.addr})) as ItemProps[])
}
const interfaces = getInterfaces()
return <Select
placeholder="10.1.1.1"
itemComponent={AutoCompleteItem}
data={[...customIpInterfaces, ...interfaces]}
searchable
dropdownPosition="bottom"
maxDropdownHeight={200}
creatable
getCreateLabel={(query) => `+ Use this: ${query}`}
onCreate={(query) => {
const item = { value: query, netint: "CUSTOM", label: query };
setCustomIpInterfaces((current) => [...current, item]);
return item;
const combobox = useCombobox({
onDropdownClose: () => {
combobox.resetSelectedOption()
},
});
const data = [...customIpInterfaces, ...interfaces]
const [selectedValue, setSelectedValue] = useState<string | null>(null);
const [search, setSearch] = useState('');
const exactOptionMatch: ItemProps|undefined = data.find((item) => item.value === search);
const filteredOptions = data.filter((item) => item.value.toLowerCase().includes(search.toLowerCase().trim())).sort((a, b) => {
if (exactOptionMatch != null) {
if (a.value == exactOptionMatch.value) return -1
if (b.value == exactOptionMatch.value) return 1
}
return a.value.localeCompare(b.value)
});
const options = filteredOptions.map((item) => (
<Combobox.Option value={item.value} key={item.value}>
( <b>{item.netint}</b> ) -{">"} <b>{item.value}</b>
</Combobox.Option>
));
return <>
<Combobox
store={combobox}
withinPortal={false}
position="bottom-end"
onOptionSubmit={(value) => {
if (value === '$create') {
const item = { value: search, netint: "CUSTOM" };
setCustomIpInterfaces((current) => [...current, item]);
setSelectedValue(search);
onChange?.(search)
} else {
setSelectedValue(value);
setSearch(value);
onChange?.(value)
}
combobox.closeDropdown();
}}
style={props.style?{width:"100%", ...props.style}:{width:"100%"}}
{...props}
/>
>
<Combobox.Target>
<TextInput
style={{width:"100%"}}
defaultValue={defaultValue}
rightSection={<Combobox.Chevron />}
value={value??(defaultValue?undefined:search)}
placeholder="10.1.1.1"
rightSectionPointerEvents="none"
onChange={(event) => {
combobox.openDropdown();
combobox.updateSelectedOptionIndex();
setSearch(event.currentTarget.value)
onChange?.(event.currentTarget.value)
}}
onClick={(e) => {
combobox.openDropdown()
}}
onFocus={(e) => {
combobox.openDropdown()
}}
onBlur={(e) => {
combobox.closeDropdown();
setSearch(selectedValue??'');
}}
/>
</Combobox.Target>
<Combobox.Dropdown>
<Combobox.Options mah={100} style={{ overflowY: 'auto' }}>
{options}
{(exactOptionMatch==null) && search.trim().length > 0 && (
<Combobox.Option value="$create">+ Use this: {search}</Combobox.Option>
)}
</Combobox.Options>
</Combobox.Dropdown>
</Combobox>
</>
}

View File

@@ -1,44 +1,38 @@
import { useEffect, useState } from 'react';
import { useEffect } from 'react';
import { ActionIcon, Container, Menu, Space } from '@mantine/core';
import { AppShell } from '@mantine/core';
import NavBar from './NavBar';
import FooterPage from './Footer';
import HeaderPage from './Header';
import { getmainpath } from '../js/utils';
import { getMainPath } from '../js/utils';
import { useLocation } from 'react-router-dom';
import { RiMenu5Fill } from 'react-icons/ri';
import { useNavbarStore } from '../js/store';
function MainLayout({ children }:{ children:any }) {
const [opened, setOpened] = useState(false);
const { navOpened } = useNavbarStore()
const location = useLocation()
useEffect(()=>{
if (location.pathname !== "/"){
sessionStorage.setItem('home_section', getmainpath())
sessionStorage.setItem('home_section', getMainPath())
}
},[location.pathname])
return <>
<AppShell
padding="md"
fixed
navbar={<NavBar closeNav={()=>setOpened(false)} opened={opened} />}
header={<HeaderPage navOpen={opened} setNav={setOpened} />}
footer={<FooterPage />}
return <AppShell
header={{ height: 70 }}
navbar={{ width: 300 , breakpoint: "md", collapsed: { mobile: !navOpened } }}
p="md"
>
<Container size="lg">
{children}
</Container>
<HeaderPage />
<NavBar />
<AppShell.Main>
<Container size="lg">
{children}
</Container>
</AppShell.Main>
<Space h="lg" />
</AppShell>
</>
}
export default MainLayout;
@@ -46,7 +40,7 @@ export default MainLayout;
export const MenuDropDownWithButton = ({children}:{children:any}) => <Menu withArrow>
<Menu.Target>
<ActionIcon variant='transparent'>
<RiMenu5Fill size={24} />
<RiMenu5Fill size={24} color='#FFF'/>
</ActionIcon>
</Menu.Target>
<Menu.Dropdown>

View File

@@ -1,4 +1,4 @@
import { Button, Group, Space, TextInput, Notification, Modal, Switch, SegmentedControl } from '@mantine/core';
import { Button, Group, Space, TextInput, Notification, Modal, Switch, SegmentedControl, Box } from '@mantine/core';
import { useForm } from '@mantine/form';
import { useState } from 'react';
import { okNotify, regex_ipv4, regex_ipv6 } from '../../js/utils';
@@ -71,12 +71,12 @@ function AddNewService({ opened, onClose }:{ opened:boolean, onClose:()=>void })
<PortAndInterface form={form} int_name="ip_int" port_name="port" label={"Public IP Interface and port (ipv4/ipv6 + CIDR allowed)"} />
<Space h="md" />
<div className='center-flex'>
<Box className='center-flex'>
<Switch
label="Auto-Start Service"
{...form.getInputProps('autostart', { type: 'checkbox' })}
/>
<div className="flex-spacer"></div>
<Box className="flex-spacer"></Box>
<SegmentedControl
data={[
{ label: 'TCP', value: 'tcp' },
@@ -84,9 +84,9 @@ function AddNewService({ opened, onClose }:{ opened:boolean, onClose:()=>void })
]}
{...form.getInputProps('proto')}
/>
</div>
</Box>
<Group position="right" mt="md">
<Group align="right" mt="md">
<Button loading={submitLoading} type="submit">Add Service</Button>
</Group>

View File

@@ -49,7 +49,7 @@ function RenameForm({ opened, onClose, service }:{ opened:boolean, onClose:()=>v
placeholder="Awesome Service Name!"
{...form.getInputProps('name')}
/>
<Group position="right" mt="md">
<Group align="right" mt="md">
<Button loading={submitLoading} type="submit">Rename</Button>
</Group>

View File

@@ -1,23 +0,0 @@
@use "../../../index.scss" as *;
.row{
width: 95%;
padding: 30px 0px;
border-radius: 20px;
margin: 10px;
@extend .center-flex;
}
.name{
font-size: 2.3em;
font-weight: bolder;
margin-right: 10px;
margin-bottom: 13px;
color:#FFF;
max-width: 300px;
overflow: hidden;
}
.name:hover{
overflow: auto;
}

View File

@@ -1,9 +1,8 @@
import { ActionIcon, Badge, Divider, Grid, Menu, Space, Title, Tooltip } from '@mantine/core';
import { ActionIcon, Badge, Box, Divider, Grid, Menu, Space, Title, Tooltip } from '@mantine/core';
import { useState } from 'react';
import { FaPlay, FaStop } from 'react-icons/fa';
import { nfregex, Service, serviceQueryKey } from '../utils';
import { MdOutlineArrowForwardIos } from "react-icons/md"
import style from "./index.module.scss";
import YesNoModal from '../../YesNoModal';
import { errorNotify, isMediumScreen, okNotify, regex_ipv4 } from '../../../js/utils';
import { BsTrashFill } from 'react-icons/bs';
@@ -72,71 +71,73 @@ function ServiceRow({ service, onClick }:{ service:Service, onClick?:()=>void })
}
return <>
<Grid className={style.row} justify="flex-end" style={{width:"100%"}}>
<Grid.Col md={4} xs={12}>
<Box className='firegex__nfregex__rowbox'>
<Grid className="firegex__nfregex__row" justify="flex-end" style={{width:"100%"}}>
<Grid.Col span={{ md:4, xs: 12 }}>
<div className={isMedium?"center-flex-row":"center-flex"}>
<div className="center-flex">
<Title className={style.name}>
<Box className={"center-flex-row"}>
<Title className="firegex__nfregex__name">
{service.name}
</Title>
<Badge size="xl" gradient={{ from: 'indigo', to: 'cyan' }} variant="gradient">
:{service.port}
</Badge>
</div>
<Badge style={isMedium?{}:{marginLeft:"20px"}} color={status_color} radius="sm" size="lg" variant="filled">Status: <u>{service.status}</u></Badge>
{isMedium?null:<Space w="xl" />}
</div>
{!isMedium?<Space h="xl" />:null}
</Grid.Col>
<Grid.Col className="center-flex" md={8} xs={12}>
{!isMedium?<div className='flex-spacer' />:<><Space w="xl" /><Space w="xl" /></>}
<Box className="center-flex" style={{ gap: 6 }}>
<Badge color={status_color} radius="md" size="lg" variant="filled">Status: <u>{service.status}</u></Badge>
<Badge size="lg" gradient={{ from: 'indigo', to: 'cyan' }} variant="gradient" radius="md">
:{service.port}
</Badge>
</Box>
{isMedium?null:<Space w="xl" />}
</Box>
</Grid.Col>
<div className="center-flex-row">
<Badge color="yellow" radius="sm" size="md" variant="filled">Connections Blocked: {service.n_packets}</Badge>
<Space h="xs" />
<Badge color="violet" radius="sm" size="md" variant="filled">Regex: {service.n_regex}</Badge>
<Space h="xs" />
<Badge color={service.ip_int.match(regex_ipv4)?"cyan":"pink"} radius="sm" size="md" variant="filled">{service.ip_int} on {service.proto}</Badge>
</div>
{isMedium?<div className='flex-spacer' />:<><Space w="xl" /><Space w="xl" /></>}
<div className="center-flex">
<MenuDropDownWithButton>
<Menu.Label><b>Rename service</b></Menu.Label>
<Menu.Item icon={<BiRename size={18} />} onClick={()=>setRenameModal(true)}>Change service name</Menu.Item>
<Divider />
<Menu.Label><b>Danger zone</b></Menu.Label>
<Menu.Item color="red" icon={<BsTrashFill size={18} />} onClick={()=>setDeleteModal(true)}>Delete Service</Menu.Item>
</MenuDropDownWithButton>
<Space w="md"/>
<Tooltip label="Stop service" zIndex={0} color="red" opened={tooltipStopOpened}>
<ActionIcon color="red" loading={buttonLoading}
onClick={stopService} size="xl" radius="md" variant="filled"
disabled={service.status === "stop"}
aria-describedby="tooltip-stop-id"
onFocus={() => setTooltipStopOpened(false)} onBlur={() => setTooltipStopOpened(false)}
onMouseEnter={() => setTooltipStopOpened(true)} onMouseLeave={() => setTooltipStopOpened(false)}>
<FaStop size="20px" />
</ActionIcon>
</Tooltip>
<Space w="md"/>
<Tooltip label="Start service" zIndex={0} color="teal">
<ActionIcon color="teal" size="xl" radius="md" onClick={startService} loading={buttonLoading}
variant="filled" disabled={!["stop","pause"].includes(service.status)?true:false}>
<FaPlay size="20px" />
</ActionIcon>
</Tooltip>
</div>
<Space w="xl" /><Space w="xl" />
{onClick?<div>
<MdOutlineArrowForwardIos onClick={onClick} style={{cursor:"pointer"}} size={45} />
<Space w="xl" />
</div>:null}
{isMedium?<><Space w="xl" /><Space w="xl" /></>:null}
</Grid.Col>
</Grid>
<Divider size="md" style={{width:"100%"}}/>
<Grid.Col className={isMedium?"center-flex":"center-flex-row"} span={{ md:8, xs: 12 }}>
<Box visibleFrom='md' className='flex-spacer' />
<Space hiddenFrom='md' h="md" />
<Space hiddenFrom='md' w="xl" />
<Space hiddenFrom='md' w="md" />
<Box className="center-flex-row">
<Badge color="yellow" radius="sm" size="md" variant="filled">Connections Blocked: {service.n_packets}</Badge>
<Space h="xs" />
<Badge color="violet" radius="sm" size="md" variant="filled">Regex: {service.n_regex}</Badge>
<Space h="xs" />
<Badge color={service.ip_int.match(regex_ipv4)?"cyan":"pink"} radius="sm" size="md" variant="filled">{service.ip_int} on {service.proto}</Badge>
</Box>
{isMedium?<Box className='flex-spacer' />:<Space h="xl" />}
<Box className="center-flex">
<MenuDropDownWithButton>
<Menu.Label><b>Rename service</b></Menu.Label>
<Menu.Item leftSection={<BiRename size={18} />} onClick={()=>setRenameModal(true)}>Change service name</Menu.Item>
<Divider />
<Menu.Label><b>Danger zone</b></Menu.Label>
<Menu.Item color="red" leftSection={<BsTrashFill size={18} />} onClick={()=>setDeleteModal(true)}>Delete Service</Menu.Item>
</MenuDropDownWithButton>
<Space w="md"/>
<Tooltip label="Stop service" zIndex={0} color="red" opened={tooltipStopOpened}>
<ActionIcon color="red" loading={buttonLoading}
onClick={stopService} size="xl" radius="md" variant="filled"
disabled={service.status === "stop"}
aria-describedby="tooltip-stop-id"
onFocus={() => setTooltipStopOpened(false)} onBlur={() => setTooltipStopOpened(false)}
onMouseEnter={() => setTooltipStopOpened(true)} onMouseLeave={() => setTooltipStopOpened(false)}>
<FaStop size="20px" />
</ActionIcon>
</Tooltip>
<Space w="md"/>
<Tooltip label="Start service" zIndex={0} color="teal">
<ActionIcon color="teal" size="xl" radius="md" onClick={startService} loading={buttonLoading}
variant="filled" disabled={!["stop","pause"].includes(service.status)?true:false}>
<FaPlay size="20px" />
</ActionIcon>
</Tooltip>
{isMedium?<Space w="xl" />:<Space w="md" />}
{onClick?<Box style={{ backgroundColor: "var(--secondary_color)", borderRadius: "38%", width:"35px", height:"35px", display:"flex", justifyContent: "center", alignItems: "center", border:"#AAA 2px solid"}}>
<MdOutlineArrowForwardIos onClick={onClick} style={{cursor:"pointer"}} size={25} />
</Box>:null}
{isMedium?<Space w="xl" />:null}
</Box>
</Grid.Col>
</Grid>
</Box>
<YesNoModal
title='Are you sure to delete this service?'
description={`You are going to delete the service '${service.port}', causing the stopping of the firewall and deleting all the regex associated. This will cause the shutdown of your service! ⚠️`}

View File

@@ -1,29 +1,19 @@
import { Collapse, Divider, Group, MantineColor, Navbar, ScrollArea, Text, ThemeIcon, Title, UnstyledButton } from "@mantine/core";
import { Collapse, Divider, Group, MantineColor, ScrollArea, Text, ThemeIcon, Title, UnstyledButton, Box, AppShell } from "@mantine/core";
import { useState } from "react";
import { IoMdGitNetwork } from "react-icons/io";
import { MdOutlineExpandLess, MdOutlineExpandMore, MdTransform } from "react-icons/md";
import { useNavigate } from "react-router-dom";
import { getmainpath } from "../../js/utils";
import { GrDirections } from "react-icons/gr";
import { PiWallLight } from "react-icons/pi";
import { useNavbarStore } from "../../js/store";
import { getMainPath } from "../../js/utils";
function NavBarButton({ navigate, closeNav, name, icon, color, disabled, onClick }:
{ navigate?: string, closeNav: () => void, name:string, icon:any, color:MantineColor, disabled?:boolean, onClick?:CallableFunction }) {
const navigator = useNavigate()
return <UnstyledButton sx={(theme) => ({
display: 'block',
width: '100%',
padding: theme.spacing.xs,
borderRadius: theme.radius.sm,
opacity: disabled ? 0.4 : 1,
color: theme.colorScheme === 'dark' ? theme.colors.dark[0] : theme.black,
backgroundColor:(navigate===getmainpath()?(theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[0]):"transparent"),
'&:hover': {
backgroundColor:
theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[0],
},
})} onClick={()=>{
return <UnstyledButton
className={`firegex__navbar__unstyled_button${navigate==getMainPath()?" selected":""}${disabled?" disabled":""}`}
onClick={()=>{
if(navigate){navigator(`/${navigate}`);closeNav()}
if (onClick) onClick()
}} disabled={disabled}>
@@ -36,17 +26,16 @@ function NavBarButton({ navigate, closeNav, name, icon, color, disabled, onClick
</UnstyledButton>
}
export default function NavBar({ closeNav, opened }: {closeNav: () => void, opened: boolean}) {
export default function NavBar() {
const [toggle, setToggleState] = useState(false);
const { navOpened, closeNav } = useNavbarStore()
return <Navbar p="md" hiddenBreakpoint="md" hidden={!opened} width={{ md: 300 }}>
<Navbar.Section px="xs" mt="xs">
<Title order={3}>[Fi]*regex 🔥</Title>
</Navbar.Section>
return <AppShell.Navbar p="md" hidden={!navOpened}>
<Box px="xs" mt="xs">
<Title order={4}>Options </Title>
</Box>
<Divider my="xs" />
<Navbar.Section grow component={ScrollArea} px="xs" mt="xs">
<Box style={{flexGrow: 1}} component={ScrollArea} px="xs" mt="xs">
<NavBarButton navigate="nfregex" closeNav={closeNav} name="Netfilter Regex" color="lime" icon={<IoMdGitNetwork />} />
<NavBarButton navigate="firewall" closeNav={closeNav} name="Firewall Rules" color="red" icon={<PiWallLight />} />
<NavBarButton navigate="porthijack" closeNav={closeNav} name="Hijack Port to Proxy" color="blue" icon={<GrDirections />} />
@@ -55,7 +44,7 @@ export default function NavBar({ closeNav, opened }: {closeNav: () => void, open
<Collapse in={toggle}>
<NavBarButton navigate="regexproxy" closeNav={closeNav} name="TCP Proxy Regex Filter" color="grape" icon={<MdTransform />} />
</Collapse>
</Navbar.Section>
</Box>
</Navbar>
</AppShell.Navbar>
}

View File

@@ -1,9 +1,5 @@
import { ActionIcon, ActionIconProps } from "@mantine/core"
import { ActionIcon, ActionIconProps, PolymorphicComponentProps } from "@mantine/core"
import { ImCheckmark, ImCross } from "react-icons/im"
import { TiTick } from "react-icons/ti"
import {PolymorphicComponentProps} from "@mantine/utils"
interface IOnOffButtonProps extends Omit<PolymorphicComponentProps<"button",ActionIconProps>, "value">{
value: boolean,

View File

@@ -1,21 +1,20 @@
import { AutocompleteItem, Select, Space, Title } from "@mantine/core"
import React, { useEffect, useState } from "react"
import { ipInterfacesQuery } from "../js/utils";
import { Box, Space, Title } from "@mantine/core"
import React from "react"
import PortInput from "./PortInput";
import { UseFormReturnType } from "@mantine/form/lib/types";
import { InterfaceInput } from "./InterfaceInput";
interface ItemProps extends AutocompleteItem {
type ItemProps = {
value: string;
netint: string;
}
} & any
const AutoCompleteItem = React.forwardRef<HTMLDivElement, ItemProps>(
({ netint, value, ...props }: ItemProps, ref) => <div ref={ref} {...props}>
({ netint, value, ...props }, ref) => <Box ref={ref} {...props}>
( <b>{netint}</b> ) -{">"} <b>{value}</b>
</div>
</Box>
);
export default function PortAndInterface({ form, int_name, port_name, label, orientation }:{ form:UseFormReturnType<any>, int_name:string, port_name:string, label?:string, orientation?:"line"|"column" }) {
@@ -24,7 +23,7 @@ export default function PortAndInterface({ form, int_name, port_name, label, ori
{label?<>
<Title order={6}>{label}</Title>
<Space h="xs" /></> :null}
<div className={(!orientation || orientation == "line")?'center-flex':"center-flex-row"} style={{width:"100%"}}>
<Box className={(!orientation || orientation == "line")?'center-flex':"center-flex-row"} style={{width:"100%"}}>
<InterfaceInput
{...form.getInputProps(int_name)}
/>
@@ -32,6 +31,6 @@ export default function PortAndInterface({ form, int_name, port_name, label, ori
<><Space w="sm" /><span style={{marginTop:"-3px", fontSize:"1.5em"}}>:</span><Space w="sm" /></>:
<Space h="md" />}
<PortInput {...form.getInputProps(port_name)} />
</div>
</Box>
</>
}

View File

@@ -1,4 +1,4 @@
import { Button, Group, Space, TextInput, Notification, Modal, Switch, SegmentedControl } from '@mantine/core';
import { Button, Group, Space, TextInput, Notification, Modal, Switch, SegmentedControl, Box } from '@mantine/core';
import { useForm } from '@mantine/form';
import { useState } from 'react';
import { okNotify, regex_ipv6_no_cidr, regex_ipv4_no_cidr } from '../../js/utils';
@@ -79,12 +79,12 @@ function AddNewService({ opened, onClose }:{ opened:boolean, onClose:()=>void })
<PortAndInterface form={form} int_name="ip_dst" port_name="proxy_port" label="Proxy/Internal IP Address and port (ipv4/ipv6)" />
<Space h="md" />
<div className='center-flex'>
<Box className='center-flex'>
<Switch
label="Auto-Start Service"
{...form.getInputProps('autostart', { type: 'checkbox' })}
/>
<div className="flex-spacer"></div>
<Box className="flex-spacer" />
<SegmentedControl
data={[
{ label: 'TCP', value: 'tcp' },
@@ -92,9 +92,9 @@ function AddNewService({ opened, onClose }:{ opened:boolean, onClose:()=>void })
]}
{...form.getInputProps('proto')}
/>
</div>
</Box>
<Group position="right" mt="md">
<Group align="right" mt="md">
<Button loading={submitLoading} type="submit">Add Service</Button>
</Group>

View File

@@ -53,7 +53,7 @@ function ChangeDestination({ opened, onClose, service }:{ opened:boolean, onClos
<form onSubmit={form.onSubmit(submitRequest)}>
<PortAndInterface form={form} int_name="ip_dst" port_name="proxy_port" />
<Group position="right" mt="md">
<Group align="right" mt="md">
<Button loading={submitLoading} type="submit">Change</Button>
</Group>
<Space h="md" />

View File

@@ -49,7 +49,7 @@ function RenameForm({ opened, onClose, service }:{ opened:boolean, onClose:()=>v
placeholder="Awesome Service Name!"
{...form.getInputProps('name')}
/>
<Group position="right" mt="md">
<Group align="right" mt="md">
<Button loading={submitLoading} type="submit">Rename</Button>
</Group>

View File

@@ -1,31 +0,0 @@
@use "../../../index.scss" as *;
.row{
width: 95%;
padding: 15px 0px;
border-radius: 20px;
margin: 10px;
@extend .center-flex;
}
.row-mobile{
@extend .row;
@extend .center-flex-row;
}
.name{
font-size: 2.3em;
font-weight: bolder;
margin-right: 10px;
margin-bottom: 13px;
color:#FFF;
}
.portInput *{
color: #FFF;
font-weight: bold;
font-size: 1em;
margin-top: -1px;
text-decoration: underline;
}

View File

@@ -1,8 +1,7 @@
import { ActionIcon, Badge, Divider, Menu, Space, Title, Tooltip } from '@mantine/core';
import { ActionIcon, Badge, Box, Divider, Grid, Menu, Space, Title, Tooltip } from '@mantine/core';
import React, { useState } from 'react';
import { FaPlay, FaStop } from 'react-icons/fa';
import { porthijack, Service } from '../utils';
import style from "./index.module.scss";
import YesNoModal from '../../YesNoModal';
import { errorNotify, isMediumScreen, okNotify } from '../../../js/utils';
import { BsArrowRepeat, BsTrashFill } from 'react-icons/bs';
@@ -90,86 +89,91 @@ function ServiceRow({ service }:{ service:Service }) {
}
return <>
<div className={isMedium?style.row:style.row_mobile} style={{width:"100%"}}>
<Space w="xl" /><Space w="xl" />
<div>
<div className="center-flex-row">
<Title order={4} className={style.name}>{service.name}</Title>
<div className="center-flex">
<Badge color={status_color} radius="sm" size="md" variant="filled">Status: <u>{service.active?"ENABLED":"DISABLED"}</u></Badge>
<Space w="sm" />
<Badge color={service.proto === "tcp"?"cyan":"orange"} radius="sm" size="md" variant="filled">
{service.proto}
</Badge>
</div>
</div>
</div>
<div className='flex-spacer' />
{isMedium?null:<Space h="xl" />}
<div className='center-flex'>
<div className="center-flex-row">
<Badge color="lime" radius="sm" size="md" variant="filled">
FROM {service.ip_src} : {service.public_port}
</Badge>
<Space h="sm" />
<Badge color="blue" radius="sm" size="md" variant="filled">
<div className="center-flex">
TO {service.ip_dst} :
<form onSubmit={form.onSubmit((v)=>portInputRef.current?.blur())}>
<PortInput
defaultValue={service.proxy_port}
size="xs"
variant="unstyled"
style={{
width: (10+form.values.proxy_port.toString().length*6.2) +"px"
}}
className={style.portInput}
onBlur={(e)=>{onChangeProxyPort({proxy_port:parseInt(e.target.value)})}}
ref={portInputRef}
{...form.getInputProps("proxy_port")}
/>
</form>
</div>
</Badge>
</div>
<Space w="xl" /><Space w="xl" />
<div className="center-flex">
<MenuDropDownWithButton>
<Menu.Label><b>Rename service</b></Menu.Label>
<Menu.Item icon={<BiRename size={18} />} onClick={()=>setRenameModal(true)}>Change service name</Menu.Item>
<Menu.Label><b>Change destination</b></Menu.Label>
<Menu.Item icon={<BsArrowRepeat size={18} />} onClick={()=>setChangeDestModal(true)}>Change hijacking destination</Menu.Item>
<Divider />
<Menu.Label><b>Danger zone</b></Menu.Label>
<Menu.Item color="red" icon={<BsTrashFill size={18} />} onClick={()=>setDeleteModal(true)}>Delete Service</Menu.Item>
</MenuDropDownWithButton>
<Space w="md"/>
<Tooltip label="Stop service" zIndex={0} color="red" opened={tooltipStopOpened}>
<ActionIcon color="red" loading={buttonLoading}
onClick={stopService} size="xl" radius="md" variant="filled"
disabled={!service.active}
aria-describedby="tooltip-stop-id"
onFocus={() => setTooltipStopOpened(false)} onBlur={() => setTooltipStopOpened(false)}
onMouseEnter={() => setTooltipStopOpened(true)} onMouseLeave={() => setTooltipStopOpened(false)}>
<FaStop size="20px" />
</ActionIcon>
</Tooltip>
<Space w="md"/>
<Tooltip label="Start service" zIndex={0} color="teal">
<ActionIcon color="teal" size="xl" radius="md" onClick={startService} loading={buttonLoading}
variant="filled" disabled={service.active}>
<FaPlay size="20px" />
</ActionIcon>
</Tooltip>
</div>
</div>
{isMedium?null:<Space h="xl" />}
<Space w="xl" /><Space w="xl" />
<Box className='firegex__nfregex__rowbox'>
<Grid className="firegex__nfregex__row" justify="flex-end" style={{width:"100%"}}>
<Grid.Col span={{ md:4, xs: 12 }}>
<Box className={"center-flex-row"}>
<Title className="firegex__nfregex__name">
{service.name}
</Title>
<Box className="center-flex" style={{ gap: 6 }}>
<Badge color={status_color} radius="md" size="lg" variant="filled">Status: <u>{service.active?"ENABLED":"DISABLED"}</u></Badge>
<Badge color={service.proto === "tcp"?"cyan":"orange"} radius="md" size="lg" variant="filled">
{service.proto}
</Badge>
</Box>
{isMedium?null:<Space w="xl" />}
</Box>
</Grid.Col>
</div>
<Divider size="sm" style={{width:"100%"}}/>
<Grid.Col className={isMedium?"center-flex":"center-flex-row"} span={{ md:8, xs: 12 }}>
<Box visibleFrom='md' className='flex-spacer' />
<Space hiddenFrom='md' h="md" />
<Space hiddenFrom='md' w="xl" />
<Space hiddenFrom='md' w="md" />
<Box className="center-flex-row">
<Badge color="lime" radius="sm" size="md" variant="filled">
FROM {service.ip_src} : {service.public_port}
</Badge>
<Space h="sm" />
<Badge color="blue" radius="sm" size="md" variant="filled">
<Box className="center-flex">
TO {service.ip_dst} :
<form onSubmit={form.onSubmit((v)=>portInputRef.current?.blur())}>
<PortInput
defaultValue={service.proxy_port}
size="xs"
variant="unstyled"
style={{
width: (10+form.values.proxy_port.toString().length*6.2) +"px"
}}
className="firegex__porthijack__servicerow__portInput"
onBlur={(e)=>{onChangeProxyPort({proxy_port:parseInt(e.target.value)})}}
ref={portInputRef}
{...form.getInputProps("proxy_port")}
/>
</form>
</Box>
</Badge>
</Box>
{isMedium?<Box className='flex-spacer' />:<Space h="xl" />}
<Box className="center-flex">
<MenuDropDownWithButton>
<Menu.Label><b>Rename service</b></Menu.Label>
<Menu.Item leftSection={<BiRename size={18} />} onClick={()=>setRenameModal(true)}>Change service name</Menu.Item>
<Menu.Label><b>Change destination</b></Menu.Label>
<Menu.Item leftSection={<BsArrowRepeat size={18} />} onClick={()=>setChangeDestModal(true)}>Change hijacking destination</Menu.Item>
<Divider />
<Menu.Label><b>Danger zone</b></Menu.Label>
<Menu.Item color="red" leftSection={<BsTrashFill size={18} />} onClick={()=>setDeleteModal(true)}>Delete Service</Menu.Item>
</MenuDropDownWithButton>
<Space w="md"/>
<Tooltip label="Stop service" zIndex={0} color="red" opened={tooltipStopOpened}>
<ActionIcon color="red" loading={buttonLoading}
onClick={stopService} size="xl" radius="md" variant="filled"
disabled={!service.active}
aria-describedby="tooltip-stop-id"
onFocus={() => setTooltipStopOpened(false)} onBlur={() => setTooltipStopOpened(false)}
onMouseEnter={() => setTooltipStopOpened(true)} onMouseLeave={() => setTooltipStopOpened(false)}>
<FaStop size="20px" />
</ActionIcon>
</Tooltip>
<Space w="md"/>
<Tooltip label="Start service" zIndex={0} color="teal">
<ActionIcon color="teal" size="xl" radius="md" onClick={startService} loading={buttonLoading}
variant="filled" disabled={service.active}>
<FaPlay size="20px" />
</ActionIcon>
</Tooltip>
</Box>
{isMedium?<Space w="xl" />:null}
</Grid.Col>
</Grid>
</Box>
<YesNoModal
title='Are you sure to delete this service?'

View File

@@ -98,7 +98,7 @@ function AddNewService({ opened, onClose }:{ opened:boolean, onClose:()=>void })
{...form.getInputProps('chosenInternalPort', { type: 'checkbox' })}
/>
<Group position="right" mt="md">
<Group align="right" mt="md">
<Button loading={submitLoading} type="submit">Add Service</Button>
</Group>

View File

@@ -80,7 +80,7 @@ function ChangePortModal({ service, opened, onClose }:{ service:Service, opened:
<Space h="md" />
<Group position="right" mt="md">
<Group align="right" mt="md">
<Button loading={submitLoading} disabled={
service.internal_port === form.values.internalPort && service.public_port === form.values.port
} type="submit">Change Port</Button>

View File

@@ -49,7 +49,7 @@ function RenameForm({ opened, onClose, service }:{ opened:boolean, onClose:()=>v
placeholder="Awesome Service Name!"
{...form.getInputProps('name')}
/>
<Group position="right" mt="md">
<Group align="right" mt="md">
<Button loading={submitLoading} type="submit">Rename</Button>
</Group>

View File

@@ -1,18 +0,0 @@
@use "../../../index.scss" as *;
.row{
width: 95%;
padding: 30px 0px;
border-radius: 20px;
margin: 10px;
@extend .center-flex;
}
.name{
font-size: 2.3em;
font-weight: bolder;
margin-right: 10px;
margin-bottom: 13px;
color:#FFF;
}

View File

@@ -1,8 +1,7 @@
import { ActionIcon, Badge, Divider, Grid, Menu, Space, Title, Tooltip } from '@mantine/core';
import { ActionIcon, Badge, Box, Divider, Grid, Menu, Space, Title, Tooltip } from '@mantine/core';
import { useState } from 'react';
import { FaPause, FaPlay, FaStop } from 'react-icons/fa';
import { MdOutlineArrowForwardIos } from "react-icons/md"
import style from "./ServiceRow.module.scss";
import YesNoModal from '../../YesNoModal';
import { errorNotify, isMediumScreen, okNotify } from '../../../js/utils';
import { BsArrowRepeat, BsTrashFill } from 'react-icons/bs';
@@ -101,34 +100,34 @@ function ServiceRow({ service, onClick }:{ service:Service, onClick?:()=>void })
}
return <>
<Grid className={style.row} justify="flex-end" style={{width:"100%"}}>
<Grid.Col md={4} xs={12}>
<div className={isMedium?"center-flex-row":"center-flex"}>
<div className="center-flex"><Title className={style.name}>{service.name}</Title> <Badge size="xl" gradient={{ from: 'indigo', to: 'cyan' }} variant="gradient">:{service.public_port}</Badge></div>
<Grid className="firegex__servicerow__row" justify="flex-end" style={{width:"100%"}}>
<Grid.Col span={{ md:4, xs: 12 }}>
<Box className={isMedium?"center-flex-row":"center-flex"}>
<Box className="center-flex"><Title className="firegex__servicerow__name">{service.name}</Title> <Badge size="xl" gradient={{ from: 'indigo', to: 'cyan' }} variant="gradient">:{service.public_port}</Badge></Box>
<Badge color={status_color} size="lg" radius="md">{service.internal_port} {"->"} {service.public_port}</Badge>
</div>
</Box>
{!isMedium?<Space h="xl" />:null}
</Grid.Col>
<Grid.Col className="center-flex" md={8} xs={12}>
{!isMedium?<div className='flex-spacer' />:<><Space w="xl" /><Space w="xl" /></>}
<div className="center-flex-row">
<Grid.Col className="center-flex" span={{ md:8, xs: 12 }}>
{!isMedium?<Box className='flex-spacer' />:<><Space w="xl" /><Space w="xl" /></>}
<Box className="center-flex-row">
<Badge style={{marginBottom:"20px"}} color={status_color} radius="sm" size="lg" variant="filled">Status: <u>{service.status}</u></Badge>
<Badge style={{marginBottom:"8px"}}color="violet" radius="sm" size="md" variant="filled">Regex: {service.n_regex}</Badge>
<Badge color="yellow" radius="sm" size="md" variant="filled">Connections Blocked: {service.n_packets}</Badge>
</div>
{isMedium?<div className='flex-spacer' />:<><Space w="xl" /><Space w="xl" /></>}
<div className="center-flex">
</Box>
{isMedium?<Box className='flex-spacer' />:<><Space w="xl" /><Space w="xl" /></>}
<Box className="center-flex">
<MenuDropDownWithButton>
<Menu.Label><b>Rename service</b></Menu.Label>
<Menu.Item icon={<BiRename size={18} />} onClick={()=>setRenameModal(true)}>Change service name</Menu.Item>
<Menu.Item leftSection={<BiRename size={18} />} onClick={()=>setRenameModal(true)}>Change service name</Menu.Item>
<Divider />
<Menu.Label><b>Change ports</b></Menu.Label>
<Menu.Item icon={<TbNumbers size={18} />} onClick={()=>setChoosePortModal(true)}>Change port</Menu.Item>
<Menu.Item icon={<BsArrowRepeat size={18} />} onClick={()=>setChangePortModal(true)}>Regen proxy port</Menu.Item>
<Menu.Item leftSection={<TbNumbers size={18} />} onClick={()=>setChoosePortModal(true)}>Change port</Menu.Item>
<Menu.Item leftSection={<BsArrowRepeat size={18} />} onClick={()=>setChangePortModal(true)}>Regen proxy port</Menu.Item>
<Divider />
<Menu.Label><b>Danger zone</b></Menu.Label>
<Menu.Item color="red" icon={<BsTrashFill size={18} />} onClick={()=>setDeleteModal(true)}>Delete Service</Menu.Item>
<Menu.Item color="red" leftSection={<BsTrashFill size={18} />} onClick={()=>setDeleteModal(true)}>Delete Service</Menu.Item>
</MenuDropDownWithButton>
<Space w="md"/>
{["pause","wait"].includes(service.status)?
@@ -158,12 +157,12 @@ function ServiceRow({ service, onClick }:{ service:Service, onClick?:()=>void })
<FaPlay size="20px" />
</ActionIcon>
</Tooltip>
</div>
</Box>
<Space w="xl" /><Space w="xl" />
{onClick?<div>
{onClick?<Box>
<MdOutlineArrowForwardIos onClick={onClick} style={{cursor:"pointer"}} size={45} />
<Space w="xl" />
</div>:null}
</Box>:null}
{!isMedium?<><Space w="xl" /><Space w="xl" /></>:null}
</Grid.Col>

View File

@@ -1,25 +0,0 @@
@use "../../vars" as *;
.box{
padding:30px;
margin:5px;
}
.outer_regex_text{
border-radius: 8px;
overflow: hidden;
margin: 6px;
}
.regex_text{
padding: 10px;
background-color: $third_color;
overflow-x: hidden;
border-radius: 8px;
}
.regex_text:hover{
overflow-x: auto;
opacity: 0.8;
}

View File

@@ -2,7 +2,6 @@ import { Grid, Text, Title, Badge, Space, ActionIcon, Tooltip, Box } from '@mant
import { useState } from 'react';
import { RegexFilter } from '../../js/models';
import { b64decode, errorNotify, getapiobject, okNotify } from '../../js/utils';
import style from "./index.module.scss";
import { BsTrashFill } from "react-icons/bs"
import YesNoModal from '../YesNoModal';
import FilterTypeSelector from '../FilterTypeSelector';
@@ -43,14 +42,14 @@ function RegexView({ regexInfo }:{ regexInfo:RegexFilter }) {
}).catch( err => errorNotify(`Regex ${regex_expr} ${regexInfo.active?"deactivation":"activation"} failed!`,`Error: ${err}`))
}
return <div className={style.box}>
return <Box className="firegex__regexview__box">
<Grid>
<Grid.Col span={2} className="center-flex">
<Title order={4}>Regex:</Title>
</Grid.Col>
<Grid.Col span={8}>
<Box className={style.outer_regex_text}>
<Text className={style.regex_text} onClick={()=>{
<Box className="firegex__regexview__outer_regex_text">
<Text className="firegex__regexview__regex_text" onClick={()=>{
clipboard.copy(regex_expr)
okNotify("Regex copied to clipboard!",`The regex '${regex_expr}' has been copied to the clipboard!`)
}}>{regex_expr}</Text>
@@ -74,7 +73,7 @@ function RegexView({ regexInfo }:{ regexInfo:RegexFilter }) {
</Grid.Col>
<Grid.Col className='center-flex' span={12}>
<div className='center-flex-row'>
<Box className='center-flex-row'>
<FilterTypeSelector
size="md"
color="gray"
@@ -82,23 +81,23 @@ function RegexView({ regexInfo }:{ regexInfo:RegexFilter }) {
value={regexInfo.is_blacklist?"blacklist":"whitelist"}
/>
<Space h="md" />
<div className='center-flex'>
<Box className='center-flex'>
<Badge size="md" color="cyan" variant="filled">Service: {regexInfo.service_id}</Badge>
<Space w="xs" />
<Badge size="md" color={regexInfo.active?"lime":"red"} variant="filled">{regexInfo.active?"ACTIVE":"DISABLED"}</Badge>
<Space w="xs" />
<Badge size="md" color="gray" variant="filled">ID: {regexInfo.id}</Badge>
</div>
</div>
<div className='flex-spacer' />
<div className='center-flex-row'>
</Box>
</Box>
<Box className='flex-spacer' />
<Box className='center-flex-row'>
<Badge size="md" color={regexInfo.is_case_sensitive?"grape":"pink"} variant="filled">Case: {regexInfo.is_case_sensitive?"SENSIIVE":"INSENSITIVE"}</Badge>
<Space h="xs" />
<Badge size="md" color="yellow" variant="filled">Packets filtered: {regexInfo.n_packets}</Badge>
<Space h="xs" />
<Badge size="md" color="blue" variant="filled">Mode: {mode_string}</Badge>
</div>
</Box>
</Grid.Col>
</Grid>
<YesNoModal
@@ -109,7 +108,7 @@ function RegexView({ regexInfo }:{ regexInfo:RegexFilter }) {
opened={deleteModal}
/>
</div>
</Box>
}
export default RegexView;

View File

@@ -5,7 +5,7 @@ function YesNoModal( { title, description, action, onClose, opened}:{ title:stri
return <Modal size="xl" title={title} opened={opened} onClose={onClose} centered>
{description}
<Group position="right" mt="md">
<Group align="right" mt="md">
<Button onClick={()=>{
onClose()
action()