Cleaning up some react

This commit is contained in:
Owen
2026-05-26 16:53:22 -07:00
parent 6ea4aa1920
commit cc8c89eeae
2 changed files with 184 additions and 109 deletions

View File

@@ -6,9 +6,7 @@ import { Input } from "@/components/ui/input";
import { import {
Select, Select,
SelectContent, SelectContent,
SelectGroup,
SelectItem, SelectItem,
SelectLabel,
SelectTrigger, SelectTrigger,
SelectValue SelectValue
} from "@/components/ui/select"; } from "@/components/ui/select";
@@ -36,7 +34,6 @@ import {
import { import {
Table, Table,
TableBody, TableBody,
TableCaption,
TableCell, TableCell,
TableHead, TableHead,
TableHeader, TableHeader,
@@ -55,18 +52,11 @@ import {
SettingsSectionTitle, SettingsSectionTitle,
SettingsSectionDescription, SettingsSectionDescription,
SettingsSectionBody, SettingsSectionBody,
SettingsSectionFooter, SettingsSectionFooter
SettingsSectionForm
} from "@app/components/Settings"; } from "@app/components/Settings";
import { ListResourceRulesResponse } from "@server/routers/resource/listResourceRules"; import { ListResourceRulesResponse } from "@server/routers/resource/listResourceRules";
import { SwitchInput } from "@app/components/SwitchInput"; import { SwitchInput } from "@app/components/SwitchInput";
import { Alert, AlertDescription, AlertTitle } from "@app/components/ui/alert";
import { ArrowUpDown, Check, InfoIcon, X, ChevronsUpDown } from "lucide-react"; import { ArrowUpDown, Check, InfoIcon, X, ChevronsUpDown } from "lucide-react";
import {
InfoSection,
InfoSections,
InfoSectionTitle
} from "@app/components/InfoSection";
import { InfoPopup } from "@app/components/ui/info-popup"; import { InfoPopup } from "@app/components/ui/info-popup";
import { import {
isValidCIDR, isValidCIDR,
@@ -78,7 +68,11 @@ import { useRouter } from "next/navigation";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { COUNTRIES } from "@server/db/countries"; import { COUNTRIES } from "@server/db/countries";
import { MAJOR_ASNS } from "@server/db/asns"; import { MAJOR_ASNS } from "@server/db/asns";
import { REGIONS, getRegionNameById, isValidRegionId } from "@server/db/regions"; import {
REGIONS,
getRegionNameById,
isValidRegionId
} from "@server/db/regions";
import { import {
Command, Command,
CommandEmpty, CommandEmpty,
@@ -109,25 +103,23 @@ type LocalRule = ArrayElement<ListResourceRulesResponse["rules"]> & {
export default function ResourceRules(props: { export default function ResourceRules(props: {
params: Promise<{ resourceId: number }>; params: Promise<{ resourceId: number }>;
}) { }) {
const params = use(props.params);
const { resource, updateResource } = useResourceContext(); const { resource, updateResource } = useResourceContext();
const api = createApiClient(useEnvContext()); const api = createApiClient(useEnvContext());
const [rules, setRules] = useState<LocalRule[]>([]); const [rules, setRules] = useState<LocalRule[]>([]);
const [rulesToRemove, setRulesToRemove] = useState<number[]>([]); const [rulesToRemove, setRulesToRemove] = useState<number[]>([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [pageLoading, setPageLoading] = useState(true); const [pageLoading, setPageLoading] = useState(true);
const [rulesEnabled, setRulesEnabled] = useState(resource.applyRules ?? false); const [rulesEnabled, setRulesEnabled] = useState(
resource.applyRules ?? false
);
useEffect(() => { useEffect(() => {
setRulesEnabled(resource.applyRules); setRulesEnabled(resource.applyRules);
}, [resource.applyRules]); }, [resource.applyRules]);
const [openCountrySelect, setOpenCountrySelect] = useState(false);
const [countrySelectValue, setCountrySelectValue] = useState("");
const [openAddRuleCountrySelect, setOpenAddRuleCountrySelect] = const [openAddRuleCountrySelect, setOpenAddRuleCountrySelect] =
useState(false); useState(false);
const [openAddRuleAsnSelect, setOpenAddRuleAsnSelect] = const [openAddRuleAsnSelect, setOpenAddRuleAsnSelect] = useState(false);
useState(false);
const [openAddRuleRegionSelect, setOpenAddRuleRegionSelect] = const [openAddRuleRegionSelect, setOpenAddRuleRegionSelect] =
useState(false); useState(false);
const router = useRouter(); const router = useRouter();
@@ -157,7 +149,10 @@ export default function ResourceRules(props: {
resolver: zodResolver(addRuleSchema), resolver: zodResolver(addRuleSchema),
defaultValues: { defaultValues: {
action: "ACCEPT", action: "ACCEPT",
match: "PATH", match:
resource.http && resource.browserAccessType == "http"
? "PATH"
: "IP",
value: "" value: ""
} }
}); });
@@ -270,16 +265,12 @@ export default function ResourceRules(props: {
setLoading(false); setLoading(false);
return; return;
} }
if ( if (data.match === "REGION" && !isValidRegionId(data.value)) {
data.match === "REGION" &&
!isValidRegionId(data.value)
) {
toast({ toast({
variant: "destructive", variant: "destructive",
title: t("rulesErrorInvalidRegion"), title: t("rulesErrorInvalidRegion"),
description: description:
t("rulesErrorInvalidRegionDescription") || t("rulesErrorInvalidRegionDescription") || "Invalid region."
"Invalid region."
}); });
setLoading(false); setLoading(false);
return; return;
@@ -564,12 +555,24 @@ export default function ResourceRules(props: {
<Select <Select
defaultValue={row.original.match} defaultValue={row.original.match}
onValueChange={( onValueChange={(
value: "CIDR" | "IP" | "PATH" | "COUNTRY" | "ASN" | "REGION" value:
| "CIDR"
| "IP"
| "PATH"
| "COUNTRY"
| "ASN"
| "REGION"
) => ) =>
updateRule(row.original.ruleId, { updateRule(row.original.ruleId, {
match: value, match: value,
value: value:
value === "COUNTRY" ? "US" : value === "ASN" ? "AS15169" : value === "REGION" ? "021" : row.original.value value === "COUNTRY"
? "US"
: value === "ASN"
? "AS15169"
: value === "REGION"
? "021"
: row.original.value
}) })
} }
> >
@@ -577,7 +580,12 @@ export default function ResourceRules(props: {
<SelectValue /> <SelectValue />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="PATH">{RuleMatch.PATH}</SelectItem> {resource.http &&
resource.browserAccessType == "http" && (
<SelectItem value="PATH">
{RuleMatch.PATH}
</SelectItem>
)}
<SelectItem value="IP">{RuleMatch.IP}</SelectItem> <SelectItem value="IP">{RuleMatch.IP}</SelectItem>
<SelectItem value="CIDR">{RuleMatch.CIDR}</SelectItem> <SelectItem value="CIDR">{RuleMatch.CIDR}</SelectItem>
{isMaxmindAvailable && ( {isMaxmindAvailable && (
@@ -669,14 +677,14 @@ export default function ResourceRules(props: {
> >
{row.original.value {row.original.value
? (() => { ? (() => {
const found = MAJOR_ASNS.find( const found = MAJOR_ASNS.find(
(asn) => (asn) =>
asn.code === asn.code ===
row.original.value row.original.value
); );
return found return found
? `${found.name} (${row.original.value})` ? `${found.name} (${row.original.value})`
: `Custom (${row.original.value})`; : `Custom (${row.original.value})`;
})() })()
: "Select ASN"} : "Select ASN"}
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" /> <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
@@ -755,7 +763,9 @@ export default function ResourceRules(props: {
className="min-w-[200px] justify-between" className="min-w-[200px] justify-between"
> >
{(() => { {(() => {
const regionName = getRegionNameById(row.original.value); const regionName = getRegionNameById(
row.original.value
);
if (!regionName) { if (!regionName) {
return t("selectRegion"); return t("selectRegion");
} }
@@ -774,7 +784,10 @@ export default function ResourceRules(props: {
{t("noRegionFound")} {t("noRegionFound")}
</CommandEmpty> </CommandEmpty>
{REGIONS.map((continent) => ( {REGIONS.map((continent) => (
<CommandGroup key={continent.id} heading={t(continent.name)}> <CommandGroup
key={continent.id}
heading={t(continent.name)}
>
<CommandItem <CommandItem
value={continent.id} value={continent.id}
keywords={[ keywords={[
@@ -790,38 +803,48 @@ export default function ResourceRules(props: {
> >
<Check <Check
className={`mr-2 h-4 w-4 ${ className={`mr-2 h-4 w-4 ${
row.original.value === continent.id row.original.value ===
continent.id
? "opacity-100" ? "opacity-100"
: "opacity-0" : "opacity-0"
}`} }`}
/> />
{t(continent.name)} ({continent.id}) {t(continent.name)} (
{continent.id})
</CommandItem> </CommandItem>
{continent.includes.map((subregion) => ( {continent.includes.map(
<CommandItem (subregion) => (
key={subregion.id} <CommandItem
value={subregion.id} key={subregion.id}
keywords={[ value={subregion.id}
t(subregion.name), keywords={[
subregion.id t(subregion.name),
]} subregion.id
onSelect={() => { ]}
updateRule( onSelect={() => {
row.original.ruleId, updateRule(
{ value: subregion.id } row.original
); .ruleId,
}} {
> value: subregion.id
<Check }
className={`mr-2 h-4 w-4 ${ );
row.original.value === subregion.id }}
? "opacity-100" >
: "opacity-0" <Check
}`} className={`mr-2 h-4 w-4 ${
/> row.original
{t(subregion.name)} ({subregion.id}) .value ===
</CommandItem> subregion.id
))} ? "opacity-100"
: "opacity-0"
}`}
/>
{t(subregion.name)} (
{subregion.id})
</CommandItem>
)
)}
</CommandGroup> </CommandGroup>
))} ))}
</CommandList> </CommandList>
@@ -1018,13 +1041,15 @@ export default function ResourceRules(props: {
<SelectValue /> <SelectValue />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
{resource.http && ( {resource.http &&
<SelectItem value="PATH"> resource.browserAccessType ==
{ "http" && (
RuleMatch.PATH <SelectItem value="PATH">
} {
</SelectItem> RuleMatch.PATH
)} }
</SelectItem>
)}
<SelectItem value="IP"> <SelectItem value="IP">
{RuleMatch.IP} {RuleMatch.IP}
</SelectItem> </SelectItem>
@@ -1311,8 +1336,8 @@ export default function ResourceRules(props: {
</PopoverContent> </PopoverContent>
</Popover> </Popover>
) : addRuleForm.watch( ) : addRuleForm.watch(
"match" "match"
) === "REGION" ? ( ) === "REGION" ? (
<Popover <Popover
open={ open={
openAddRuleRegionSelect openAddRuleRegionSelect
@@ -1334,8 +1359,16 @@ export default function ResourceRules(props: {
> >
{field.value {field.value
? (() => { ? (() => {
const regionName = getRegionNameById(field.value); const regionName =
const translatedName = regionName ? t(regionName) : field.value; getRegionNameById(
field.value
);
const translatedName =
regionName
? t(
regionName
)
: field.value;
return `${translatedName} (${field.value})`; return `${translatedName} (${field.value})`;
})() })()
: t( : t(
@@ -1357,43 +1390,31 @@ export default function ResourceRules(props: {
"noRegionFound" "noRegionFound"
)} )}
</CommandEmpty> </CommandEmpty>
{REGIONS.map((continent) => ( {REGIONS.map(
<CommandGroup key={continent.id} heading={t(continent.name)}> (
<CommandItem continent
value={continent.id} ) => (
keywords={[ <CommandGroup
t(continent.name), key={
continent.id continent.id
]} }
onSelect={() => { heading={t(
field.onChange( continent.name
continent.id )}
);
setOpenAddRuleRegionSelect(
false
);
}}
> >
<Check
className={`mr-2 h-4 w-4 ${
field.value === continent.id
? "opacity-100"
: "opacity-0"
}`}
/>
{t(continent.name)} ({continent.id})
</CommandItem>
{continent.includes.map((subregion) => (
<CommandItem <CommandItem
key={subregion.id} value={
value={subregion.id} continent.id
}
keywords={[ keywords={[
t(subregion.name), t(
subregion.id continent.name
),
continent.id
]} ]}
onSelect={() => { onSelect={() => {
field.onChange( field.onChange(
subregion.id continent.id
); );
setOpenAddRuleRegionSelect( setOpenAddRuleRegionSelect(
false false
@@ -1402,16 +1423,71 @@ export default function ResourceRules(props: {
> >
<Check <Check
className={`mr-2 h-4 w-4 ${ className={`mr-2 h-4 w-4 ${
field.value === subregion.id field.value ===
continent.id
? "opacity-100" ? "opacity-100"
: "opacity-0" : "opacity-0"
}`} }`}
/> />
{t(subregion.name)} ({subregion.id}) {t(
continent.name
)}{" "}
(
{
continent.id
}
)
</CommandItem> </CommandItem>
))} {continent.includes.map(
</CommandGroup> (
))} subregion
) => (
<CommandItem
key={
subregion.id
}
value={
subregion.id
}
keywords={[
t(
subregion.name
),
subregion.id
]}
onSelect={() => {
field.onChange(
subregion.id
);
setOpenAddRuleRegionSelect(
false
);
}}
>
<Check
className={`mr-2 h-4 w-4 ${
field.value ===
subregion.id
? "opacity-100"
: "opacity-0"
}`}
/>
{t(
subregion.name
)}{" "}
(
{
subregion.id
}
)
</CommandItem>
)
)}
</CommandGroup>
)
)}
</CommandList> </CommandList>
</Command> </Command>
</PopoverContent> </PopoverContent>

View File

@@ -19,7 +19,6 @@ import { Laptop, LogOut, Moon, Sun, Smartphone, Trash2 } from "lucide-react";
import { useTheme } from "next-themes"; import { useTheme } from "next-themes";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import Link from "next/link"; import Link from "next/link";
import { build } from "@server/build";
import { useState } from "react"; import { useState } from "react";
import { useUserContext } from "@app/hooks/useUserContext"; import { useUserContext } from "@app/hooks/useUserContext";
import Disable2FaForm from "./Disable2FaForm"; import Disable2FaForm from "./Disable2FaForm";