Canvas: Prettier
Change-Id: I620dde109df0f29f0c85c6fe150e347d2c32a03e
diff --git a/apps/canvas/front/src/components/node-gateway-https.tsx b/apps/canvas/front/src/components/node-gateway-https.tsx
index 6effb26..e3f2c42 100644
--- a/apps/canvas/front/src/components/node-gateway-https.tsx
+++ b/apps/canvas/front/src/components/node-gateway-https.tsx
@@ -1,399 +1,468 @@
import { v4 as uuidv4 } from "uuid";
-import { useStateStore, AppNode, GatewayHttpsNode, ServiceNode, nodeLabel, useEnv, nodeIsConnectable } from '@/lib/state';
-import { Handle, Position, useNodes } from '@xyflow/react';
-import { NodeRect } from './node-rect';
-import { useCallback, useEffect, useMemo } from 'react';
+import {
+ useStateStore,
+ AppNode,
+ GatewayHttpsNode,
+ ServiceNode,
+ nodeLabel,
+ useEnv,
+ nodeIsConnectable,
+} from "@/lib/state";
+import { Handle, Position, useNodes } from "@xyflow/react";
+import { NodeRect } from "./node-rect";
+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 { 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"),
- subdomain: z.string().min(1, "required"),
+ network: z.string().min(1, "reqired"),
+ subdomain: z.string().min(1, "required"),
});
const connectedToSchema = z.object({
- id: z.string(),
- portId: z.string(),
+ id: z.string(),
+ portId: z.string(),
});
const authEnabledSchema = z.object({
- enabled: z.boolean(),
+ enabled: z.boolean(),
});
const authGroupSchema = z.object({
- group: z.string(),
+ group: z.string(),
});
const authNoAuthPatternSchema = z.object({
- noAuthPathPattern: z.string(),
+ noAuthPathPattern: z.string(),
});
export function NodeGatewayHttps(node: GatewayHttpsNode) {
- const { id, selected } = node;
- const isConnectableNetwork = useMemo(() => nodeIsConnectable(node, "subdomain"), [node]);
- const isConnectable = useMemo(() => nodeIsConnectable(node, "https"), [node]);
- return (
- <NodeRect id={id} selected={selected} type={node.type} state={node.data.state}>
- {nodeLabel(node)}
- <Handle
- type={"source"}
- id="subdomain"
- position={Position.Top}
- isConnectable={isConnectableNetwork}
- isConnectableStart={isConnectableNetwork}
- isConnectableEnd={isConnectableNetwork}
- />
- <Handle
- type={"target"}
- id="https"
- position={Position.Bottom}
- isConnectable={isConnectable}
- isConnectableStart={isConnectable}
- isConnectableEnd={isConnectable}
- />
- </NodeRect>
- );
+ const { id, selected } = node;
+ const isConnectableNetwork = useMemo(() => nodeIsConnectable(node, "subdomain"), [node]);
+ const isConnectable = useMemo(() => nodeIsConnectable(node, "https"), [node]);
+ return (
+ <NodeRect id={id} selected={selected} type={node.type} state={node.data.state}>
+ {nodeLabel(node)}
+ <Handle
+ type={"source"}
+ id="subdomain"
+ position={Position.Top}
+ isConnectable={isConnectableNetwork}
+ isConnectableStart={isConnectableNetwork}
+ isConnectableEnd={isConnectableNetwork}
+ />
+ <Handle
+ type={"target"}
+ id="https"
+ position={Position.Bottom}
+ isConnectable={isConnectable}
+ isConnectableStart={isConnectable}
+ isConnectableEnd={isConnectable}
+ />
+ </NodeRect>
+ );
}
export function NodeGatewayHttpsDetails({ id, data }: GatewayHttpsNode) {
- const store = useStateStore();
- const env = useEnv();
- const form = useForm<z.infer<typeof schema>>({
- resolver: zodResolver(schema),
- mode: "onChange",
- defaultValues: {
- network: data.network,
- subdomain: data.subdomain,
- },
- });
- useEffect(() => {
- const sub = form.watch((value: DeepPartial<z.infer<typeof schema>>, { name }: { name?: keyof z.infer<typeof schema> | undefined, type?: EventType | undefined }) => {
- if (name === "network") {
- let edges = store.edges;
- if (data.network !== undefined) {
- edges = edges.filter((e) => {
- if (e.source === id && e.sourceHandle === "subdomain" && e.target === data.network && e.targetHandle === "subdomain") {
- return false;
- } else {
- return true;
- }
- });
- }
- if (value.network !== undefined) {
- edges = edges.concat({
- id: uuidv4(),
- source: id,
- sourceHandle: "subdomain",
- target: value.network,
- targetHandle: "subdomain",
- });
- }
- store.setEdges(edges);
- store.updateNodeData<"gateway-https">(id, { network: value.network });
- } else if (name === "subdomain") {
- store.updateNodeData<"gateway-https">(id, { subdomain: value.subdomain });
- }
- });
- return () => sub.unsubscribe();
- }, [id, data, form, store]);
- const connectedToForm = useForm<z.infer<typeof connectedToSchema>>({
- resolver: zodResolver(connectedToSchema),
- mode: "onChange",
- defaultValues: {
- id: data.https?.serviceId,
- portId: data.https?.portId,
- },
- });
- useEffect(() => {
- connectedToForm.reset({
- id: data.https?.serviceId,
- portId: data.https?.portId,
- });
- }, [connectedToForm, data]);
- const nodes = useNodes<AppNode>();
- const selected = useMemo(() => {
- if (data !== undefined && data.https !== undefined) {
- const https = data.https;
- return nodes.find((n) => n.id === https.serviceId)! as ServiceNode;
- }
- return null;
- }, [data, nodes]);
- const selectable = useMemo(() => {
- return nodes.filter((n) => {
- if (n.id === id) {
- return false;
- }
- if (selected !== null && selected.id === id) {
- return true;
- }
- if (n.type !== "app") {
- return false;
- }
- return n.data && n.data.ports && n.data.ports.length > 0;
- })
- }, [id, 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 }) => {
- if (type !== "change") {
- return;
- }
- switch (name) {
- case "id": {
- if (!value.id) {
- break;
- }
- const current = store.edges.filter((e) => e.target === id);
- const cid = current[0] ? current[0].id : undefined;
- store.replaceEdge({
- source: value.id,
- sourceHandle: "ports",
- target: id,
- targetHandle: "https",
- }, cid);
- break;
- }
- case "portId":
- store.updateNodeData<"gateway-https">(id, {
- https: {
- serviceId: value.id,
- portId: value.portId,
- }
- });
- break;
- }
- });
- return () => sub.unsubscribe();
- }, [id, 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, authGroupForm]);
- 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, authNoAuthPatternFrom]);
- return (
- <>
- <Form {...form}>
- <form className="space-y-2">
- <FormField
- control={form.control}
- name="network"
- render={({ field }) => (
- <FormItem>
- <Select onValueChange={field.onChange} defaultValue={field.value}>
- <FormControl>
- <SelectTrigger>
- <SelectValue placeholder="Network" />
- </SelectTrigger>
- </FormControl>
- <SelectContent>
- {env.networks.map((n) => (
- <SelectItem key={n.name} value={n.domain}>{`${n.name} - ${n.domain}`}</SelectItem>
- ))}
- </SelectContent>
- </Select>
- <FormMessage />
- </FormItem>
- )}
- />
- <FormField
- control={form.control}
- name="subdomain"
- render={({ field }) => (
- <FormItem>
- <FormControl>
- <Input placeholder="subdomain" className="border border-black" {...field} />
- </FormControl>
- <FormMessage />
- </FormItem>
- )}
- />
- </form>
- </Form>
- <Form {...connectedToForm}>
- <form className="space-y-2">
- <FormField
- control={connectedToForm.control}
- name="id"
- render={({ field }) => (
- <FormItem>
- <Select onValueChange={field.onChange} defaultValue={field.value}>
- <FormControl>
- <SelectTrigger>
- <SelectValue placeholder="Service" />
- </SelectTrigger>
- </FormControl>
- <SelectContent>
- {selectable.map((n) => (
- <SelectItem key={n.id} value={n.id}>{nodeLabel(n)}</SelectItem>
- ))}
- </SelectContent>
- </Select>
- <FormMessage />
- </FormItem>
- )}
- />
- <FormField
- control={connectedToForm.control}
- name="portId"
- render={({ field }) => (
- <FormItem>
- <Select onValueChange={field.onChange} defaultValue={field.value}>
- <FormControl>
- <SelectTrigger>
- <SelectValue placeholder="Port" />
- </SelectTrigger>
- </FormControl>
- <SelectContent>
- {selected && selected.data.ports.map((p) => (
- <SelectItem key={p.id} value={p.id}>{p.name} - {p.value}</SelectItem>
- ))}
- </SelectContent>
- </Select>
- <FormMessage />
- </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
+ const store = useStateStore();
+ const env = useEnv();
+ const form = useForm<z.infer<typeof schema>>({
+ resolver: zodResolver(schema),
+ mode: "onChange",
+ defaultValues: {
+ network: data.network,
+ subdomain: data.subdomain,
+ },
+ });
+ useEffect(() => {
+ const sub = form.watch(
+ (
+ value: DeepPartial<z.infer<typeof schema>>,
+ { name }: { name?: keyof z.infer<typeof schema> | undefined; type?: EventType | undefined },
+ ) => {
+ if (name === "network") {
+ let edges = store.edges;
+ if (data.network !== undefined) {
+ edges = edges.filter((e) => {
+ if (
+ e.source === id &&
+ e.sourceHandle === "subdomain" &&
+ e.target === data.network &&
+ e.targetHandle === "subdomain"
+ ) {
+ return false;
+ } else {
+ return true;
+ }
+ });
+ }
+ if (value.network !== undefined) {
+ edges = edges.concat({
+ id: uuidv4(),
+ source: id,
+ sourceHandle: "subdomain",
+ target: value.network,
+ targetHandle: "subdomain",
+ });
+ }
+ store.setEdges(edges);
+ store.updateNodeData<"gateway-https">(id, { network: value.network });
+ } else if (name === "subdomain") {
+ store.updateNodeData<"gateway-https">(id, { subdomain: value.subdomain });
+ }
+ },
+ );
+ return () => sub.unsubscribe();
+ }, [id, data, form, store]);
+ const connectedToForm = useForm<z.infer<typeof connectedToSchema>>({
+ resolver: zodResolver(connectedToSchema),
+ mode: "onChange",
+ defaultValues: {
+ id: data.https?.serviceId,
+ portId: data.https?.portId,
+ },
+ });
+ useEffect(() => {
+ connectedToForm.reset({
+ id: data.https?.serviceId,
+ portId: data.https?.portId,
+ });
+ }, [connectedToForm, data]);
+ const nodes = useNodes<AppNode>();
+ const selected = useMemo(() => {
+ if (data !== undefined && data.https !== undefined) {
+ const https = data.https;
+ return nodes.find((n) => n.id === https.serviceId)! as ServiceNode;
+ }
+ return null;
+ }, [data, nodes]);
+ const selectable = useMemo(() => {
+ return nodes.filter((n) => {
+ if (n.id === id) {
+ return false;
+ }
+ if (selected !== null && selected.id === id) {
+ return true;
+ }
+ if (n.type !== "app") {
+ return false;
+ }
+ return n.data && n.data.ports && n.data.ports.length > 0;
+ });
+ }, [id, 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 },
+ ) => {
+ if (type !== "change") {
+ return;
+ }
+ switch (name) {
+ case "id": {
+ if (!value.id) {
+ break;
+ }
+ const current = store.edges.filter((e) => e.target === id);
+ const cid = current[0] ? current[0].id : undefined;
+ store.replaceEdge(
+ {
+ source: value.id,
+ sourceHandle: "ports",
+ target: id,
+ targetHandle: "https",
+ },
+ cid,
+ );
+ break;
+ }
+ case "portId":
+ store.updateNodeData<"gateway-https">(id, {
+ https: {
+ serviceId: value.id,
+ portId: value.portId,
+ },
+ });
+ break;
+ }
+ },
+ );
+ return () => sub.unsubscribe();
+ }, [id, 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, authGroupForm],
+ );
+ 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, authNoAuthPatternFrom],
+ );
+ return (
+ <>
+ <Form {...form}>
+ <form className="space-y-2">
+ <FormField
+ control={form.control}
+ name="network"
+ render={({ field }) => (
+ <FormItem>
+ <Select onValueChange={field.onChange} defaultValue={field.value}>
+ <FormControl>
+ <SelectTrigger>
+ <SelectValue placeholder="Network" />
+ </SelectTrigger>
+ </FormControl>
+ <SelectContent>
+ {env.networks.map((n) => (
+ <SelectItem
+ key={n.name}
+ value={n.domain}
+ >{`${n.name} - ${n.domain}`}</SelectItem>
+ ))}
+ </SelectContent>
+ </Select>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+ <FormField
+ control={form.control}
+ name="subdomain"
+ render={({ field }) => (
+ <FormItem>
+ <FormControl>
+ <Input placeholder="subdomain" className="border border-black" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+ </form>
+ </Form>
+ <Form {...connectedToForm}>
+ <form className="space-y-2">
+ <FormField
+ control={connectedToForm.control}
+ name="id"
+ render={({ field }) => (
+ <FormItem>
+ <Select onValueChange={field.onChange} defaultValue={field.value}>
+ <FormControl>
+ <SelectTrigger>
+ <SelectValue placeholder="Service" />
+ </SelectTrigger>
+ </FormControl>
+ <SelectContent>
+ {selectable.map((n) => (
+ <SelectItem key={n.id} value={n.id}>
+ {nodeLabel(n)}
+ </SelectItem>
+ ))}
+ </SelectContent>
+ </Select>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+ <FormField
+ control={connectedToForm.control}
+ name="portId"
+ render={({ field }) => (
+ <FormItem>
+ <Select onValueChange={field.onChange} defaultValue={field.value}>
+ <FormControl>
+ <SelectTrigger>
+ <SelectValue placeholder="Port" />
+ </SelectTrigger>
+ </FormControl>
+ <SelectContent>
+ {selected &&
+ selected.data.ports.map((p) => (
+ <SelectItem key={p.id} value={p.id}>
+ {p.name} - {p.value}
+ </SelectItem>
+ ))}
+ </SelectContent>
+ </Select>
+ <FormMessage />
+ </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>
+ </>
+ ) : (
+ <></>
+ )}
+ </>
+ );
+}