chore(site): premium paywall for <WorkspaceProxyPage /> (#27567)

This commit is contained in:
Jake Howell
2026-07-28 18:58:18 +10:00
committed by GitHub
parent c351280a37
commit ea2ad4d6c6
4 changed files with 66 additions and 26 deletions
+10 -4
View File
@@ -13,6 +13,7 @@ import { cachedQuery } from "#/api/queries/util";
import type { Region, WorkspaceProxy } from "#/api/typesGenerated";
import { useAuthenticated } from "#/hooks/useAuthenticated";
import { useEmbeddedMetadata } from "#/hooks/useEmbeddedMetadata";
import { useFeatureVisibility } from "#/modules/dashboard/useFeatureVisibility";
import { type ProxyLatencyReport, useProxyLatency } from "./useProxyLatency";
export type Proxies = readonly Region[] | readonly WorkspaceProxy[];
@@ -97,6 +98,7 @@ export const ProxyProvider: FC<PropsWithChildren> = ({ children }) => {
const { permissions } = useAuthenticated();
const { metadata } = useEmbeddedMetadata();
const { workspace_proxy: workspaceProxyEnabled } = useFeatureVisibility();
const {
data: proxiesResp,
@@ -106,11 +108,15 @@ export const ProxyProvider: FC<PropsWithChildren> = ({ children }) => {
} = useQuery(
cachedQuery({
metadata: metadata.regions,
queryKey: ["get-proxies"],
queryKey: ["get-proxies", workspaceProxyEnabled],
queryFn: async (): Promise<readonly Region[]> => {
const apiCall = permissions.editWorkspaceProxies
? API.getWorkspaceProxies
: API.getWorkspaceProxyRegions;
// Detailed proxy status requires the workspace_proxy entitlement.
// Fall back to regions when unlicensed so admins do not hit a
// Premium feature error on every page load.
const apiCall =
permissions.editWorkspaceProxies && workspaceProxyEnabled
? API.getWorkspaceProxies
: API.getWorkspaceProxyRegions;
const resp = await apiCall();
return resp.regions;
@@ -1,5 +1,6 @@
import type { FC } from "react";
import { useProxy } from "#/contexts/ProxyContext";
import { useFeatureVisibility } from "#/modules/dashboard/useFeatureVisibility";
import { WorkspaceProxyView } from "./WorkspaceProxyView";
const WorkspaceProxyPage: FC = () => {
@@ -11,6 +12,7 @@ const WorkspaceProxyPage: FC = () => {
isLoading: proxiesLoading,
proxy,
} = useProxy();
const { workspace_proxy: workspaceProxyEnabled } = useFeatureVisibility();
return (
<WorkspaceProxyView
@@ -20,6 +22,7 @@ const WorkspaceProxyPage: FC = () => {
hasLoaded={proxiesFetched}
getWorkspaceProxiesError={proxiesError}
preferredProxy={proxy.proxy}
showPaywall={!workspaceProxyEnabled}
/>
);
};
@@ -11,6 +11,9 @@ import { WorkspaceProxyView } from "./WorkspaceProxyView";
const meta: Meta<typeof WorkspaceProxyView> = {
title: "pages/UserSettingsPage/WorkspaceProxyView",
component: WorkspaceProxyView,
args: {
showPaywall: false,
},
};
export default meta;
@@ -36,6 +39,13 @@ export const Example: Story = {
},
};
export const Paywall: Story = {
args: {
...Example.args,
showPaywall: true,
},
};
export const Loading: Story = {
args: {
...Example.args,
@@ -1,9 +1,11 @@
import type { FC } from "react";
import type { Region } from "#/api/typesGenerated";
import { ErrorAlert } from "#/components/Alert/ErrorAlert";
import { PaywallPremium } from "#/components/Paywall/PaywallPremium";
import {
SettingsHeader,
SettingsHeaderDescription,
SettingsHeaderDocsLink,
SettingsHeaderTitle,
} from "#/components/SettingsHeader/SettingsHeader";
import {
@@ -16,6 +18,7 @@ import {
import { TableEmpty } from "#/components/TableEmpty/TableEmpty";
import { TableLoader } from "#/components/TableLoader/TableLoader";
import type { ProxyLatencyReport } from "#/contexts/useProxyLatency";
import { docs } from "#/utils/docs";
import { ProxyRow } from "./WorkspaceProxyRow";
interface WorkspaceProxyViewProps {
@@ -26,6 +29,7 @@ interface WorkspaceProxyViewProps {
hasLoaded: boolean;
preferredProxy?: Region;
selectProxyError?: unknown;
showPaywall: boolean;
}
export const WorkspaceProxyView: FC<WorkspaceProxyViewProps> = ({
@@ -35,10 +39,17 @@ export const WorkspaceProxyView: FC<WorkspaceProxyViewProps> = ({
isLoading,
hasLoaded,
selectProxyError,
showPaywall,
}) => {
return (
<div className="flex flex-col gap-4">
<SettingsHeader>
<SettingsHeader
actions={
<SettingsHeaderDocsLink
href={docs("/admin/networking/workspace-proxies")}
/>
}
>
<SettingsHeaderTitle>Workspace Proxies</SettingsHeaderTitle>
<SettingsHeaderDescription>
Workspace proxies improve terminal and web app connections to
@@ -46,28 +57,38 @@ export const WorkspaceProxyView: FC<WorkspaceProxyViewProps> = ({
</SettingsHeaderDescription>
</SettingsHeader>
{Boolean(getWorkspaceProxiesError) && (
<ErrorAlert error={getWorkspaceProxiesError} />
)}
{Boolean(selectProxyError) && <ErrorAlert error={selectProxyError} />}
{showPaywall ? (
<PaywallPremium
message="Workspace Proxies"
description="Workspace proxies provide low-latency connections for geo-distributed teams. You need a Premium license to use this feature."
documentationLink={docs("/admin/networking/workspace-proxies")}
/>
) : (
<>
{Boolean(getWorkspaceProxiesError) && (
<ErrorAlert error={getWorkspaceProxiesError} />
)}
{Boolean(selectProxyError) && <ErrorAlert error={selectProxyError} />}
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[60%]">Proxy</TableHead>
<TableHead className="w-[20%]">Status</TableHead>
<TableHead className="w-[20%]">Latency</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<ProxiesTableBody
proxies={proxies}
proxyLatencies={proxyLatencies}
isLoading={isLoading}
hasLoaded={hasLoaded}
/>
</TableBody>
</Table>
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[60%]">Proxy</TableHead>
<TableHead className="w-[20%]">Status</TableHead>
<TableHead className="w-[20%]">Latency</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<ProxiesTableBody
proxies={proxies}
proxyLatencies={proxyLatencies}
isLoading={isLoading}
hasLoaded={hasLoaded}
/>
</TableBody>
</Table>
</>
)}
</div>
);
};