Remove browser gateway targets for regular targets

This commit is contained in:
Owen
2026-06-05 15:30:42 -07:00
parent 8e5d9e94a9
commit 772ac8af73
28 changed files with 259 additions and 1254 deletions

View File

@@ -138,11 +138,6 @@ export function ProxyResourceTargetsForm({
const [selectedTargetForHealthCheck, setSelectedTargetForHealthCheck] =
useState<LocalTarget | null>(null);
const [bgDestination, setBgDestination] = useState("");
const [bgDestinationPort, setBgDestinationPort] = useState("");
const [bgSiteId, setBgSiteId] = useState<number | null>(null);
const [bgTargetId, setBgTargetId] = useState<number | null>(null);
const initializeDockerForSite = async (siteId: number) => {
if (dockerStates.has(siteId)) {
return;
@@ -207,42 +202,6 @@ export function ProxyResourceTargetsForm({
})
);
// Browser-gateway targets (edit mode only)
const { data: bgTargetsResponse } = useQuery({
queryKey: ["browserGatewayTargets", resource?.resourceId, orgId],
queryFn: async () => {
const res = await api.get(
`/org/${orgId}/resource/${resource!.resourceId}/browser-gateway-targets`
);
return res.data.data as {
targets: Array<{
browserGatewayTargetId: number;
resourceId: number;
siteId: number;
type: string;
destination: string;
destinationPort: number;
}>;
};
},
enabled: !!resource
});
useEffect(() => {
if (!bgTargetsResponse?.targets?.length) return;
const bgt = bgTargetsResponse.targets[0];
setBgDestination(bgt.destination);
setBgDestinationPort(String(bgt.destinationPort));
setBgSiteId(bgt.siteId);
setBgTargetId(bgt.browserGatewayTargetId);
}, [bgTargetsResponse]);
useEffect(() => {
if (sites.length > 0 && bgSiteId === null) {
setBgSiteId(sites[0].siteId);
}
}, [sites, bgSiteId]);
const updateTarget = useCallback(
(targetId: number, data: Partial<LocalTarget>) => {
setTargets((prevTargets) => {
@@ -603,6 +562,8 @@ export function ProxyResourceTargetsForm({
const newTarget: LocalTarget = {
targetId: -Date.now(),
ip: "",
mode: ((resource?.mode as LocalTarget["mode"]) ??
(isHttp ? "http" : "tcp")) as LocalTarget["mode"],
method: isHttp ? "http" : null,
port: 0,
siteId: sites.length > 0 ? sites[0].siteId : 0,

View File

@@ -31,21 +31,10 @@ import { GetResourceResponse } from "@server/routers/resource";
import type { ResourceContextType } from "@app/contexts/resourceContext";
type ExistingTarget = {
browserGatewayTargetId: number;
targetId: number;
siteId: number;
};
const sshFormSchema = z.object({
authDaemonPort: z.string().refine(
(val) => {
if (!val) return true;
const n = Number(val);
return Number.isInteger(n) && n >= 1 && n <= 65535;
},
{ message: "Port must be between 1 and 65535" }
)
});
export default function SshSettingsPage(props: {
params: Promise<{ orgId: string }>;
}) {
@@ -61,7 +50,7 @@ export default function SshSettingsPage(props: {
<PaidFeaturesAlert
tiers={tierMatrix[TierFeature.AdvancedPublicResources]}
/>
<SshServerForm
<RdpServerForm
orgId={params.orgId}
resource={resource}
updateResource={updateResource}
@@ -71,7 +60,7 @@ export default function SshSettingsPage(props: {
);
}
function SshServerForm({
function RdpServerForm({
orgId,
resource,
updateResource,
@@ -101,20 +90,18 @@ function SshServerForm({
useState<ExistingTarget | null>(null);
const { data: bgTargetsResponse } = useQuery({
queryKey: ["browserGatewayTargets", resource.resourceId, orgId],
queryKey: ["resourceTargets", resource.resourceId, orgId, "rdp"],
queryFn: async () => {
const res = await api.get(
`/org/${orgId}/resource/${resource.resourceId}/browser-gateway-targets`
);
const res = await api.get(`/resource/${resource.resourceId}/targets`);
return res.data.data as {
targets: Array<{
browserGatewayTargetId: number;
targetId: number;
resourceId: number;
siteId: number;
siteName?: string;
type: string;
destination: string;
destinationPort: number;
mode: string | null;
ip: string;
port: number;
}>;
};
}
@@ -122,14 +109,17 @@ function SshServerForm({
useEffect(() => {
if (!bgTargetsResponse?.targets?.length) return;
const targets = bgTargetsResponse.targets;
const targets = bgTargetsResponse.targets.filter(
(t) => t.mode === "rdp"
);
if (!targets.length) return;
const first = targets[0];
setBgDestination(first.destination);
setBgDestinationPort(String(first.destinationPort));
setBgDestination(first.ip);
setBgDestinationPort(String(first.port));
setExistingTargets(
targets.map((t) => ({
browserGatewayTargetId: t.browserGatewayTargetId,
targetId: t.targetId,
siteId: t.siteId
}))
);
@@ -159,9 +149,7 @@ function SshServerForm({
);
await Promise.all(
toDelete.map((t) =>
api.delete(
`/org/${orgId}/browser-gateway-target/${t.browserGatewayTargetId}`
)
api.delete(`/target/${t.targetId}`)
)
);
@@ -171,12 +159,13 @@ function SshServerForm({
await Promise.all(
toUpdate.map((t) =>
api.post(
`/org/${orgId}/browser-gateway-target/${t.browserGatewayTargetId}`,
`/target/${t.targetId}`,
{
type: "rdp",
destination: bgDestination,
destinationPort: Number(bgDestinationPort),
siteId: t.siteId
mode: "rdp",
ip: bgDestination,
port: Number(bgDestinationPort),
siteId: t.siteId,
hcEnabled: false
}
)
)
@@ -188,20 +177,20 @@ function SshServerForm({
const created = await Promise.all(
toCreate.map((s) =>
api.put(
`/org/${orgId}/resource/${resource.resourceId}/browser-gateway-target`,
`/resource/${resource.resourceId}/target`,
{
siteId: s.siteId,
type: "rdp",
destination: bgDestination,
destinationPort: Number(bgDestinationPort)
mode: "rdp",
ip: bgDestination,
port: Number(bgDestinationPort),
hcEnabled: false
}
)
)
);
const newTargets: ExistingTarget[] = created.map((res, i) => ({
browserGatewayTargetId:
res.data.data.browserGatewayTargetId,
targetId: res.data.data.targetId,
siteId: toCreate[i].siteId
}));
setExistingTargets([...toUpdate, ...newTargets]);

View File

@@ -54,8 +54,9 @@ import { GetResourceResponse } from "@server/routers/resource";
import type { ResourceContextType } from "@app/contexts/resourceContext";
type ExistingTarget = {
browserGatewayTargetId: number;
targetId: number;
siteId: number;
authToken?: string | null;
};
const sshFormSchema = z.object({
@@ -154,20 +155,19 @@ function SshServerForm({
const [nativeSiteOpen, setNativeSiteOpen] = useState(false);
const { data: bgTargetsResponse } = useQuery({
queryKey: ["browserGatewayTargets", resource.resourceId, orgId],
queryKey: ["resourceTargets", resource.resourceId, orgId, "ssh"],
queryFn: async () => {
const res = await api.get(
`/org/${orgId}/resource/${resource.resourceId}/browser-gateway-targets`
);
const res = await api.get(`/resource/${resource.resourceId}/targets`);
return res.data.data as {
targets: Array<{
browserGatewayTargetId: number;
targetId: number;
resourceId: number;
siteId: number;
siteName?: string;
type: string;
destination: string;
destinationPort: number;
mode: string | null;
ip: string;
port: number;
authToken?: string | null;
}>;
};
}
@@ -175,7 +175,10 @@ function SshServerForm({
useEffect(() => {
if (!bgTargetsResponse?.targets?.length) return;
const targets = bgTargetsResponse.targets;
const targets = bgTargetsResponse.targets.filter(
(t) => t.mode === "ssh"
);
if (!targets.length) return;
const first = targets[0];
if (isNativeInitially) {
setSelectedNativeSite({
@@ -184,16 +187,18 @@ function SshServerForm({
type: "newt" as const
});
setNativeExistingTarget({
browserGatewayTargetId: first.browserGatewayTargetId,
siteId: first.siteId
targetId: first.targetId,
siteId: first.siteId,
authToken: first.authToken
});
} else {
setBgDestination(first.destination);
setBgDestinationPort(String(first.destinationPort));
setBgDestination(first.ip);
setBgDestinationPort(String(first.port));
setExistingTargets(
targets.map((t) => ({
browserGatewayTargetId: t.browserGatewayTargetId,
siteId: t.siteId
targetId: t.targetId,
siteId: t.siteId,
authToken: t.authToken
}))
);
setSelectedSites(
@@ -236,28 +241,31 @@ function SshServerForm({
if (selectedNativeSite) {
if (nativeExistingTarget) {
await api.post(
`/org/${orgId}/browser-gateway-target/${nativeExistingTarget.browserGatewayTargetId}`,
`/target/${nativeExistingTarget.targetId}`,
{
type: "ssh",
destination: "localhost",
destinationPort: 22,
siteId: selectedNativeSite.siteId
mode: "ssh",
ip: "localhost",
port: 22,
siteId: selectedNativeSite.siteId,
authToken: nativeExistingTarget.authToken,
hcEnabled: false
}
);
} else {
const res = await api.put(
`/org/${orgId}/resource/${resource.resourceId}/browser-gateway-target`,
`/resource/${resource.resourceId}/target`,
{
siteId: selectedNativeSite.siteId,
type: "ssh",
destination: "localhost",
destinationPort: 22
mode: "ssh",
ip: "localhost",
port: 22,
hcEnabled: false
}
);
setNativeExistingTarget({
browserGatewayTargetId:
res.data.data.browserGatewayTargetId,
siteId: selectedNativeSite.siteId
targetId: res.data.data.targetId,
siteId: selectedNativeSite.siteId,
authToken: res.data.data.authToken
});
}
}
@@ -275,9 +283,7 @@ function SshServerForm({
);
await Promise.all(
toDelete.map((t) =>
api.delete(
`/org/${orgId}/browser-gateway-target/${t.browserGatewayTargetId}`
)
api.delete(`/target/${t.targetId}`)
)
);
@@ -287,12 +293,14 @@ function SshServerForm({
await Promise.all(
toUpdate.map((t) =>
api.post(
`/org/${orgId}/browser-gateway-target/${t.browserGatewayTargetId}`,
`/target/${t.targetId}`,
{
type: "ssh",
destination: bgDestination,
destinationPort: Number(bgDestinationPort),
siteId: t.siteId
mode: "ssh",
ip: bgDestination,
port: Number(bgDestinationPort),
siteId: t.siteId,
authToken: t.authToken,
hcEnabled: false
}
)
)
@@ -304,12 +312,13 @@ function SshServerForm({
const created = await Promise.all(
toCreate.map((s) =>
api.put(
`/org/${orgId}/resource/${resource.resourceId}/browser-gateway-target`,
`/resource/${resource.resourceId}/target`,
{
siteId: s.siteId,
type: "ssh",
destination: bgDestination,
destinationPort: Number(bgDestinationPort)
mode: "ssh",
ip: bgDestination,
port: Number(bgDestinationPort),
hcEnabled: false
}
)
)
@@ -317,9 +326,9 @@ function SshServerForm({
const newTargets: ExistingTarget[] = created.map(
(res, i) => ({
browserGatewayTargetId:
res.data.data.browserGatewayTargetId,
siteId: toCreate[i].siteId
targetId: res.data.data.targetId,
siteId: toCreate[i].siteId,
authToken: res.data.data.authToken
})
);
setExistingTargets([...toUpdate, ...newTargets]);

View File

@@ -29,21 +29,10 @@ import { GetResourceResponse } from "@server/routers/resource";
import type { ResourceContextType } from "@app/contexts/resourceContext";
type ExistingTarget = {
browserGatewayTargetId: number;
targetId: number;
siteId: number;
};
const sshFormSchema = z.object({
authDaemonPort: z.string().refine(
(val) => {
if (!val) return true;
const n = Number(val);
return Number.isInteger(n) && n >= 1 && n <= 65535;
},
{ message: "Port must be between 1 and 65535" }
)
});
export default function SshSettingsPage(props: {
params: Promise<{ orgId: string }>;
}) {
@@ -59,7 +48,7 @@ export default function SshSettingsPage(props: {
<PaidFeaturesAlert
tiers={tierMatrix[TierFeature.AdvancedPublicResources]}
/>
<SshServerForm
<VncServerForm
orgId={params.orgId}
resource={resource}
updateResource={updateResource}
@@ -69,7 +58,7 @@ export default function SshSettingsPage(props: {
);
}
function SshServerForm({
function VncServerForm({
orgId,
resource,
updateResource,
@@ -99,20 +88,18 @@ function SshServerForm({
useState<ExistingTarget | null>(null);
const { data: bgTargetsResponse } = useQuery({
queryKey: ["browserGatewayTargets", resource.resourceId, orgId],
queryKey: ["resourceTargets", resource.resourceId, orgId, "vnc"],
queryFn: async () => {
const res = await api.get(
`/org/${orgId}/resource/${resource.resourceId}/browser-gateway-targets`
);
const res = await api.get(`/resource/${resource.resourceId}/targets`);
return res.data.data as {
targets: Array<{
browserGatewayTargetId: number;
targetId: number;
resourceId: number;
siteId: number;
siteName?: string;
type: string;
destination: string;
destinationPort: number;
mode: string | null;
ip: string;
port: number;
}>;
};
}
@@ -120,14 +107,17 @@ function SshServerForm({
useEffect(() => {
if (!bgTargetsResponse?.targets?.length) return;
const targets = bgTargetsResponse.targets;
const targets = bgTargetsResponse.targets.filter(
(t) => t.mode === "vnc"
);
if (!targets.length) return;
const first = targets[0];
setBgDestination(first.destination);
setBgDestinationPort(String(first.destinationPort));
setBgDestination(first.ip);
setBgDestinationPort(String(first.port));
setExistingTargets(
targets.map((t) => ({
browserGatewayTargetId: t.browserGatewayTargetId,
targetId: t.targetId,
siteId: t.siteId
}))
);
@@ -157,9 +147,7 @@ function SshServerForm({
);
await Promise.all(
toDelete.map((t) =>
api.delete(
`/org/${orgId}/browser-gateway-target/${t.browserGatewayTargetId}`
)
api.delete(`/target/${t.targetId}`)
)
);
@@ -169,12 +157,13 @@ function SshServerForm({
await Promise.all(
toUpdate.map((t) =>
api.post(
`/org/${orgId}/browser-gateway-target/${t.browserGatewayTargetId}`,
`/target/${t.targetId}`,
{
type: "vnc",
destination: bgDestination,
destinationPort: Number(bgDestinationPort),
siteId: t.siteId
mode: "vnc",
ip: bgDestination,
port: Number(bgDestinationPort),
siteId: t.siteId,
hcEnabled: false
}
)
)
@@ -186,20 +175,20 @@ function SshServerForm({
const created = await Promise.all(
toCreate.map((s) =>
api.put(
`/org/${orgId}/resource/${resource.resourceId}/browser-gateway-target`,
`/resource/${resource.resourceId}/target`,
{
siteId: s.siteId,
type: "vnc",
destination: bgDestination,
destinationPort: Number(bgDestinationPort)
mode: "vnc",
ip: bgDestination,
port: Number(bgDestinationPort),
hcEnabled: false
}
)
)
);
const newTargets: ExistingTarget[] = created.map((res, i) => ({
browserGatewayTargetId:
res.data.data.browserGatewayTargetId,
targetId: res.data.data.targetId,
siteId: toCreate[i].siteId
}));
setExistingTargets([...toUpdate, ...newTargets]);

View File

@@ -498,12 +498,13 @@ export default function Page() {
if (isNative) {
if (nativeSelectedSite) {
await api.put(
`/org/${orgId}/resource/${id}/browser-gateway-target`,
`/resource/${id}/target`,
{
siteId: nativeSelectedSite.siteId,
type: "ssh",
destination: "localhost",
destinationPort: 22
mode: "ssh",
ip: "localhost",
port: 22,
hcEnabled: false
}
);
}
@@ -516,12 +517,13 @@ export default function Page() {
: [];
for (const site of sitesToCreate) {
await api.put(
`/org/${orgId}/resource/${id}/browser-gateway-target`,
`/resource/${id}/target`,
{
siteId: site.siteId,
type: "ssh",
destination: bgDestination,
destinationPort: Number(bgDestinationPort)
mode: "ssh",
ip: bgDestination,
port: Number(bgDestinationPort),
hcEnabled: false
}
);
}
@@ -533,12 +535,14 @@ export default function Page() {
} else if (resourceType === "rdp" || resourceType === "vnc") {
for (const site of bgSelectedSites) {
await api.put(
`/org/${orgId}/resource/${id}/browser-gateway-target`,
`/resource/${id}/target`,
{
siteId: site.siteId,
type: resourceType,
destination: bgDestination,
destinationPort: Number(bgDestinationPort)
mode: resourceType,
ip: bgDestination,
port: Number(bgDestinationPort),
authToken: null,
hcEnabled: false
}
);
}