fixed mantine forms and menu + improvements on dev mode with vite
This commit is contained in:
@@ -60,7 +60,7 @@ function App() {
|
||||
password:"",
|
||||
},
|
||||
validate:{
|
||||
password: (value) => value !== ""
|
||||
password: (value) => value !== "" ? null : "Password is required",
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -25,9 +25,9 @@ function AddNewRegex({ opened, onClose, service }:{ opened:boolean, onClose:()=>
|
||||
deactive:false
|
||||
},
|
||||
validate:{
|
||||
regex: (value) => value !== "",
|
||||
type: (value) => ["blacklist","whitelist"].includes(value),
|
||||
mode: (value) => ['C -> S', 'S -> C', 'C <-> S'].includes(value)
|
||||
regex: (value) => value !== "" ? null : "Regex is required",
|
||||
type: (value) => ["blacklist","whitelist"].includes(value) ? null : "Invalid type",
|
||||
mode: (value) => ['C -> S', 'S -> C', 'C <-> S'].includes(value) ? null : "Invalid mode",
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ function ResetPasswordModal({ opened, onClose }:{ opened: boolean, onClose: () =
|
||||
expire:true
|
||||
},
|
||||
validate:{
|
||||
password: (value) => value !== ""
|
||||
password: (value) => value !== ""? null : "Password is required"
|
||||
}
|
||||
})
|
||||
const [loadingBtn, setLoadingBtn] = useState(false)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import { ActionIcon, Divider, Image, Menu, Tooltip, MediaQuery, Burger, Space, Header } from '@mantine/core';
|
||||
import { ActionIcon, Divider, Image, Menu, Tooltip, MediaQuery, Burger, Space, Header, Button, ThemeIcon } from '@mantine/core';
|
||||
import style from "./index.module.scss";
|
||||
import { errorNotify, getmainpath, logout } from '../../js/utils';
|
||||
import { AiFillHome } from "react-icons/ai"
|
||||
@@ -9,6 +9,8 @@ import { MdOutlineSettingsBackupRestore } from 'react-icons/md';
|
||||
import { ImExit } from 'react-icons/im';
|
||||
import ResetPasswordModal from './ResetPasswordModal';
|
||||
import ResetModal from './ResetModal';
|
||||
import { RiMenu5Fill } from 'react-icons/ri';
|
||||
import { MenuDropDownWithButton } from '../MainLayout';
|
||||
|
||||
|
||||
function HeaderPage({navOpen, setNav, ...other}: { navOpen: boolean, setNav:React.Dispatch<React.SetStateAction<boolean>>}) {
|
||||
@@ -51,15 +53,13 @@ function HeaderPage({navOpen, setNav, ...other}: { navOpen: boolean, setNav:Reac
|
||||
|
||||
<div className="flex-spacer" />
|
||||
|
||||
|
||||
<Menu>
|
||||
<MenuDropDownWithButton>
|
||||
<Menu.Label>Firewall Access</Menu.Label>
|
||||
<Menu.Item icon={<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>
|
||||
</MenuDropDownWithButton>
|
||||
<Space w="md" />
|
||||
<Tooltip label="Home" position='bottom' color="teal" opened={tooltipHomeOpened}>
|
||||
<ActionIcon color="teal" style={{marginRight:"10px"}}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Container, Space } from '@mantine/core';
|
||||
import { ActionIcon, Container, Menu, Space, ThemeIcon } 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 { useLocation } from 'react-router-dom';
|
||||
import { RiMenu5Fill } from 'react-icons/ri';
|
||||
|
||||
|
||||
|
||||
@@ -41,3 +42,14 @@ function MainLayout({ children }:{ children:any }) {
|
||||
}
|
||||
|
||||
export default MainLayout;
|
||||
|
||||
export const MenuDropDownWithButton = ({children}:{children:any}) => <Menu withArrow>
|
||||
<Menu.Target>
|
||||
<ActionIcon variant='transparent'>
|
||||
<RiMenu5Fill size={24} />
|
||||
</ActionIcon>
|
||||
</Menu.Target>
|
||||
<Menu.Dropdown>
|
||||
{children}
|
||||
</Menu.Dropdown>
|
||||
</Menu>
|
||||
|
||||
@@ -25,10 +25,10 @@ function AddNewService({ opened, onClose }:{ opened:boolean, onClose:()=>void })
|
||||
autostart: true
|
||||
},
|
||||
validate:{
|
||||
name: (value) => value !== ""?true:false,
|
||||
port: (value) => value>0 && value<65536,
|
||||
proto: (value) => ["tcp","udp"].includes(value),
|
||||
ip_int: (value) => value.match(regex_ipv6)?true:false || value.match(regex_ipv4)?true:false
|
||||
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",
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ function RenameForm({ opened, onClose, service }:{ opened:boolean, onClose:()=>v
|
||||
|
||||
const form = useForm({
|
||||
initialValues: { name:service.name },
|
||||
validate:{ name: (value) => value !== "" }
|
||||
validate:{ name: (value) => value !== ""? null : "Service name is required" }
|
||||
})
|
||||
|
||||
const close = () =>{
|
||||
|
||||
@@ -9,6 +9,7 @@ import { errorNotify, okNotify, regex_ipv4 } from '../../../js/utils';
|
||||
import { BsTrashFill } from 'react-icons/bs';
|
||||
import { BiRename } from 'react-icons/bi'
|
||||
import RenameForm from './RenameForm';
|
||||
import { MenuDropDownWithButton } from '../../MainLayout';
|
||||
|
||||
function ServiceRow({ service, onClick }:{ service:Service, onClick?:()=>void }) {
|
||||
|
||||
@@ -108,13 +109,13 @@ function ServiceRow({ service, onClick }:{ service:Service, onClick?:()=>void })
|
||||
<><Space w="xl" /><Space w="xl" /></>
|
||||
</MediaQuery>
|
||||
<div className="center-flex">
|
||||
<Menu>
|
||||
<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>
|
||||
</Menu>
|
||||
</MenuDropDownWithButton>
|
||||
<Space w="md"/>
|
||||
<Tooltip label="Stop service" zIndex={0} color="red" opened={tooltipStopOpened}>
|
||||
<ActionIcon color="red" loading={buttonLoading}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { Autocomplete, AutocompleteItem, Space, Title } from "@mantine/core"
|
||||
import { Autocomplete, AutocompleteItem, Select, Space, Title } from "@mantine/core"
|
||||
import React, { useEffect, useState } from "react"
|
||||
import { getipinterfaces } from "../js/utils";
|
||||
import PortInput from "./PortInput";
|
||||
import { UseFormReturnType } from "@mantine/form/lib/types";
|
||||
|
||||
interface ItemProps extends AutocompleteItem {
|
||||
label: string;
|
||||
netint: string;
|
||||
}
|
||||
|
||||
const AutoCompleteItem = React.forwardRef<HTMLDivElement, ItemProps>(
|
||||
({ label, value, ...props }: ItemProps, ref) => <div ref={ref} {...props}>
|
||||
( <b>{label}</b> ) -{">"} <b>{value}</b>
|
||||
({ netint, value, ...props }: ItemProps, ref) => <div ref={ref} {...props}>
|
||||
( <b>{netint}</b> ) -{">"} <b>{value}</b>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -21,7 +21,7 @@ export default function PortAndInterface({ form, int_name, port_name, label }:{
|
||||
|
||||
useEffect(()=>{
|
||||
getipinterfaces().then(data => {
|
||||
setIpInterfaces(data.map(item => ({label:item.name, value:item.addr})));
|
||||
setIpInterfaces(data.map(item => ({netint:item.name, value:item.addr, label:item.addr})));
|
||||
})
|
||||
},[])
|
||||
|
||||
@@ -29,17 +29,26 @@ export default function PortAndInterface({ form, int_name, port_name, label }:{
|
||||
{label?<>
|
||||
<Title order={6}>{label}</Title>
|
||||
<Space h="xs" /></> :null}
|
||||
|
||||
<div className='center-flex' style={{width:"100%"}}>
|
||||
<Autocomplete
|
||||
placeholder="10.1.1.1"
|
||||
itemComponent={AutoCompleteItem}
|
||||
data={ipInterfaces}
|
||||
{...form.getInputProps(int_name)}
|
||||
style={{width:"100%"}}
|
||||
/>
|
||||
<Space w="sm" /><span style={{marginTop:"-3px", fontSize:"1.5em"}}>:</span><Space w="sm" />
|
||||
<PortInput {...form.getInputProps(port_name)} />
|
||||
</div>
|
||||
<div className='center-flex' style={{width:"100%"}}>
|
||||
<Select
|
||||
placeholder="10.1.1.1"
|
||||
itemComponent={AutoCompleteItem}
|
||||
data={ipInterfaces}
|
||||
searchable
|
||||
dropdownPosition="bottom"
|
||||
maxDropdownHeight={100}
|
||||
creatable
|
||||
getCreateLabel={(query) => `+ Use this: ${query}`}
|
||||
onCreate={(query) => {
|
||||
const item = { value: query, netint: "CUSTOM", label: query };
|
||||
setIpInterfaces((current) => [...current, item]);
|
||||
return item;
|
||||
}}
|
||||
{...form.getInputProps(int_name)}
|
||||
style={{width:"100%"}}
|
||||
/>
|
||||
<Space w="sm" /><span style={{marginTop:"-3px", fontSize:"1.5em"}}>:</span><Space w="sm" />
|
||||
<PortInput {...form.getInputProps(port_name)} />
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
@@ -29,12 +29,12 @@ function AddNewService({ opened, onClose }:{ opened:boolean, onClose:()=>void })
|
||||
autostart: false,
|
||||
},
|
||||
validate:{
|
||||
name: (value) => value !== ""?true:false,
|
||||
public_port: (value) => value>0 && value<65536,
|
||||
proxy_port: (value) => value>0 && value<65536,
|
||||
proto: (value) => ["tcp","udp"].includes(value),
|
||||
ip_src: (value) => value.match(regex_ipv6_no_cidr)?true:false || value.match(regex_ipv4_no_cidr)?true:false,
|
||||
ip_dst: (value) => value.match(regex_ipv6_no_cidr)?true:false || value.match(regex_ipv4_no_cidr)?true:false
|
||||
name: (value) => value !== ""? null : "Service name is required",
|
||||
public_port: (value) => (value>0 && value<65536) ? null : "Invalid public port",
|
||||
proxy_port: (value) => (value>0 && value<65536) ? null : "Invalid proxy port",
|
||||
proto: (value) => ["tcp","udp"].includes(value) ? null : "Invalid protocol",
|
||||
ip_src: (value) => (value.match(regex_ipv6_no_cidr) || value.match(regex_ipv4_no_cidr)) ? null : "Invalid source IP address",
|
||||
ip_dst: (value) => (value.match(regex_ipv6_no_cidr) || value.match(regex_ipv4_no_cidr)) ? null : "Invalid destination IP address",
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ function ChangeDestination({ opened, onClose, service }:{ opened:boolean, onClos
|
||||
proxy_port:service.proxy_port
|
||||
},
|
||||
validate:{
|
||||
proxy_port: (value) => value>0 && value<65536,
|
||||
ip_dst: (value) => value.match(regex_ipv6_no_cidr)?true:false || value.match(regex_ipv4_no_cidr)?true:false
|
||||
proxy_port: (value) => (value>0 && value<65536) ? null : "Invalid proxy port",
|
||||
ip_dst: (value) => (value.match(regex_ipv6_no_cidr) || value.match(regex_ipv4_no_cidr))? null : "Invalid destination IP address",
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ function RenameForm({ opened, onClose, service }:{ opened:boolean, onClose:()=>v
|
||||
|
||||
const form = useForm({
|
||||
initialValues: { name:service.name },
|
||||
validate:{ name: (value) => value !== "" }
|
||||
validate:{ name: (value) => value !== ""? null : "Service name is required" }
|
||||
})
|
||||
|
||||
const close = () =>{
|
||||
|
||||
@@ -11,6 +11,7 @@ import RenameForm from './RenameForm';
|
||||
import ChangeDestination from './ChangeDestination';
|
||||
import PortInput from '../../PortInput';
|
||||
import { useForm } from '@mantine/form';
|
||||
import { MenuDropDownWithButton } from '../../MainLayout';
|
||||
|
||||
function ServiceRow({ service }:{ service:Service }) {
|
||||
|
||||
@@ -25,7 +26,7 @@ function ServiceRow({ service }:{ service:Service }) {
|
||||
|
||||
const form = useForm({
|
||||
initialValues: { proxy_port:service.proxy_port },
|
||||
validate:{ proxy_port: (value) => value > 0 && value < 65536 }
|
||||
validate:{ proxy_port: (value) => (value > 0 && value < 65536)? null : "Invalid proxy port" }
|
||||
})
|
||||
|
||||
const onChangeProxyPort = ({proxy_port}:{proxy_port:number}) => {
|
||||
@@ -132,7 +133,7 @@ function ServiceRow({ service }:{ service:Service }) {
|
||||
|
||||
<Space w="xl" /><Space w="xl" />
|
||||
<div className="center-flex">
|
||||
<Menu>
|
||||
<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>
|
||||
@@ -140,7 +141,7 @@ function ServiceRow({ service }:{ service:Service }) {
|
||||
<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>
|
||||
</MenuDropDownWithButton>
|
||||
<Space w="md"/>
|
||||
<Tooltip label="Stop service" zIndex={0} color="red" opened={tooltipStopOpened}>
|
||||
<ActionIcon color="red" loading={buttonLoading}
|
||||
|
||||
@@ -25,9 +25,9 @@ function AddNewService({ opened, onClose }:{ opened:boolean, onClose:()=>void })
|
||||
autostart: true
|
||||
},
|
||||
validate:{
|
||||
name: (value) => value !== ""?true:false,
|
||||
port: (value) => value>0 && value<65536,
|
||||
internalPort: (value) => value>0 && value<65536,
|
||||
name: (value) => value !== ""? null : "Service name is required",
|
||||
port: (value) => (value>0 && value<65536) ? null : "Invalid port",
|
||||
internalPort: (value) => (value>0 && value<65536) ? null : "Invalid internal port",
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ function ChangePortModal({ service, opened, onClose }:{ service:Service, opened:
|
||||
port: service.public_port
|
||||
},
|
||||
validate:{
|
||||
internalPort: (value) => value>0 && value<65536,
|
||||
port: (value) => value>0 && value<65536
|
||||
internalPort: (value) => (value>0 && value<65536) ? null : "Invalid internal port",
|
||||
port: (value) => (value>0 && value<65536) ? null : "Invalid public port",
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ function RenameForm({ opened, onClose, service }:{ opened:boolean, onClose:()=>v
|
||||
|
||||
const form = useForm({
|
||||
initialValues: { name:service.name },
|
||||
validate:{ name: (value) => value !== "" }
|
||||
validate:{ name: (value) => value !== ""? null : "Service name is required" }
|
||||
})
|
||||
|
||||
const close = () =>{
|
||||
|
||||
@@ -11,6 +11,7 @@ import { BiRename } from 'react-icons/bi'
|
||||
import ChangePortModal from './ChangePortModal';
|
||||
import RenameForm from './RenameForm';
|
||||
import { regexproxy, Service } from '../utils';
|
||||
import { MenuDropDownWithButton } from '../../MainLayout';
|
||||
|
||||
//"status":"stop"/"wait"/"active"/"pause",
|
||||
function ServiceRow({ service, onClick }:{ service:Service, onClick?:()=>void }) {
|
||||
@@ -139,7 +140,7 @@ function ServiceRow({ service, onClick }:{ service:Service, onClick?:()=>void })
|
||||
<><Space w="xl" /><Space w="xl" /></>
|
||||
</MediaQuery>
|
||||
<div className="center-flex">
|
||||
<Menu>
|
||||
<MenuDropDownWithButton>
|
||||
<Menu.Label><b>Rename service</b></Menu.Label>
|
||||
<Menu.Item icon={<BiRename size={18} />} onClick={()=>setRenameModal(true)}>Change service name</Menu.Item>
|
||||
<Divider />
|
||||
@@ -149,7 +150,7 @@ function ServiceRow({ service, onClick }:{ service:Service, onClick?:()=>void })
|
||||
<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>
|
||||
</MenuDropDownWithButton>
|
||||
<Space w="md"/>
|
||||
{["pause","wait"].includes(service.status)?
|
||||
|
||||
|
||||
Reference in New Issue
Block a user