add copy code snippets to raw tcp/udp

This commit is contained in:
Milo Schwartz 2025-01-30 22:31:29 -05:00
parent f40d91ff9e
commit 844b12d363
No known key found for this signature in database
3 changed files with 320 additions and 232 deletions

View file

@ -60,7 +60,6 @@ const configSchema = z.object({
.transform(stoi) .transform(stoi)
.pipe(portSchema), .pipe(portSchema),
internal_hostname: z.string().transform((url) => url.toLowerCase()), internal_hostname: z.string().transform((url) => url.toLowerCase()),
secure_cookies: z.boolean(),
session_cookie_name: z.string(), session_cookie_name: z.string(),
resource_access_token_param: z.string(), resource_access_token_param: z.string(),
resource_session_request_param: z.string(), resource_session_request_param: z.string(),

View file

@ -62,6 +62,7 @@ import {
import { subdomainSchema } from "@server/schemas/subdomainSchema"; import { subdomainSchema } from "@server/schemas/subdomainSchema";
import Link from "next/link"; import Link from "next/link";
import { SquareArrowOutUpRight } from "lucide-react"; import { SquareArrowOutUpRight } from "lucide-react";
import CopyTextBox from "@app/components/CopyTextBox";
const createResourceFormSchema = z const createResourceFormSchema = z
.object({ .object({
@ -129,6 +130,10 @@ export default function CreateResourceForm({
const [sites, setSites] = useState<ListSitesResponse["sites"]>([]); const [sites, setSites] = useState<ListSitesResponse["sites"]>([]);
const [domainSuffix, setDomainSuffix] = useState<string>(org.org.domain); const [domainSuffix, setDomainSuffix] = useState<string>(org.org.domain);
const [showSnippets, setShowSnippets] = useState(false);
const [resourceId, setResourceId] = useState<number | null>(null);
const form = useForm<CreateResourceFormValues>({ const form = useForm<CreateResourceFormValues>({
resolver: zodResolver(createResourceFormSchema), resolver: zodResolver(createResourceFormSchema),
defaultValues: { defaultValues: {
@ -186,10 +191,20 @@ export default function CreateResourceForm({
if (res && res.status === 201) { if (res && res.status === 201) {
const id = res.data.data.resourceId; const id = res.data.data.resourceId;
// navigate to the resource page setResourceId(id);
router.push(`/${orgId}/settings/resources/${id}`);
if (data.http) {
goToResource();
} else {
setShowSnippets(true);
} }
} }
}
function goToResource() {
// navigate to the resource page
router.push(`/${orgId}/settings/resources/${resourceId}`);
}
return ( return (
<> <>
@ -211,6 +226,7 @@ export default function CreateResourceForm({
</CredenzaDescription> </CredenzaDescription>
</CredenzaHeader> </CredenzaHeader>
<CredenzaBody> <CredenzaBody>
{!showSnippets && (
<Form {...form}> <Form {...form}>
<form <form
onSubmit={form.handleSubmit(onSubmit)} onSubmit={form.handleSubmit(onSubmit)}
@ -230,8 +246,9 @@ export default function CreateResourceForm({
/> />
</FormControl> </FormControl>
<FormDescription> <FormDescription>
This is the name that will be This is the name that will
displayed for this resource. be displayed for this
resource.
</FormDescription> </FormDescription>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@ -250,13 +267,15 @@ export default function CreateResourceForm({
</FormLabel> </FormLabel>
<FormDescription> <FormDescription>
Toggle if this is an Toggle if this is an
HTTP resource or a raw HTTP resource or a
TCP/UDP resource raw TCP/UDP resource
</FormDescription> </FormDescription>
</div> </div>
<FormControl> <FormControl>
<Switch <Switch
checked={field.value} checked={
field.value
}
onCheckedChange={ onCheckedChange={
field.onChange field.onChange
} }
@ -273,11 +292,14 @@ export default function CreateResourceForm({
name="subdomain" name="subdomain"
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Subdomain</FormLabel> <FormLabel>
Subdomain
</FormLabel>
<FormControl> <FormControl>
<CustomDomainInput <CustomDomainInput
value={ value={
field.value ?? "" field.value ??
""
} }
domainSuffix={ domainSuffix={
domainSuffix domainSuffix
@ -292,9 +314,10 @@ export default function CreateResourceForm({
/> />
</FormControl> </FormControl>
<FormDescription> <FormDescription>
This is the fully qualified This is the fully
domain name that will be qualified domain name
used to access the resource. that will be used to
access the resource.
</FormDescription> </FormDescription>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@ -310,7 +333,8 @@ export default function CreateResourceForm({
rel="noopener noreferrer" rel="noopener noreferrer"
> >
<span> <span>
Learn how to configure TCP/UDP resources Learn how to configure TCP/UDP
resources
</span> </span>
<SquareArrowOutUpRight size={14} /> <SquareArrowOutUpRight size={14} />
</Link> </Link>
@ -347,8 +371,8 @@ export default function CreateResourceForm({
</SelectContent> </SelectContent>
</Select> </Select>
<FormDescription> <FormDescription>
The protocol to use for The protocol to use
the resource for the resource
</FormDescription> </FormDescription>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@ -385,9 +409,10 @@ export default function CreateResourceForm({
/> />
</FormControl> </FormControl>
<FormDescription> <FormDescription>
The port number to proxy The port number to
requests to (required proxy requests to
for non-HTTP resources) (required for
non-HTTP resources)
</FormDescription> </FormDescription>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@ -416,7 +441,9 @@ export default function CreateResourceForm({
> >
{field.value {field.value
? sites.find( ? sites.find(
(site) => (
site
) =>
site.siteId === site.siteId ===
field.value field.value
)?.name )?.name
@ -430,11 +457,14 @@ export default function CreateResourceForm({
<CommandInput placeholder="Search site..." /> <CommandInput placeholder="Search site..." />
<CommandList> <CommandList>
<CommandEmpty> <CommandEmpty>
No site found. No site
found.
</CommandEmpty> </CommandEmpty>
<CommandGroup> <CommandGroup>
{sites.map( {sites.map(
(site) => ( (
site
) => (
<CommandItem <CommandItem
value={ value={
site.niceId site.niceId
@ -470,8 +500,8 @@ export default function CreateResourceForm({
</PopoverContent> </PopoverContent>
</Popover> </Popover>
<FormDescription> <FormDescription>
This is the site that will be This is the site that will
used in the dashboard. be used in the dashboard.
</FormDescription> </FormDescription>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@ -479,16 +509,75 @@ export default function CreateResourceForm({
/> />
</form> </form>
</Form> </Form>
)}
{showSnippets && (
<div>
<div className="flex items-start space-x-4 mb-6 last:mb-0">
<div className="flex-shrink-0 w-8 h-8 bg-muted text-primary-foreground rounded-full flex items-center justify-center font-bold">
1
</div>
<div className="flex-grow">
<h3 className="text-lg font-semibold mb-3">
Traefik: Add Entrypoints
</h3>
<CopyTextBox
text={`entryPoints:
${form.getValues("protocol")}-${form.getValues("proxyPort")}:
address: ":${form.getValues("proxyPort")}/${form.getValues("protocol")}"`}
wrapText={false}
/>
</div>
</div>
<div className="flex items-start space-x-4 mb-6 last:mb-0">
<div className="flex-shrink-0 w-8 h-8 bg-muted text-primary-foreground rounded-full flex items-center justify-center font-bold">
2
</div>
<div className="flex-grow">
<h3 className="text-lg font-semibold mb-3">
Gerbil: Expose Ports in Docker
Compose
</h3>
<CopyTextBox
text={`ports:
- ${form.getValues("proxyPort")}:${form.getValues("proxyPort")}${form.getValues("protocol") === "tcp" ? "" : "/" + form.getValues("protocol")}`}
wrapText={false}
/>
</div>
</div>
<Link
className="text-sm text-primary flex items-center gap-1"
href="https://docs.fossorial.io/Getting%20Started/tcp-udp"
target="_blank"
rel="noopener noreferrer"
>
<span>
Make sure to follow the full guide
</span>
<SquareArrowOutUpRight size={14} />
</Link>
</div>
)}
</CredenzaBody> </CredenzaBody>
<CredenzaFooter> <CredenzaFooter>
<Button {!showSnippets && <Button
type="submit" type="submit"
form="create-resource-form" form="create-resource-form"
loading={loading} loading={loading}
disabled={loading} disabled={loading}
> >
Create Resource Create Resource
</Button> </Button>}
{showSnippets && <Button
loading={loading}
onClick={() => goToResource()}
>
Go to Resource
</Button>}
<CredenzaClose asChild> <CredenzaClose asChild>
<Button variant="outline">Close</Button> <Button variant="outline">Close</Button>
</CredenzaClose> </CredenzaClose>

View file

@ -130,7 +130,7 @@ export default function ReverseProxyTargets(props: {
const addTargetForm = useForm({ const addTargetForm = useForm({
resolver: zodResolver(addTargetSchema), resolver: zodResolver(addTargetSchema),
defaultValues: { defaultValues: {
ip: "localhost", ip: "",
method: resource.http ? "http" : null, method: resource.http ? "http" : null,
port: resource.http ? 80 : resource.proxyPort || 1234 port: resource.http ? 80 : resource.proxyPort || 1234
// protocol: "TCP", // protocol: "TCP",