mirror of
https://github.com/fosrl/pangolin.git
synced 2025-08-02 09:05:49 +02:00
Add enable rules toggle
This commit is contained in:
parent
874c67345e
commit
9694261f3e
3 changed files with 121 additions and 44 deletions
|
@ -29,7 +29,8 @@ const updateResourceBodySchema = z
|
|||
blockAccess: z.boolean().optional(),
|
||||
proxyPort: z.number().int().min(1).max(65535).optional(),
|
||||
emailWhitelistEnabled: z.boolean().optional(),
|
||||
isBaseDomain: z.boolean().optional()
|
||||
isBaseDomain: z.boolean().optional(),
|
||||
applyRules: z.boolean().optional(),
|
||||
})
|
||||
.strict()
|
||||
.refine((data) => Object.keys(data).length > 0, {
|
||||
|
|
|
@ -131,7 +131,7 @@ export default function ReverseProxyTargets(props: {
|
|||
resolver: zodResolver(addTargetSchema),
|
||||
defaultValues: {
|
||||
ip: "",
|
||||
method: resource.http ? "http" : null,
|
||||
method: resource.http ? "http" : null
|
||||
// protocol: "TCP",
|
||||
} as z.infer<typeof addTargetSchema>
|
||||
});
|
||||
|
@ -316,17 +316,31 @@ export default function ReverseProxyTargets(props: {
|
|||
}
|
||||
|
||||
async function saveSsl(val: boolean) {
|
||||
const res = await api.post(`/resource/${params.resourceId}`, {
|
||||
ssl: val
|
||||
});
|
||||
const res = await api
|
||||
.post(`/resource/${params.resourceId}`, {
|
||||
ssl: val
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Failed to update SSL configuration",
|
||||
description: formatAxiosError(
|
||||
err,
|
||||
"An error occurred while updating the SSL configuration"
|
||||
)
|
||||
});
|
||||
});
|
||||
|
||||
setSslEnabled(val);
|
||||
updateResource({ ssl: val });
|
||||
if (res && res.status === 200) {
|
||||
setSslEnabled(val);
|
||||
updateResource({ ssl: val });
|
||||
|
||||
toast({
|
||||
title: "SSL Configuration",
|
||||
description: "SSL configuration updated successfully"
|
||||
});
|
||||
toast({
|
||||
title: "SSL Configuration",
|
||||
description: "SSL configuration updated successfully"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const columns: ColumnDef<LocalTarget>[] = [
|
||||
|
@ -652,7 +666,8 @@ export default function ReverseProxyTargets(props: {
|
|||
</Table>
|
||||
</TableContainer>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Adding more than one target above will enable load balancing.
|
||||
Adding more than one target above will enable load
|
||||
balancing.
|
||||
</p>
|
||||
</SettingsSectionBody>
|
||||
<SettingsSectionFooter>
|
||||
|
|
|
@ -56,6 +56,7 @@ import {
|
|||
SettingsSectionFooter
|
||||
} from "@app/components/Settings";
|
||||
import { ListResourceRulesResponse } from "@server/routers/resource/listResourceRules";
|
||||
import { SwitchInput } from "@app/components/SwitchInput";
|
||||
|
||||
// Schema for rule validation
|
||||
const addRuleSchema = z.object({
|
||||
|
@ -74,12 +75,13 @@ export default function ResourceRules(props: {
|
|||
}) {
|
||||
const params = use(props.params);
|
||||
const { toast } = useToast();
|
||||
const { resource } = useResourceContext();
|
||||
const { resource, updateResource } = useResourceContext();
|
||||
const api = createApiClient(useEnvContext());
|
||||
const [rules, setRules] = useState<LocalRule[]>([]);
|
||||
const [rulesToRemove, setRulesToRemove] = useState<number[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [pageLoading, setPageLoading] = useState(true);
|
||||
const [rulesEnabled, setRulesEnabled] = useState(resource.applyRules);
|
||||
|
||||
const addRuleForm = useForm({
|
||||
resolver: zodResolver(addRuleSchema),
|
||||
|
@ -180,6 +182,34 @@ export default function ResourceRules(props: {
|
|||
);
|
||||
}
|
||||
|
||||
async function saveApplyRules(val: boolean) {
|
||||
const res = await api
|
||||
.post(`/resource/${params.resourceId}`, {
|
||||
applyRules: val
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Failed to update rules",
|
||||
description: formatAxiosError(
|
||||
err,
|
||||
"An error occurred while updating rules"
|
||||
)
|
||||
});
|
||||
});
|
||||
|
||||
if (res && res.status === 200) {
|
||||
setRulesEnabled(val);
|
||||
updateResource({ applyRules: val });
|
||||
|
||||
toast({
|
||||
title: "Enable Rules",
|
||||
description: "Rule evaluation has been updated"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function saveRules() {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
@ -199,7 +229,10 @@ export default function ResourceRules(props: {
|
|||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
if (rule.match === "PATH" && !isValidUrlGlobPattern(rule.value)) {
|
||||
if (
|
||||
rule.match === "PATH" &&
|
||||
!isValidUrlGlobPattern(rule.value)
|
||||
) {
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Invalid URL path",
|
||||
|
@ -334,6 +367,25 @@ export default function ResourceRules(props: {
|
|||
|
||||
return (
|
||||
<SettingsContainer>
|
||||
<SettingsSection>
|
||||
<SettingsSectionHeader>
|
||||
<SettingsSectionTitle>Enable Rules</SettingsSectionTitle>
|
||||
<SettingsSectionDescription>
|
||||
Enable or disable rule evaluation for this resource
|
||||
</SettingsSectionDescription>
|
||||
</SettingsSectionHeader>
|
||||
<SettingsSectionBody>
|
||||
<SwitchInput
|
||||
id="rules-toggle"
|
||||
label="Enable Rules"
|
||||
defaultChecked={resource.applyRules}
|
||||
onCheckedChange={async (val) => {
|
||||
await saveApplyRules(val);
|
||||
}}
|
||||
/>
|
||||
</SettingsSectionBody>
|
||||
</SettingsSection>
|
||||
|
||||
<SettingsSection>
|
||||
<SettingsSectionHeader>
|
||||
<SettingsSectionTitle>
|
||||
|
@ -400,9 +452,11 @@ export default function ResourceRules(props: {
|
|||
<SelectItem value="CIDR">
|
||||
CIDR
|
||||
</SelectItem>
|
||||
<SelectItem value="PATH">
|
||||
PATH
|
||||
</SelectItem>
|
||||
{resource.http && (
|
||||
<SelectItem value="PATH">
|
||||
PATH
|
||||
</SelectItem>
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
@ -421,14 +475,21 @@ export default function ResourceRules(props: {
|
|||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormDescription>
|
||||
Enter CIDR or path value based
|
||||
on match type
|
||||
Enter CIDR{" "}
|
||||
{resource.http
|
||||
? "or path value"
|
||||
: ""}{" "}
|
||||
based on match type
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Button type="submit" variant="outline">
|
||||
<Button
|
||||
type="submit"
|
||||
variant="outline"
|
||||
disabled={loading || !rulesEnabled}
|
||||
>
|
||||
Add Rule
|
||||
</Button>
|
||||
</form>
|
||||
|
@ -518,35 +579,35 @@ function isValidCIDR(cidr: string): boolean {
|
|||
|
||||
function isValidUrlGlobPattern(pattern: string): boolean {
|
||||
// Remove leading slash if present
|
||||
pattern = pattern.startsWith('/') ? pattern.slice(1) : pattern;
|
||||
|
||||
pattern = pattern.startsWith("/") ? pattern.slice(1) : pattern;
|
||||
|
||||
// Empty string is not valid
|
||||
if (!pattern) {
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Split path into segments
|
||||
const segments = pattern.split('/');
|
||||
|
||||
const segments = pattern.split("/");
|
||||
|
||||
// Check each segment
|
||||
for (let i = 0; i < segments.length; i++) {
|
||||
const segment = segments[i];
|
||||
|
||||
// Empty segments are not allowed (double slashes)
|
||||
if (!segment && i !== segments.length - 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If segment contains *, it must be exactly *
|
||||
if (segment.includes('*') && segment !== '*') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for invalid characters
|
||||
if (!/^[a-zA-Z0-9_*-]*$/.test(segment)) {
|
||||
return false;
|
||||
}
|
||||
const segment = segments[i];
|
||||
|
||||
// Empty segments are not allowed (double slashes)
|
||||
if (!segment && i !== segments.length - 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If segment contains *, it must be exactly *
|
||||
if (segment.includes("*") && segment !== "*") {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for invalid characters
|
||||
if (!/^[a-zA-Z0-9_*-]*$/.test(segment)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue