diff --git a/messages/en-US.json b/messages/en-US.json index be70e0781..141b686d6 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -240,6 +240,7 @@ "domainType": "Domain Type", "subdomain": "Subdomain", "baseDomain": "Base Domain", + "configure": "Configure", "subdomnainDescription": "The subdomain where the resource will be accessible.", "resourceRawSettings": "TCP/UDP Settings", "resourceRawSettingsDescription": "Configure how the resource will be accessed over TCP/UDP", diff --git a/server/routers/resource/createResource.ts b/server/routers/resource/createResource.ts index f8b7551e9..420cf0644 100644 --- a/server/routers/resource/createResource.ts +++ b/server/routers/resource/createResource.ts @@ -23,7 +23,10 @@ import { OpenAPITags, registry } from "@server/openApi"; import { build } from "@server/build"; import { createCertificate } from "#dynamic/routers/certificates/createCertificate"; import { getUniqueResourceName } from "@server/db/names"; -import { validateAndConstructDomain, checkWildcardDomainConflict } from "@server/lib/domainUtils"; +import { + validateAndConstructDomain, + checkWildcardDomainConflict +} from "@server/lib/domainUtils"; import { isSubscribed } from "#dynamic/lib/isSubscribed"; import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed"; import { tierMatrix } from "@server/lib/billing/tierMatrix"; @@ -40,7 +43,8 @@ const createHttpResourceSchema = z protocol: z.enum(["tcp", "udp"]), domainId: z.string(), stickySession: z.boolean().optional(), - postAuthPath: z.string().nullable().optional() + postAuthPath: z.string().nullable().optional(), + browserAccessType: z.enum(["http", "ssh", "rdp", "vnc"]).optional() }) .refine( (data) => { @@ -198,7 +202,7 @@ async function createHttpResource( ); } - const { name, domainId, postAuthPath } = parsedBody.data; + const { name, domainId, postAuthPath, browserAccessType } = parsedBody.data; const subdomain = parsedBody.data.subdomain; const stickySession = parsedBody.data.stickySession; @@ -323,6 +327,7 @@ async function createHttpResource( name, subdomain: finalSubdomain, http: true, + browserAccessType: browserAccessType, protocol: "tcp", ssl: true, stickySession: stickySession, diff --git a/src/app/[orgId]/settings/resources/proxy/[niceId]/http/page.tsx b/src/app/[orgId]/settings/resources/proxy/[niceId]/http/page.tsx index 7415085f9..221bc8014 100644 --- a/src/app/[orgId]/settings/resources/proxy/[niceId]/http/page.tsx +++ b/src/app/[orgId]/settings/resources/proxy/[niceId]/http/page.tsx @@ -121,10 +121,6 @@ export default function ReverseProxyTargetsPage(props: { const params = use(props.params); const { resource, updateResource } = useResourceContext(); - const [targetMode, setTargetMode] = useState< - "http" | "ssh" | "rdp" | "vnc" - >((resource.browserAccessType as "http" | "ssh" | "rdp" | "vnc") || "http"); - const { data: remoteTargets = [], isLoading: isLoadingTargets } = useQuery( resourceQueries.resourceTargets({ resourceId: resource.resourceId @@ -141,12 +137,10 @@ export default function ReverseProxyTargetsPage(props: { orgId={params.orgId} initialTargets={remoteTargets} resource={resource} - targetMode={targetMode} - setTargetMode={setTargetMode} updateResource={updateResource} /> - {resource.http && targetMode === "http" && ( + {resource.http && ( void; updateResource: ResourceContextType["updateResource"]; }) { const t = useTranslations(); @@ -310,7 +300,6 @@ function ProxyResourceTargetsForm({ useEffect(() => { if (!bgTargetsResponse?.targets?.length) return; const bgt = bgTargetsResponse.targets[0]; - setTargetMode(bgt.type as "ssh" | "rdp" | "vnc"); setBgDestination(bgt.destination); setBgDestinationPort(String(bgt.destinationPort)); setBgSiteId(bgt.siteId); @@ -781,55 +770,6 @@ function ProxyResourceTargetsForm({ const [, formAction, isSubmitting] = useActionState(saveTargets, null); async function saveTargets() { - if (targetMode !== "http") { - try { - if (!bgDestination || !bgDestinationPort) { - if (bgTargetId) { - await api.delete( - `/org/${orgId}/browser-gateway-target/${bgTargetId}` - ); - setBgTargetId(null); - } - } else if (bgTargetId) { - await api.post( - `/org/${orgId}/browser-gateway-target/${bgTargetId}`, - { - type: targetMode, - destination: bgDestination, - destinationPort: Number(bgDestinationPort), - siteId: bgSiteId - } - ); - } else { - const res = await api.put( - `/org/${orgId}/resource/${resource.resourceId}/browser-gateway-target`, - { - siteId: bgSiteId ?? sites[0]?.siteId, - type: targetMode, - destination: bgDestination, - destinationPort: Number(bgDestinationPort) - } - ); - setBgTargetId(res.data.data.browserGatewayTargetId); - } - toast({ - title: t("settingsUpdated"), - description: t("settingsUpdatedDescription") - }); - } catch (err) { - console.error(err); - toast({ - variant: "destructive", - title: t("settingsErrorUpdate"), - description: formatAxiosError( - err, - t("settingsErrorUpdateDescription") - ) - }); - } - return; - } - // Validate that no targets have blank IPs or invalid ports const targetsWithInvalidFields = targets.filter( (target) => @@ -944,187 +884,102 @@ function ProxyResourceTargetsForm({ -
- Target Type - -
- {targetMode === "http" ? ( + {targets.length > 0 ? ( <> - {targets.length > 0 ? ( - <> -
- - - {table - .getHeaderGroups() - .map((headerGroup) => ( - - {headerGroup.headers.map( - (header) => { - const isActionsColumn = - header - .column - .id === - "actions"; - return ( - - {header.isPlaceholder - ? null - : flexRender( - header - .column - .columnDef - .header, - header.getContext() - )} - - ); - } - )} - - ))} - - - {table.getRowModel().rows - ?.length ? ( - table - .getRowModel() - .rows.map((row) => ( - - {row - .getVisibleCells() - .map( - ( - cell - ) => { - const isActionsColumn = - cell - .column - .id === - "actions"; - return ( - - {flexRender( - cell - .column - .columnDef - .cell, - cell.getContext() - )} - - ); +
+
+ + {table + .getHeaderGroups() + .map((headerGroup) => ( + + {headerGroup.headers.map( + (header) => { + const isActionsColumn = + header.column + .id === + "actions"; + return ( + + {header.isPlaceholder + ? null + : flexRender( + header + .column + .columnDef + .header, + header.getContext() + )} + + ); + } + )} + + ))} + + + {table.getRowModel().rows?.length ? ( + table + .getRowModel() + .rows.map((row) => ( + + {row + .getVisibleCells() + .map((cell) => { + const isActionsColumn = + cell.column + .id === + "actions"; + return ( + - )) - ) : ( - - - {t("targetNoOne")} - + className={ + isActionsColumn + ? "sticky right-0 z-10 w-auto min-w-fit bg-card" + : "" + } + > + {flexRender( + cell + .column + .columnDef + .cell, + cell.getContext() + )} + + ); + })} - )} - - {/* */} - {/* {t('targetNoOneDescription')} */} - {/* */} -
-
-
-
- -
- - -
-
-
- - ) : ( -
-

- {t("targetNoOne")} -

+ {t("targetNoOne")} + + + )} + + {/* */} + {/* {t('targetNoOneDescription')} */} + {/* */} + +
+
+
-
- )} - {build === "saas" && - targets.length > 1 && - new Set(targets.map((t) => t.siteId)).size > - 1 && ( -

- {t("proxyMultiSiteRoundRobinNodeHelp")}{" "} - + + - . -

- )} - - ) : ( -
-
-
- - - setBgDestination(e.target.value) - } - /> -
-
- - - setBgDestinationPort(e.target.value) - } - /> + {t("advancedMode")} + +
- {sites.length > 1 && ( -
- - -
- )} + + ) : ( +
+

+ {t("targetNoOne")} +

+
)} + {build === "saas" && + targets.length > 1 && + new Set(targets.map((t) => t.siteId)).size > 1 && ( +

+ {t("proxyMultiSiteRoundRobinNodeHelp")}{" "} + + {t("learnMore")} + + + . +

+ )}
diff --git a/src/app/[orgId]/settings/resources/proxy/create/page.tsx b/src/app/[orgId]/settings/resources/proxy/create/page.tsx index 513adcc20..8edc5a7b7 100644 --- a/src/app/[orgId]/settings/resources/proxy/create/page.tsx +++ b/src/app/[orgId]/settings/resources/proxy/create/page.tsx @@ -250,7 +250,7 @@ export default function Page() { // SSH-specific state const [sshServerMode, setSshServerMode] = useState<"standard" | "native">( - "standard" + "native" ); const [pamMode, setPamMode] = useState<"passthrough" | "push">( "passthrough" @@ -544,7 +544,8 @@ export default function Page() { try { const payload: any = { name: baseData.name, - http: isHttpResource + http: isHttpResource, + browserAccessType: resourceType }; let sanitizedSubdomain: string | undefined; @@ -1265,7 +1266,7 @@ export default function Page() { {t("resourceCreateGeneral")} - {t("resourceCreateDescription")} + {t("resourceCreateGeneralDescription")}