From 960853ed29e31da44e7d3a390f061e4f6436a21e Mon Sep 17 00:00:00 2001 From: ahmed-abdelhamid Date: Tue, 3 Oct 2023 09:54:21 +0300 Subject: [PATCH 1/8] list near nodes --- .../near/[nodeName]/components/api-tab.tsx | 260 ++++++++++++++++++ .../components/bitcoin-node-stats.tsx | 104 +++++++ .../[nodeName]/components/danger-zone-tab.tsx | 76 +++++ .../[nodeName]/components/protocol-tab.tsx | 53 ++++ .../near/[nodeName]/components/wallet-tab.tsx | 131 +++++++++ .../deployments/near/[nodeName]/page.tsx | 139 ++++++++++ .../deployments/near/components/client.tsx | 60 ++++ .../components/create-bitcoin-node-form.tsx | 197 +++++++++++++ .../(main)/deployments/near/new/page.tsx | 35 +++ .../(main)/deployments/near/page.tsx | 21 ++ src/enums/index.ts | 6 + src/types/index.ts | 17 ++ 12 files changed, 1099 insertions(+) create mode 100644 src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/api-tab.tsx create mode 100644 src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/bitcoin-node-stats.tsx create mode 100644 src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/danger-zone-tab.tsx create mode 100644 src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/protocol-tab.tsx create mode 100644 src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/wallet-tab.tsx create mode 100644 src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/page.tsx create mode 100644 src/app/(dashboard)/[workspaceId]/(main)/deployments/near/components/client.tsx create mode 100644 src/app/(dashboard)/[workspaceId]/(main)/deployments/near/components/create-bitcoin-node-form.tsx create mode 100644 src/app/(dashboard)/[workspaceId]/(main)/deployments/near/new/page.tsx create mode 100644 src/app/(dashboard)/[workspaceId]/(main)/deployments/near/page.tsx diff --git a/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/api-tab.tsx b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/api-tab.tsx new file mode 100644 index 00000000..84a2bfa3 --- /dev/null +++ b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/api-tab.tsx @@ -0,0 +1,260 @@ +"use client"; + +import * as z from "zod"; +import Link from "next/link"; +import { useParams } from "next/navigation"; +import { isAxiosError } from "axios"; +import { useFieldArray, useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { MinusCircle, PlusCircle } from "lucide-react"; + +import { client } from "@/lib/client-instance"; +import { BitcoinNode, Secret } from "@/types"; +import { Roles, SecretType } from "@/enums"; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Switch } from "@/components/ui/switch"; +import { Button } from "@/components/ui/button"; +import { Alert, AlertDescription } from "@/components/ui/alert"; +import { TabsFooter } from "@/components/ui/tabs"; +import { Input } from "@/components/ui/input"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; + +interface APITabProps { + node: BitcoinNode; + role: Roles; + secrets: Secret[]; +} + +const schema = z.object({ + rpc: z.boolean(), + txIndex: z.boolean(), + rpcUsers: z + .object({ + username: z.string().min(1, "Username is required"), + passwordSecretName: z.string().min(1, "Please select a password"), + }) + .array() + .nonempty(), +}); + +type Schema = z.infer; + +export const APITab: React.FC = ({ node, role, secrets }) => { + const params = useParams(); + const { rpc, txIndex, rpcUsers } = node; + + const form = useForm({ + resolver: zodResolver(schema), + defaultValues: { rpc, txIndex, rpcUsers }, + }); + + const { + formState: { + isSubmitted, + isSubmitting, + isValid, + isDirty, + isSubmitSuccessful, + errors, + }, + control, + reset, + setError, + } = form; + + const { fields, append, remove } = useFieldArray({ + control, + name: "rpcUsers", + }); + + const onSubmit = async (values: Schema) => { + try { + const { data } = await client.put( + `/bitcoin/nodes/${node.name}`, + values + ); + const { rpc, txIndex, rpcUsers } = data; + reset({ rpc, txIndex, rpcUsers }); + } catch (error) { + if (isAxiosError(error)) { + const { response } = error; + + setError("root", { + type: response?.status.toString(), + message: "Something went wrong.", + }); + } + } + }; + + return ( +
+ + ( + + JSON-RPC Server + + + + + )} + /> + + ( + + + Transaction Index + + + + + + )} + /> + +
+ RPC Users + {fields.map(({ id }, idx) => ( +
+ ( + + Username + + + + + + )} + /> + + ( + + Password + + + + )} + /> + + {idx === fields.length - 1 && role !== Roles.Reader && ( +
+ {fields.length > 1 && ( + + )} + +
+ )} +
+ ))} +
+ + {isSubmitSuccessful && ( + + + API settings have been updated successfully. + + + )} + + {errors.root && ( + + {errors.root.message} + + )} + + {role !== Roles.Reader && ( + + + + )} + + + ); +}; diff --git a/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/bitcoin-node-stats.tsx b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/bitcoin-node-stats.tsx new file mode 100644 index 00000000..011b2971 --- /dev/null +++ b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/bitcoin-node-stats.tsx @@ -0,0 +1,104 @@ +"use client"; + +import useSWRSubscription from "swr/subscription"; +import type { SWRSubscription } from "swr/subscription"; +import { cx } from "class-variance-authority"; + +import { Skeleton } from "@/components/ui/skeleton"; +import { Alert, AlertDescription } from "@/components/ui/alert"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { getWsBaseURL } from "@/lib/utils"; +import { AlertTriangle } from "lucide-react"; +import { BitcoinStats, StatsError } from "@/types"; + +interface BitcoinNodeStatsProps { + nodeName: string; + token: string; + workspaceId: string; +} + +const WS_URL = getWsBaseURL(); + +export const BitcoinNodeStats: React.FC = ({ + nodeName, + token, + workspaceId, +}) => { + const subscription: SWRSubscription< + string, + BitcoinStats | StatsError, + string + > = (key, { next }) => { + const socket = new WebSocket(key); + socket.onmessage = (event: MessageEvent) => { + const stats = JSON.parse(event.data); + next(null, stats); + }; + socket.onerror = () => next("Connection Error (Can not access node stats)"); + + return () => socket.close(); + }; + const { data, error } = useSWRSubscription( + `${WS_URL}/bitcoin/nodes/${nodeName}/stats?authorization=Bearer ${token}&workspace_id=${workspaceId}`, + subscription + ); + + if (error) { + return ( + + + {error} + + + ); + } + if (!data) + return ( + <> +
+ +
+
+ +
+ + ); + + return ( +
+
+ + + Blocks + + + {!("error" in data) && + new Intl.NumberFormat("en-US").format(+data.blockCount)} + + + + + Peers + + + {!("error" in data) && data.peerCount} + + +
+ {"error" in data && typeof data.error === "string" && ( +
+
+ )} +
+ ); +}; diff --git a/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/danger-zone-tab.tsx b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/danger-zone-tab.tsx new file mode 100644 index 00000000..e3d82113 --- /dev/null +++ b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/danger-zone-tab.tsx @@ -0,0 +1,76 @@ +"use client"; + +import { useState } from "react"; +import { useParams, useRouter } from "next/navigation"; +import qs from "query-string"; + +import { AlertModal } from "@/components/modals/alert-modal"; +import { DeleteNodeForm } from "@/components/delete-node-form"; +import { useToast } from "@/components/ui/use-toast"; +import { TabsFooter } from "@/components/ui/tabs"; +import { Button } from "@/components/ui/button"; +import { BitcoinNode } from "@/types"; +import { client } from "@/lib/client-instance"; + +interface DangerZoneTabProps { + node: BitcoinNode; +} + +export const DangerZoneTab: React.FC = ({ node }) => { + const params = useParams(); + const router = useRouter(); + const { toast } = useToast(); + + const [open, setOpen] = useState(false); + + async function onDeleteBitcoinNode() { + const url = qs.stringifyUrl({ + url: `/bitcoin/nodes/${node.name}`, + query: { workspace_id: params.workspaceId }, + }); + await client.delete(url); + router.push(`/${params.workspaceId}/deployments/bitcoin`); + router.refresh(); + toast({ + title: "Bitcoin node has been deleted", + description: `${node.name} node has been deleted successfully.`, + }); + setOpen(false); + } + + return ( + <> +
+

+ By deleting this node, all connected apps will lose access to the + Blockchain Network. +

+

+ Node attached volume that persists Blockchain data will not be + removed, you need to delete it yourself. +

+

+ Are you sure you want to delete this node? +

+ + + +
+ + setOpen(false)} + title="Delete Bitcoin Node" + description={`This action cann't be undone. This will permnantly delete (${node.name}) Bitcoin Node.`} + > + + + + ); +}; diff --git a/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/protocol-tab.tsx b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/protocol-tab.tsx new file mode 100644 index 00000000..6085569f --- /dev/null +++ b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/protocol-tab.tsx @@ -0,0 +1,53 @@ +import { EditImageVersionForm } from "@/components/edit-image-version-form"; +import { BitcoinNetworks, Roles } from "@/enums"; +import { getEnumKey } from "@/lib/utils"; +import { BitcoinNode, Version } from "@/types"; + +interface ProtocolTabProps { + node: BitcoinNode; + role: Roles; + versions: Version[]; +} + +export const ProtocolTab: React.FC = ({ + node, + role, + versions, +}) => { + const { network, image, name } = node; + return ( + <> +
    +
  • + Protocol + Bitcoin +
  • + +
  • + Network + + {getEnumKey(BitcoinNetworks, network)} + +
  • + +
  • + Client + + Bitcoin Core + +
  • +
+ + + ); +}; diff --git a/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/wallet-tab.tsx b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/wallet-tab.tsx new file mode 100644 index 00000000..137b6d44 --- /dev/null +++ b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/wallet-tab.tsx @@ -0,0 +1,131 @@ +"use client"; + +import * as z from "zod"; +import { isAxiosError } from "axios"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; + +import { client } from "@/lib/client-instance"; +import { BitcoinNode } from "@/types"; +import { Roles } from "@/enums"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, +} from "@/components/ui/form"; +import { Switch } from "@/components/ui/switch"; +import { Button } from "@/components/ui/button"; +import { Alert, AlertDescription } from "@/components/ui/alert"; +import { TabsFooter } from "@/components/ui/tabs"; + +interface WalletTabProps { + node: BitcoinNode; + role: Roles; +} + +const schema = z.object({ + wallet: z.boolean(), +}); + +type Schema = z.infer; + +export const WalletTab: React.FC = ({ node, role }) => { + const { wallet } = node; + + const form = useForm({ + resolver: zodResolver(schema), + defaultValues: { wallet }, + }); + + const { + formState: { + isSubmitted, + isSubmitting, + isValid, + isDirty, + isSubmitSuccessful, + errors, + }, + reset, + setError, + } = form; + + const onSubmit = async (values: Schema) => { + try { + const { data } = await client.put( + `/bitcoin/nodes/${node.name}`, + values + ); + reset({ wallet: data.wallet }); + } catch (error) { + if (isAxiosError(error)) { + const { response } = error; + + setError("root", { + type: response?.status.toString(), + message: "Something went wrong.", + }); + } + } + }; + + return ( +
+ + ( + +
+ Wallet + + + +
+ + Load wallet and enable wallet RPC calls + +
+ )} + /> + + {isSubmitSuccessful && ( + + + Wallet settings have been updated successfully. + + + )} + + {errors.root && ( + + {errors.root.message} + + )} + + {role !== Roles.Reader && ( + + + + )} + + + ); +}; diff --git a/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/page.tsx b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/page.tsx new file mode 100644 index 00000000..dce4735c --- /dev/null +++ b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/page.tsx @@ -0,0 +1,139 @@ +import { notFound } from "next/navigation"; +import { cookies } from "next/headers"; +import { format, parseISO } from "date-fns"; + +import { getWorkspace } from "@/services/get-workspace"; +import { getSecrets } from "@/services/get-secrets"; +import { getNode } from "@/services/get-node"; +import { getClientVersions } from "@/services/get-client-versions"; +import { Protocol, Roles, SecretType, StorageItems } from "@/enums"; +import { BitcoinNode } from "@/types"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { Heading } from "@/components/ui/heading"; +import { NodeStatus } from "@/components/node-status"; +import { NodeMetrics } from "@/components/node-metrics"; +import { Logs } from "@/components/logs"; +import { ResourcesForm } from "@/components/resources-form"; +import { BitcoinNodeStats } from "./components/bitcoin-node-stats"; +import { ProtocolTab } from "./components/protocol-tab"; +import { APITab } from "./components/api-tab"; +import { DangerZoneTab } from "./components/danger-zone-tab"; +import { WalletTab } from "./components/wallet-tab"; + +export default async function BitcoinPage({ + params, +}: { + params: { workspaceId: string; nodeName: string }; +}) { + const token = cookies().get(StorageItems.AUTH_TOKEN); + const { workspaceId, nodeName } = params; + const { role } = await getWorkspace(workspaceId); + const secrets = await getSecrets(workspaceId, SecretType.Password); + + try { + const node = await getNode( + workspaceId, + `/bitcoin/nodes/${nodeName}` + ); + + const { versions } = await getClientVersions( + { + protocol: "bitcoin", + component: "node", + client: "bitcoin-core", + }, + node.image + ); + + return ( +
+
+
+ {token && ( + + )} + +
+
+ {token && ( + <> + + + + )} +
+ + + Protocol + API + Wallet + Logs + Resources + {role === Roles.Admin && ( + + Danger Zone + + )} + + + + + + + + + + + + {token && ( + + )} + + + + + {role === Roles.Admin && ( + + + + )} + +
+
+ ); + } catch (e) { + notFound(); + } +} diff --git a/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/components/client.tsx b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/components/client.tsx new file mode 100644 index 00000000..25d23e44 --- /dev/null +++ b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/components/client.tsx @@ -0,0 +1,60 @@ +"use client"; + +import { useParams, useRouter } from "next/navigation"; +import { Plus } from "lucide-react"; + +import { Button } from "@/components/ui/button"; +import { Heading } from "@/components/ui/heading"; +import { DeploymentsList } from "@/components/deployments-list"; +import { BitcoinNetworks, NEARNetworks, Roles } from "@/enums"; +import { getEnumKey } from "@/lib/utils"; +import { NoResult } from "@/components/no-result"; +import { NEARNode } from "@/types"; + +interface NEARClientProps { + data: NEARNode[]; + role: Roles; +} + +export const NEARClient: React.FC = ({ data, role }) => { + const router = useRouter(); + const params = useParams(); + + const mainNodesInfo = data.map(({ name, network }) => ({ + name, + network: getEnumKey(NEARNetworks, network), + client: "Near Core", + url: `/${params.workspaceId}/deployments/near/${name}`, + })); + + return ( + <> +
+ + + {role !== Roles.Reader && !!data.length && ( + + )} +
+ + + {!data.length && ( + + )} + + ); +}; diff --git a/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/components/create-bitcoin-node-form.tsx b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/components/create-bitcoin-node-form.tsx new file mode 100644 index 00000000..4b18b588 --- /dev/null +++ b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/components/create-bitcoin-node-form.tsx @@ -0,0 +1,197 @@ +"use client"; + +import * as z from "zod"; +import { useParams, useRouter } from "next/navigation"; +import { isAxiosError } from "axios"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; + +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { Button } from "@/components/ui/button"; +import { Alert, AlertDescription } from "@/components/ui/alert"; +import { BitcoinNetworks } from "@/enums"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { useToast } from "@/components/ui/use-toast"; +import { getSelectItems } from "@/lib/utils"; +import { client } from "@/lib/client-instance"; +import { Version } from "@/types"; + +const schema = z.object({ + name: z + .string() + .min(1, "Node name is required") + .max(64, "Too long name") + .trim() + .refine((value) => /^\S*$/.test(value), { + message: "Invalid character used", + }), + network: z.nativeEnum(BitcoinNetworks, { + required_error: "Please select a Network", + }), + workspace_id: z.string().min(1), + image: z.string().min(1), +}); + +type SchemaType = z.infer; + +export const CreateBitcoinNodeForm: React.FC<{ images: Version[] }> = ({ + images, +}) => { + const { toast } = useToast(); + const router = useRouter(); + const { workspaceId } = useParams(); + + const defaultValues = { + name: "", + network: undefined, + image: images[0].image, + }; + const form = useForm({ + resolver: zodResolver(schema), + defaultValues, + }); + + const { + formState: { isSubmitted, isSubmitting, isValid, isDirty, errors }, + setError, + } = form; + + async function onSubmit(values: z.infer) { + try { + await client.post("/bitcoin/nodes", values); + router.push(`/${workspaceId}/deployments/bitcoin`); + router.refresh(); + toast({ + title: "Bitcoin node has been created", + description: `${values.name} node has been created successfully, and will be up and running in few seconds.`, + }); + } catch (error) { + if (isAxiosError(error)) { + const { response } = error; + + if (response?.status === 400) { + setError("root", { + type: response?.status.toString(), + message: "Name already exists.", + }); + return; + } + + if (response?.status === 403) { + setError("root", { + type: response?.status.toString(), + message: "Reached Nodes Limit.", + }); + return; + } + + setError("root", { + type: response?.status.toString(), + message: "Something went wrong.", + }); + } + } + } + + return ( +
+ + } + /> + + ( + + Node Name + + + + + + )} + /> + + ( + + Network + + + + + )} + /> + +

+ Client:{" "} + + Bitcoin Core + +

+ + + + {errors.root && ( + + {errors.root.message} + + )} + + + ); +}; diff --git a/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/new/page.tsx b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/new/page.tsx new file mode 100644 index 00000000..a8512483 --- /dev/null +++ b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/new/page.tsx @@ -0,0 +1,35 @@ +import { notFound } from "next/navigation"; + +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { CreateBitcoinNodeForm } from "../components/create-bitcoin-node-form"; +import { getClientVersions } from "@/services/get-client-versions"; +import { getWorkspace } from "@/services/get-workspace"; +import { Roles } from "@/enums"; + +export default async function CreateNewBitcoinNodePage({ + params, +}: { + params: { workspaceId: string }; +}) { + const { workspaceId } = params; + const { role } = await getWorkspace(workspaceId); + + if (role === Roles.Reader) notFound(); + + const { versions } = await getClientVersions({ + protocol: "bitcoin", + component: "node", + client: "bitcoin-core", + }); + + return ( + + + Create New Bitcoin Node + + + + + + ); +} diff --git a/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/page.tsx b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/page.tsx new file mode 100644 index 00000000..138a5614 --- /dev/null +++ b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/page.tsx @@ -0,0 +1,21 @@ +import { getWorkspace } from "@/services/get-workspace"; +import { getNodes } from "@/services/get-nodes"; +import { NEARNode } from "@/types"; +import { NEARClient } from "./components/client"; + +export default async function BitcoinPage({ + params, +}: { + params: { workspaceId: string }; +}) { + const { data } = await getNodes(params.workspaceId, "/near/nodes"); + const { role } = await getWorkspace(params.workspaceId); + + return ( +
+
+ +
+
+ ); +} diff --git a/src/enums/index.ts b/src/enums/index.ts index 866b567c..401bd879 100644 --- a/src/enums/index.ts +++ b/src/enums/index.ts @@ -41,6 +41,12 @@ export enum FilecoinNetworks { Calibration = "calibration", } +export enum NEARNetworks { + Mainnet = "mainnet", + Testnet = "testnet", + Betanet = "betanet", +} + export enum Protocol { aptos = "aptos", bitcoin = "bitcoin", diff --git a/src/types/index.ts b/src/types/index.ts index 0afbcea4..733bfd22 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -8,6 +8,7 @@ import { ExecutionClientSyncMode, IPFSConfigProfile, IPFSRouting, + NEARNetworks, ValidatorClients, } from "@/enums"; @@ -204,6 +205,22 @@ export interface IPFSClusterPeer extends ClientImage, ResourcesInfo { createdAt: string; } +export interface NEARNode extends ClientImage, ResourcesInfo { + name: string; + network: NEARNetworks; + archive: boolean; + nodePrivateKeySecretName: string; + minPeers: number; + p2pPort: number; + bootnodes: string[]; + validatorSecretName: string; + telemetryURL: string; + prometheusPort: number; + rpc: boolean; + rpcPort: number; + createdAt: string; +} + export interface StatsError { error: string; } From 150180ff58f1c301b07a4b8b46811d3384945d75 Mon Sep 17 00:00:00 2001 From: ahmed-abdelhamid Date: Tue, 3 Oct 2023 10:02:19 +0300 Subject: [PATCH 2/8] create near node --- ...ode-form.tsx => create-near-node-form.tsx} | 46 +++++++++++++------ .../(main)/deployments/near/new/page.tsx | 10 ++-- 2 files changed, 37 insertions(+), 19 deletions(-) rename src/app/(dashboard)/[workspaceId]/(main)/deployments/near/components/{create-bitcoin-node-form.tsx => create-near-node-form.tsx} (79%) diff --git a/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/components/create-bitcoin-node-form.tsx b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/components/create-near-node-form.tsx similarity index 79% rename from src/app/(dashboard)/[workspaceId]/(main)/deployments/near/components/create-bitcoin-node-form.tsx rename to src/app/(dashboard)/[workspaceId]/(main)/deployments/near/components/create-near-node-form.tsx index 4b18b588..94561b3c 100644 --- a/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/components/create-bitcoin-node-form.tsx +++ b/src/app/(dashboard)/[workspaceId]/(main)/deployments/near/components/create-near-node-form.tsx @@ -17,7 +17,7 @@ import { import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { Alert, AlertDescription } from "@/components/ui/alert"; -import { BitcoinNetworks } from "@/enums"; +import { NEARNetworks } from "@/enums"; import { Select, SelectContent, @@ -29,6 +29,7 @@ import { useToast } from "@/components/ui/use-toast"; import { getSelectItems } from "@/lib/utils"; import { client } from "@/lib/client-instance"; import { Version } from "@/types"; +import { Switch } from "@/components/ui/switch"; const schema = z.object({ name: z @@ -39,16 +40,17 @@ const schema = z.object({ .refine((value) => /^\S*$/.test(value), { message: "Invalid character used", }), - network: z.nativeEnum(BitcoinNetworks, { - required_error: "Please select a Network", + network: z.nativeEnum(NEARNetworks, { + required_error: "Network is required", }), + archive: z.boolean().optional().default(false), workspace_id: z.string().min(1), image: z.string().min(1), }); -type SchemaType = z.infer; +type Schema = z.infer; -export const CreateBitcoinNodeForm: React.FC<{ images: Version[] }> = ({ +export const CreateNEARNodeForm: React.FC<{ images: Version[] }> = ({ images, }) => { const { toast } = useToast(); @@ -57,10 +59,9 @@ export const CreateBitcoinNodeForm: React.FC<{ images: Version[] }> = ({ const defaultValues = { name: "", - network: undefined, image: images[0].image, }; - const form = useForm({ + const form = useForm({ resolver: zodResolver(schema), defaultValues, }); @@ -70,13 +71,13 @@ export const CreateBitcoinNodeForm: React.FC<{ images: Version[] }> = ({ setError, } = form; - async function onSubmit(values: z.infer) { + async function onSubmit(values: Schema) { try { - await client.post("/bitcoin/nodes", values); - router.push(`/${workspaceId}/deployments/bitcoin`); + await client.post("/near/nodes", values); + router.push(`/${workspaceId}/deployments/near`); router.refresh(); toast({ - title: "Bitcoin node has been created", + title: "NEAR node has been created", description: `${values.name} node has been created successfully, and will be up and running in few seconds.`, }); } catch (error) { @@ -153,7 +154,7 @@ export const CreateBitcoinNodeForm: React.FC<{ images: Version[] }> = ({ - {getSelectItems(BitcoinNetworks).map(({ value, label }) => ( + {getSelectItems(NEARNetworks).map(({ value, label }) => ( {label} @@ -169,15 +170,32 @@ export const CreateBitcoinNodeForm: React.FC<{ images: Version[] }> = ({

Client:{" "} - Bitcoin Core + NEAR Core

+ ( + + Archive Node + + + + + )} + /> + + )} + + + + )} + /> + + ( + + Minimum Peers + + + + + + )} + /> + + ( + + P2P Port + + + + + + )} + /> + + ( + + Boot Nodes + +