diff --git a/server/routers/target/createTarget.ts b/server/routers/target/createTarget.ts index 0752c93c..3d9cf2de 100644 --- a/server/routers/target/createTarget.ts +++ b/server/routers/target/createTarget.ts @@ -63,7 +63,7 @@ const createTargetSchema = z .enum(["exact", "prefix", "regex", "stripPrefix"]) .optional() .nullable(), - priority: z.number().int().min(1).max(1000) + priority: z.number().int().min(1).max(1000).optional().nullable() }) .strict(); @@ -224,7 +224,7 @@ export async function createTarget( pathMatchType: targetData.pathMatchType, rewritePath: targetData.rewritePath, rewritePathType: targetData.rewritePathType, - priority: targetData.priority + priority: targetData.priority || 100 }) .returning(); diff --git a/src/app/[orgId]/settings/resources/[niceId]/proxy/page.tsx b/src/app/[orgId]/settings/resources/[niceId]/proxy/page.tsx index 6a3a9834..ed52ae2b 100644 --- a/src/app/[orgId]/settings/resources/[niceId]/proxy/page.tsx +++ b/src/app/[orgId]/settings/resources/[niceId]/proxy/page.tsx @@ -135,7 +135,7 @@ const addTargetSchema = z .enum(["exact", "prefix", "regex", "stripPrefix"]) .optional() .nullable(), - priority: z.number().int().min(1).max(1000) + priority: z.number().int().min(1).max(1000).optional() }) .refine( (data) => { @@ -429,17 +429,19 @@ export default function ReverseProxyTargets(props: { }, [isAdvancedMode]); function addNewTarget() { + const isHttp = resource.http; + const newTarget: LocalTarget = { targetId: -Date.now(), // Use negative timestamp as temporary ID ip: "", - method: resource.http ? "http" : null, + method: isHttp ? "http" : null, port: 0, siteId: sites.length > 0 ? sites[0].siteId : 0, - path: null, - pathMatchType: null, - rewritePath: null, - rewritePathType: null, - priority: 100, + path: isHttp ? null : null, + pathMatchType: isHttp ? null : null, + rewritePath: isHttp ? null : null, + rewritePathType: isHttp ? null : null, + priority: isHttp ? 100 : 100, enabled: true, resourceId: resource.resourceId, hcEnabled: false, @@ -515,25 +517,31 @@ export default function ReverseProxyTargets(props: { try { setTargetsLoading(true); - const response = await api.post< - AxiosResponse - >(`/target`, { + const data: any = { resourceId: resource.resourceId, siteId: target.siteId, ip: target.ip, method: target.method, port: target.port, - path: target.path, - pathMatchType: target.pathMatchType, - rewritePath: target.rewritePath, - rewritePathType: target.rewritePathType, - priority: target.priority, enabled: target.enabled, hcEnabled: target.hcEnabled, hcPath: target.hcPath, hcInterval: target.hcInterval, 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 + >(`/target`, data); if (response.status === 200) { // 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 isHttp = resource.http; const newTarget: LocalTarget = { ...data, - path: data.path || null, - pathMatchType: data.pathMatchType || null, - rewritePath: data.rewritePath || null, - rewritePathType: data.rewritePathType || null, + path: isHttp ? (data.path || null) : null, + pathMatchType: isHttp ? (data.pathMatchType || null) : null, + rewritePath: isHttp ? (data.rewritePath || null) : null, + rewritePathType: isHttp ? (data.rewritePathType || null) : null, siteType: site?.type || null, enabled: true, targetId: new Date().getTime(), new: true, resourceId: resource.resourceId, - priority: 100, + priority: isHttp ? (data.priority || 100) : 100, hcEnabled: false, hcPath: null, hcMethod: null, @@ -720,7 +729,7 @@ export default function ReverseProxyTargets(props: { // Save targets for (const target of targets) { - const data = { + const data: any = { ip: target.ip, port: target.port, method: target.method, @@ -736,14 +745,18 @@ export default function ReverseProxyTargets(props: { hcHeaders: target.hcHeaders || null, hcFollowRedirects: target.hcFollowRedirects || null, hcMethod: target.hcMethod || null, - hcStatus: target.hcStatus || null, - path: target.path, - pathMatchType: target.pathMatchType, - rewritePath: target.rewritePath, - rewritePathType: target.rewritePathType, - priority: target.priority + hcStatus: target.hcStatus || null }; + // 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) { const res = await api.put< AxiosResponse @@ -815,6 +828,7 @@ export default function ReverseProxyTargets(props: { const getColumns = (): ColumnDef[] => { const baseColumns: ColumnDef[] = []; + const isHttp = resource.http; const priorityColumn: ColumnDef = { id: "priority", @@ -1047,7 +1061,7 @@ export default function ReverseProxyTargets(props: { variant="ghost" role="combobox" 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 && "text-muted-foreground" )} @@ -1129,7 +1143,7 @@ export default function ReverseProxyTargets(props: { { const input = e.target.value.trim(); const hasProtocol = @@ -1313,15 +1327,20 @@ export default function ReverseProxyTargets(props: { }; if (isAdvancedMode) { - return [ - matchPathColumn, + const columns = [ addressColumn, - rewritePathColumn, - priorityColumn, healthCheckColumn, enabledColumn, actionsColumn ]; + + // Only include path-related columns for HTTP resources + if (isHttp) { + columns.unshift(matchPathColumn); + columns.splice(3, 0, rewritePathColumn, priorityColumn); + } + + return columns; } else { return [ addressColumn, @@ -1450,7 +1469,7 @@ export default function ReverseProxyTargets(props: { /> diff --git a/src/app/[orgId]/settings/resources/create/page.tsx b/src/app/[orgId]/settings/resources/create/page.tsx index a5782aaf..ab5cf500 100644 --- a/src/app/[orgId]/settings/resources/create/page.tsx +++ b/src/app/[orgId]/settings/resources/create/page.tsx @@ -148,7 +148,7 @@ const addTargetSchema = z .enum(["exact", "prefix", "regex", "stripPrefix"]) .optional() .nullable(), - priority: z.number().int().min(1).max(1000) + priority: z.number().int().min(1).max(1000).optional() }) .refine( (data) => { @@ -268,17 +268,19 @@ export default function Page() { }, [isAdvancedMode]); function addNewTarget() { + const isHttp = baseForm.watch("http"); + const newTarget: LocalTarget = { targetId: -Date.now(), // Use negative timestamp as temporary ID ip: "", - method: baseForm.watch("http") ? "http" : null, + method: isHttp ? "http" : null, port: 0, siteId: sites.length > 0 ? sites[0].siteId : 0, - path: null, - pathMatchType: null, - rewritePath: null, - rewritePathType: null, - priority: 100, + path: isHttp ? null : null, + pathMatchType: isHttp ? null : null, + rewritePath: isHttp ? null : null, + rewritePathType: isHttp ? null : null, + priority: isHttp ? 100 : 100, enabled: true, resourceId: 0, hcEnabled: false, @@ -352,7 +354,7 @@ export default function Page() { pathMatchType: null, rewritePath: null, rewritePathType: null, - priority: 100 + priority: baseForm.watch("http") ? 100 : undefined } as z.infer }); @@ -362,7 +364,8 @@ export default function Page() { return targets.every((target) => { try { - addTargetSchema.parse({ + const isHttp = baseForm.watch("http"); + const targetData: any = { ip: target.ip, method: target.method, port: target.port, @@ -370,9 +373,15 @@ export default function Page() { path: target.path, pathMatchType: target.pathMatchType, rewritePath: target.rewritePath, - rewritePathType: target.rewritePathType, - priority: target.priority - }); + rewritePathType: target.rewritePathType + }; + + // Only include priority for HTTP resources + if (isHttp) { + targetData.priority = target.priority; + } + + addTargetSchema.parse(targetData); return true; } catch { return false; @@ -436,18 +445,20 @@ export default function Page() { const site = sites.find((site) => site.siteId === data.siteId); + const isHttp = baseForm.watch("http"); + const newTarget: LocalTarget = { ...data, - path: data.path || null, - pathMatchType: data.pathMatchType || null, - rewritePath: data.rewritePath || null, - rewritePathType: data.rewritePathType || null, + path: isHttp ? (data.path || null) : null, + pathMatchType: isHttp ? (data.pathMatchType || null) : null, + rewritePath: isHttp ? (data.rewritePath || null) : null, + rewritePathType: isHttp ? (data.rewritePathType || null) : null, siteType: site?.type || null, enabled: true, targetId: new Date().getTime(), new: true, resourceId: 0, // Will be set when resource is created - priority: 100, // Default priority + priority: isHttp ? (data.priority || 100) : 100, // Default priority hcEnabled: false, hcPath: null, hcMethod: null, @@ -473,7 +484,7 @@ export default function Page() { pathMatchType: null, rewritePath: null, rewritePathType: null, - priority: 100 + priority: isHttp ? 100 : undefined }); } @@ -564,7 +575,7 @@ export default function Page() { if (targets.length > 0) { try { for (const target of targets) { - const data = { + const data: any = { ip: target.ip, port: target.port, method: target.method, @@ -581,14 +592,18 @@ export default function Page() { hcPort: target.hcPort || null, hcFollowRedirects: target.hcFollowRedirects || null, - hcStatus: target.hcStatus || null, - path: target.path, - pathMatchType: target.pathMatchType, - rewritePath: target.rewritePath, - rewritePathType: target.rewritePathType, - priority: target.priority + hcStatus: target.hcStatus || null }; + // 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); } } catch (targetError) { @@ -730,6 +745,7 @@ export default function Page() { const getColumns = (): ColumnDef[] => { const baseColumns: ColumnDef[] = []; + const isHttp = baseForm.watch("http"); const priorityColumn: ColumnDef = { id: "priority", @@ -962,7 +978,7 @@ export default function Page() { variant="ghost" role="combobox" 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 && "text-muted-foreground" )} @@ -1027,7 +1043,7 @@ export default function Page() { }) } > - + {row.original.method || "http"} @@ -1044,7 +1060,7 @@ export default function Page() { { const input = e.target.value.trim(); const hasProtocol = @@ -1228,15 +1244,20 @@ export default function Page() { }; if (isAdvancedMode) { - return [ - matchPathColumn, + const columns = [ addressColumn, - rewritePathColumn, - priorityColumn, healthCheckColumn, enabledColumn, actionsColumn ]; + + // Only include path-related columns for HTTP resources + if (isHttp) { + columns.unshift(matchPathColumn); + columns.splice(3, 0, rewritePathColumn, priorityColumn); + } + + return columns; } else { return [ addressColumn, @@ -1681,7 +1702,7 @@ export default function Page() { />