Clean up the ui a bit

This commit is contained in:
Owen
2026-05-26 15:05:30 -07:00
parent df1e28aabd
commit f81ae24ba7
2 changed files with 68 additions and 53 deletions

View File

@@ -220,8 +220,9 @@
"resourceRawDescriptionCloud": "Proxy requests over raw TCP/UDP using a port number. Requires sites to connect to a remote node.", "resourceRawDescriptionCloud": "Proxy requests over raw TCP/UDP using a port number. Requires sites to connect to a remote node.",
"resourceCreate": "Create Resource", "resourceCreate": "Create Resource",
"resourceCreateDescription": "Follow the steps below to create a new resource", "resourceCreateDescription": "Follow the steps below to create a new resource",
"resourceCreateGeneralDescription": "Configure the basic resource settings including the name and the type",
"resourceSeeAll": "See All Resources", "resourceSeeAll": "See All Resources",
"resourceInfo": "Resource Information", "resourceCreateGeneral": "General",
"resourceNameDescription": "This is the display name for the resource.", "resourceNameDescription": "This is the display name for the resource.",
"siteSelect": "Select site", "siteSelect": "Select site",
"siteSearch": "Search site", "siteSearch": "Search site",
@@ -231,9 +232,11 @@
"noCountryFound": "No country found.", "noCountryFound": "No country found.",
"siteSelectionDescription": "This site will provide connectivity to the target.", "siteSelectionDescription": "This site will provide connectivity to the target.",
"resourceType": "Resource Type", "resourceType": "Resource Type",
"resourceTypeDescription": "Determine how to access the resource", "resourceTypeDescription": "This controls the resource protocol and how it will be rendered in the browser. This cant be changed later.",
"resourceDomainDescription": "The resource will be served at this fully qualified domain name.",
"resourceHTTPSSettings": "HTTPS Settings", "resourceHTTPSSettings": "HTTPS Settings",
"resourceHTTPSSettingsDescription": "Configure how the resource will be accessed over HTTPS", "resourceHTTPSSettingsDescription": "Configure how the resource will be accessed over HTTPS",
"resourcePortDescription": "The external port on the Pangolin instance or node where the resource will be accessible.",
"domainType": "Domain Type", "domainType": "Domain Type",
"subdomain": "Subdomain", "subdomain": "Subdomain",
"baseDomain": "Base Domain", "baseDomain": "Base Domain",
@@ -1982,9 +1985,9 @@
"sshServerMode": "Mode", "sshServerMode": "Mode",
"sshServerModeStandard": "Standard SSH Server", "sshServerModeStandard": "Standard SSH Server",
"sshServerModePangolin": "Pangolin SSH", "sshServerModePangolin": "Pangolin SSH",
"sshServerModeStandardDescription": "Uses a Pangolin auth daemon to manage SSH authentication on the site or remote host.", "sshServerModeStandardDescription": "Routes commands over network to an SSH server such as OpenSSH.",
"sshServerModeNative": "Native SSH Server", "sshServerModeNative": "Native SSH Server",
"sshServerModeNativeDescription": "SSH authentication is handled natively by an existing SSH server without a separate auth daemon.", "sshServerModeNativeDescription": "Executes commands directly on the host via the Site Connector. No network config required.",
"sshAuthenticationMethod": "Authentication Method", "sshAuthenticationMethod": "Authentication Method",
"sshAuthMethodManual": "Manual Authentication", "sshAuthMethodManual": "Manual Authentication",
"sshAuthMethodManualDescription": "Requires existing host credentials. Bypasses automatic provisioning.", "sshAuthMethodManualDescription": "Requires existing host credentials. Bypasses automatic provisioning.",
@@ -3354,5 +3357,6 @@
"memberPortalResourceDisabled": "Resource Disabled", "memberPortalResourceDisabled": "Resource Disabled",
"memberPortalShowingResources": "Showing {start}-{end} of {total} resources", "memberPortalShowingResources": "Showing {start}-{end} of {total} resources",
"memberPortalPrevious": "Previous", "memberPortalPrevious": "Previous",
"memberPortalNext": "Next" "memberPortalNext": "Next",
"httpSettings": "HTTP Settings"
} }

View File

@@ -19,7 +19,14 @@ import {
SettingsSectionTitle SettingsSectionTitle
} from "@app/components/Settings"; } from "@app/components/Settings";
import HeaderTitle from "@app/components/SettingsSectionTitle"; import HeaderTitle from "@app/components/SettingsSectionTitle";
import { StrategySelect, type StrategyOption } from "@app/components/StrategySelect"; import {
OptionSelect,
type OptionSelectOption
} from "@app/components/OptionSelect";
import {
StrategySelect,
type StrategyOption
} from "@app/components/StrategySelect";
import { ResourceTargetAddressItem } from "@app/components/resource-target-address-item"; import { ResourceTargetAddressItem } from "@app/components/resource-target-address-item";
import { BrowserGatewayTargetForm } from "@app/components/BrowserGatewayTargetForm"; import { BrowserGatewayTargetForm } from "@app/components/BrowserGatewayTargetForm";
import { import {
@@ -565,7 +572,9 @@ export default function Page() {
} }
const res = await api const res = await api
.put<AxiosResponse<Resource>>(`/org/${orgId}/resource/`, payload) .put<
AxiosResponse<Resource>
>(`/org/${orgId}/resource/`, payload)
.catch((e) => { .catch((e) => {
toast({ toast({
variant: "destructive", variant: "destructive",
@@ -880,9 +889,7 @@ export default function Page() {
variant="outline" variant="outline"
size="sm" size="sm"
className="h-7 text-xs gap-1" className="h-7 text-xs gap-1"
onClick={() => onClick={() => openHealthCheckDialog(row.original)}
openHealthCheckDialog(row.original)
}
> >
<Settings className="h-3.5 w-3.5" /> <Settings className="h-3.5 w-3.5" />
{row.original.hcEnabled ? ( {row.original.hcEnabled ? (
@@ -1224,6 +1231,12 @@ export default function Page() {
udp: "UDP" udp: "UDP"
}; };
const typeOptions: OptionSelectOption<NewResourceType>[] =
availableTypes.map((type) => ({
value: type,
label: typeLabels[type]
}));
return ( return (
<> <>
<div className="flex justify-between"> <div className="flex justify-between">
@@ -1249,14 +1262,14 @@ export default function Page() {
<SettingsSection> <SettingsSection>
<SettingsSectionHeader> <SettingsSectionHeader>
<SettingsSectionTitle> <SettingsSectionTitle>
{t("resourceInfo")} {t("resourceCreateGeneral")}
</SettingsSectionTitle> </SettingsSectionTitle>
<SettingsSectionDescription> <SettingsSectionDescription>
{t("resourceCreateDescription")} {t("resourceCreateDescription")}
</SettingsSectionDescription> </SettingsSectionDescription>
</SettingsSectionHeader> </SettingsSectionHeader>
<SettingsSectionBody> <SettingsSectionBody>
<SettingsSectionForm> <SettingsSectionForm variant="half">
{/* Name */} {/* Name */}
<Form {...baseForm}> <Form {...baseForm}>
<form <form
@@ -1298,28 +1311,12 @@ export default function Page() {
<p className="text-sm font-medium"> <p className="text-sm font-medium">
{t("type")} {t("type")}
</p> </p>
<div className="flex flex-wrap gap-2"> <OptionSelect<NewResourceType>
{availableTypes.map((type) => ( options={typeOptions}
<button value={resourceType}
key={type} onChange={setResourceType}
type="button" cols={6}
onClick={() => />
setResourceType(
type
)
}
className={cn(
"px-4 py-1.5 rounded-md border text-sm font-medium transition-colors",
resourceType ===
type
? "border-primary bg-primary/10 text-primary"
: "border-input bg-background hover:bg-accent text-foreground"
)}
>
{typeLabels[type]}
</button>
))}
</div>
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
{t("resourceTypeDescription")} {t("resourceTypeDescription")}
</p> </p>
@@ -1327,24 +1324,32 @@ export default function Page() {
{/* Domain/Subdomain (HTTP-based types) */} {/* Domain/Subdomain (HTTP-based types) */}
{isHttpResource && ( {isHttpResource && (
<DomainPicker <div className="space-y-2">
allowWildcard={true} <DomainPicker
orgId={orgId as string} allowWildcard={true}
warnOnProvidedDomain={ orgId={orgId as string}
remoteExitNodes.length >= 1 warnOnProvidedDomain={
} remoteExitNodes.length >=
onDomainChange={(res) => { 1
if (!res) return; }
httpForm.setValue( onDomainChange={(res) => {
"subdomain", if (!res) return;
res.subdomain httpForm.setValue(
); "subdomain",
httpForm.setValue( res.subdomain
"domainId", );
res.domainId httpForm.setValue(
); "domainId",
}} res.domainId
/> );
}}
/>
<p className="text-sm text-muted-foreground">
{t(
"resourceDomainDescription"
)}
</p>
</div>
)} )}
{/* Proxy Port (TCP/UDP types) */} {/* Proxy Port (TCP/UDP types) */}
@@ -1396,6 +1401,11 @@ export default function Page() {
/> />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
<FormDescription>
{t(
"resourcePortDescription"
)}
</FormDescription>
</FormItem> </FormItem>
)} )}
/> />
@@ -1786,7 +1796,8 @@ export default function Page() {
</TableHeader> </TableHeader>
<TableBody> <TableBody>
{table.getRowModel() {table.getRowModel()
.rows?.length ? ( .rows
?.length ? (
table table
.getRowModel() .getRowModel()
.rows.map( .rows.map(