Merge branch 'main' of https://github.com/Code-Victor/sandbox into feat/light-theme
This commit is contained in:
@ -1,34 +1,38 @@
|
||||
"use client";
|
||||
"use client"
|
||||
|
||||
import { useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useTerminal } from "@/context/TerminalContext";
|
||||
import { Play, Pause, Globe, Globe2 } from "lucide-react";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||
import { Sandbox, User } from "@/lib/types";
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover"
|
||||
import { useTerminal } from "@/context/TerminalContext"
|
||||
import { Sandbox, User } from "@/lib/types"
|
||||
import { Globe } from "lucide-react"
|
||||
import { useState } from "react"
|
||||
|
||||
export default function DeployButtonModal({
|
||||
userData,
|
||||
data,
|
||||
}: {
|
||||
userData: User;
|
||||
data: Sandbox;
|
||||
userData: User
|
||||
data: Sandbox
|
||||
}) {
|
||||
const { deploy } = useTerminal();
|
||||
const [isDeploying, setIsDeploying] = useState(false);
|
||||
const { deploy } = useTerminal()
|
||||
const [isDeploying, setIsDeploying] = useState(false)
|
||||
|
||||
const handleDeploy = () => {
|
||||
if (isDeploying) {
|
||||
console.log("Stopping deployment...");
|
||||
setIsDeploying(false);
|
||||
console.log("Stopping deployment...")
|
||||
setIsDeploying(false)
|
||||
} else {
|
||||
console.log("Starting deployment...");
|
||||
setIsDeploying(true);
|
||||
console.log("Starting deployment...")
|
||||
setIsDeploying(true)
|
||||
deploy(() => {
|
||||
setIsDeploying(false);
|
||||
});
|
||||
setIsDeploying(false)
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -39,7 +43,10 @@ export default function DeployButtonModal({
|
||||
Deploy
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="p-4 w-full max-w-xs sm:max-w-sm md:max-w-md lg:max-w-lg xl:max-w-xl rounded-lg shadow-lg" style={{ backgroundColor: 'rgb(10,10,10)', color: 'white' }}>
|
||||
<PopoverContent
|
||||
className="p-4 w-full max-w-xs sm:max-w-sm md:max-w-md lg:max-w-lg xl:max-w-xl rounded-lg shadow-lg"
|
||||
style={{ backgroundColor: "rgb(10,10,10)", color: "white" }}
|
||||
>
|
||||
<h3 className="font-semibold text-gray-300 mb-2">Domains</h3>
|
||||
<div className="flex flex-col gap-4">
|
||||
<DeploymentOption
|
||||
@ -49,16 +56,30 @@ export default function DeployButtonModal({
|
||||
user={userData.name}
|
||||
/>
|
||||
</div>
|
||||
<Button variant="outline" className="mt-4 w-full bg-[#0a0a0a] text-white hover:bg-[#262626]" onClick={handleDeploy}>
|
||||
{isDeploying ? "Deploying..." : "Update"}
|
||||
<Button
|
||||
variant="outline"
|
||||
className="mt-4 w-full bg-[#0a0a0a] text-white hover:bg-[#262626]"
|
||||
onClick={handleDeploy}
|
||||
>
|
||||
{isDeploying ? "Deploying..." : "Update"}
|
||||
</Button>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
function DeploymentOption({ icon, domain, timestamp, user }: { icon: React.ReactNode; domain: string; timestamp: string; user: string }) {
|
||||
function DeploymentOption({
|
||||
icon,
|
||||
domain,
|
||||
timestamp,
|
||||
user,
|
||||
}: {
|
||||
icon: React.ReactNode
|
||||
domain: string
|
||||
timestamp: string
|
||||
user: string
|
||||
}) {
|
||||
return (
|
||||
<div className="flex flex-col gap-2 w-full text-left p-2 rounded-md border border-gray-700 bg-gray-900">
|
||||
<div className="flex items-start gap-2 relative">
|
||||
@ -72,7 +93,9 @@ function DeploymentOption({ icon, domain, timestamp, user }: { icon: React.React
|
||||
{domain}
|
||||
</a>
|
||||
</div>
|
||||
<p className="text-sm text-gray-400 mt-0 ml-7">{timestamp} • {user}</p>
|
||||
<p className="text-sm text-gray-400 mt-0 ml-7">
|
||||
{timestamp} • {user}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
@ -1,60 +1,57 @@
|
||||
"use client";
|
||||
"use client"
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { z } from "zod";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
} from "@/components/ui/dialog"
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { z } from "zod"
|
||||
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
} from "@/components/ui/form"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { Sandbox } from "@/lib/types";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { deleteSandbox, updateSandbox } from "@/lib/actions";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { toast } from "sonner";
|
||||
} from "@/components/ui/select"
|
||||
import { deleteSandbox, updateSandbox } from "@/lib/actions"
|
||||
import { Sandbox } from "@/lib/types"
|
||||
import { Loader2 } from "lucide-react"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useState } from "react"
|
||||
import { toast } from "sonner"
|
||||
|
||||
const formSchema = z.object({
|
||||
name: z.string().min(1).max(16),
|
||||
visibility: z.enum(["public", "private"]),
|
||||
});
|
||||
})
|
||||
|
||||
export default function EditSandboxModal({
|
||||
open,
|
||||
setOpen,
|
||||
data,
|
||||
}: {
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
data: Sandbox;
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
data: Sandbox
|
||||
}) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [loadingDelete, setLoadingDelete] = useState(false);
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [loadingDelete, setLoadingDelete] = useState(false)
|
||||
|
||||
const router = useRouter();
|
||||
const router = useRouter()
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
@ -62,22 +59,22 @@ export default function EditSandboxModal({
|
||||
name: data.name,
|
||||
visibility: data.visibility,
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
async function onSubmit(values: z.infer<typeof formSchema>) {
|
||||
setLoading(true);
|
||||
await updateSandbox({ id: data.id, ...values });
|
||||
setLoading(true)
|
||||
await updateSandbox({ id: data.id, ...values })
|
||||
|
||||
toast.success("Sandbox updated successfully");
|
||||
toast.success("Sandbox updated successfully")
|
||||
|
||||
setLoading(false);
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
async function onDelete() {
|
||||
setLoadingDelete(true);
|
||||
await deleteSandbox(data.id);
|
||||
setLoadingDelete(true)
|
||||
await deleteSandbox(data.id)
|
||||
|
||||
router.push("/dashboard");
|
||||
router.push("/dashboard")
|
||||
}
|
||||
|
||||
return (
|
||||
@ -153,5 +150,5 @@ export default function EditSandboxModal({
|
||||
</Button>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
@ -1,73 +1,78 @@
|
||||
"use client";
|
||||
"use client"
|
||||
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { Play, StopCircle } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useTerminal } from "@/context/TerminalContext";
|
||||
import { usePreview } from "@/context/PreviewContext";
|
||||
import { toast } from "sonner";
|
||||
import { Sandbox } from "@/lib/types";
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { usePreview } from "@/context/PreviewContext"
|
||||
import { useTerminal } from "@/context/TerminalContext"
|
||||
import { Sandbox } from "@/lib/types"
|
||||
import { Play, StopCircle } from "lucide-react"
|
||||
import { useEffect, useRef } from "react"
|
||||
import { toast } from "sonner"
|
||||
|
||||
export default function RunButtonModal({
|
||||
isRunning,
|
||||
setIsRunning,
|
||||
sandboxData,
|
||||
}: {
|
||||
isRunning: boolean;
|
||||
setIsRunning: (running: boolean) => void;
|
||||
sandboxData: Sandbox;
|
||||
isRunning: boolean
|
||||
setIsRunning: (running: boolean) => void
|
||||
sandboxData: Sandbox
|
||||
}) {
|
||||
const { createNewTerminal, closeTerminal, terminals } = useTerminal();
|
||||
const { setIsPreviewCollapsed, previewPanelRef } = usePreview();
|
||||
const { createNewTerminal, closeTerminal, terminals } = useTerminal()
|
||||
const { setIsPreviewCollapsed, previewPanelRef } = usePreview()
|
||||
// Ref to keep track of the last created terminal's ID
|
||||
const lastCreatedTerminalRef = useRef<string | null>(null);
|
||||
const lastCreatedTerminalRef = useRef<string | null>(null)
|
||||
|
||||
// Effect to update the lastCreatedTerminalRef when a new terminal is added
|
||||
useEffect(() => {
|
||||
if (terminals.length > 0 && !isRunning) {
|
||||
const latestTerminal = terminals[terminals.length - 1];
|
||||
if (latestTerminal && latestTerminal.id !== lastCreatedTerminalRef.current) {
|
||||
lastCreatedTerminalRef.current = latestTerminal.id;
|
||||
const latestTerminal = terminals[terminals.length - 1]
|
||||
if (
|
||||
latestTerminal &&
|
||||
latestTerminal.id !== lastCreatedTerminalRef.current
|
||||
) {
|
||||
lastCreatedTerminalRef.current = latestTerminal.id
|
||||
}
|
||||
}
|
||||
}, [terminals, isRunning]);
|
||||
}, [terminals, isRunning])
|
||||
|
||||
const handleRun = async () => {
|
||||
if (isRunning && lastCreatedTerminalRef.current)
|
||||
{
|
||||
await closeTerminal(lastCreatedTerminalRef.current);
|
||||
lastCreatedTerminalRef.current = null;
|
||||
setIsPreviewCollapsed(true);
|
||||
previewPanelRef.current?.collapse();
|
||||
}
|
||||
else if (!isRunning && terminals.length < 4)
|
||||
{
|
||||
const command = sandboxData.type === "streamlit"
|
||||
? "pip install -r requirements.txt && streamlit run main.py --server.runOnSave true"
|
||||
: "yarn install && yarn dev";
|
||||
|
||||
if (isRunning && lastCreatedTerminalRef.current) {
|
||||
await closeTerminal(lastCreatedTerminalRef.current)
|
||||
lastCreatedTerminalRef.current = null
|
||||
setIsPreviewCollapsed(true)
|
||||
previewPanelRef.current?.collapse()
|
||||
} else if (!isRunning && terminals.length < 4) {
|
||||
const command =
|
||||
sandboxData.type === "streamlit"
|
||||
? "pip install -r requirements.txt && streamlit run main.py --server.runOnSave true"
|
||||
: "yarn install && yarn dev"
|
||||
|
||||
try {
|
||||
// Create a new terminal with the appropriate command
|
||||
await createNewTerminal(command);
|
||||
setIsPreviewCollapsed(false);
|
||||
previewPanelRef.current?.expand();
|
||||
await createNewTerminal(command)
|
||||
setIsPreviewCollapsed(false)
|
||||
previewPanelRef.current?.expand()
|
||||
} catch (error) {
|
||||
toast.error("Failed to create new terminal.");
|
||||
console.error("Error creating new terminal:", error);
|
||||
return;
|
||||
toast.error("Failed to create new terminal.")
|
||||
console.error("Error creating new terminal:", error)
|
||||
return
|
||||
}
|
||||
} else if (!isRunning) {
|
||||
toast.error("You've reached the maximum number of terminals.");
|
||||
return;
|
||||
toast.error("You've reached the maximum number of terminals.")
|
||||
return
|
||||
}
|
||||
|
||||
setIsRunning(!isRunning);
|
||||
};
|
||||
setIsRunning(!isRunning)
|
||||
}
|
||||
|
||||
return (
|
||||
<Button variant="outline" onClick={handleRun}>
|
||||
{isRunning ? <StopCircle className="w-4 h-4 mr-2" /> : <Play className="w-4 h-4 mr-2" />}
|
||||
{isRunning ? 'Stop' : 'Run'}
|
||||
{isRunning ? (
|
||||
<StopCircle className="w-4 h-4 mr-2" />
|
||||
) : (
|
||||
<Play className="w-4 h-4 mr-2" />
|
||||
)}
|
||||
{isRunning ? "Stop" : "Run"}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -6,10 +6,11 @@ import {
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog"
|
||||
import { z } from "zod"
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { z } from "zod"
|
||||
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
@ -18,14 +19,13 @@ import {
|
||||
FormMessage,
|
||||
} from "@/components/ui/form"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Link, Loader2, UserPlus, X } from "lucide-react"
|
||||
import { useState } from "react"
|
||||
import { Sandbox } from "@/lib/types"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { shareSandbox } from "@/lib/actions"
|
||||
import { Sandbox } from "@/lib/types"
|
||||
import { DialogDescription } from "@radix-ui/react-dialog"
|
||||
import { Link, Loader2, UserPlus } from "lucide-react"
|
||||
import { useState } from "react"
|
||||
import { toast } from "sonner"
|
||||
import SharedUser from "./sharedUser"
|
||||
import { DialogDescription } from "@radix-ui/react-dialog"
|
||||
|
||||
const formSchema = z.object({
|
||||
email: z.string().email(),
|
||||
|
Reference in New Issue
Block a user