Skip to content

Commit

Permalink
Merge pull request #7 from kotalco/near
Browse files Browse the repository at this point in the history
  • Loading branch information
mFarghaly authored Oct 17, 2023
2 parents c0493c9 + cf5a614 commit 3ffa0e6
Show file tree
Hide file tree
Showing 16 changed files with 1,663 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export const ExecutionClientNodeStats: React.FC<
</TooltipProvider>
</CardTitle>
</CardHeader>
<CardContent className="flex items-center text-3xl font-light text-gray-500 truncate gap-x-2">
<CardContent className="flex items-center text-3xl font-light text-foreground/50 truncate gap-x-2">
{!("error" in data) && (
<>
{!data.peersCount ? (
Expand All @@ -118,7 +118,7 @@ export const ExecutionClientNodeStats: React.FC<
<CardHeader>
<CardTitle>Peers</CardTitle>
</CardHeader>
<CardContent className="text-3xl font-light text-gray-500 truncate">
<CardContent className="text-3xl font-light text-foreground/50 truncate">
{!("error" in data) && data.peersCount}
</CardContent>
</Card>
Expand Down
Original file line number Diff line number Diff line change
@@ -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 { NEARNode } from "@/types";
import { client } from "@/lib/client-instance";

interface DangerZoneTabProps {
node: NEARNode;
}

export const DangerZoneTab: React.FC<DangerZoneTabProps> = ({ node }) => {
const params = useParams();
const router = useRouter();
const { toast } = useToast();

const [open, setOpen] = useState(false);

async function onDeleteNEARNode() {
const url = qs.stringifyUrl({
url: `/near/nodes/${node.name}`,
query: { workspace_id: params.workspaceId },
});
await client.delete(url);
router.push(`/${params.workspaceId}/deployments/near`);
router.refresh();
toast({
title: "Near node has been deleted",
description: `${node.name} node has been deleted successfully.`,
});
setOpen(false);
}

return (
<>
<div>
<p className="text-muted-foreground">
By deleting this node, all connected apps will lose access to the
Blockchain Network.
</p>
<p className="text-muted-foreground">
Node attached volume that persists Blockchain data will not be
removed, you need to delete it yourself.
</p>
<p className="text-muted-foreground">
Are you sure you want to delete this node?
</p>
<TabsFooter>
<Button
variant="destructive"
className="btn btn-alert"
onClick={() => setOpen(true)}
>
Delete Node
</Button>
</TabsFooter>
</div>

<AlertModal
isOpen={open}
onClose={() => setOpen(false)}
title="Delete NEAR Node"
description={`This action cann't be undone. This will permnantly delete (${node.name}) NEAR Node.`}
>
<DeleteNodeForm nodeName={node.name} onDelete={onDeleteNEARNode} />
</AlertModal>
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
"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 { AlertCircle, AlertTriangle, RefreshCw } from "lucide-react";
import { BitcoinStats, NEARStats, StatsError } from "@/types";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";

interface NEARNodeStatsProps {
nodeName: string;
token: string;
workspaceId: string;
}

const WS_URL = getWsBaseURL();

export const NEARNodeStats: React.FC<NEARNodeStatsProps> = ({
nodeName,
token,
workspaceId,
}) => {
const subscription: SWRSubscription<
string,
NEARStats | StatsError,
string
> = (key, { next }) => {
const socket = new WebSocket(key);
socket.onmessage = (event: MessageEvent<string>) => {
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}/near/nodes/${nodeName}/stats?authorization=Bearer ${token}&workspace_id=${workspaceId}`,
subscription
);

if (error) {
return (
<Alert variant="destructive" className="lg:col-span-2">
<AlertDescription className="flex items-start justify-center gap-x-2">
<AlertTriangle className="w-5 h-5" /> {error}
</AlertDescription>
</Alert>
);
}

if (!data)
return (
<>
<div className="space-y-2 lg:col-span-1">
<Skeleton className="w-full h-[128px]" />
</div>
<div className="space-y-2 lg:col-span-1">
<Skeleton className="w-full h-[128px]" />
</div>
</>
);

return (
<div className="relative lg:col-span-2">
<div
className={cx(
"grid grid-cols-1 gap-5 lg:grid-cols-2",
"error" in data ? "blur-lg" : ""
)}
>
<Card>
<CardHeader>
<CardTitle className="items-start">
Blocks
<TooltipProvider>
<Tooltip>
<TooltipTrigger>
<AlertCircle className="w-4 h-4 ml-2" />
</TooltipTrigger>
<TooltipContent>
If block number doesn&apos;t change, it means node is not
syncing or syncing headers
</TooltipContent>
</Tooltip>
</TooltipProvider>
</CardTitle>
</CardHeader>
<CardContent className="flex items-center text-3xl font-light text-foreground/50 truncate gap-x-2">
{!("error" in data) && (
<>
{data.syncing ? (
<RefreshCw className="w-5 h-5 animate-spin" />
) : (
<AlertTriangle className="w-5 h-5 text-yellow-600" />
)}
<span>
{new Intl.NumberFormat("en-US").format(
+data.latestBlockHeight
)}
</span>
</>
)}
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="items-start">
Peers
<TooltipProvider>
<Tooltip>
<TooltipTrigger>
<AlertCircle className="w-4 h-4 ml-2" />
</TooltipTrigger>
<TooltipContent>Active peers / Max peers</TooltipContent>
</Tooltip>
</TooltipProvider>
</CardTitle>
</CardHeader>
<CardContent className="text-3xl font-light text-foreground/50 truncate">
{!("error" in data) && (
<>
{data.activePeersCount} / {data.maxPeersCount}
</>
)}
</CardContent>
</Card>
</div>
{"error" in data && typeof data.error === "string" && (
<div className="absolute inset-0 flex items-center justify-center space-x-4">
<AlertTriangle
className="w-10 h-10 leading-9 text-yellow-500"
aria-hidden="true"
/>
<p className="text-3xl text-gray-600">{data.error}</p>
</div>
)}
</div>
);
};
Loading

0 comments on commit 3ffa0e6

Please sign in to comment.