hide path match and rewrite in raw resource

This commit is contained in:
miloschwartz
2025-10-16 14:30:09 -07:00
parent bca2eef2e8
commit e8a57e432c
3 changed files with 110 additions and 70 deletions

View File

@@ -63,7 +63,7 @@ const createTargetSchema = z
.enum(["exact", "prefix", "regex", "stripPrefix"]) .enum(["exact", "prefix", "regex", "stripPrefix"])
.optional() .optional()
.nullable(), .nullable(),
priority: z.number().int().min(1).max(1000) priority: z.number().int().min(1).max(1000).optional().nullable()
}) })
.strict(); .strict();
@@ -224,7 +224,7 @@ export async function createTarget(
pathMatchType: targetData.pathMatchType, pathMatchType: targetData.pathMatchType,
rewritePath: targetData.rewritePath, rewritePath: targetData.rewritePath,
rewritePathType: targetData.rewritePathType, rewritePathType: targetData.rewritePathType,
priority: targetData.priority priority: targetData.priority || 100
}) })
.returning(); .returning();

View File

@@ -135,7 +135,7 @@ const addTargetSchema = z
.enum(["exact", "prefix", "regex", "stripPrefix"]) .enum(["exact", "prefix", "regex", "stripPrefix"])
.optional() .optional()
.nullable(), .nullable(),
priority: z.number().int().min(1).max(1000) priority: z.number().int().min(1).max(1000).optional()
}) })
.refine( .refine(
(data) => { (data) => {
@@ -429,17 +429,19 @@ export default function ReverseProxyTargets(props: {
}, [isAdvancedMode]); }, [isAdvancedMode]);
function addNewTarget() { function addNewTarget() {
const isHttp = resource.http;
const newTarget: LocalTarget = { const newTarget: LocalTarget = {
targetId: -Date.now(), // Use negative timestamp as temporary ID targetId: -Date.now(), // Use negative timestamp as temporary ID
ip: "", ip: "",
method: resource.http ? "http" : null, method: isHttp ? "http" : null,
port: 0, port: 0,
siteId: sites.length > 0 ? sites[0].siteId : 0, siteId: sites.length > 0 ? sites[0].siteId : 0,
path: null, path: isHttp ? null : null,
pathMatchType: null, pathMatchType: isHttp ? null : null,
rewritePath: null, rewritePath: isHttp ? null : null,
rewritePathType: null, rewritePathType: isHttp ? null : null,
priority: 100, priority: isHttp ? 100 : 100,
enabled: true, enabled: true,
resourceId: resource.resourceId, resourceId: resource.resourceId,
hcEnabled: false, hcEnabled: false,
@@ -515,25 +517,31 @@ export default function ReverseProxyTargets(props: {
try { try {
setTargetsLoading(true); setTargetsLoading(true);
const response = await api.post< const data: any = {
AxiosResponse<CreateTargetResponse>
>(`/target`, {
resourceId: resource.resourceId, resourceId: resource.resourceId,
siteId: target.siteId, siteId: target.siteId,
ip: target.ip, ip: target.ip,
method: target.method, method: target.method,
port: target.port, port: target.port,
path: target.path,
pathMatchType: target.pathMatchType,
rewritePath: target.rewritePath,
rewritePathType: target.rewritePathType,
priority: target.priority,
enabled: target.enabled, enabled: target.enabled,
hcEnabled: target.hcEnabled, hcEnabled: target.hcEnabled,
hcPath: target.hcPath, hcPath: target.hcPath,
hcInterval: target.hcInterval, hcInterval: target.hcInterval,
hcTimeout: target.hcTimeout hcTimeout: target.hcTimeout
}); };
// Only include path-related fields for HTTP resources
if (resource.http) {
data.path = target.path;
data.pathMatchType = target.pathMatchType;
data.rewritePath = target.rewritePath;
data.rewritePathType = target.rewritePathType;
data.priority = target.priority;
}
const response = await api.post<
AxiosResponse<CreateTargetResponse>
>(`/target`, data);
if (response.status === 200) { if (response.status === 200) {
// Update the target with the new ID and remove the new flag // Update the target with the new ID and remove the new flag
@@ -616,19 +624,20 @@ export default function ReverseProxyTargets(props: {
// } // }
const site = sites.find((site) => site.siteId === data.siteId); const site = sites.find((site) => site.siteId === data.siteId);
const isHttp = resource.http;
const newTarget: LocalTarget = { const newTarget: LocalTarget = {
...data, ...data,
path: data.path || null, path: isHttp ? (data.path || null) : null,
pathMatchType: data.pathMatchType || null, pathMatchType: isHttp ? (data.pathMatchType || null) : null,
rewritePath: data.rewritePath || null, rewritePath: isHttp ? (data.rewritePath || null) : null,
rewritePathType: data.rewritePathType || null, rewritePathType: isHttp ? (data.rewritePathType || null) : null,
siteType: site?.type || null, siteType: site?.type || null,
enabled: true, enabled: true,
targetId: new Date().getTime(), targetId: new Date().getTime(),
new: true, new: true,
resourceId: resource.resourceId, resourceId: resource.resourceId,
priority: 100, priority: isHttp ? (data.priority || 100) : 100,
hcEnabled: false, hcEnabled: false,
hcPath: null, hcPath: null,
hcMethod: null, hcMethod: null,
@@ -720,7 +729,7 @@ export default function ReverseProxyTargets(props: {
// Save targets // Save targets
for (const target of targets) { for (const target of targets) {
const data = { const data: any = {
ip: target.ip, ip: target.ip,
port: target.port, port: target.port,
method: target.method, method: target.method,
@@ -736,14 +745,18 @@ export default function ReverseProxyTargets(props: {
hcHeaders: target.hcHeaders || null, hcHeaders: target.hcHeaders || null,
hcFollowRedirects: target.hcFollowRedirects || null, hcFollowRedirects: target.hcFollowRedirects || null,
hcMethod: target.hcMethod || null, hcMethod: target.hcMethod || null,
hcStatus: target.hcStatus || null, hcStatus: target.hcStatus || null
path: target.path,
pathMatchType: target.pathMatchType,
rewritePath: target.rewritePath,
rewritePathType: target.rewritePathType,
priority: target.priority
}; };
// Only include path-related fields for HTTP resources
if (resource.http) {
data.path = target.path;
data.pathMatchType = target.pathMatchType;
data.rewritePath = target.rewritePath;
data.rewritePathType = target.rewritePathType;
data.priority = target.priority;
}
if (target.new) { if (target.new) {
const res = await api.put< const res = await api.put<
AxiosResponse<CreateTargetResponse> AxiosResponse<CreateTargetResponse>
@@ -815,6 +828,7 @@ export default function ReverseProxyTargets(props: {
const getColumns = (): ColumnDef<LocalTarget>[] => { const getColumns = (): ColumnDef<LocalTarget>[] => {
const baseColumns: ColumnDef<LocalTarget>[] = []; const baseColumns: ColumnDef<LocalTarget>[] = [];
const isHttp = resource.http;
const priorityColumn: ColumnDef<LocalTarget> = { const priorityColumn: ColumnDef<LocalTarget> = {
id: "priority", id: "priority",
@@ -1047,7 +1061,7 @@ export default function ReverseProxyTargets(props: {
variant="ghost" variant="ghost"
role="combobox" role="combobox"
className={cn( className={cn(
"w-[180px] justify-between text-sm font-medium border-r pr-4 rounded-none h-8 hover:bg-transparent", "w-[180px] justify-between text-sm border-r pr-4 rounded-none h-8 hover:bg-transparent",
!row.original.siteId && !row.original.siteId &&
"text-muted-foreground" "text-muted-foreground"
)} )}
@@ -1129,7 +1143,7 @@ export default function ReverseProxyTargets(props: {
<Input <Input
defaultValue={row.original.ip} defaultValue={row.original.ip}
placeholder="IP / Hostname" placeholder="IP / Hostname"
className="flex-1 min-w-[120px] border-none placeholder-gray-400" className="flex-1 min-w-[120px] pl-0 border-none placeholder-gray-400"
onBlur={(e) => { onBlur={(e) => {
const input = e.target.value.trim(); const input = e.target.value.trim();
const hasProtocol = const hasProtocol =
@@ -1313,15 +1327,20 @@ export default function ReverseProxyTargets(props: {
}; };
if (isAdvancedMode) { if (isAdvancedMode) {
return [ const columns = [
matchPathColumn,
addressColumn, addressColumn,
rewritePathColumn,
priorityColumn,
healthCheckColumn, healthCheckColumn,
enabledColumn, enabledColumn,
actionsColumn actionsColumn
]; ];
// Only include path-related columns for HTTP resources
if (isHttp) {
columns.unshift(matchPathColumn);
columns.splice(3, 0, rewritePathColumn, priorityColumn);
}
return columns;
} else { } else {
return [ return [
addressColumn, addressColumn,
@@ -1450,7 +1469,7 @@ export default function ReverseProxyTargets(props: {
/> />
<label <label
htmlFor="advanced-mode-toggle" htmlFor="advanced-mode-toggle"
className="text-sm font-medium" className="text-sm"
> >
{t("advancedMode")} {t("advancedMode")}
</label> </label>

View File

@@ -148,7 +148,7 @@ const addTargetSchema = z
.enum(["exact", "prefix", "regex", "stripPrefix"]) .enum(["exact", "prefix", "regex", "stripPrefix"])
.optional() .optional()
.nullable(), .nullable(),
priority: z.number().int().min(1).max(1000) priority: z.number().int().min(1).max(1000).optional()
}) })
.refine( .refine(
(data) => { (data) => {
@@ -268,17 +268,19 @@ export default function Page() {
}, [isAdvancedMode]); }, [isAdvancedMode]);
function addNewTarget() { function addNewTarget() {
const isHttp = baseForm.watch("http");
const newTarget: LocalTarget = { const newTarget: LocalTarget = {
targetId: -Date.now(), // Use negative timestamp as temporary ID targetId: -Date.now(), // Use negative timestamp as temporary ID
ip: "", ip: "",
method: baseForm.watch("http") ? "http" : null, method: isHttp ? "http" : null,
port: 0, port: 0,
siteId: sites.length > 0 ? sites[0].siteId : 0, siteId: sites.length > 0 ? sites[0].siteId : 0,
path: null, path: isHttp ? null : null,
pathMatchType: null, pathMatchType: isHttp ? null : null,
rewritePath: null, rewritePath: isHttp ? null : null,
rewritePathType: null, rewritePathType: isHttp ? null : null,
priority: 100, priority: isHttp ? 100 : 100,
enabled: true, enabled: true,
resourceId: 0, resourceId: 0,
hcEnabled: false, hcEnabled: false,
@@ -352,7 +354,7 @@ export default function Page() {
pathMatchType: null, pathMatchType: null,
rewritePath: null, rewritePath: null,
rewritePathType: null, rewritePathType: null,
priority: 100 priority: baseForm.watch("http") ? 100 : undefined
} as z.infer<typeof addTargetSchema> } as z.infer<typeof addTargetSchema>
}); });
@@ -362,7 +364,8 @@ export default function Page() {
return targets.every((target) => { return targets.every((target) => {
try { try {
addTargetSchema.parse({ const isHttp = baseForm.watch("http");
const targetData: any = {
ip: target.ip, ip: target.ip,
method: target.method, method: target.method,
port: target.port, port: target.port,
@@ -370,9 +373,15 @@ export default function Page() {
path: target.path, path: target.path,
pathMatchType: target.pathMatchType, pathMatchType: target.pathMatchType,
rewritePath: target.rewritePath, rewritePath: target.rewritePath,
rewritePathType: target.rewritePathType, rewritePathType: target.rewritePathType
priority: target.priority };
});
// Only include priority for HTTP resources
if (isHttp) {
targetData.priority = target.priority;
}
addTargetSchema.parse(targetData);
return true; return true;
} catch { } catch {
return false; return false;
@@ -436,18 +445,20 @@ export default function Page() {
const site = sites.find((site) => site.siteId === data.siteId); const site = sites.find((site) => site.siteId === data.siteId);
const isHttp = baseForm.watch("http");
const newTarget: LocalTarget = { const newTarget: LocalTarget = {
...data, ...data,
path: data.path || null, path: isHttp ? (data.path || null) : null,
pathMatchType: data.pathMatchType || null, pathMatchType: isHttp ? (data.pathMatchType || null) : null,
rewritePath: data.rewritePath || null, rewritePath: isHttp ? (data.rewritePath || null) : null,
rewritePathType: data.rewritePathType || null, rewritePathType: isHttp ? (data.rewritePathType || null) : null,
siteType: site?.type || null, siteType: site?.type || null,
enabled: true, enabled: true,
targetId: new Date().getTime(), targetId: new Date().getTime(),
new: true, new: true,
resourceId: 0, // Will be set when resource is created resourceId: 0, // Will be set when resource is created
priority: 100, // Default priority priority: isHttp ? (data.priority || 100) : 100, // Default priority
hcEnabled: false, hcEnabled: false,
hcPath: null, hcPath: null,
hcMethod: null, hcMethod: null,
@@ -473,7 +484,7 @@ export default function Page() {
pathMatchType: null, pathMatchType: null,
rewritePath: null, rewritePath: null,
rewritePathType: null, rewritePathType: null,
priority: 100 priority: isHttp ? 100 : undefined
}); });
} }
@@ -564,7 +575,7 @@ export default function Page() {
if (targets.length > 0) { if (targets.length > 0) {
try { try {
for (const target of targets) { for (const target of targets) {
const data = { const data: any = {
ip: target.ip, ip: target.ip,
port: target.port, port: target.port,
method: target.method, method: target.method,
@@ -581,14 +592,18 @@ export default function Page() {
hcPort: target.hcPort || null, hcPort: target.hcPort || null,
hcFollowRedirects: hcFollowRedirects:
target.hcFollowRedirects || null, target.hcFollowRedirects || null,
hcStatus: target.hcStatus || null, hcStatus: target.hcStatus || null
path: target.path,
pathMatchType: target.pathMatchType,
rewritePath: target.rewritePath,
rewritePathType: target.rewritePathType,
priority: target.priority
}; };
// Only include path-related fields for HTTP resources
if (isHttp) {
data.path = target.path;
data.pathMatchType = target.pathMatchType;
data.rewritePath = target.rewritePath;
data.rewritePathType = target.rewritePathType;
data.priority = target.priority;
}
await api.put(`/resource/${id}/target`, data); await api.put(`/resource/${id}/target`, data);
} }
} catch (targetError) { } catch (targetError) {
@@ -730,6 +745,7 @@ export default function Page() {
const getColumns = (): ColumnDef<LocalTarget>[] => { const getColumns = (): ColumnDef<LocalTarget>[] => {
const baseColumns: ColumnDef<LocalTarget>[] = []; const baseColumns: ColumnDef<LocalTarget>[] = [];
const isHttp = baseForm.watch("http");
const priorityColumn: ColumnDef<LocalTarget> = { const priorityColumn: ColumnDef<LocalTarget> = {
id: "priority", id: "priority",
@@ -962,7 +978,7 @@ export default function Page() {
variant="ghost" variant="ghost"
role="combobox" role="combobox"
className={cn( className={cn(
"w-[180px] justify-between text-sm font-medium border-r pr-4 rounded-none h-8 hover:bg-transparent", "w-[180px] justify-between text-sm border-r pr-4 rounded-none h-8 hover:bg-transparent",
!row.original.siteId && !row.original.siteId &&
"text-muted-foreground" "text-muted-foreground"
)} )}
@@ -1027,7 +1043,7 @@ export default function Page() {
}) })
} }
> >
<SelectTrigger className="h-8 px-2 w-[70px] text-sm font-normal border-none bg-transparent shadow-none focus:ring-0 focus:outline-none focus-visible:ring-0 data-[state=open]:bg-transparent"> <SelectTrigger className="h-8 px-2 w-[70px] border-none bg-transparent shadow-none focus:ring-0 focus:outline-none focus-visible:ring-0 data-[state=open]:bg-transparent">
{row.original.method || "http"} {row.original.method || "http"}
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@@ -1044,7 +1060,7 @@ export default function Page() {
<Input <Input
defaultValue={row.original.ip} defaultValue={row.original.ip}
placeholder="IP / Hostname" placeholder="IP / Hostname"
className="flex-1 min-w-[120px] border-none placeholder-gray-400" className="flex-1 min-w-[120px] pl-0 border-none placeholder-gray-400"
onBlur={(e) => { onBlur={(e) => {
const input = e.target.value.trim(); const input = e.target.value.trim();
const hasProtocol = const hasProtocol =
@@ -1228,15 +1244,20 @@ export default function Page() {
}; };
if (isAdvancedMode) { if (isAdvancedMode) {
return [ const columns = [
matchPathColumn,
addressColumn, addressColumn,
rewritePathColumn,
priorityColumn,
healthCheckColumn, healthCheckColumn,
enabledColumn, enabledColumn,
actionsColumn actionsColumn
]; ];
// Only include path-related columns for HTTP resources
if (isHttp) {
columns.unshift(matchPathColumn);
columns.splice(3, 0, rewritePathColumn, priorityColumn);
}
return columns;
} else { } else {
return [ return [
addressColumn, addressColumn,
@@ -1681,7 +1702,7 @@ export default function Page() {
/> />
<label <label
htmlFor="advanced-mode-toggle" htmlFor="advanced-mode-toggle"
className="text-sm font-medium" className="text-sm"
> >
{t("advancedMode")} {t("advancedMode")}
</label> </label>