add snippets to create resource

This commit is contained in:
miloschwartz 2025-04-28 21:45:43 -04:00
parent 599d0a52bf
commit 18e6f16ce7
No known key found for this signature in database
5 changed files with 634 additions and 496 deletions

View file

@ -137,7 +137,8 @@ LQIDAQAB
hostId: this.hostId,
isHostLicensed: true,
isLicenseValid: false,
maxSites: undefined
maxSites: undefined,
usedSites: siteCount.value
};
try {

View file

@ -67,6 +67,12 @@ import { SwitchInput } from "@app/components/SwitchInput";
import { useRouter } from "next/navigation";
import { isTargetValid } from "@server/lib/validators";
import { tlsNameSchema } from "@server/lib/schemas";
import { ChevronsUpDown } from "lucide-react";
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger
} from "@app/components/ui/collapsible";
const addTargetSchema = z.object({
ip: z.string().refine(isTargetValid),
@ -145,6 +151,7 @@ export default function ReverseProxyTargets(props: {
const [proxySettingsLoading, setProxySettingsLoading] = useState(false);
const [pageLoading, setPageLoading] = useState(true);
const [isAdvancedOpen, setIsAdvancedOpen] = useState(false);
const router = useRouter();
const addTargetForm = useForm({
@ -589,26 +596,57 @@ export default function ReverseProxyTargets(props: {
</FormItem>
)}
/>
<Collapsible
open={isAdvancedOpen}
onOpenChange={setIsAdvancedOpen}
className="space-y-2"
>
<div className="flex items-center justify-between space-x-4">
<CollapsibleTrigger asChild>
<Button
variant="text"
size="sm"
className="p-0 flex items-center justify-start gap-2 w-full"
>
<h4 className="text-sm font-semibold">
Advanced TLS Settings
</h4>
<div>
<ChevronsUpDown className="h-4 w-4" />
<span className="sr-only">
Toggle
</span>
</div>
</Button>
</CollapsibleTrigger>
</div>
<CollapsibleContent className="space-y-2">
<FormField
control={tlsSettingsForm.control}
control={
tlsSettingsForm.control
}
name="tlsServerName"
render={({ field }) => (
<FormItem>
<FormLabel>
TLS Server Name (SNI)
TLS Server Name
(SNI)
</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormDescription>
The TLS Server Name to use
for SNI. Leave empty to use
The TLS Server Name
to use for SNI.
Leave empty to use
the default.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
</CollapsibleContent>
</Collapsible>
</form>
</Form>
</SettingsSectionForm>

View file

@ -59,6 +59,9 @@ import {
} from "@app/components/ui/popover";
import { CaretSortIcon, CheckIcon } from "@radix-ui/react-icons";
import { cn } from "@app/lib/cn";
import { SquareArrowOutUpRight } from "lucide-react";
import CopyTextBox from "@app/components/CopyTextBox";
import Link from "next/link";
const baseResourceFormSchema = z.object({
name: z.string().min(1).max(255),
@ -108,6 +111,8 @@ export default function Page() {
{ domainId: string; baseDomain: string }[]
>([]);
const [createLoading, setCreateLoading] = useState(false);
const [showSnippets, setShowSnippets] = useState(false);
const [resourceId, setResourceId] = useState<number | null>(null);
const resourceTypes: ReadonlyArray<ResourceTypeOption> = [
{
@ -202,7 +207,14 @@ export default function Page() {
if (res && res.status === 201) {
const id = res.data.data.resourceId;
setResourceId(id);
if (isHttp) {
router.push(`/${orgId}/settings/resources/${id}`);
} else {
setShowSnippets(true);
router.refresh();
}
}
} catch (e) {
console.error("Error creating resource:", e);
@ -301,6 +313,7 @@ export default function Page() {
{!loadingPage && (
<div>
{!showSnippets ? (
<SettingsContainer>
<SettingsSection>
<SettingsSectionHeader>
@ -324,13 +337,15 @@ export default function Page() {
Name
</FormLabel>
<FormControl>
<Input {...field} />
<Input
{...field}
/>
</FormControl>
<FormMessage />
<FormDescription>
This is the display
name for the
resource.
This is the
display name for
the resource.
</FormDescription>
</FormItem>
)}
@ -421,8 +436,9 @@ export default function Page() {
<FormMessage />
<FormDescription>
This site will
provide connectivity
to the resource.
provide
connectivity to
the resource.
</FormDescription>
</FormItem>
)}
@ -483,10 +499,13 @@ export default function Page() {
httpForm.control
}
name="isBaseDomain"
render={({ field }) => (
render={({
field
}) => (
<FormItem>
<FormLabel>
Domain Type
Domain
Type
</FormLabel>
<Select
value={
@ -608,9 +627,10 @@ export default function Page() {
</div>
</div>
<FormDescription>
The subdomain where
your resource will
be accessible.
The subdomain
where your
resource will be
accessible.
</FormDescription>
</FormItem>
)}
@ -623,10 +643,13 @@ export default function Page() {
httpForm.control
}
name="domainId"
render={({ field }) => (
render={({
field
}) => (
<FormItem>
<FormLabel>
Base Domain
Base
Domain
</FormLabel>
<Select
onValueChange={
@ -692,7 +715,9 @@ export default function Page() {
id="tcp-udp-settings-form"
>
<Controller
control={tcpUdpForm.control}
control={
tcpUdpForm.control
}
name="protocol"
render={({ field }) => (
<FormItem>
@ -725,7 +750,9 @@ export default function Page() {
/>
<FormField
control={tcpUdpForm.control}
control={
tcpUdpForm.control
}
name="proxyPort"
render={({ field }) => (
<FormItem>
@ -759,8 +786,9 @@ export default function Page() {
<FormMessage />
<FormDescription>
The external
port number to
proxy requests.
port number
to proxy
requests.
</FormDescription>
</FormItem>
)}
@ -771,7 +799,6 @@ export default function Page() {
</SettingsSectionBody>
</SettingsSection>
)}
</SettingsContainer>
<div className="flex justify-end space-x-2 mt-8">
<Button
@ -801,6 +828,81 @@ export default function Page() {
Create Resource
</Button>
</div>
</SettingsContainer>
) : (
<SettingsContainer>
<SettingsSection>
<SettingsSectionHeader>
<SettingsSectionTitle>
Configuration Snippets
</SettingsSectionTitle>
<SettingsSectionDescription>
Copy and paste these configuration snippets to set up your TCP/UDP resource
</SettingsSectionDescription>
</SettingsSectionHeader>
<SettingsSectionBody>
<div className="space-y-6">
<div className="space-y-4">
<h3 className="text-lg font-semibold">
Traefik: Add Entrypoints
</h3>
<CopyTextBox
text={`entryPoints:
${tcpUdpForm.getValues("protocol")}-${tcpUdpForm.getValues("proxyPort")}:
address: ":${tcpUdpForm.getValues("proxyPort")}/${tcpUdpForm.getValues("protocol")}"`}
wrapText={false}
/>
</div>
<div className="space-y-4">
<h3 className="text-lg font-semibold">
Gerbil: Expose Ports in Docker Compose
</h3>
<CopyTextBox
text={`ports:
- ${tcpUdpForm.getValues("proxyPort")}:${tcpUdpForm.getValues("proxyPort")}${tcpUdpForm.getValues("protocol") === "tcp" ? "" : "/" + tcpUdpForm.getValues("protocol")}`}
wrapText={false}
/>
</div>
<Link
className="text-sm text-primary flex items-center gap-1"
href="https://docs.fossorial.io/Pangolin/tcp-udp"
target="_blank"
rel="noopener noreferrer"
>
<span>
Learn how to configure TCP/UDP resources
</span>
<SquareArrowOutUpRight size={14} />
</Link>
</div>
</SettingsSectionBody>
</SettingsSection>
<div className="flex justify-end space-x-2 mt-8">
<Button
type="button"
variant="outline"
onClick={() =>
router.push(`/${orgId}/settings/resources`)
}
>
Back to Resources
</Button>
<Button
type="button"
onClick={() =>
router.push(
`/${orgId}/settings/resources/${resourceId}`
)
}
>
Go to Resource
</Button>
</div>
</SettingsContainer>
)}
</div>
)}
</>

View file

@ -57,9 +57,7 @@ import {
import { CheckIcon, ChevronsUpDown } from "lucide-react";
import { Checkbox } from "@app/components/ui/checkbox";
import { GenerateAccessTokenResponse } from "@server/routers/accessToken";
import {
constructShareLink
} from "@app/lib/shareLinks";
import { constructShareLink } from "@app/lib/shareLinks";
import { ShareLinkRow } from "./ShareLinksTable";
import { QRCodeCanvas, QRCodeSVG } from "qrcode.react";
import {
@ -528,11 +526,9 @@ export default function CreateShareLinkForm({
accessTokenId
}
token={accessToken}
resourceUrl={
form.getValues(
resourceUrl={form.getValues(
"resourceUrl"
)
}
)}
/>
</div>
</div>

View file

@ -33,9 +33,10 @@ export default function LicenseViolation() {
return (
<div className="fixed bottom-0 left-0 right-0 w-full bg-yellow-500 text-black p-4 text-center z-50">
<p>
License Violation: Using {licenseStatus.usedSites} sites
exceeds your licensed limit of {licenseStatus.maxSites}{" "}
sites. Follow license terms to continue using all features.
License Violation: This server is using{" "}
{licenseStatus.usedSites} sites which exceeds its licensed
limit of {licenseStatus.maxSites} sites. Follow license
terms to continue using all features.
</p>
</div>
);