firewall Frontend Improvements
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.11.0",
|
||||
"@hello-pangea/dnd": "^16.3.0",
|
||||
"@mantine/core": "^6.0.13",
|
||||
"@mantine/form": "^6.0.13",
|
||||
"@mantine/hooks": "^6.0.13",
|
||||
@@ -21,6 +22,7 @@
|
||||
"@types/react": "^18.0.12",
|
||||
"@types/react-dom": "^18.0.5",
|
||||
"buffer": "^6.0.3",
|
||||
"clsx": "^2.0.0",
|
||||
"react": "^18.1.0",
|
||||
"react-dom": "^18.1.0",
|
||||
"react-icons": "^4.4.0",
|
||||
|
||||
@@ -50,7 +50,7 @@ export type ServerResponseListed = {
|
||||
}
|
||||
|
||||
export const rulesQueryKey = ["firewall","rules"]
|
||||
export const firewallRulesQuery = () => useQuery({queryKey:rulesQueryKey, queryFn:firewall.rules})
|
||||
export const firewallRulesQuery = () => useQuery({queryKey:rulesQueryKey, queryFn:firewall.rules, refetchInterval: false})
|
||||
|
||||
export const firewall = {
|
||||
rules: async() => {
|
||||
@@ -72,7 +72,7 @@ export const firewall = {
|
||||
const { status } = await postapi(`firewall/rule/${rule_id}/rename`,{ name }) as ServerResponse;
|
||||
return status === "ok"?undefined:status
|
||||
},
|
||||
servicesadd: async (data:RuleAddForm) => {
|
||||
ruleset: async (data:RuleAddForm) => {
|
||||
return await postapi("firewall/rules/set", data) as ServerResponseListed;
|
||||
}
|
||||
}
|
||||
@@ -97,8 +97,8 @@ export function getapiobject(){
|
||||
|
||||
export function HomeRedirector(){
|
||||
const section = sessionStorage.getItem("home_section")
|
||||
const path = section?`/${section}`:`/nfregex`
|
||||
return <Navigate to={path} />
|
||||
const path = section?`/${section}`:`/firewall`
|
||||
return <Navigate to={path} replace/>
|
||||
}
|
||||
|
||||
export function fireUpdateRequest(){ //TODO: change me: specify what to update
|
||||
|
||||
24
frontend/src/pages/Firewall/DndListHandle.module.scss
Normal file
24
frontend/src/pages/Firewall/DndListHandle.module.scss
Normal file
@@ -0,0 +1,24 @@
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: var(--mantine-radius-md);
|
||||
border: rem(1px) solid light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-5));
|
||||
padding: var(--mantine-spacing-sm) var(--mantine-spacing-xl);
|
||||
padding-left: calc(var(--mantine-spacing-xl) - var(--mantine-spacing-md));
|
||||
background-color: light-dark(var(--mantine-color-white), var(--mantine-color-dark-5));
|
||||
margin-bottom: var(--mantine-spacing-sm);
|
||||
}
|
||||
|
||||
.itemDragging {
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
.dragHandle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
color: light-dark(var(--mantine-color-gray-6), var(--mantine-color-dark-1));
|
||||
padding-left: var(--mantine-spacing-md);
|
||||
padding-right: var(--mantine-spacing-md);
|
||||
}
|
||||
@@ -1,42 +1,261 @@
|
||||
import { ActionIcon, Badge, LoadingOverlay, Space, Title, Tooltip } from "@mantine/core"
|
||||
import { ActionIcon, Badge, LoadingOverlay, NativeSelect, SegmentedControl, Space, Switch, Title, Tooltip } from "@mantine/core"
|
||||
import { useEffect, useState } from "react";
|
||||
import { BsPlusLg } from "react-icons/bs"
|
||||
import { firewall, firewallRulesQuery } from "../../components/Firewall/utils";
|
||||
import { errorNotify, getErrorMessage } from "../../js/utils";
|
||||
|
||||
import { rem, Text } from '@mantine/core';
|
||||
import { ActionType, Rule, firewall, firewallRulesQuery } from "../../components/Firewall/utils";
|
||||
import cx from 'clsx'
|
||||
import { errorNotify, getErrorMessage, okNotify } from "../../js/utils";
|
||||
import { useListState } from '@mantine/hooks';
|
||||
import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd';
|
||||
import { TbGripVertical, TbReload } from "react-icons/tb";
|
||||
import classes from './DndListHandle.module.scss';
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { TiTick } from "react-icons/ti";
|
||||
import YesNoModal from "../../components/YesNoModal";
|
||||
|
||||
/*
|
||||
{
|
||||
"rules": [
|
||||
{
|
||||
"active": true,
|
||||
"name": "R1",
|
||||
"proto": "tcp",
|
||||
"ip_src": "0.0.0.0/0",
|
||||
"ip_dst": "0.0.0.0/0",
|
||||
"port_src_from": 1,
|
||||
"port_dst_from": 3030,
|
||||
"port_src_to": 65535,
|
||||
"port_dst_to": 3030,
|
||||
"action": "reject",
|
||||
"mode": "I"
|
||||
},
|
||||
{
|
||||
"active": true,
|
||||
"name": "R2",
|
||||
"proto": "tcp",
|
||||
"ip_src": "0.0.0.0/0",
|
||||
"ip_dst": "0.0.0.0/0",
|
||||
"port_src_from": 1,
|
||||
"port_dst_from": 3030,
|
||||
"port_src_to": 65535,
|
||||
"port_dst_to": 3030,
|
||||
"action": "drop",
|
||||
"mode": "O"
|
||||
},
|
||||
{
|
||||
"active": false,
|
||||
"name": "R3",
|
||||
"proto": "udp",
|
||||
"ip_src": "192.168.0.1/24",
|
||||
"ip_dst": "0.0.0.0/0",
|
||||
"port_src_from": 1,
|
||||
"port_dst_from": 2020,
|
||||
"port_src_to": 65535,
|
||||
"port_dst_to": 2020,
|
||||
"action": "drop",
|
||||
"mode": "I"
|
||||
},
|
||||
{
|
||||
"active": true,
|
||||
"name": "R4",
|
||||
"proto": "any",
|
||||
"ip_src": "::/0",
|
||||
"ip_dst": "fdfd::ffff:123/64",
|
||||
"port_src_from": 1,
|
||||
"port_dst_from": 1,
|
||||
"port_src_to": 1,
|
||||
"port_dst_to": 1,
|
||||
"action": "accept",
|
||||
"mode": "I"
|
||||
}
|
||||
],
|
||||
"policy": "accept"
|
||||
}
|
||||
*/
|
||||
|
||||
export const Firewall = () => {
|
||||
|
||||
const [tooltipAddOpened, setTooltipAddOpened] = useState(false);
|
||||
const [tooltipRefreshOpened, setTooltipRefreshOpened] = useState(false);
|
||||
const [tooltipApplyOpened, setTooltipApplyOpened] = useState(false);
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const [currentPolicy, setCurrentPolicy] = useState<ActionType>(ActionType.ACCEPT)
|
||||
const queryClient = useQueryClient()
|
||||
const rules = firewallRulesQuery()
|
||||
|
||||
const [state, handlers] = useListState<Rule>([]);
|
||||
const [enableFwModal, setEnableFwModal] = useState(false)
|
||||
const [applyChangeModal, setApplyChangeModal] = useState(false)
|
||||
|
||||
useEffect(()=> {
|
||||
if(rules.isError)
|
||||
errorNotify("Firewall Update failed!", getErrorMessage(rules.error))
|
||||
},[rules.isError])
|
||||
|
||||
useEffect(()=> {
|
||||
if(!rules.isLoading && rules.isSuccess)
|
||||
handlers.setState(JSON.parse(JSON.stringify(rules.data?.rules??[])))
|
||||
},[rules.isSuccess, rules.isLoading])
|
||||
|
||||
const fwEnabled = rules.data?.enabled??false
|
||||
const valuesChanged = JSON.stringify(rules.data?.rules) != JSON.stringify(state) || rules.data?.policy != currentPolicy
|
||||
|
||||
const enableFirewall = () => {
|
||||
if (valuesChanged){
|
||||
applyChangesRaw().then(()=>enableFirewallRaw())
|
||||
}else{
|
||||
enableFirewallRaw()
|
||||
}
|
||||
}
|
||||
|
||||
const enableFirewallRaw = () => {
|
||||
return firewall.enable()
|
||||
.then(()=>okNotify("Firewall enabled", "The firewall has been enabled"))
|
||||
.catch((e)=>errorNotify("Firewall enable failed!", getErrorMessage(e)))
|
||||
}
|
||||
|
||||
const disableFirewallRaw = () => {
|
||||
return firewall.disable()
|
||||
.then(()=>okNotify("Firewall disabled", "The firewall has been disabled"))
|
||||
.catch((e)=>errorNotify("Firewall disable failed!", getErrorMessage(e)))
|
||||
}
|
||||
|
||||
const switchState = () => {
|
||||
if (fwEnabled)
|
||||
disableFirewallRaw()
|
||||
else
|
||||
if ([ActionType.REJECT, ActionType.DROP].includes(currentPolicy) || valuesChanged){
|
||||
setEnableFwModal(true)
|
||||
}else{
|
||||
enableFirewall()
|
||||
}
|
||||
}
|
||||
|
||||
const applyChanges = () => {
|
||||
if (fwEnabled && rules.data?.policy == ActionType.ACCEPT && [ActionType.REJECT, ActionType.DROP].includes(currentPolicy)){
|
||||
setApplyChangeModal(true)
|
||||
}else{
|
||||
applyChangesRaw()
|
||||
}
|
||||
}
|
||||
|
||||
const applyChangesRaw = () => {
|
||||
return firewall.ruleset({rules:state, policy:currentPolicy})
|
||||
.then(()=>okNotify("Firewall rules applied", "The firewall rules has been applied"))
|
||||
.catch((e)=>errorNotify("Firewall rules apply failed!", getErrorMessage(e)))
|
||||
}
|
||||
|
||||
const items = state.map((item, index) => (
|
||||
<Draggable key={index} index={index} draggableId={index.toString()}>
|
||||
{(provided, snapshot) => (
|
||||
<div
|
||||
className={cx(classes.item, { [classes.itemDragging]: snapshot.isDragging })}
|
||||
ref={provided.innerRef}
|
||||
{...provided.draggableProps}
|
||||
>
|
||||
<div {...provided.dragHandleProps} className={classes.dragHandle}>
|
||||
<TbGripVertical style={{ width: rem(18), height: rem(18) }} />
|
||||
</div>
|
||||
<Space w="sm" />
|
||||
<Switch
|
||||
defaultChecked
|
||||
label="I agree to sell my privacy"
|
||||
/>
|
||||
<div>
|
||||
<Text>{item.name}</Text>
|
||||
<Text c="dimmed" size="sm">
|
||||
{JSON.stringify(item)}
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
));
|
||||
|
||||
|
||||
return <>
|
||||
<Space h="sm" />
|
||||
<LoadingOverlay visible={rules.isLoading} />
|
||||
<div className='center-flex'>
|
||||
<Title order={4}>Firewall Rules</Title>
|
||||
<div className='flex-spacer' />
|
||||
<Title order={3}>Firewall Rules</Title>
|
||||
<div className='flex-spacer' />
|
||||
Enabled: <Space w="sm" /> <Switch checked={fwEnabled} onChange={switchState} />
|
||||
<Space w="sm" />
|
||||
Policy:
|
||||
<Space w="xs" />
|
||||
<SegmentedControl
|
||||
data={[
|
||||
{
|
||||
value: ActionType.ACCEPT,
|
||||
label: 'Accept',
|
||||
},
|
||||
{
|
||||
value: ActionType.REJECT,
|
||||
label: 'Reject',
|
||||
},
|
||||
{
|
||||
value: ActionType.DROP,
|
||||
label: 'Drop',
|
||||
}
|
||||
]}
|
||||
value={currentPolicy}
|
||||
onChange={(value)=>setCurrentPolicy(value as ActionType)}
|
||||
/>
|
||||
<Space w="xs" />
|
||||
<Badge size="sm" color="green" variant="filled">Rules: {rules.isLoading?0:rules.data?.rules.length}</Badge>
|
||||
<Space w="xs" />
|
||||
<Badge size="sm" color="yellow" variant="filled">Policy: {rules.isLoading?"unknown":rules.data?.policy}</Badge>
|
||||
<Space w="xs" />
|
||||
<Badge size="sm" color="violet" variant="filled">Enabled: {rules.isLoading?"?":(rules.data?.enabled?"🟢":"🔴")}</Badge>
|
||||
<Space w="xs" />
|
||||
<Tooltip label="Add a new rule" position='bottom' color="blue" opened={tooltipAddOpened}>
|
||||
<ActionIcon color="blue" onClick={()=>setOpen(true)} size="lg" radius="md" variant="filled"
|
||||
onFocus={() => setTooltipAddOpened(false)} onBlur={() => setTooltipAddOpened(false)}
|
||||
onMouseEnter={() => setTooltipAddOpened(true)} onMouseLeave={() => setTooltipAddOpened(false)}><BsPlusLg size={18} /></ActionIcon>
|
||||
</Tooltip>
|
||||
<Space w="xs" />
|
||||
<Tooltip label="Refresh" position='bottom' color="indigo" opened={tooltipRefreshOpened}>
|
||||
<ActionIcon color="indigo" onClick={()=>queryClient.invalidateQueries(["firewall"])} size="lg" radius="md" variant="filled"
|
||||
loading={rules.isFetching}
|
||||
onFocus={() => setTooltipRefreshOpened(false)} onBlur={() => setTooltipRefreshOpened(false)}
|
||||
onMouseEnter={() => setTooltipRefreshOpened(true)} onMouseLeave={() => setTooltipRefreshOpened(false)}><TbReload size={18} /></ActionIcon>
|
||||
</Tooltip>
|
||||
<Space w="xs" />
|
||||
<Tooltip label="Apply" position='bottom' color="grape" opened={tooltipApplyOpened}>
|
||||
<ActionIcon color="grape" onClick={applyChanges} size="lg" radius="md" variant="filled"
|
||||
onFocus={() => setTooltipApplyOpened(false)} onBlur={() => setTooltipApplyOpened(false)}
|
||||
onMouseEnter={() => setTooltipApplyOpened(true)} onMouseLeave={() => setTooltipApplyOpened(false)}
|
||||
disabled={!valuesChanged}
|
||||
><TiTick size={22} /></ActionIcon>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<LoadingOverlay visible={rules.isLoading} />
|
||||
<Space h="xl" />
|
||||
|
||||
<DragDropContext
|
||||
onDragEnd={({ destination, source }) =>
|
||||
handlers.reorder({ from: source.index, to: destination?.index || 0 })
|
||||
}
|
||||
>
|
||||
<Droppable droppableId="dnd-list" direction="vertical">
|
||||
{(provided) => (
|
||||
<div {...provided.droppableProps} ref={provided.innerRef}>
|
||||
{items}
|
||||
{provided.placeholder}
|
||||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
</DragDropContext>
|
||||
|
||||
<YesNoModal
|
||||
title='Are you sure to apply the changes to the firewall?'
|
||||
description={`If there is a malconfiguration you can lose the access to your server! ⚠️`}
|
||||
onClose={()=>setEnableFwModal(false) }
|
||||
action={enableFirewall}
|
||||
opened={enableFwModal}
|
||||
/>
|
||||
|
||||
<YesNoModal
|
||||
title='Are you sure to apply the changes to the firewall?'
|
||||
description={`If there is a malconfiguration you can lose the access to your server! ⚠️`}
|
||||
onClose={()=>setApplyChangeModal(false) }
|
||||
action={applyChangesRaw}
|
||||
opened={applyChangeModal}
|
||||
/>
|
||||
|
||||
</>
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import { nfregexServiceQuery } from '../../components/NFRegex/utils';
|
||||
import { errorNotify, getErrorMessage } from '../../js/utils';
|
||||
import AddNewService from '../../components/NFRegex/AddNewService';
|
||||
import AddNewRegex from '../../components/AddNewRegex';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { TbReload } from 'react-icons/tb';
|
||||
|
||||
|
||||
function NFRegex({ children }: { children: any }) {
|
||||
@@ -14,16 +16,16 @@ function NFRegex({ children }: { children: any }) {
|
||||
const navigator = useNavigate()
|
||||
const [open, setOpen] = useState(false);
|
||||
const {srv} = useParams()
|
||||
const queryClient = useQueryClient()
|
||||
const [tooltipRefreshOpened, setTooltipRefreshOpened] = useState(false);
|
||||
const [tooltipAddServOpened, setTooltipAddServOpened] = useState(false);
|
||||
const [tooltipAddOpened, setTooltipAddOpened] = useState(false);
|
||||
|
||||
const services = nfregexServiceQuery()
|
||||
|
||||
useEffect(()=> {
|
||||
if(services.isError){
|
||||
if(services.isError)
|
||||
errorNotify("NFRegex Update failed!", getErrorMessage(services.error))
|
||||
}
|
||||
|
||||
},[services.isError])
|
||||
|
||||
const closeModal = () => {setOpen(false);}
|
||||
@@ -51,6 +53,13 @@ function NFRegex({ children }: { children: any }) {
|
||||
onMouseEnter={() => setTooltipAddOpened(true)} onMouseLeave={() => setTooltipAddOpened(false)}><BsPlusLg size={18} /></ActionIcon>
|
||||
</Tooltip>
|
||||
}
|
||||
<Space w="xs" />
|
||||
<Tooltip label="Refresh" position='bottom' color="indigo" opened={tooltipRefreshOpened}>
|
||||
<ActionIcon color="indigo" onClick={()=>queryClient.invalidateQueries(["nfregex"])} size="lg" radius="md" variant="filled"
|
||||
loading={services.isFetching}
|
||||
onFocus={() => setTooltipRefreshOpened(false)} onBlur={() => setTooltipRefreshOpened(false)}
|
||||
onMouseEnter={() => setTooltipRefreshOpened(true)} onMouseLeave={() => setTooltipRefreshOpened(false)}><TbReload size={18} /></ActionIcon>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div id="service-list" className="center-flex-row">
|
||||
{srv?null:<>
|
||||
|
||||
@@ -5,6 +5,8 @@ import ServiceRow from '../../components/PortHijack/ServiceRow';
|
||||
import { porthijackServiceQuery } from '../../components/PortHijack/utils';
|
||||
import { errorNotify, getErrorMessage } from '../../js/utils';
|
||||
import AddNewService from '../../components/PortHijack/AddNewService';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { TbReload } from 'react-icons/tb';
|
||||
|
||||
|
||||
function PortHijack() {
|
||||
@@ -12,14 +14,15 @@ function PortHijack() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [tooltipAddServOpened, setTooltipAddServOpened] = useState(false);
|
||||
const [tooltipAddOpened, setTooltipAddOpened] = useState(false);
|
||||
const queryClient = useQueryClient()
|
||||
const [tooltipRefreshOpened, setTooltipRefreshOpened] = useState(false);
|
||||
|
||||
|
||||
const services = porthijackServiceQuery()
|
||||
|
||||
useEffect(()=>{
|
||||
if(services.isError){
|
||||
if(services.isError)
|
||||
errorNotify("Porthijack Update failed!", getErrorMessage(services.error))
|
||||
}
|
||||
},[services.isError])
|
||||
|
||||
const closeModal = () => {setOpen(false);}
|
||||
@@ -36,6 +39,13 @@ function PortHijack() {
|
||||
onFocus={() => setTooltipAddOpened(false)} onBlur={() => setTooltipAddOpened(false)}
|
||||
onMouseEnter={() => setTooltipAddOpened(true)} onMouseLeave={() => setTooltipAddOpened(false)}><BsPlusLg size={18} /></ActionIcon>
|
||||
</Tooltip>
|
||||
<Space w="xs" />
|
||||
<Tooltip label="Refresh" position='bottom' color="indigo" opened={tooltipRefreshOpened}>
|
||||
<ActionIcon color="indigo" onClick={()=>queryClient.invalidateQueries(["porthijack"])} size="lg" radius="md" variant="filled"
|
||||
loading={services.isFetching}
|
||||
onFocus={() => setTooltipRefreshOpened(false)} onBlur={() => setTooltipRefreshOpened(false)}
|
||||
onMouseEnter={() => setTooltipRefreshOpened(true)} onMouseLeave={() => setTooltipRefreshOpened(false)}><TbReload size={18} /></ActionIcon>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div id="service-list" className="center-flex-row">
|
||||
<LoadingOverlay visible={services.isLoading} />
|
||||
@@ -52,7 +62,6 @@ function PortHijack() {
|
||||
</>}
|
||||
<AddNewService opened={open} onClose={closeModal} />
|
||||
</div>
|
||||
<AddNewService opened={open} onClose={closeModal} />
|
||||
</>
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ import { regexproxyServiceQuery } from '../../components/RegexProxy/utils';
|
||||
import { errorNotify, getErrorMessage } from '../../js/utils';
|
||||
import AddNewService from '../../components/RegexProxy/AddNewService';
|
||||
import AddNewRegex from '../../components/AddNewRegex';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { TbReload } from 'react-icons/tb';
|
||||
|
||||
|
||||
function RegexProxy({ children }: { children: any }) {
|
||||
@@ -16,6 +18,8 @@ function RegexProxy({ children }: { children: any }) {
|
||||
const {srv} = useParams()
|
||||
const [tooltipAddServOpened, setTooltipAddServOpened] = useState(false);
|
||||
const [tooltipAddOpened, setTooltipAddOpened] = useState(false);
|
||||
const queryClient = useQueryClient()
|
||||
const [tooltipRefreshOpened, setTooltipRefreshOpened] = useState(false);
|
||||
|
||||
const services = regexproxyServiceQuery()
|
||||
|
||||
@@ -50,6 +54,13 @@ function RegexProxy({ children }: { children: any }) {
|
||||
onMouseEnter={() => setTooltipAddOpened(true)} onMouseLeave={() => setTooltipAddOpened(false)}><BsPlusLg size={18} /></ActionIcon>
|
||||
</Tooltip>
|
||||
}
|
||||
<Space w="xs" />
|
||||
<Tooltip label="Refresh" position='bottom' color="indigo" opened={tooltipRefreshOpened}>
|
||||
<ActionIcon color="indigo" onClick={()=>queryClient.invalidateQueries(["regexproxy"])} size="lg" radius="md" variant="filled"
|
||||
loading={services.isFetching}
|
||||
onFocus={() => setTooltipRefreshOpened(false)} onBlur={() => setTooltipRefreshOpened(false)}
|
||||
onMouseEnter={() => setTooltipRefreshOpened(true)} onMouseLeave={() => setTooltipRefreshOpened(false)}><TbReload size={18} /></ActionIcon>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div id="service-list" className="center-flex-row">
|
||||
{srv?null:<>
|
||||
|
||||
@@ -188,6 +188,13 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.11"
|
||||
|
||||
"@babel/runtime@^7.12.1", "@babel/runtime@^7.22.5":
|
||||
version "7.22.15"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.15.tgz#38f46494ccf6cf020bd4eed7124b425e83e523b8"
|
||||
integrity sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.14.0"
|
||||
|
||||
"@babel/template@^7.22.5":
|
||||
version "7.22.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec"
|
||||
@@ -448,6 +455,19 @@
|
||||
aria-hidden "^1.1.3"
|
||||
tabbable "^6.0.1"
|
||||
|
||||
"@hello-pangea/dnd@^16.3.0":
|
||||
version "16.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@hello-pangea/dnd/-/dnd-16.3.0.tgz#3776212f812df4e8e69c42831ec8ab7ff3a087d6"
|
||||
integrity sha512-RYQ/K8shtJoyNPvFWz0gfXIK7HF3P3mL9UZFGMuHB0ljRSXVgMjVFI/FxcZmakMzw6tO7NflWLriwTNBow/4vw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.22.5"
|
||||
css-box-model "^1.2.1"
|
||||
memoize-one "^6.0.0"
|
||||
raf-schd "^4.0.3"
|
||||
react-redux "^8.1.1"
|
||||
redux "^4.2.1"
|
||||
use-memo-one "^1.1.3"
|
||||
|
||||
"@jest/expect-utils@^29.5.0":
|
||||
version "29.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.5.0.tgz#f74fad6b6e20f924582dc8ecbf2cb800fe43a036"
|
||||
@@ -873,6 +893,14 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194"
|
||||
integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==
|
||||
|
||||
"@types/hoist-non-react-statics@^3.3.1":
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#dc1e9ded53375d37603c479cc12c693b0878aa2a"
|
||||
integrity sha512-YIQtIg4PKr7ZyqNPZObpxfHsHEmuB8dXCxd6qVcGuQVDK2bpsF7bYNnBJ4Nn7giuACZg+WewExgrtAJ3XnA4Xw==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
hoist-non-react-statics "^3.3.0"
|
||||
|
||||
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44"
|
||||
@@ -956,6 +984,11 @@
|
||||
dependencies:
|
||||
"@types/jest" "*"
|
||||
|
||||
"@types/use-sync-external-store@^0.0.3":
|
||||
version "0.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43"
|
||||
integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==
|
||||
|
||||
"@types/yargs-parser@*":
|
||||
version "21.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b"
|
||||
@@ -1166,6 +1199,11 @@ clsx@1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188"
|
||||
integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==
|
||||
|
||||
clsx@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.0.0.tgz#12658f3fd98fafe62075595a5c30e43d18f3d00b"
|
||||
integrity sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==
|
||||
|
||||
color-convert@^1.9.0:
|
||||
version "1.9.3"
|
||||
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
|
||||
@@ -1223,6 +1261,13 @@ cosmiconfig@^8.1.3:
|
||||
parse-json "^5.0.0"
|
||||
path-type "^4.0.0"
|
||||
|
||||
css-box-model@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1"
|
||||
integrity sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==
|
||||
dependencies:
|
||||
tiny-invariant "^1.0.6"
|
||||
|
||||
css.escape@^1.5.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb"
|
||||
@@ -1556,7 +1601,7 @@ has@^1.0.3:
|
||||
dependencies:
|
||||
function-bind "^1.1.1"
|
||||
|
||||
hoist-non-react-statics@^3.3.1:
|
||||
hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
|
||||
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
|
||||
@@ -1900,6 +1945,11 @@ lz-string@^1.5.0:
|
||||
resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941"
|
||||
integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==
|
||||
|
||||
memoize-one@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045"
|
||||
integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==
|
||||
|
||||
micromatch@^4.0.4:
|
||||
version "4.0.5"
|
||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
|
||||
@@ -2044,6 +2094,11 @@ prop-types@^15.6.2:
|
||||
object-assign "^4.1.1"
|
||||
react-is "^16.13.1"
|
||||
|
||||
raf-schd@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a"
|
||||
integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==
|
||||
|
||||
react-dom@^18.1.0:
|
||||
version "18.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
|
||||
@@ -2072,6 +2127,18 @@ react-is@^18.0.0:
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
|
||||
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
|
||||
|
||||
react-redux@^8.1.1:
|
||||
version "8.1.2"
|
||||
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.1.2.tgz#9076bbc6b60f746659ad6d51cb05de9c5e1e9188"
|
||||
integrity sha512-xJKYI189VwfsFc4CJvHqHlDrzyFTY/3vZACbE+rr/zQ34Xx1wQfB4OTOSeOSNrF6BDVe8OOdxIrAnMGXA3ggfw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.1"
|
||||
"@types/hoist-non-react-statics" "^3.3.1"
|
||||
"@types/use-sync-external-store" "^0.0.3"
|
||||
hoist-non-react-statics "^3.3.2"
|
||||
react-is "^18.0.0"
|
||||
use-sync-external-store "^1.0.0"
|
||||
|
||||
react-refresh@^0.14.0:
|
||||
version "0.14.0"
|
||||
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
|
||||
@@ -2161,11 +2228,23 @@ redent@^3.0.0:
|
||||
indent-string "^4.0.0"
|
||||
strip-indent "^3.0.0"
|
||||
|
||||
redux@^4.2.1:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197"
|
||||
integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.9.2"
|
||||
|
||||
regenerator-runtime@^0.13.11:
|
||||
version "0.13.11"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
|
||||
integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
|
||||
|
||||
regenerator-runtime@^0.14.0:
|
||||
version "0.14.0"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45"
|
||||
integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==
|
||||
|
||||
regexp.prototype.flags@^1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb"
|
||||
@@ -2326,6 +2405,11 @@ tabbable@^6.0.1:
|
||||
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.2.0.tgz#732fb62bc0175cfcec257330be187dcfba1f3b97"
|
||||
integrity sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==
|
||||
|
||||
tiny-invariant@^1.0.6:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642"
|
||||
integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==
|
||||
|
||||
to-fast-properties@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
|
||||
@@ -2385,6 +2469,11 @@ use-latest@^1.2.1:
|
||||
dependencies:
|
||||
use-isomorphic-layout-effect "^1.1.1"
|
||||
|
||||
use-memo-one@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.3.tgz#2fd2e43a2169eabc7496960ace8c79efef975e99"
|
||||
integrity sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==
|
||||
|
||||
use-sidecar@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2"
|
||||
@@ -2393,7 +2482,7 @@ use-sidecar@^1.1.2:
|
||||
detect-node-es "^1.1.0"
|
||||
tslib "^2.0.0"
|
||||
|
||||
use-sync-external-store@^1.2.0:
|
||||
use-sync-external-store@^1.0.0, use-sync-external-store@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
|
||||
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
|
||||
|
||||
Reference in New Issue
Block a user