Canvas: Expose ingress auth details
Change-Id: I337163f5919db5c8e48d6d429dcdc6420b196d3d
diff --git a/apps/canvas/front/package-lock.json b/apps/canvas/front/package-lock.json
index 867e8c6..39c0823 100644
--- a/apps/canvas/front/package-lock.json
+++ b/apps/canvas/front/package-lock.json
@@ -10,6 +10,7 @@
"dependencies": {
"@hookform/resolvers": "^3.9.1",
"@radix-ui/react-accordion": "^1.2.1",
+ "@radix-ui/react-checkbox": "^1.3.1",
"@radix-ui/react-collapsible": "^1.1.1",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-icons": "^1.3.1",
@@ -1090,6 +1091,193 @@
}
}
},
+ "node_modules/@radix-ui/react-checkbox": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.1.tgz",
+ "integrity": "sha512-xTaLKAO+XXMPK/BpVTSaAAhlefmvMSACjIhK9mGsImvX2ljcTDm8VGR1CuS1uYcNdR5J+oiOhoJZc5un6bh3VQ==",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-presence": "1.1.4",
+ "@radix-ui/react-primitive": "2.1.2",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-use-previous": "1.1.1",
+ "@radix-ui/react-use-size": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/primitive": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz",
+ "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="
+ },
+ "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
+ "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-context": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
+ "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-presence": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz",
+ "integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-primitive": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.2.tgz",
+ "integrity": "sha512-uHa+l/lKfxuDD2zjN/0peM/RhhSmRjr5YWdk/37EnSv1nJ88uvG85DPexSm8HdFQROd2VdERJ6ynXbkCFi+APw==",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.2.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-slot": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.2.tgz",
+ "integrity": "sha512-y7TBO4xN4Y94FvcWIOIh18fM4R1A8S4q1jhoz4PNzOoHsFcN8pogcFmZrTYAm4F9VRUrWP/Mw7xSKybIeRI+CQ==",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-use-controllable-state": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
+ "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
+ "dependencies": {
+ "@radix-ui/react-use-effect-event": "0.0.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-use-layout-effect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
+ "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-use-previous": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz",
+ "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-use-size": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz",
+ "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-collapsible": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.1.tgz",
@@ -1776,6 +1964,37 @@
}
}
},
+ "node_modules/@radix-ui/react-use-effect-event": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
+ "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-effect-event/node_modules/@radix-ui/react-use-layout-effect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
+ "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-use-escape-keydown": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz",
diff --git a/apps/canvas/front/package.json b/apps/canvas/front/package.json
index 9eefaff..4c9ba0c 100644
--- a/apps/canvas/front/package.json
+++ b/apps/canvas/front/package.json
@@ -16,6 +16,7 @@
"dependencies": {
"@hookform/resolvers": "^3.9.1",
"@radix-ui/react-accordion": "^1.2.1",
+ "@radix-ui/react-checkbox": "^1.3.1",
"@radix-ui/react-collapsible": "^1.1.1",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-icons": "^1.3.1",
diff --git a/apps/canvas/front/src/components/node-gateway-https.tsx b/apps/canvas/front/src/components/node-gateway-https.tsx
index 1397f5c..e618943 100644
--- a/apps/canvas/front/src/components/node-gateway-https.tsx
+++ b/apps/canvas/front/src/components/node-gateway-https.tsx
@@ -2,13 +2,17 @@
import { useStateStore, AppNode, GatewayHttpsNode, ServiceNode, nodeLabel, useEnv, nodeIsConnectable } from '@/lib/state';
import { Handle, Position, useNodes } from '@xyflow/react';
import { NodeRect } from './node-rect';
-import { useEffect, useMemo } from 'react';
+import { useCallback, useEffect, useMemo } from 'react';
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm, EventType, DeepPartial } from 'react-hook-form';
import { Form, FormControl, FormField, FormItem, FormMessage } from './ui/form';
import { Input } from './ui/input';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './ui/select';
+import { Checkbox } from "./ui/checkbox";
+import { Label } from "./ui/label";
+import { Button } from "./ui/button";
+import { XIcon } from "lucide-react";
const schema = z.object({
network: z.string().min(1, "reqired"),
@@ -20,6 +24,18 @@
portId: z.string(),
});
+const authEnabledSchema = z.object({
+ enabled: z.boolean(),
+});
+
+const authGroupSchema = z.object({
+ group: z.string(),
+});
+
+const authNoAuthPatternSchema = z.object({
+ noAuthPathPattern: z.string(),
+});
+
export function NodeGatewayHttps(node: GatewayHttpsNode) {
const { id, selected } = node;
const isConnectableNetwork = useMemo(() => nodeIsConnectable(node, "subdomain"), [node]);
@@ -29,19 +45,19 @@
{nodeLabel(node)}
<Handle
type={"source"}
- id="subdomain"
+ id="subdomain"
position={Position.Top}
isConnectable={isConnectableNetwork}
- isConnectableStart={isConnectableNetwork}
- isConnectableEnd={isConnectableNetwork}
+ isConnectableStart={isConnectableNetwork}
+ isConnectableEnd={isConnectableNetwork}
/>
<Handle
type={"target"}
- id="https"
+ id="https"
position={Position.Bottom}
isConnectable={isConnectable}
- isConnectableStart={isConnectable}
- isConnectableEnd={isConnectable}
+ isConnectableStart={isConnectable}
+ isConnectableEnd={isConnectable}
/>
</NodeRect>
);
@@ -64,7 +80,6 @@
let edges = store.edges;
if (data.network !== undefined) {
edges = edges.filter((e) => {
- console.log(e);
if (e.source === id && e.sourceHandle === "subdomain" && e.target === data.network && e.targetHandle === "subdomain") {
return false;
} else {
@@ -127,7 +142,6 @@
}, [nodes, selected]);
useEffect(() => {
const sub = connectedToForm.watch((value: DeepPartial<z.infer<typeof connectedToSchema>>, { name, type }: { name?: keyof z.infer<typeof connectedToSchema> | undefined, type?: EventType | undefined }) => {
- console.log({ name, type });
if (type !== "change") {
return;
}
@@ -157,11 +171,86 @@
});
return () => sub.unsubscribe();
}, [connectedToForm, store, selectable]);
+ const authEnabledForm = useForm<z.infer<typeof authEnabledSchema>>({
+ resolver: zodResolver(authEnabledSchema),
+ mode: "onChange",
+ defaultValues: {
+ enabled: data.auth ? data.auth.enabled : false,
+ },
+ });
+ const authGroupForm = useForm<z.infer<typeof authGroupSchema>>({
+ resolver: zodResolver(authGroupSchema),
+ mode: "onSubmit",
+ defaultValues: {
+ group: "",
+ },
+ }); const authNoAuthPatternFrom = useForm<z.infer<typeof authNoAuthPatternSchema>>({
+ resolver: zodResolver(authNoAuthPatternSchema),
+ mode: "onChange",
+ defaultValues: {
+ noAuthPathPattern: "",
+ },
+ });
+ useEffect(() => {
+ const sub = authEnabledForm.watch((value, { name }) => {
+ if (name === "enabled") {
+ store.updateNodeData<"gateway-https">(id, {
+ auth: {
+ ...data.auth,
+ enabled: value.enabled,
+ }
+ })
+ }
+ });
+ return () => sub.unsubscribe();
+ }, [id, data, authEnabledForm, store]);
+ const removeGroup = useCallback((group: string) => {
+ const groups = data?.auth?.groups || [];
+ store.updateNodeData<"gateway-https">(id, {
+ auth: {
+ ...data.auth,
+ groups: groups.filter((g) => g !== group),
+ },
+ });
+ return true;
+ }, [id, data, store]);
+ const onGroupSubmit = useCallback((values: z.infer<typeof authGroupSchema>) => {
+ const groups = data.auth?.groups || [];
+ groups.push(values.group)
+ store.updateNodeData<"gateway-https">(id, {
+ auth: {
+ ...data.auth,
+ groups,
+ },
+ });
+ authGroupForm.reset();
+ }, [id, data, store]);
+ const removeNoAuthPathPattern = useCallback((path: string) => {
+ const noAuthPathPatterns = data?.auth?.noAuthPathPatterns || [];
+ store.updateNodeData<"gateway-https">(id, {
+ auth: {
+ ...data.auth,
+ noAuthPathPatterns: noAuthPathPatterns.filter((p) => p !== path),
+ },
+ });
+ return true;
+ }, [id, data, store]);
+ const onNoAuthPathPatternSubmit = useCallback((values: z.infer<typeof authNoAuthPatternSchema>) => {
+ const noAuthPathPatterns = data.auth?.noAuthPathPatterns || [];
+ noAuthPathPatterns.push(values.noAuthPathPattern)
+ store.updateNodeData<"gateway-https">(id, {
+ auth: {
+ ...data.auth,
+ noAuthPathPatterns,
+ },
+ });
+ authNoAuthPatternFrom.reset();
+ }, [id, data, store]);
return (
<>
<Form {...form}>
<form className="space-y-2">
- <FormField
+ <FormField
control={form.control}
name="network"
render={({ field }) => (
@@ -182,7 +271,7 @@
</FormItem>
)}
/>
- <FormField
+ <FormField
control={form.control}
name="subdomain"
render={({ field }) => (
@@ -198,7 +287,7 @@
</Form>
<Form {...connectedToForm}>
<form className="space-y-2">
- <FormField
+ <FormField
control={connectedToForm.control}
name="id"
render={({ field }) => (
@@ -219,7 +308,7 @@
</FormItem>
)}
/>
- <FormField
+ <FormField
control={connectedToForm.control}
name="portId"
render={({ field }) => (
@@ -237,11 +326,73 @@
</SelectContent>
</Select>
<FormMessage />
- </FormItem>
+ </FormItem>
)}
/>
</form>
</Form>
+ Auth
+ <Form {...authEnabledForm}>
+ <form className="space-y-2">
+ <FormField
+ control={authEnabledForm.control}
+ name="enabled"
+ render={({ field }) => (
+ <FormItem>
+ <Checkbox id="authEnabled" onCheckedChange={field.onChange} checked={field.value} />
+ <Label htmlFor="authEnabled">Enabled</Label>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+ </form>
+ </Form>
+ {data && data.auth && data.auth.enabled ? (
+ <>
+ Authorized Groups
+ <ul>
+ {(data.auth.groups || []).map((p) => (<li key={p}><Button size={"icon"} variant={"ghost"} onClick={() => removeGroup(p)}><XIcon /></Button> {p}</li>))}
+ </ul>
+ <Form {...authGroupForm}>
+ <form className="flex flex-row space-x-1" onSubmit={authGroupForm.handleSubmit(onGroupSubmit)}>
+ <FormField
+ control={authGroupForm.control}
+ name="group"
+ render={({ field }) => (
+ <FormItem>
+ <FormControl>
+ <Input placeholder="group" className="border border-black" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+ <Button type="submit">Add Group</Button>
+ </form>
+ </Form>
+ Auth optional path patterns
+ <ul>
+ {(data.auth.noAuthPathPatterns || []).map((p) => (<li key={p}><Button size={"icon"} variant={"ghost"} onClick={() => removeNoAuthPathPattern(p)}><XIcon /></Button> {p}</li>))}
+ </ul>
+ <Form {...authNoAuthPatternFrom}>
+ <form className="flex flex-row space-x-1" onSubmit={authNoAuthPatternFrom.handleSubmit(onNoAuthPathPatternSubmit)}>
+ <FormField
+ control={authNoAuthPatternFrom.control}
+ name="noAuthPathPattern"
+ render={({ field }) => (
+ <FormItem>
+ <FormControl>
+ <Input placeholder="group" className="border border-black" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+ <Button type="submit">Add</Button>
+ </form>
+ </Form>
+ </>
+ ) : (<></>)}
</>
);
}
\ No newline at end of file
diff --git a/apps/canvas/front/src/components/ui/checkbox.tsx b/apps/canvas/front/src/components/ui/checkbox.tsx
new file mode 100644
index 0000000..8d02b28
--- /dev/null
+++ b/apps/canvas/front/src/components/ui/checkbox.tsx
@@ -0,0 +1,27 @@
+import * as React from "react"
+import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
+import { cn } from "@/lib/utils"
+import { CheckIcon } from "@radix-ui/react-icons"
+
+const Checkbox = React.forwardRef<
+ React.ElementRef<typeof CheckboxPrimitive.Root>,
+ React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
+>(({ className, ...props }, ref) => (
+ <CheckboxPrimitive.Root
+ ref={ref}
+ className={cn(
+ "peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
+ className
+ )}
+ {...props}
+ >
+ <CheckboxPrimitive.Indicator
+ className={cn("flex items-center justify-center text-current")}
+ >
+ <CheckIcon className="h-4 w-4" />
+ </CheckboxPrimitive.Indicator>
+ </CheckboxPrimitive.Root>
+))
+Checkbox.displayName = CheckboxPrimitive.Root.displayName
+
+export { Checkbox }
diff --git a/apps/canvas/front/src/lib/config.ts b/apps/canvas/front/src/lib/config.ts
index 22353f8..d6646c9 100644
--- a/apps/canvas/front/src/lib/config.ts
+++ b/apps/canvas/front/src/lib/config.ts
@@ -121,7 +121,13 @@
port: {
name: n.data.ports.find((p) => p.id === i.data.https!.portId)!.name,
},
- auth: { enabled: false },
+ auth: (i.data.auth?.enabled || false ? {
+ enabled: true,
+ groups: i.data.auth!.groups,
+ noAuthPathPatterns: i.data.auth!.noAuthPathPatterns,
+ } : {
+ enabled: false,
+ }),
})),
expose: findExpose(n),
preBuildCommands: n.data.preBuildCommands ? n.data.preBuildCommands.split("\n").map((cmd) => ({ bin: cmd })) : [],
diff --git a/apps/canvas/front/src/lib/state.ts b/apps/canvas/front/src/lib/state.ts
index ee6f6d2..02fd983 100644
--- a/apps/canvas/front/src/lib/state.ts
+++ b/apps/canvas/front/src/lib/state.ts
@@ -41,6 +41,11 @@
network?: string;
subdomain?: string;
https?: PortConnectedTo;
+ auth?: {
+ enabled: boolean;
+ groups: string[];
+ noAuthPathPatterns: string[];
+ }
};
export type GatewayHttpsNode = Node<GatewayHttpsData> & {