Skip to content

Commit

Permalink
Lint
Browse files Browse the repository at this point in the history
  • Loading branch information
CannonLock committed Jan 14, 2025
1 parent a3e7dfa commit c1d3ef1
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 85 deletions.
5 changes: 4 additions & 1 deletion web_ui/frontend/app/config/Config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,10 @@ function Config({ metadata }: { metadata: ParameterMetadataRecord }) {
'getConfig',
async () =>
await alertOnError(
async () => (await getConfig()).json(), 'Could not get config', dispatch)
async () => (await getConfig()).json(),
'Could not get config',
dispatch
)
);

const serverConfig = useMemo(() => {
Expand Down
188 changes: 114 additions & 74 deletions web_ui/frontend/app/director/components/GeoIpErrorTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,111 +19,151 @@ import { tableCellClasses } from '@mui/material/TableCell';
import useSWR from 'swr';

import { query_raw, VectorResponseData } from '@/components';
import { GeoIPOverride, GeoIPOverrideForm, ParameterValueRecord, submitConfigChange } from '@/components/configuration';
import {
GeoIPOverride,
GeoIPOverrideForm,
ParameterValueRecord,
submitConfigChange,
} from '@/components/configuration';
import { alertOnError } from '@/helpers/util';
import { Dispatch, useCallback, useContext, useMemo, useState } from 'react';
import { AlertDispatchContext, AlertReducerAction } from '@/components/AlertProvider';
import {
AlertDispatchContext,
AlertReducerAction,
} from '@/components/AlertProvider';
import { getConfig } from '@/helpers/api';
import LatitudeLongitudePicker from '@/components/LatitudeLongitudePicker';
import ObjectModal from '@/components/configuration/Fields/ObjectField/ObjectModal';
import CircularProgress from '@mui/material/CircularProgress';

const GeoIpErrorTable = () => {

const dispatch = useContext(AlertDispatchContext);
const {data: ipErrors} = useSWR('geoip_errors', getIpErrorRows)
const { data: ipErrors } = useSWR('geoip_errors', getIpErrorRows);

const { data: config, mutate, error, isValidating } = useSWR<ParameterValueRecord | undefined>(
const {
data: config,
mutate,
error,
isValidating,
} = useSWR<ParameterValueRecord | undefined>(
'getConfig',
async () =>
await alertOnError(getOverriddenGeoIps, 'Could not get config', dispatch)
);
const patchedIps = useMemo(() => {
return config?.GeoIPOverrides === undefined ?
[] :
Object.values(config.GeoIPOverrides).map((x: GeoIPOverride) => x.ip)
}, [config])
const [geoIPOverrides, setGeoIPOverrides] = useState<Record<string, GeoIPOverride>>({})
return config?.GeoIPOverrides === undefined
? []
: Object.values(config.GeoIPOverrides).map((x: GeoIPOverride) => x.ip);
}, [config]);
const [geoIPOverrides, setGeoIPOverrides] = useState<
Record<string, GeoIPOverride>
>({});

const [open, setOpen] = useState(false)
const [ip, setIp] = useState("")
const [open, setOpen] = useState(false);
const [ip, setIp] = useState('');

const onSubmit = useCallback((x: GeoIPOverride) => {
setGeoIPOverrides((p) => {
return {...p, [x.ip]: x}
})
setOpen(false)
}, [])
return { ...p, [x.ip]: x };
});
setOpen(false);
}, []);

return (
<>
<Typography variant={"h4"} pb={2}>
<Typography variant={'h4'} pb={2}>
Un-located Networks
{isValidating && <CircularProgress size={"24px"} sx={{ml: 1}}/>}
{isValidating && <CircularProgress size={'24px'} sx={{ ml: 1 }} />}
</Typography>
<Paper sx={{overflow: "hidden"}}>
<TableContainer sx={{ maxHeight: 250}}>
<Table stickyHeader sx={{ minWidth: 650 }} size={"small"} aria-label="simple table">
<Paper sx={{ overflow: 'hidden' }}>
<TableContainer sx={{ maxHeight: 250 }}>
<Table
stickyHeader
sx={{ minWidth: 650 }}
size={'small'}
aria-label='simple table'
>
<TableHead>
<TableRow>
<StyledTableCell>Un-located Network</StyledTableCell>
<StyledTableCell align="right">Project</StyledTableCell>
<StyledTableCell align="right">Source</StyledTableCell>
<StyledTableCell align={"right"}># of Errors</StyledTableCell>
<StyledTableCell align="right">Locate</StyledTableCell>
<StyledTableCell align='right'>Project</StyledTableCell>
<StyledTableCell align='right'>Source</StyledTableCell>
<StyledTableCell align={'right'}># of Errors</StyledTableCell>
<StyledTableCell align='right'>Locate</StyledTableCell>
</TableRow>
</TableHead>
<TableBody>
{ipErrors && ipErrors
.filter((x) => !patchedIps.includes(x.metric?.network))
.sort((a, b) => parseInt(b.value[1]) - parseInt(a.value[1]))
.map((row) => (
<TableRow
key={row.metric?.network}
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
>
<TableCell>{row.metric?.network}</TableCell>
<TableCell align="right">{row.metric?.proj}</TableCell>
<TableCell align="right">{row.metric?.source}</TableCell>
<TableCell align="right">{parseInt(row.value[1]).toLocaleString()}</TableCell>
<TableCell align="right">
<Button
onClick={() => {
setIp(row.metric?.network)
setOpen(true)
}}
{ipErrors &&
ipErrors
.filter((x) => !patchedIps.includes(x.metric?.network))
.sort((a, b) => parseInt(b.value[1]) - parseInt(a.value[1]))
.map((row) => (
<TableRow
key={row.metric?.network}
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
>
{Object.keys(geoIPOverrides).includes(row.metric?.network) ? "Pending" : "Locate"}
</Button>
</TableCell>
</TableRow>
))}
<TableCell>{row.metric?.network}</TableCell>
<TableCell align='right'>{row.metric?.proj}</TableCell>
<TableCell align='right'>{row.metric?.source}</TableCell>
<TableCell align='right'>
{parseInt(row.value[1]).toLocaleString()}
</TableCell>
<TableCell align='right'>
<Button
onClick={() => {
setIp(row.metric?.network);
setOpen(true);
}}
>
{Object.keys(geoIPOverrides).includes(
row.metric?.network
)
? 'Pending'
: 'Locate'}
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
{Object.keys(geoIPOverrides).length > 0 && (
<Button
sx={{m:1}}
variant={"outlined"}
sx={{ m: 1 }}
variant={'outlined'}
onClick={async () => {
const overrides = [...Object.values(config?.GeoIPOverrides || []), ...Object.values(geoIPOverrides)]
const value = await alertOnError(async () => submitConfigChange({GeoIPOverrides: overrides}), 'Could not submit IP patches', dispatch)
if(value !== undefined) {
mutate()
setGeoIPOverrides({})
const overrides = [
...Object.values(config?.GeoIPOverrides || []),
...Object.values(geoIPOverrides),
];
const value = await alertOnError(
async () => submitConfigChange({ GeoIPOverrides: overrides }),
'Could not submit IP patches',
dispatch
);
if (value !== undefined) {
mutate();
setGeoIPOverrides({});
}
}}
>
Submit IP Patches ({Object.keys(geoIPOverrides).length})
</Button>
)}
</Paper>
<ObjectModal name={"Locate Network IP"} handleClose={() => setOpen(!open)} open={open}>
<GeoIPOverrideForm value={{ip: ip, coordinate: {lat: "37", long: "20"}}} onSubmit={onSubmit} />
<ObjectModal
name={'Locate Network IP'}
handleClose={() => setOpen(!open)}
open={open}
>
<GeoIPOverrideForm
value={{ ip: ip, coordinate: { lat: '37', long: '20' } }}
onSubmit={onSubmit}
/>
</ObjectModal>
</>
)
}
);
};

interface GeoUpdateFormProps {
open: boolean;
Expand All @@ -132,30 +172,30 @@ interface GeoUpdateFormProps {
}

const StyledTableCell = styled(TableCell)(({ theme }) => ({

[`&.${tableCellClasses.head}`]: {
backgroundColor: theme.palette.warning.main
backgroundColor: theme.palette.warning.main,
},
}));

const getIpErrorRows = async () => {
const response = await query_raw<VectorResponseData>("last_over_time(pelican_director_geoip_errors[1d])")
return response.data.result
}
const response = await query_raw<VectorResponseData>(
'last_over_time(pelican_director_geoip_errors[1d])'
);
return response.data.result;
};

const getOverriddenGeoIps = async () => {
let tries = 0
while(tries < 2) {
let tries = 0;
while (tries < 2) {
try {
const response = await getConfig()
const config = await response.json()
return {GeoIPOverrides: config.GeoIPOverrides}
} catch(e) {
tries++
await new Promise(r => setTimeout(r, (10 ** tries) * 500));

const response = await getConfig();
const config = await response.json();
return { GeoIPOverrides: config.GeoIPOverrides };
} catch (e) {
tries++;
await new Promise((r) => setTimeout(r, 10 ** tries * 500));
}
}
}
};

export default GeoIpErrorTable;
8 changes: 4 additions & 4 deletions web_ui/frontend/components/LatitudeLongitudePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,21 @@ const LatitudeLongitudePicker = ({
<label>
Latitude:
<input
type="number"
type='number'
value={latitude}
onChange={(e) => setLatitude(parseFloat(e.target.value))}
/>
</label>
<label>
Longitude:
<input
type="number"
type='number'
value={longitude}
onChange={(e) => setLongitude(parseFloat(e.target.value))}
/>
</label>
</div>
);
}
};

export default LatitudeLongitudePicker
export default LatitudeLongitudePicker;
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,31 @@ const GeoIPOverrideForm = ({ onSubmit, value }: FormProps<GeoIPOverride>) => {

const setLatitude = useCallback((latitude: number) => {
setGeoIP((geoIP) => {
return { ...geoIP, coordinate: { ...geoIP?.coordinate, lat: latitude.toString() } }
})
return {
...geoIP,
coordinate: { ...geoIP?.coordinate, lat: latitude.toString() },
};
});
}, []);

const setLongitude = useCallback((longitude: number) => {
setGeoIP((geoIP) => {
return { ...geoIP, coordinate: { ...geoIP?.coordinate, long: longitude.toString() } }
return {
...geoIP,
coordinate: { ...geoIP?.coordinate, long: longitude.toString() },
};
});
}, []);

return (
<>
<Box height={"200px"} width={"400px"} maxWidth={"100%"}>
<UpdateSinglePoint latitude={lat} longitude={long} setLatitude={setLatitude} setLongitude={setLongitude} />
<Box height={'200px'} width={'400px'} maxWidth={'100%'}>
<UpdateSinglePoint
latitude={lat}
longitude={long}
setLatitude={setLatitude}
setLongitude={setLongitude}
/>
</Box>
<Box my={2}>
<StringField
Expand Down
4 changes: 3 additions & 1 deletion web_ui/frontend/components/configuration/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ export const verifyIpAddress = (ip: string) => {
const isValidv4 =
/^(?:(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(?!$)|$)){4}$/.test(ip);
const isValidv6 =
/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/.test(ip)
/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/.test(
ip
);
return isValidv4 || isValidv6 ? undefined : 'Invalid IP Address';
};

Expand Down

0 comments on commit c1d3ef1

Please sign in to comment.