diff --git a/components/ui/alert.jsx b/components/ui/alert.jsx
new file mode 100644
index 0000000..e4f179e
--- /dev/null
+++ b/components/ui/alert.jsx
@@ -0,0 +1,47 @@
+import * as React from "react"
+import { cva } from "class-variance-authority";
+
+import { cn } from "@/lib/utils"
+
+const alertVariants = cva(
+ "relative w-full rounded-lg border border-neutral-200 p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-neutral-950 dark:border-neutral-800 dark:[&>svg]:text-neutral-50",
+ {
+ variants: {
+ variant: {
+ default: "bg-white text-neutral-950 dark:bg-neutral-950 dark:text-neutral-50",
+ destructive:
+ "border-red-500/50 text-red-500 dark:border-red-500 [&>svg]:text-red-500 dark:border-red-900/50 dark:text-red-900 dark:dark:border-red-900 dark:[&>svg]:text-red-900",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+)
+
+const Alert = React.forwardRef(({ className, variant, ...props }, ref) => (
+
+))
+Alert.displayName = "Alert"
+
+const AlertTitle = React.forwardRef(({ className, ...props }, ref) => (
+
+))
+AlertTitle.displayName = "AlertTitle"
+
+const AlertDescription = React.forwardRef(({ className, ...props }, ref) => (
+
+))
+AlertDescription.displayName = "AlertDescription"
+
+export { Alert, AlertTitle, AlertDescription }
diff --git a/components/ui/button.jsx b/components/ui/button.jsx
new file mode 100644
index 0000000..83544dc
--- /dev/null
+++ b/components/ui/button.jsx
@@ -0,0 +1,47 @@
+import * as React from "react"
+import { Slot } from "@radix-ui/react-slot"
+import { cva } from "class-variance-authority";
+
+import { cn } from "@/lib/utils"
+
+const buttonVariants = cva(
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 dark:ring-offset-neutral-950 dark:focus-visible:ring-neutral-300",
+ {
+ variants: {
+ variant: {
+ default: "bg-neutral-900 text-neutral-50 hover:bg-neutral-900/90 dark:bg-neutral-50 dark:text-neutral-900 dark:hover:bg-neutral-50/90",
+ destructive:
+ "bg-red-500 text-neutral-50 hover:bg-red-500/90 dark:bg-red-900 dark:text-neutral-50 dark:hover:bg-red-900/90",
+ outline:
+ "border border-neutral-200 bg-white hover:bg-neutral-100 hover:text-neutral-900 dark:border-neutral-800 dark:bg-neutral-950 dark:hover:bg-neutral-800 dark:hover:text-neutral-50",
+ secondary:
+ "bg-neutral-100 text-neutral-900 hover:bg-neutral-100/80 dark:bg-neutral-800 dark:text-neutral-50 dark:hover:bg-neutral-800/80",
+ ghost: "hover:bg-neutral-100 hover:text-neutral-900 dark:hover:bg-neutral-800 dark:hover:text-neutral-50",
+ link: "text-neutral-900 underline-offset-4 hover:underline dark:text-neutral-50",
+ },
+ size: {
+ default: "h-10 px-4 py-2",
+ sm: "h-9 rounded-md px-3",
+ lg: "h-11 rounded-md px-8",
+ icon: "h-10 w-10",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ }
+)
+
+const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
+ const Comp = asChild ? Slot : "button"
+ return (
+ ()
+ );
+})
+Button.displayName = "Button"
+
+export { Button, buttonVariants }
diff --git a/package-lock.json b/package-lock.json
index 4d474f3..8886a69 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1460,6 +1460,7 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz",
"integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==",
+ "license": "MIT",
"dependencies": {
"@radix-ui/react-compose-refs": "1.1.1"
},
diff --git a/pages/index.js b/pages/index.js
index 2e606d3..9f04fcf 100644
--- a/pages/index.js
+++ b/pages/index.js
@@ -19,6 +19,7 @@ import {
Globe,
Info,
Wallet,
+ Terminal,
} from "lucide-react";
import {
LineChart,
@@ -436,6 +437,16 @@ export default function Dashboard() {
+
+
+ Run a testnet node
+
diff --git a/pages/run.js b/pages/run.js
new file mode 100644
index 0000000..efe5c7b
--- /dev/null
+++ b/pages/run.js
@@ -0,0 +1,564 @@
+"use client";
+
+import { useState, useEffect } from 'react';
+import Head from 'next/head';
+import Image from 'next/image';
+import Link from 'next/link';
+import { Info, Activity, Terminal, AlertTriangle, X } from 'lucide-react';
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
+ DialogFooter,
+} from "@/components/ui/dialog";
+import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
+import { Button } from "@/components/ui/button";
+import { motion } from "framer-motion";
+
+export default function RunPage() {
+ const [hasAgreed, setHasAgreed] = useState(false);
+ const [showDisclaimer, setShowDisclaimer] = useState(true);
+
+ useEffect(() => {
+ // Check if user has previously agreed
+ const agreed = localStorage.getItem('codex-disclaimer-agreed');
+ if (agreed === 'true') {
+ setHasAgreed(true);
+ setShowDisclaimer(false);
+ }
+ }, []);
+
+ const handleAgree = () => {
+ localStorage.setItem('codex-disclaimer-agreed', 'true');
+ setHasAgreed(true);
+ setShowDisclaimer(false);
+ };
+
+ return (
+
+
+
Run a Node | Codex
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Disclaimer Dialog */}
+
+
+
+
+
+

+
+
Run a Node
+ Testnet
+
+
+
+
+
+
+
View Metrics
+
+
+
+
+
+
+
+
+ Run a Codex Node
+
+
+ {hasAgreed ? (
+
+ {/* Tutorial Section */}
+
+ {/* Step 1: Port Forwarding */}
+
+
+
+ 1
+
+
+
Port Forwarding
+
Configure your network to allow Codex connections
+
+
+
Required
+
+
+
+
Required Ports
+
+ -
+
+ UDP
+
+
+
Port 8090/UDP
+
Required for node discovery
+
+
+ -
+
+ TCP
+
+
+
Port 8070/TCP
+
Required for data exchange
+
+
+
+
+
+
+
+
+ {/* Step 2: Install Codex */}
+
+
+
+
+ 2
+
+
+
Install Codex
+
Download and install the Codex Storage CLI
+
+
+
Required
+
+
+
+
Prerequisites
+
+ Before you begin, ensure you have Node.js installed on your machine. The Codex CLI requires Node.js to run.
+
+
+
+
Installation Steps
+
+ -
+ Open your terminal
+
+ -
+ Run the following command:
+
+
npx codexstorage
+
+
+
+ -
+ Select option 1: "Download and install Codex" from the menu
+
+ -
+ Follow the prompts to complete the installation
+
+
+
+
+
+
+ {/* Step 3: Run Your Node */}
+
+
+
+
+ 3
+
+
+
Run Your Node
+
Start your Codex node and verify its status
+
+
+
Required
+
+
+
+
Starting Your Node
+
+ -
+ Select option 2: "Run Codex node" from the main menu
+
+ -
+ Press Enter to use default ports (or enter custom ports if needed)
+
+ -
+ Keep this terminal window open to keep your node running
+
+
+
+
+ Keep Terminal Active
+
+ The node stops running once you close this terminal. Keep it open to maintain node operation.
+
+
+
+
+
Verify Node Status
+
+ -
+ Open a new terminal window
+
+ -
+ Run
npx codexstorage again
+
+ -
+ Select option 3: "Check node status"
+
+ -
+ Choose "View Node Information" to see your unique Node ID
+
+
+
+
+ Important
+
+ Make sure to save your Node ID as you'll need it for the verification step.
+
+
+
+
+
+
+ {/* Step 4: Test Your Node */}
+
+
+
+
+ 4
+
+
+
Test Your Node
+
Upload and download files to test your setup
+
+
+
Optional
+
+
+
+
Upload a File
+
+ You can upload a file using either of these methods:
+
+
+ -
+ Select option 4: "Upload a file" from the main menu
+
+ -
+ Or use the command:
+
+
npx codexstorage --upload <PATH-TO-THE-FILE>
+
+
+
+
+
+
+
Download a File
+
+ To download a file from the network:
+
+
+ -
+ Select option 5: "Download a file" from the main menu
+
+ -
+ Or use the command:
+
+
npx codexstorage --download <CID>
+
+
+
+
+
+
+ File Persistence
+
+ Testnet files are not persistent and are cleared within 48 hours.
+
+
+
+
+
+
+ {/* Step 5: Verify & Get Role */}
+
+
+
+
+ 5
+
+
+
Verify Your Node
+
Get your Altruistic Mode role on Discord
+
+
+
Required
+
+
+
+
Discord Verification
+
+ -
+ Join the{' '}
+
+ Codex Discord
+
+
+ -
+ Go to the #bot channel
+
+ -
+ Run the command:
+
+
+
+
+
+ Success
+
+ Upon successful verification, you'll receive the @Altruistic Mode role! 🎉
+
+
+
+
+
What can I do next?
+
+
+
+
+
+ ) : (
+
+
+
+
Privacy Agreement Required
+
+ Please agree to the privacy disclaimer to view the node setup instructions.
+
+
+
+
+ )}
+
+
+ );
+}