From ec3bd84aaf532600c0091428188fc97162ad36a9 Mon Sep 17 00:00:00 2001 From: Domingo Dirutigliano Date: Wed, 12 Feb 2025 22:24:59 +0100 Subject: [PATCH] Frontend re-styling --- README.md | 2 +- frontend/bun.lock | 14 +- frontend/package.json | 12 +- .../src/components/NFRegex/AddNewService.tsx | 12 +- .../NFRegex/ServiceRow/RenameForm.tsx | 12 +- .../components/NFRegex/ServiceRow/index.tsx | 60 +++---- .../components/PortHijack/AddNewService.tsx | 12 +- .../ServiceRow/ChangeDestination.tsx | 11 +- .../PortHijack/ServiceRow/RenameForm.tsx | 12 +- .../PortHijack/ServiceRow/index.tsx | 56 +++--- frontend/src/components/RegexView/index.tsx | 62 +++---- frontend/src/components/YesNoModal.tsx | 2 +- frontend/src/index.css | 72 ++++++-- frontend/src/pages/NFRegex/ServiceDetails.tsx | 161 +++++++++++++++++- 14 files changed, 330 insertions(+), 170 deletions(-) diff --git a/README.md b/README.md index aa4bc3a..1e4e8b5 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ This means that firegex is projected to avoid any possibility to have the servic Initiially the project was based only on regex filters, and also now the main function uses regexes, but firegex have and will have also other filtering tools. # Credits -- Copyright (c) 2022 Pwnzer0tt1 +- Copyright (c) 2022-2025 Pwnzer0tt1 ## Star History diff --git a/frontend/bun.lock b/frontend/bun.lock index 01d62fd..526f399 100644 --- a/frontend/bun.lock +++ b/frontend/bun.lock @@ -141,17 +141,17 @@ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], - "@mantine/core": ["@mantine/core@7.16.2", "", { "dependencies": { "@floating-ui/react": "^0.26.28", "clsx": "^2.1.1", "react-number-format": "^5.4.3", "react-remove-scroll": "^2.6.2", "react-textarea-autosize": "8.5.6", "type-fest": "^4.27.0" }, "peerDependencies": { "@mantine/hooks": "7.16.2", "react": "^18.x || ^19.x", "react-dom": "^18.x || ^19.x" } }, "sha512-6dwFz+8HrOqFan7GezgpoWyZSCxedh10S8iILGVsc3GXiD4gzo+3VZndZKccktkYZ3GVC9E3cCS3SxbiyKSAVw=="], + "@mantine/core": ["@mantine/core@7.16.3", "", { "dependencies": { "@floating-ui/react": "^0.26.28", "clsx": "^2.1.1", "react-number-format": "^5.4.3", "react-remove-scroll": "^2.6.2", "react-textarea-autosize": "8.5.6", "type-fest": "^4.27.0" }, "peerDependencies": { "@mantine/hooks": "7.16.3", "react": "^18.x || ^19.x", "react-dom": "^18.x || ^19.x" } }, "sha512-cxhIpfd2i0Zmk9TKdejYAoIvWouMGhzK3OOX+VRViZ5HEjnTQCGl2h3db56ThqB6NfVPCno6BPbt5lwekTtmuQ=="], - "@mantine/form": ["@mantine/form@7.16.2", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "klona": "^2.0.6" }, "peerDependencies": { "react": "^18.x || ^19.x" } }, "sha512-JZkLbZ7xWAZndPrxObkf10gjHj57x8yvI/vobjDhfWN3zFPTSWmSSF6yBE1FpITseOs3oR03hlkqG6EclK6g+g=="], + "@mantine/form": ["@mantine/form@7.16.3", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "klona": "^2.0.6" }, "peerDependencies": { "react": "^18.x || ^19.x" } }, "sha512-GqomUG2Ri5adxYsTU1S5IhKRPcqTG5JkPvMERns8PQAcUz/lvzsnk3wY1v4K5CEbCAdpimle4bSsZTM9g697vg=="], - "@mantine/hooks": ["@mantine/hooks@7.16.2", "", { "peerDependencies": { "react": "^18.x || ^19.x" } }, "sha512-ZFHQhDi9T+r6VR5NEeE47gigPPIAHVIKDOCWsCsbCqHc3yz5l8kiO2RdfUmsTKV2KD/AiXnAw4b6pjQEP58GOg=="], + "@mantine/hooks": ["@mantine/hooks@7.16.3", "", { "peerDependencies": { "react": "^18.x || ^19.x" } }, "sha512-B94FBWk5Sc81tAjV+B3dGh/gKzfqzpzVC/KHyBRWOOyJRqeeRbI/FAaJo4zwppyQo1POSl5ArdyjtDRrRIj2SQ=="], - "@mantine/modals": ["@mantine/modals@7.16.2", "", { "peerDependencies": { "@mantine/core": "7.16.2", "@mantine/hooks": "7.16.2", "react": "^18.x || ^19.x", "react-dom": "^18.x || ^19.x" } }, "sha512-REwAV53Fcz021EE3zLyYdkdFlfG+b24y279Y+eA1jCCH9VMLivXL+gacrox4BcpzREsic9nGVInSNv3VJwPlAQ=="], + "@mantine/modals": ["@mantine/modals@7.16.3", "", { "peerDependencies": { "@mantine/core": "7.16.3", "@mantine/hooks": "7.16.3", "react": "^18.x || ^19.x", "react-dom": "^18.x || ^19.x" } }, "sha512-BJuDzRugK6xLbuFTTo8NLJumVvVmSYsNVcEtmlXOWTE3NkDGktBXGKo8V1B0XfJ9/d/rZw7HCE0p4i76MtA+bQ=="], - "@mantine/notifications": ["@mantine/notifications@7.16.2", "", { "dependencies": { "@mantine/store": "7.16.2", "react-transition-group": "4.4.5" }, "peerDependencies": { "@mantine/core": "7.16.2", "@mantine/hooks": "7.16.2", "react": "^18.x || ^19.x", "react-dom": "^18.x || ^19.x" } }, "sha512-U342XWiiRI1NvOlLsI6PH/pSNe0rxNClJ2w5orvjOMXvaAfDe52mhnzRmtzRxYENp06++3b/G7MjPH+466rF9Q=="], + "@mantine/notifications": ["@mantine/notifications@7.16.3", "", { "dependencies": { "@mantine/store": "7.16.3", "react-transition-group": "4.4.5" }, "peerDependencies": { "@mantine/core": "7.16.3", "@mantine/hooks": "7.16.3", "react": "^18.x || ^19.x", "react-dom": "^18.x || ^19.x" } }, "sha512-wtEME9kSYfXWYmAmQUZ8c+rwNmhdWRBaW1mlPdQsPkzMqkv4q6yy0IpgwcnuHStSG9EHaQBXazmVxMZJdEAWBQ=="], - "@mantine/store": ["@mantine/store@7.16.2", "", { "peerDependencies": { "react": "^18.x || ^19.x" } }, "sha512-9dEGLosrYSePlAwhfx3CxTLcWu2M98TtuYnelAiHEdNEkyafirvZxNt4paMoFXLKR1XPm5wdjDK7bdTaE0t7Og=="], + "@mantine/store": ["@mantine/store@7.16.3", "", { "peerDependencies": { "react": "^18.x || ^19.x" } }, "sha512-6M2M5+0BrRtnVv+PUmr04tY1RjPqyapaHplo90uK1NMhP/1EIqrwTL9KoEtCNCJ5pog1AQtu0bj0QPbqUvxwLg=="], "@rollup/pluginutils": ["@rollup/pluginutils@5.1.4", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ=="], @@ -205,7 +205,7 @@ "@types/jest": ["@types/jest@27.5.2", "", { "dependencies": { "jest-matcher-utils": "^27.0.0", "pretty-format": "^27.0.0" } }, "sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA=="], - "@types/node": ["@types/node@20.17.16", "", { "dependencies": { "undici-types": "~6.19.2" } }, "sha512-vOTpLduLkZXePLxHiHsBLp98mHGnl8RptV4YAO3HfKO5UHjDvySGbxKtpYfy8Sx5+WKcgc45qNreJJRVM3L6mw=="], + "@types/node": ["@types/node@20.17.17", "", { "dependencies": { "undici-types": "~6.19.2" } }, "sha512-/WndGO4kIfMicEQLTi/mDANUu/iVUhT7KboZPdEqqHQ4aTS+3qT3U5gIqWDFV+XouorjfgGqvKILJeHhuQgFYg=="], "@types/prop-types": ["@types/prop-types@15.7.14", "", {}, "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ=="], diff --git a/frontend/package.json b/frontend/package.json index 8a0cba7..071420d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -5,14 +5,14 @@ "private": true, "dependencies": { "@hello-pangea/dnd": "^16.6.0", - "@mantine/core": "^7.16.2", - "@mantine/form": "^7.16.2", - "@mantine/hooks": "^7.16.2", - "@mantine/modals": "^7.16.2", - "@mantine/notifications": "^7.16.2", + "@mantine/core": "^7.16.3", + "@mantine/form": "^7.16.3", + "@mantine/hooks": "^7.16.3", + "@mantine/modals": "^7.16.3", + "@mantine/notifications": "^7.16.3", "@tanstack/react-query": "^4.36.1", "@types/jest": "^27.5.2", - "@types/node": "^20.17.16", + "@types/node": "^20.17.17", "@types/react": "^18.3.18", "@types/react-dom": "^18.3.5", "buffer": "^6.0.3", diff --git a/frontend/src/components/NFRegex/AddNewService.tsx b/frontend/src/components/NFRegex/AddNewService.tsx index f0dbc17..f88f7a9 100644 --- a/frontend/src/components/NFRegex/AddNewService.tsx +++ b/frontend/src/components/NFRegex/AddNewService.tsx @@ -86,16 +86,16 @@ function AddNewService({ opened, onClose }:{ opened:boolean, onClose:()=>void }) /> - + - - {error?<> - } color="red" onClose={()=>{setError(null)}}> - Error: {error} - :null} + + } color="red" onClose={()=>{setError(null)}}> + Error: {error} + + :null} diff --git a/frontend/src/components/NFRegex/ServiceRow/RenameForm.tsx b/frontend/src/components/NFRegex/ServiceRow/RenameForm.tsx index 412be2c..a643bec 100644 --- a/frontend/src/components/NFRegex/ServiceRow/RenameForm.tsx +++ b/frontend/src/components/NFRegex/ServiceRow/RenameForm.tsx @@ -49,16 +49,16 @@ function RenameForm({ opened, onClose, service }:{ opened:boolean, onClose:()=>v placeholder="Awesome Service Name!" {...form.getInputProps('name')} /> - + - - {error?<> - } color="red" onClose={()=>{setError(null)}}> - Error: {error} - :null} + + } color="red" onClose={()=>{setError(null)}}> + Error: {error} + + :null} diff --git a/frontend/src/components/NFRegex/ServiceRow/index.tsx b/frontend/src/components/NFRegex/ServiceRow/index.tsx index 0ec16a2..d8167bc 100644 --- a/frontend/src/components/NFRegex/ServiceRow/index.tsx +++ b/frontend/src/components/NFRegex/ServiceRow/index.tsx @@ -2,7 +2,7 @@ import { ActionIcon, Badge, Box, Divider, Grid, Menu, Space, Title, Tooltip } fr import { useState } from 'react'; import { FaPlay, FaStop } from 'react-icons/fa'; import { nfregex, Service, serviceQueryKey } from '../utils'; -import { MdOutlineArrowForwardIos } from "react-icons/md" +import { MdDoubleArrow, MdOutlineArrowForwardIos } from "react-icons/md" import YesNoModal from '../../YesNoModal'; import { errorNotify, isMediumScreen, okNotify, regex_ipv4 } from '../../../js/utils'; import { BsTrashFill } from 'react-icons/bs'; @@ -10,8 +10,10 @@ import { BiRename } from 'react-icons/bi' import RenameForm from './RenameForm'; import { MenuDropDownWithButton } from '../../MainLayout'; import { useQueryClient } from '@tanstack/react-query'; +import { FaFilter } from "react-icons/fa"; +import { VscRegex } from "react-icons/vsc"; -function ServiceRow({ service, onClick }:{ service:Service, onClick?:()=>void }) { +export default function ServiceRow({ service, onClick }:{ service:Service, onClick?:()=>void }) { let status_color = "gray"; switch(service.status){ @@ -72,36 +74,34 @@ function ServiceRow({ service, onClick }:{ service:Service, onClick?:()=>void }) return <> - - - - - + <Box className="firegex__nfregex__row" style={{width:"100%", flexDirection: isMedium?"row":"column"}}> + <Box> + <Box className="center-flex" style={{ justifyContent: "flex-start" }}> + <MdDoubleArrow size={30} style={{color: "white"}}/> + <Title className="firegex__nfregex__name" ml="xs"> {service.name} - - Status: {service.status} - - :{service.port} - - - {isMedium?null:} - + + {service.status} + + :{service.port} + + + {isMedium?null:} + - - - - - + - Connections Blocked: {service.n_packets} - - Regex: {service.n_regex} - {service.ip_int} on {service.proto} + + + {service.n_packets} + + {service.n_regex} + - {isMedium?:} + {isMedium?:} Rename service @@ -129,14 +129,12 @@ function ServiceRow({ service, onClick }:{ service:Service, onClick?:()=>void }) {isMedium?:} - {onClick? + {onClick? :null} - {isMedium?:null} - - - + + void }) /> } - -export default ServiceRow; diff --git a/frontend/src/components/PortHijack/AddNewService.tsx b/frontend/src/components/PortHijack/AddNewService.tsx index b685672..44622be 100644 --- a/frontend/src/components/PortHijack/AddNewService.tsx +++ b/frontend/src/components/PortHijack/AddNewService.tsx @@ -94,16 +94,16 @@ function AddNewService({ opened, onClose }:{ opened:boolean, onClose:()=>void }) /> - + - - {error?<> - } color="red" onClose={()=>{setError(null)}}> - Error: {error} - :null} + + } color="red" onClose={()=>{setError(null)}}> + Error: {error} + + :null} diff --git a/frontend/src/components/PortHijack/ServiceRow/ChangeDestination.tsx b/frontend/src/components/PortHijack/ServiceRow/ChangeDestination.tsx index e4f2bef..8d135e9 100644 --- a/frontend/src/components/PortHijack/ServiceRow/ChangeDestination.tsx +++ b/frontend/src/components/PortHijack/ServiceRow/ChangeDestination.tsx @@ -53,15 +53,16 @@ function ChangeDestination({ opened, onClose, service }:{ opened:boolean, onClos
- + - {error?<> - } color="red" onClose={()=>{setError(null)}}> - Error: {error} - :null} + + } color="red" onClose={()=>{setError(null)}}> + Error: {error} + + :null} diff --git a/frontend/src/components/PortHijack/ServiceRow/RenameForm.tsx b/frontend/src/components/PortHijack/ServiceRow/RenameForm.tsx index 84f9fba..4d75c42 100644 --- a/frontend/src/components/PortHijack/ServiceRow/RenameForm.tsx +++ b/frontend/src/components/PortHijack/ServiceRow/RenameForm.tsx @@ -49,16 +49,16 @@ function RenameForm({ opened, onClose, service }:{ opened:boolean, onClose:()=>v placeholder="Awesome Service Name!" {...form.getInputProps('name')} /> - + - - {error?<> - } color="red" onClose={()=>{setError(null)}}> - Error: {error} - :null} + + } color="red" onClose={()=>{setError(null)}}> + Error: {error} + + :null} diff --git a/frontend/src/components/PortHijack/ServiceRow/index.tsx b/frontend/src/components/PortHijack/ServiceRow/index.tsx index d481f75..2f4a136 100644 --- a/frontend/src/components/PortHijack/ServiceRow/index.tsx +++ b/frontend/src/components/PortHijack/ServiceRow/index.tsx @@ -8,11 +8,11 @@ import { BsArrowRepeat, BsTrashFill } from 'react-icons/bs'; import { BiRename } from 'react-icons/bi' import RenameForm from './RenameForm'; import ChangeDestination from './ChangeDestination'; -import PortInput from '../../PortInput'; import { useForm } from '@mantine/form'; import { MenuDropDownWithButton } from '../../MainLayout'; +import { MdDoubleArrow } from "react-icons/md"; -function ServiceRow({ service }:{ service:Service }) { +export default function ServiceRow({ service }:{ service:Service }) { let status_color = service.active ? "teal": "red" @@ -72,40 +72,36 @@ function ServiceRow({ service }:{ service:Service }) { return <> - - - - + <Box className="firegex__nfregex__row" style={{width:"100%", flexDirection: isMedium?"row":"column"}}> + <Box> + <Box className="center-flex" style={{ justifyContent: "flex-start" }}> + <MdDoubleArrow size={30} style={{color: "white"}}/> + <Title className="firegex__nfregex__name" ml="xs"> {service.name} - - Status: {service.active?"ENABLED":"DISABLED"} - - {service.proto} - - - {isMedium?null:} - + + {service.active?"ENABLED":"DISABLED"} + + {service.proto} + + + {isMedium?null:} + - - - - - - + - - FROM {service.ip_src} : {service.public_port} + + FROM {service.ip_src} :{service.public_port} - + - TO {service.ip_dst} : service.proxy_port + TO {service.ip_dst} :{service.proxy_port} - {isMedium?:} + {isMedium?:} Rename service @@ -134,14 +130,10 @@ function ServiceRow({ service }:{ service:Service }) { - - {isMedium?:null} - - - + + - } - -export default ServiceRow; diff --git a/frontend/src/components/RegexView/index.tsx b/frontend/src/components/RegexView/index.tsx index 20b9d18..e5b0821 100644 --- a/frontend/src/components/RegexView/index.tsx +++ b/frontend/src/components/RegexView/index.tsx @@ -1,18 +1,19 @@ -import { Grid, Text, Title, Badge, Space, ActionIcon, Tooltip, Box } from '@mantine/core'; +import { Text, Title, Badge, Space, ActionIcon, Tooltip, Box } from '@mantine/core'; import { useState } from 'react'; import { RegexFilter } from '../../js/models'; -import { b64decode, errorNotify, getapiobject, okNotify } from '../../js/utils'; +import { b64decode, errorNotify, getapiobject, isMediumScreen, okNotify } from '../../js/utils'; import { BsTrashFill } from "react-icons/bs" import YesNoModal from '../YesNoModal'; import { FaPause, FaPlay } from 'react-icons/fa'; import { useClipboard } from '@mantine/hooks'; - +import { FaFilter } from "react-icons/fa"; +import { VscRegex } from "react-icons/vsc"; function RegexView({ regexInfo }:{ regexInfo:RegexFilter }) { const mode_string = regexInfo.mode === "C"? "C -> S": regexInfo.mode === "S"? "S -> C": - regexInfo.mode === "B"? "S <-> C": "🤔" + regexInfo.mode === "B"? "C <-> S": "🤔" let regex_expr = b64decode(regexInfo.regex); @@ -20,6 +21,7 @@ function RegexView({ regexInfo }:{ regexInfo:RegexFilter }) { const [deleteTooltipOpened, setDeleteTooltipOpened] = useState(false); const [statusTooltipOpened, setStatusTooltipOpened] = useState(false); const clipboard = useClipboard({ timeout: 500 }); + const isMedium = isMediumScreen(); const deleteRegex = () => { getapiobject().regexdelete(regexInfo.id).then(res => { @@ -42,57 +44,39 @@ function RegexView({ regexInfo }:{ regexInfo:RegexFilter }) { } return - - - Regex: - - + + { clipboard.copy(regex_expr) okNotify("Regex copied to clipboard!",`The regex '${regex_expr}' has been copied to the clipboard!`) }}>{regex_expr} - - setStatusTooltipOpened(false)} onBlur={() => setStatusTooltipOpened(false)} - onMouseEnter={() => setStatusTooltipOpened(true)} onMouseLeave={() => setStatusTooltipOpened(false)} + onFocus={() => setStatusTooltipOpened(false)} onBlur={() => setStatusTooltipOpened(false)} + onMouseEnter={() => setStatusTooltipOpened(true)} onMouseLeave={() => setStatusTooltipOpened(false)} >{regexInfo.active?:} setDeleteModal(true)} size="xl" radius="md" variant="filled" - onFocus={() => setDeleteTooltipOpened(false)} onBlur={() => setDeleteTooltipOpened(false)} - onMouseEnter={() => setDeleteTooltipOpened(true)} onMouseLeave={() => setDeleteTooltipOpened(false)} + onFocus={() => setDeleteTooltipOpened(false)} onBlur={() => setDeleteTooltipOpened(false)} + onMouseEnter={() => setDeleteTooltipOpened(true)} onMouseLeave={() => setDeleteTooltipOpened(false)} > - - - - - - - Service: {regexInfo.service_id} - - {regexInfo.active?"ACTIVE":"DISABLED"} - - ID: {regexInfo.id} - - - - - - Case: {regexInfo.is_case_sensitive?"SENSIIVE":"INSENSITIVE"} - - Packets filtered: {regexInfo.n_packets} - - Mode: {mode_string} - - - + + + {regexInfo.n_packets} + + {regexInfo.active?"ACTIVE":"DISABLED"} + + {regexInfo.is_case_sensitive?"Strict":"Loose"} + + {mode_string} + + {description} - +