diff --git a/src/api/ddns.ts b/src/api/ddns.ts new file mode 100644 index 0000000..0b74c2d --- /dev/null +++ b/src/api/ddns.ts @@ -0,0 +1,18 @@ +import { ModelDDNSForm } from "@/types" +import { fetcher, FetcherMethod } from "./api" + +export const createDDNSProfile = async (data: ModelDDNSForm): Promise => { + return fetcher(FetcherMethod.POST, '/api/v1/ddns', data) +} + +export const updateDDNSProfile = async (id: number, data: ModelDDNSForm): Promise => { + return fetcher(FetcherMethod.PATCH, `/api/v1/ddns/${id}`, data) +} + +export const deleteDDNSProfiles = async (id: number[]): Promise => { + return fetcher(FetcherMethod.POST, '/api/v1/batch-delete/ddns', id) +} + +export const getDDNSProviders = async (): Promise => { + return fetcher(FetcherMethod.GET, '/api/v1/ddns/providers', null) +} diff --git a/src/api/nat.ts b/src/api/nat.ts new file mode 100644 index 0000000..524a02e --- /dev/null +++ b/src/api/nat.ts @@ -0,0 +1,14 @@ +import { ModelNATForm } from "@/types" +import { fetcher, FetcherMethod } from "./api" + +export const createNAT = async (data: ModelNATForm): Promise => { + return fetcher(FetcherMethod.POST, '/api/v1/nat', data) +} + +export const updateNAT = async (id: number, data: ModelNATForm): Promise => { + return fetcher(FetcherMethod.PATCH, `/api/v1/nat/${id}`, data) +} + +export const deleteNAT = async (id: number[]): Promise => { + return fetcher(FetcherMethod.POST, '/api/v1/batch-delete/nat', id) +} diff --git a/src/components/ddns.tsx b/src/components/ddns.tsx new file mode 100644 index 0000000..680449f --- /dev/null +++ b/src/components/ddns.tsx @@ -0,0 +1,361 @@ +import { Button } from "@/components/ui/button" +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog" +import { Input } from "@/components/ui/input" +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select" +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form" +import { ScrollArea } from "@/components/ui/scroll-area" +import { useForm } from "react-hook-form" +import { z } from "zod" +import { zodResolver } from "@hookform/resolvers/zod" +import { ModelDDNSProfile } from "@/types" +import { Checkbox } from "@/components/ui/checkbox" +import { Label } from "@/components/ui/label" +import { conv } from "@/lib/utils" +import { useState } from "react" +import { KeyedMutator } from "swr" +import { asOptionalField } from "@/lib/utils" +import { IconButton } from "@/components/xui/icon-button" +import { ddnsTypes, ddnsRequestTypes } from "@/types" +import { createDDNSProfile, updateDDNSProfile } from "@/api/ddns" +import { Textarea } from "./ui/textarea" + +interface DDNSCardProps { + data?: ModelDDNSProfile; + providers: string[]; + mutate: KeyedMutator; +} + +const ddnsFormSchema = z.object({ + max_retries: z.coerce.number().int().min(1), + enable_ipv4: asOptionalField(z.boolean()), + enable_ipv6: asOptionalField(z.boolean()), + name: z.string().min(1), + provider: z.string(), + domains: z.array(z.string()), + access_id: asOptionalField(z.string()), + access_secret: asOptionalField(z.string()), + webhook_url: asOptionalField(z.string().url()), + webhook_method: asOptionalField(z.coerce.number().int().min(1).max(255)), + webhook_request_type: asOptionalField(z.coerce.number().int().min(1).max(255).default(1)), + webhook_request_body: asOptionalField(z.string()), + webhook_headers: asOptionalField(z.string()), +}); + +export const DDNSCard: React.FC = ({ data, providers, mutate }) => { + const form = useForm>({ + resolver: zodResolver(ddnsFormSchema), + defaultValues: data ? data : { + max_retries: 3, + name: "", + provider: "dummy", + domains: [], + }, + resetOptions: { + keepDefaultValues: false, + } + }) + + const [open, setOpen] = useState(false); + + const onSubmit = async (values: z.infer) => { + data?.id ? await updateDDNSProfile(data.id, values) : await createDDNSProfile(values); + setOpen(false); + await mutate(); + form.reset(); + } + + return ( + + + {data + ? + + : + + } + + + +
+ + New DDNS Profile + + +
+ + ( + + Name + + + + + + )} + /> + ( + + Provider + + + + )} + /> + ( + + Domains (separate with comma) + + { + const arr = conv.strToArr(e.target.value); + field.onChange(arr); + }} + /> + + + + )} + /> + ( + + Credential 1 + + + + + + )} + /> + ( + + Credential 2 + + + + + + )} + /> + ( + + Maximum retry attempts + + + + + + )} + /> + ( + + Webhook URL + + + + + + )} + /> + ( + + Webhook Request Method + + + + )} + /> + ( + + Webhook Request Type + + + + )} + /> + ( + + Webhook Request Headers + +