-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7 from kotalco/near
- Loading branch information
Showing
16 changed files
with
1,663 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
76 changes: 76 additions & 0 deletions
76
...ashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/danger-zone-tab.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
</> | ||
); | ||
}; |
150 changes: 150 additions & 0 deletions
150
...ashboard)/[workspaceId]/(main)/deployments/near/[nodeName]/components/near-node-stats.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'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> | ||
); | ||
}; |
Oops, something went wrong.