optional nfqueue fail-open option
This commit is contained in:
@@ -237,17 +237,15 @@ class NfQueue {
|
||||
nlh = nfq_nlmsg_put(queue_msg_buffer, NFQNL_MSG_CONFIG, queue_num);
|
||||
nfq_nlmsg_cfg_put_params(nlh, NFQNL_COPY_PACKET, 0xffff);
|
||||
|
||||
#ifdef NFQUEUE_FAIL_OPEN
|
||||
char * enable_fail_open = getenv("FIREGEX_NFQUEUE_FAIL_OPEN");
|
||||
|
||||
if (strcmp(enable_fail_open, "1") == 0){
|
||||
mnl_attr_put_u32(nlh, NFQA_CFG_FLAGS, htonl(NFQA_CFG_F_GSO|NFQA_CFG_F_FAIL_OPEN));
|
||||
mnl_attr_put_u32(nlh, NFQA_CFG_MASK, htonl(NFQA_CFG_F_GSO|NFQA_CFG_F_FAIL_OPEN));
|
||||
|
||||
#else
|
||||
|
||||
}else{
|
||||
mnl_attr_put_u32(nlh, NFQA_CFG_FLAGS, htonl(NFQA_CFG_F_GSO));
|
||||
mnl_attr_put_u32(nlh, NFQA_CFG_MASK, htonl(NFQA_CFG_F_GSO));
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
|
||||
_clear();
|
||||
|
||||
@@ -9,10 +9,7 @@ using namespace Firegex::Regex;
|
||||
using Firegex::NfQueue::MultiThreadQueue;
|
||||
|
||||
/*
|
||||
|
||||
Compile options:
|
||||
NFQUEUE_FAIL_OPEN - enable fail-open option of nfqueueß
|
||||
---
|
||||
USE_PIPES_FOR_BLOKING_QUEUE - use pipes instead of conditional variable, queue and mutex for blocking queue
|
||||
*/
|
||||
|
||||
@@ -64,13 +61,13 @@ int main(int argc, char *argv[]){
|
||||
stream_mode = false;
|
||||
}
|
||||
|
||||
bool fail_open = strcmp(getenv("FIREGEX_NFQUEUE_FAIL_OPEN"), "1") == 0;
|
||||
|
||||
regex_config.reset(new RegexRules(stream_mode));
|
||||
|
||||
|
||||
MultiThreadQueue<RegexNfQueue> queue_manager(n_of_threads);
|
||||
|
||||
osyncstream(cout) << "QUEUE " << queue_manager.queue_num() << endl;
|
||||
cerr << "[info] [main] Queue: " << queue_manager.queue_num() << " threads assigned: " << n_of_threads << " stream mode: " << stream_mode << endl;
|
||||
cerr << "[info] [main] Queue: " << queue_manager.queue_num() << " threads assigned: " << n_of_threads << " stream mode: " << stream_mode << " fail open: " << fail_open << endl;
|
||||
|
||||
thread qthr([&](){
|
||||
queue_manager.start();
|
||||
|
||||
@@ -88,7 +88,11 @@ class FiregexInterceptor:
|
||||
self.process = await asyncio.create_subprocess_exec(
|
||||
proxy_binary_path,
|
||||
stdout=asyncio.subprocess.PIPE, stdin=asyncio.subprocess.PIPE,
|
||||
env={"MATCH_MODE": "stream" if self.srv.proto == "tcp" else "block", "NTHREADS": os.getenv("NTHREADS","1")},
|
||||
env={
|
||||
"MATCH_MODE": "stream" if self.srv.proto == "tcp" else "block",
|
||||
"NTHREADS": os.getenv("NTHREADS","1"),
|
||||
"FIREGEX_NFQUEUE_FAIL_OPEN": "1" if self.srv.fail_open else "0",
|
||||
},
|
||||
)
|
||||
line_fut = self.process.stdout.readuntil()
|
||||
try:
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import base64
|
||||
|
||||
class Service:
|
||||
def __init__(self, service_id: str, status: str, port: int, name: str, proto: str, ip_int: str, **other):
|
||||
def __init__(self, service_id: str, status: str, port: int, name: str, proto: str, ip_int: str, fail_open: bool, **other):
|
||||
self.id = service_id
|
||||
self.status = status
|
||||
self.port = port
|
||||
self.name = name
|
||||
self.proto = proto
|
||||
self.ip_int = ip_int
|
||||
self.fail_open = fail_open
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, var: dict):
|
||||
|
||||
@@ -19,10 +19,17 @@ class ServiceModel(BaseModel):
|
||||
ip_int: str
|
||||
n_regex: int
|
||||
n_packets: int
|
||||
fail_open: bool
|
||||
|
||||
class RenameForm(BaseModel):
|
||||
name:str
|
||||
|
||||
class SettingsForm(BaseModel):
|
||||
port: PortType|None = None
|
||||
proto: str|None = None
|
||||
ip_int: str|None = None
|
||||
fail_open: bool|None = None
|
||||
|
||||
class RegexModel(BaseModel):
|
||||
regex:str
|
||||
mode:str
|
||||
@@ -44,6 +51,7 @@ class ServiceAddForm(BaseModel):
|
||||
port: PortType
|
||||
proto: str
|
||||
ip_int: str
|
||||
fail_open: bool = False
|
||||
|
||||
class ServiceAddResponse(BaseModel):
|
||||
status:str
|
||||
@@ -59,6 +67,7 @@ db = SQLite('db/nft-regex.db', {
|
||||
'name': 'VARCHAR(100) NOT NULL UNIQUE',
|
||||
'proto': 'VARCHAR(3) NOT NULL CHECK (proto IN ("tcp", "udp"))',
|
||||
'ip_int': 'VARCHAR(100) NOT NULL',
|
||||
'fail_open': 'BOOLEAN NOT NULL CHECK (fail_open IN (0, 1)) DEFAULT 1'
|
||||
},
|
||||
'regexes': {
|
||||
'regex': 'TEXT NOT NULL',
|
||||
@@ -128,6 +137,7 @@ async def get_service_list():
|
||||
s.name name,
|
||||
s.proto proto,
|
||||
s.ip_int ip_int,
|
||||
s.fail_open fail_open,
|
||||
COUNT(r.regex_id) n_regex,
|
||||
COALESCE(SUM(r.blocked_packets),0) n_packets
|
||||
FROM services s LEFT JOIN regexes r ON s.service_id = r.service_id
|
||||
@@ -145,6 +155,7 @@ async def get_service_by_id(service_id: str):
|
||||
s.name name,
|
||||
s.proto proto,
|
||||
s.ip_int ip_int,
|
||||
s.fail_open fail_open,
|
||||
COUNT(r.regex_id) n_regex,
|
||||
COALESCE(SUM(r.blocked_packets),0) n_packets
|
||||
FROM services s LEFT JOIN regexes r ON s.service_id = r.service_id
|
||||
@@ -190,6 +201,45 @@ async def service_rename(service_id: str, form: RenameForm):
|
||||
await refresh_frontend()
|
||||
return {'status': 'ok'}
|
||||
|
||||
@app.put('/services/{service_id}/settings', response_model=StatusMessageModel)
|
||||
async def service_settings(service_id: str, form: SettingsForm):
|
||||
"""Request to change the settings of a specific service (will cause a restart)"""
|
||||
|
||||
if form.proto is not None and form.proto not in ["tcp", "udp"]:
|
||||
raise HTTPException(status_code=400, detail="Invalid protocol")
|
||||
|
||||
if form.port is not None and (form.port < 1 or form.port > 65535):
|
||||
raise HTTPException(status_code=400, detail="Invalid port")
|
||||
|
||||
if form.ip_int is not None:
|
||||
try:
|
||||
form.ip_int = ip_parse(form.ip_int)
|
||||
except ValueError:
|
||||
raise HTTPException(status_code=400, detail="Invalid address")
|
||||
|
||||
keys = []
|
||||
values = []
|
||||
|
||||
for key, value in form.model_dump(exclude_none=True).items():
|
||||
keys.append(key)
|
||||
values.append(value)
|
||||
|
||||
if len(keys) == 0:
|
||||
raise HTTPException(status_code=400, detail="No settings to change provided")
|
||||
|
||||
try:
|
||||
db.query(f'UPDATE services SET {", ".join([f"{key}=?" for key in keys])} WHERE service_id = ?;', *values, service_id)
|
||||
except sqlite3.IntegrityError:
|
||||
raise HTTPException(status_code=400, detail="A service with these settings already exists")
|
||||
|
||||
old_status = firewall.get(service_id).status
|
||||
await firewall.remove(service_id)
|
||||
await firewall.reload()
|
||||
await firewall.get(service_id).next(old_status)
|
||||
|
||||
await refresh_frontend()
|
||||
return {'status': 'ok'}
|
||||
|
||||
@app.get('/services/{service_id}/regexes', response_model=list[RegexModel])
|
||||
async def get_service_regexe_list(service_id: str):
|
||||
"""Get the list of the regexes of a service"""
|
||||
@@ -275,8 +325,8 @@ async def add_new_service(form: ServiceAddForm):
|
||||
srv_id = None
|
||||
try:
|
||||
srv_id = gen_service_id()
|
||||
db.query("INSERT INTO services (service_id ,name, port, status, proto, ip_int) VALUES (?, ?, ?, ?, ?, ?)",
|
||||
srv_id, refactor_name(form.name), form.port, STATUS.STOP, form.proto, form.ip_int)
|
||||
db.query("INSERT INTO services (service_id ,name, port, status, proto, ip_int, fail_open) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
srv_id, refactor_name(form.name), form.port, STATUS.STOP, form.proto, form.ip_int, form.fail_open)
|
||||
except sqlite3.IntegrityError:
|
||||
raise HTTPException(status_code=400, detail="This type of service already exists")
|
||||
await firewall.reload()
|
||||
|
||||
139
frontend/src/components/NFRegex/AddEditService.tsx
Normal file
139
frontend/src/components/NFRegex/AddEditService.tsx
Normal file
@@ -0,0 +1,139 @@
|
||||
import { Button, Group, Space, TextInput, Notification, Modal, Switch, SegmentedControl, Box, Tooltip } from '@mantine/core';
|
||||
import { useForm } from '@mantine/form';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { okNotify, regex_ipv4, regex_ipv6 } from '../../js/utils';
|
||||
import { ImCross } from "react-icons/im"
|
||||
import { nfregex, Service } from './utils';
|
||||
import PortAndInterface from '../PortAndInterface';
|
||||
import { IoMdInformationCircleOutline } from "react-icons/io";
|
||||
import { ServiceAddForm as ServiceAddFormOriginal } from './utils';
|
||||
|
||||
type ServiceAddForm = ServiceAddFormOriginal & {autostart: boolean}
|
||||
|
||||
function AddEditService({ opened, onClose, edit }:{ opened:boolean, onClose:()=>void, edit?:Service }) {
|
||||
|
||||
const initialValues = {
|
||||
name: "",
|
||||
port:edit?.port??8080,
|
||||
ip_int:edit?.ip_int??"",
|
||||
proto:edit?.proto??"tcp",
|
||||
fail_open: edit?.fail_open??false,
|
||||
autostart: true
|
||||
}
|
||||
|
||||
const form = useForm({
|
||||
initialValues: initialValues,
|
||||
validate:{
|
||||
name: (value) => edit? null : value !== "" ? null : "Service name is required",
|
||||
port: (value) => (value>0 && value<65536) ? null : "Invalid port",
|
||||
proto: (value) => ["tcp","udp"].includes(value) ? null : "Invalid protocol",
|
||||
ip_int: (value) => (value.match(regex_ipv6) || value.match(regex_ipv4)) ? null : "Invalid IP address",
|
||||
}
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (opened){
|
||||
form.setInitialValues(initialValues)
|
||||
form.reset()
|
||||
}
|
||||
}, [opened])
|
||||
|
||||
const close = () =>{
|
||||
onClose()
|
||||
form.reset()
|
||||
setError(null)
|
||||
}
|
||||
|
||||
const [submitLoading, setSubmitLoading] = useState(false)
|
||||
const [error, setError] = useState<string|null>(null)
|
||||
|
||||
const submitRequest = ({ name, port, autostart, proto, ip_int, fail_open }:ServiceAddForm) =>{
|
||||
setSubmitLoading(true)
|
||||
if (edit){
|
||||
nfregex.settings(edit.service_id, { port, proto, ip_int, fail_open }).then( res => {
|
||||
if (!res){
|
||||
setSubmitLoading(false)
|
||||
close();
|
||||
okNotify(`Service ${name} settings updated`, `Successfully updated settings for service ${name}`)
|
||||
}
|
||||
}).catch( err => {
|
||||
setSubmitLoading(false)
|
||||
setError("Request Failed! [ "+err+" ]")
|
||||
})
|
||||
}else{
|
||||
nfregex.servicesadd({ name, port, proto, ip_int, fail_open }).then( res => {
|
||||
if (res.status === "ok" && res.service_id){
|
||||
setSubmitLoading(false)
|
||||
close();
|
||||
if (autostart) nfregex.servicestart(res.service_id)
|
||||
okNotify(`Service ${name} has been added`, `Successfully added service with port ${port}`)
|
||||
}else{
|
||||
setSubmitLoading(false)
|
||||
setError("Invalid request! [ "+res.status+" ]")
|
||||
}
|
||||
}).catch( err => {
|
||||
setSubmitLoading(false)
|
||||
setError("Request Failed! [ "+err+" ]")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return <Modal size="xl" title={edit?`Editing ${edit.name} service`:"Add a new service"} opened={opened} onClose={close} closeOnClickOutside={false} centered>
|
||||
<form onSubmit={form.onSubmit(submitRequest)}>
|
||||
{!edit?<TextInput
|
||||
label="Service name"
|
||||
placeholder="Challenge 01"
|
||||
{...form.getInputProps('name')}
|
||||
/>:null}
|
||||
<Space h="md" />
|
||||
<PortAndInterface form={form} int_name="ip_int" port_name="port" label={"Public IP Interface and port (ipv4/ipv6 + CIDR allowed)"} />
|
||||
<Space h="md" />
|
||||
|
||||
<Box className='center-flex'>
|
||||
<Box>
|
||||
{!edit?<Switch
|
||||
label="Auto-Start Service"
|
||||
{...form.getInputProps('autostart', { type: 'checkbox' })}
|
||||
/>:null}
|
||||
<Space h="sm" />
|
||||
<Switch
|
||||
label={<Box className='center-flex'>
|
||||
Enable fail-open nfqueue
|
||||
<Space w="xs" />
|
||||
<Tooltip label={<>
|
||||
Firegex use internally nfqueue to handle packets<br />enabling this option will allow packets to pass through the firewall <br /> in case the filtering is too slow or too many traffic is coming<br />
|
||||
</>}>
|
||||
<IoMdInformationCircleOutline size={15} />
|
||||
</Tooltip>
|
||||
</Box>}
|
||||
{...form.getInputProps('fail_open', { type: 'checkbox' })}
|
||||
/>
|
||||
</Box>
|
||||
<Box className="flex-spacer"></Box>
|
||||
<SegmentedControl
|
||||
data={[
|
||||
{ label: 'TCP', value: 'tcp' },
|
||||
{ label: 'UDP', value: 'udp' },
|
||||
]}
|
||||
{...form.getInputProps('proto')}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Group justify='flex-end' mt="md" mb="sm">
|
||||
<Button loading={submitLoading} type="submit" disabled={edit?!form.isDirty():false}>{edit?"Edit Service":"Add Service"}</Button>
|
||||
</Group>
|
||||
|
||||
{error?<>
|
||||
<Space h="md" />
|
||||
<Notification icon={<ImCross size={14} />} color="red" onClose={()=>{setError(null)}}>
|
||||
Error: {error}
|
||||
</Notification><Space h="md" />
|
||||
</>:null}
|
||||
|
||||
</form>
|
||||
</Modal>
|
||||
|
||||
}
|
||||
|
||||
export default AddEditService;
|
||||
@@ -1,105 +0,0 @@
|
||||
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';
|
||||
import { ImCross } from "react-icons/im"
|
||||
import { nfregex } from './utils';
|
||||
import PortAndInterface from '../PortAndInterface';
|
||||
|
||||
type ServiceAddForm = {
|
||||
name:string,
|
||||
port:number,
|
||||
proto:string,
|
||||
ip_int:string,
|
||||
autostart: boolean,
|
||||
}
|
||||
|
||||
function AddNewService({ opened, onClose }:{ opened:boolean, onClose:()=>void }) {
|
||||
|
||||
const form = useForm({
|
||||
initialValues: {
|
||||
name:"",
|
||||
port:8080,
|
||||
ip_int:"",
|
||||
proto:"tcp",
|
||||
autostart: true
|
||||
},
|
||||
validate:{
|
||||
name: (value) => value !== "" ? null : "Service name is required",
|
||||
port: (value) => (value>0 && value<65536) ? null : "Invalid port",
|
||||
proto: (value) => ["tcp","udp"].includes(value) ? null : "Invalid protocol",
|
||||
ip_int: (value) => (value.match(regex_ipv6) || value.match(regex_ipv4)) ? null : "Invalid IP address",
|
||||
}
|
||||
})
|
||||
|
||||
const close = () =>{
|
||||
onClose()
|
||||
form.reset()
|
||||
setError(null)
|
||||
}
|
||||
|
||||
const [submitLoading, setSubmitLoading] = useState(false)
|
||||
const [error, setError] = useState<string|null>(null)
|
||||
|
||||
const submitRequest = ({ name, port, autostart, proto, ip_int }:ServiceAddForm) =>{
|
||||
setSubmitLoading(true)
|
||||
nfregex.servicesadd({name, port, proto, ip_int }).then( res => {
|
||||
if (res.status === "ok" && res.service_id){
|
||||
setSubmitLoading(false)
|
||||
close();
|
||||
if (autostart) nfregex.servicestart(res.service_id)
|
||||
okNotify(`Service ${name} has been added`, `Successfully added service with port ${port}`)
|
||||
}else{
|
||||
setSubmitLoading(false)
|
||||
setError("Invalid request! [ "+res.status+" ]")
|
||||
}
|
||||
}).catch( err => {
|
||||
setSubmitLoading(false)
|
||||
setError("Request Failed! [ "+err+" ]")
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
return <Modal size="xl" title="Add a new service" opened={opened} onClose={close} closeOnClickOutside={false} centered>
|
||||
<form onSubmit={form.onSubmit(submitRequest)}>
|
||||
<TextInput
|
||||
label="Service name"
|
||||
placeholder="Challenge 01"
|
||||
{...form.getInputProps('name')}
|
||||
/>
|
||||
<Space h="md" />
|
||||
<PortAndInterface form={form} int_name="ip_int" port_name="port" label={"Public IP Interface and port (ipv4/ipv6 + CIDR allowed)"} />
|
||||
<Space h="md" />
|
||||
|
||||
<Box className='center-flex'>
|
||||
<Switch
|
||||
label="Auto-Start Service"
|
||||
{...form.getInputProps('autostart', { type: 'checkbox' })}
|
||||
/>
|
||||
<Box className="flex-spacer"></Box>
|
||||
<SegmentedControl
|
||||
data={[
|
||||
{ label: 'TCP', value: 'tcp' },
|
||||
{ label: 'UDP', value: 'udp' },
|
||||
]}
|
||||
{...form.getInputProps('proto')}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Group justify='flex-end' mt="md" mb="sm">
|
||||
<Button loading={submitLoading} type="submit">Add Service</Button>
|
||||
</Group>
|
||||
|
||||
{error?<>
|
||||
<Space h="md" />
|
||||
<Notification icon={<ImCross size={14} />} color="red" onClose={()=>{setError(null)}}>
|
||||
Error: {error}
|
||||
</Notification><Space h="md" />
|
||||
</>:null}
|
||||
|
||||
</form>
|
||||
</Modal>
|
||||
|
||||
}
|
||||
|
||||
export default AddNewService;
|
||||
@@ -12,6 +12,8 @@ import { MenuDropDownWithButton } from '../../MainLayout';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { FaFilter } from "react-icons/fa";
|
||||
import { VscRegex } from "react-icons/vsc";
|
||||
import { IoSettingsSharp } from 'react-icons/io5';
|
||||
import AddEditService from '../AddEditService';
|
||||
|
||||
export default function ServiceRow({ service, onClick }:{ service:Service, onClick?:()=>void }) {
|
||||
|
||||
@@ -26,6 +28,7 @@ export default function ServiceRow({ service, onClick }:{ service:Service, onCli
|
||||
const [tooltipStopOpened, setTooltipStopOpened] = useState(false);
|
||||
const [deleteModal, setDeleteModal] = useState(false)
|
||||
const [renameModal, setRenameModal] = useState(false)
|
||||
const [editModal, setEditModal] = useState(false)
|
||||
const isMedium = isMediumScreen()
|
||||
|
||||
const stopService = async () => {
|
||||
@@ -104,7 +107,8 @@ export default function ServiceRow({ service, onClick }:{ service:Service, onCli
|
||||
{isMedium?<Space w="xl" />:<Space h="lg" />}
|
||||
<Box className="center-flex">
|
||||
<MenuDropDownWithButton>
|
||||
<Menu.Label><b>Rename service</b></Menu.Label>
|
||||
<Menu.Item><b>Edit service</b></Menu.Item>
|
||||
<Menu.Item leftSection={<IoSettingsSharp size={18} />} onClick={()=>setEditModal(true)}>Service Settings</Menu.Item>
|
||||
<Menu.Item leftSection={<BiRename size={18} />} onClick={()=>setRenameModal(true)}>Change service name</Menu.Item>
|
||||
<Divider />
|
||||
<Menu.Label><b>Danger zone</b></Menu.Label>
|
||||
@@ -148,5 +152,10 @@ export default function ServiceRow({ service, onClick }:{ service:Service, onCli
|
||||
opened={renameModal}
|
||||
service={service}
|
||||
/>
|
||||
<AddEditService
|
||||
opened={editModal}
|
||||
onClose={()=>setEditModal(false)}
|
||||
edit={service}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ export type Service = {
|
||||
ip_int: string,
|
||||
n_packets:number,
|
||||
n_regex:number,
|
||||
fail_open:boolean,
|
||||
}
|
||||
|
||||
export type ServiceAddForm = {
|
||||
@@ -19,6 +20,14 @@ export type ServiceAddForm = {
|
||||
port:number,
|
||||
proto:string,
|
||||
ip_int:string,
|
||||
fail_open: boolean,
|
||||
}
|
||||
|
||||
export type ServiceSettings = {
|
||||
port?:number,
|
||||
proto?:string,
|
||||
ip_int?:string,
|
||||
fail_open?: boolean,
|
||||
}
|
||||
|
||||
export type ServiceAddResponse = {
|
||||
@@ -79,5 +88,9 @@ export const nfregex = {
|
||||
},
|
||||
serviceregexes: async (service_id:string) => {
|
||||
return await getapi(`nfregex/services/${service_id}/regexes`) as RegexFilter[];
|
||||
}
|
||||
},
|
||||
settings: async (service_id:string, data:ServiceSettings) => {
|
||||
const { status } = await putapi(`nfregex/services/${service_id}/settings`,data) as ServerResponse;
|
||||
return status === "ok"?undefined:status
|
||||
},
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { Navigate, useNavigate, useParams } from 'react-router-dom';
|
||||
import RegexView from '../../components/RegexView';
|
||||
import AddNewRegex from '../../components/AddNewRegex';
|
||||
import { BsPlusLg } from "react-icons/bs";
|
||||
import { nfregexServiceQuery, nfregexServiceRegexesQuery } from '../../components/NFRegex/utils';
|
||||
import { nfregexServiceQuery, nfregexServiceRegexesQuery, Service } from '../../components/NFRegex/utils';
|
||||
import { Badge, Divider, Menu } from '@mantine/core';
|
||||
import { useState } from 'react';
|
||||
import { FaFilter, FaPlay, FaStop } from 'react-icons/fa';
|
||||
@@ -18,6 +18,8 @@ import { MenuDropDownWithButton } from '../../components/MainLayout';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { FaArrowLeft } from "react-icons/fa";
|
||||
import { VscRegex } from 'react-icons/vsc';
|
||||
import { IoSettingsSharp } from 'react-icons/io5';
|
||||
import AddEditService from '../../components/NFRegex/AddEditService';
|
||||
|
||||
export default function ServiceDetailsNFRegex() {
|
||||
|
||||
@@ -29,6 +31,7 @@ export default function ServiceDetailsNFRegex() {
|
||||
const regexesList = nfregexServiceRegexesQuery(srv??"")
|
||||
const [deleteModal, setDeleteModal] = useState(false)
|
||||
const [renameModal, setRenameModal] = useState(false)
|
||||
const [editModal, setEditModal] = useState(false)
|
||||
const [buttonLoading, setButtonLoading] = useState(false)
|
||||
const queryClient = useQueryClient()
|
||||
const [tooltipStopOpened, setTooltipStopOpened] = useState(false);
|
||||
@@ -108,7 +111,8 @@ export default function ServiceDetailsNFRegex() {
|
||||
</Badge>
|
||||
|
||||
<MenuDropDownWithButton>
|
||||
<Menu.Label><b>Rename service</b></Menu.Label>
|
||||
<Menu.Item><b>Edit service</b></Menu.Item>
|
||||
<Menu.Item leftSection={<IoSettingsSharp size={18} />} onClick={()=>setEditModal(true)}>Service Settings</Menu.Item>
|
||||
<Menu.Item leftSection={<BiRename size={18} />} onClick={()=>setRenameModal(true)}>Change service name</Menu.Item>
|
||||
<Divider />
|
||||
<Menu.Label><b>Danger zone</b></Menu.Label>
|
||||
@@ -190,5 +194,10 @@ export default function ServiceDetailsNFRegex() {
|
||||
opened={renameModal}
|
||||
service={serviceInfo}
|
||||
/>
|
||||
<AddEditService
|
||||
opened={editModal}
|
||||
onClose={()=>setEditModal(false)}
|
||||
edit={serviceInfo}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useNavigate, useParams } from 'react-router-dom';
|
||||
import ServiceRow from '../../components/NFRegex/ServiceRow';
|
||||
import { nfregexServiceQuery } from '../../components/NFRegex/utils';
|
||||
import { errorNotify, getErrorMessage, isMediumScreen } from '../../js/utils';
|
||||
import AddNewService from '../../components/NFRegex/AddNewService';
|
||||
import AddEditService from '../../components/NFRegex/AddEditService';
|
||||
import AddNewRegex from '../../components/AddNewRegex';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { TbReload } from 'react-icons/tb';
|
||||
@@ -81,13 +81,12 @@ function NFRegex({ children }: { children: any }) {
|
||||
</Tooltip>
|
||||
</Box>
|
||||
</>}
|
||||
<AddNewService opened={open} onClose={closeModal} />
|
||||
</>}
|
||||
</Box>
|
||||
{srv?children:null}
|
||||
{srv?
|
||||
<AddNewRegex opened={open} onClose={closeModal} service={srv} />:
|
||||
<AddNewService opened={open} onClose={closeModal} />
|
||||
<AddEditService opened={open} onClose={closeModal} />
|
||||
}
|
||||
</>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user