mirror of
https://github.com/LukeHagar/dokploy.git
synced 2025-12-06 04:19:37 +00:00
feat: add dokploy cloud modal
This commit is contained in:
@@ -145,7 +145,7 @@ export const SetupServer = ({ serverId }: Props) => {
|
||||
Automatic process
|
||||
</span>
|
||||
<Link
|
||||
href="https://docs.dokploy.com/en/docs/core/get-started/introduction"
|
||||
href="https://docs.dokploy.com/docs/core/multi-server/instructions#requirements"
|
||||
target="_blank"
|
||||
className="text-primary flex flex-row gap-2"
|
||||
>
|
||||
|
||||
@@ -31,8 +31,12 @@ import { SetupServer } from "./setup-server";
|
||||
import { ShowDockerContainersModal } from "./show-docker-containers-modal";
|
||||
import { ShowTraefikFileSystemModal } from "./show-traefik-file-system-modal";
|
||||
import { UpdateServer } from "./update-server";
|
||||
import { useRouter } from "next/router";
|
||||
import { WelcomeSuscription } from "./welcome-stripe/welcome-suscription";
|
||||
|
||||
export const ShowServers = () => {
|
||||
const router = useRouter();
|
||||
const query = router.query;
|
||||
const { data, refetch } = api.server.all.useQuery();
|
||||
const { mutateAsync } = api.server.remove.useMutation();
|
||||
const { data: sshKeys } = api.sshKey.all.useQuery();
|
||||
@@ -42,6 +46,7 @@ export const ShowServers = () => {
|
||||
|
||||
return (
|
||||
<div className="p-6 space-y-6">
|
||||
{query?.success && <WelcomeSuscription />}
|
||||
<div className="space-y-2 flex flex-row justify-between items-end">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold">Servers</h1>
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
import { AlertBlock } from "@/components/shared/alert-block";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { DialogFooter } from "@/components/ui/dialog";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { api } from "@/utils/api";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { PlusIcon } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { toast } from "sonner";
|
||||
import { z } from "zod";
|
||||
|
||||
const Schema = z.object({
|
||||
name: z.string().min(1, {
|
||||
message: "Name is required",
|
||||
}),
|
||||
description: z.string().optional(),
|
||||
ipAddress: z.string().min(1, {
|
||||
message: "IP Address is required",
|
||||
}),
|
||||
port: z.number().optional(),
|
||||
username: z.string().optional(),
|
||||
sshKeyId: z.string().min(1, {
|
||||
message: "SSH Key is required",
|
||||
}),
|
||||
});
|
||||
|
||||
type Schema = z.infer<typeof Schema>;
|
||||
|
||||
interface Props {
|
||||
stepper: any;
|
||||
}
|
||||
|
||||
export const CreateServer = ({ stepper }: Props) => {
|
||||
const { data: sshKeys } = api.sshKey.all.useQuery();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const { data: canCreateMoreServers, refetch } =
|
||||
api.stripe.canCreateMoreServers.useQuery();
|
||||
const { mutateAsync, error, isError } = api.server.create.useMutation();
|
||||
const cloudSSHKey = sshKeys?.find(
|
||||
(sshKey) => sshKey.name === "dokploy-cloud-ssh-key",
|
||||
);
|
||||
|
||||
const form = useForm<Schema>({
|
||||
defaultValues: {
|
||||
description: "Dokploy Cloud Server",
|
||||
name: "My First Server",
|
||||
ipAddress: "",
|
||||
port: 22,
|
||||
username: "root",
|
||||
sshKeyId: cloudSSHKey?.sshKeyId || "",
|
||||
},
|
||||
resolver: zodResolver(Schema),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
form.reset({
|
||||
description: "Dokploy Cloud Server",
|
||||
name: "My First Server",
|
||||
ipAddress: "",
|
||||
port: 22,
|
||||
username: "root",
|
||||
sshKeyId: cloudSSHKey?.sshKeyId || "",
|
||||
});
|
||||
}, [form, form.reset, form.formState.isSubmitSuccessful, sshKeys]);
|
||||
|
||||
useEffect(() => {
|
||||
refetch();
|
||||
}, [isOpen]);
|
||||
|
||||
const onSubmit = async (data: Schema) => {
|
||||
await mutateAsync({
|
||||
name: data.name,
|
||||
description: data.description || "",
|
||||
ipAddress: data.ipAddress || "",
|
||||
port: data.port || 22,
|
||||
username: data.username || "root",
|
||||
sshKeyId: data.sshKeyId || "",
|
||||
})
|
||||
.then(async (data) => {
|
||||
toast.success("Server Created");
|
||||
stepper.next();
|
||||
})
|
||||
.catch(() => {
|
||||
toast.error("Error to create a server");
|
||||
});
|
||||
};
|
||||
return (
|
||||
<Card className="bg-background flex flex-col gap-4">
|
||||
<div className="flex flex-col gap-2 pt-5 px-4">
|
||||
{!canCreateMoreServers && (
|
||||
<AlertBlock type="warning">
|
||||
You cannot create more servers,{" "}
|
||||
<Link href="/dashboard/settings/billing" className="text-primary">
|
||||
Please upgrade your plan
|
||||
</Link>
|
||||
</AlertBlock>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<CardContent className="flex flex-col">
|
||||
<Form {...form}>
|
||||
<form
|
||||
id="hook-form-add-server"
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
className="grid w-full gap-4"
|
||||
>
|
||||
<div className="flex flex-col gap-4 ">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Hostinger Server" {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="description"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Description</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea
|
||||
placeholder="This server is for databases..."
|
||||
className="resize-none"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="sshKeyId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Select a SSH Key</FormLabel>
|
||||
{!cloudSSHKey && (
|
||||
<AlertBlock>
|
||||
Looks like you didn't have the SSH Key yet, you can create
|
||||
one{" "}
|
||||
<Link
|
||||
href="/dashboard/settings/ssh-keys"
|
||||
className="text-primary"
|
||||
>
|
||||
here
|
||||
</Link>
|
||||
</AlertBlock>
|
||||
)}
|
||||
|
||||
<Select
|
||||
onValueChange={field.onChange}
|
||||
defaultValue={field.value}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a SSH Key" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{sshKeys?.map((sshKey) => (
|
||||
<SelectItem
|
||||
key={sshKey.sshKeyId}
|
||||
value={sshKey.sshKeyId}
|
||||
>
|
||||
{sshKey.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
<SelectLabel>
|
||||
Registries ({sshKeys?.length})
|
||||
</SelectLabel>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="ipAddress"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>IP Address</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="192.168.1.100" {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="port"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Port</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="22"
|
||||
{...field}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value;
|
||||
if (value === "") {
|
||||
field.onChange(0);
|
||||
} else {
|
||||
const number = Number.parseInt(value, 10);
|
||||
if (!Number.isNaN(number)) {
|
||||
field.onChange(number);
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="username"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Username</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="root" {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</form>
|
||||
|
||||
<DialogFooter className="pt-5">
|
||||
<Button
|
||||
isLoading={form.formState.isSubmitting}
|
||||
// disabled={!canCreateMoreServers}
|
||||
form="hook-form-add-server"
|
||||
type="submit"
|
||||
>
|
||||
Create
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</Form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,152 @@
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { api } from "@/utils/api";
|
||||
import { ExternalLinkIcon, Loader2 } from "lucide-react";
|
||||
import copy from "copy-to-clipboard";
|
||||
import { CopyIcon } from "lucide-react";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { CodeEditor } from "@/components/shared/code-editor";
|
||||
import Link from "next/link";
|
||||
|
||||
export const CreateSSHKey = () => {
|
||||
const { data, refetch } = api.sshKey.all.useQuery();
|
||||
const generateMutation = api.sshKey.generate.useMutation();
|
||||
const { mutateAsync, isLoading } = api.sshKey.create.useMutation();
|
||||
const hasCreatedKey = useRef(false);
|
||||
|
||||
const cloudSSHKey = data?.find(
|
||||
(sshKey) => sshKey.name === "dokploy-cloud-ssh-key",
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const createKey = async () => {
|
||||
if (!data || cloudSSHKey || hasCreatedKey.current || isLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
hasCreatedKey.current = true;
|
||||
|
||||
try {
|
||||
const keys = await generateMutation.mutateAsync({
|
||||
type: "rsa",
|
||||
});
|
||||
await mutateAsync({
|
||||
name: "dokploy-cloud-ssh-key",
|
||||
description: "Used on Dokploy Cloud",
|
||||
privateKey: keys.privateKey,
|
||||
publicKey: keys.publicKey,
|
||||
});
|
||||
await refetch();
|
||||
} catch (error) {
|
||||
console.error("Error creating SSH key:", error);
|
||||
hasCreatedKey.current = false;
|
||||
}
|
||||
};
|
||||
|
||||
createKey();
|
||||
}, [data]);
|
||||
|
||||
return (
|
||||
<Card className="h-full bg-transparent">
|
||||
<CardContent>
|
||||
<div className="grid w-full gap-4 pt-4">
|
||||
{isLoading ? (
|
||||
<div className="min-h-[25vh] justify-center flex items-center gap-4">
|
||||
<Loader2
|
||||
className="animate-spin text-muted-foreground"
|
||||
size={32}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex flex-col gap-2 text-sm text-muted-foreground">
|
||||
<p className="text-primary text-base font-semibold">
|
||||
You have two options to add SSH Keys to your server:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>1. Add The SSH Key to Server Manually</li>
|
||||
|
||||
<li>
|
||||
2. Add the public SSH Key when you create a server in your
|
||||
preffered provider (Hostinger, Digital Ocean, Hetzner, etc){" "}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div className="flex flex-col gap-2 w-full border rounded-lg p-4">
|
||||
<span className="text-base font-semibold text-primary">
|
||||
Option 1
|
||||
</span>
|
||||
<ul>
|
||||
<li className="items-center flex gap-1">
|
||||
1. Login to your server{" "}
|
||||
</li>
|
||||
<li>
|
||||
2. When you are logged in run the following command
|
||||
<div className="flex relative flex-col gap-4 w-full mt-2">
|
||||
<CodeEditor
|
||||
lineWrapping
|
||||
language="properties"
|
||||
value={`echo "${cloudSSHKey?.publicKey}" >> ~/.ssh/authorized_keys`}
|
||||
readOnly
|
||||
className="font-mono opacity-60"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="absolute right-2 top-2"
|
||||
onClick={() => {
|
||||
copy(
|
||||
`echo "${cloudSSHKey?.publicKey}" >> ~/.ssh/authorized_keys`,
|
||||
);
|
||||
toast.success("Copied to clipboard");
|
||||
}}
|
||||
>
|
||||
<CopyIcon className="size-4" />
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
<li className="mt-1">
|
||||
3. You're done, follow the next step to insert the details
|
||||
of your server.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 w-full mt-2 border rounded-lg p-4">
|
||||
<span className="text-base font-semibold text-primary">
|
||||
Option 2
|
||||
</span>
|
||||
<div className="flex flex-col gap-4 w-full overflow-auto">
|
||||
<div className="flex relative flex-col gap-2 overflow-y-auto">
|
||||
<div className="text-sm text-primary flex flex-row gap-2 items-center">
|
||||
Copy Public Key
|
||||
<button
|
||||
type="button"
|
||||
className=" right-2 top-8"
|
||||
onClick={() => {
|
||||
copy(
|
||||
cloudSSHKey?.publicKey || "Generate a SSH Key",
|
||||
);
|
||||
toast.success("SSH Copied to clipboard");
|
||||
}}
|
||||
>
|
||||
<CopyIcon className="size-4 text-muted-foreground" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Link
|
||||
href="https://docs.dokploy.com/docs/core/multi-server/instructions#requirements"
|
||||
target="_blank"
|
||||
className="text-primary flex flex-row gap-2"
|
||||
>
|
||||
View Tutorial <ExternalLinkIcon className="size-4" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,163 @@
|
||||
import { ShowDeployment } from "@/components/dashboard/application/deployments/show-deployment";
|
||||
import { DateTooltip } from "@/components/shared/date-tooltip";
|
||||
import { DialogAction } from "@/components/shared/dialog-action";
|
||||
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
CardDescription,
|
||||
CardContent,
|
||||
} from "@/components/ui/card";
|
||||
import { RocketIcon } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { EditScript } from "../edit-script";
|
||||
import { api } from "@/utils/api";
|
||||
import { useState } from "react";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import {
|
||||
Select,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
} from "@/components/ui/select";
|
||||
|
||||
export const Setup = () => {
|
||||
const { data: servers } = api.server.all.useQuery();
|
||||
const [serverId, setServerId] = useState<string>(
|
||||
servers?.[0]?.serverId || "",
|
||||
);
|
||||
const { data: server } = api.server.one.useQuery(
|
||||
{
|
||||
serverId,
|
||||
},
|
||||
{
|
||||
enabled: !!serverId,
|
||||
},
|
||||
);
|
||||
|
||||
const [activeLog, setActiveLog] = useState<string | null>(null);
|
||||
const { data: deployments, refetch } = api.deployment.allByServer.useQuery(
|
||||
{ serverId },
|
||||
{
|
||||
enabled: !!serverId,
|
||||
},
|
||||
);
|
||||
|
||||
const { mutateAsync, isLoading } = api.server.setup.useMutation();
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<Card className="bg-background">
|
||||
<CardHeader className="flex flex-row items-center justify-between flex-wrap gap-2">
|
||||
<div className="flex flex-col gap-2 w-full">
|
||||
<Label>Select a server</Label>
|
||||
<Select onValueChange={setServerId} defaultValue={serverId}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a server" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{servers?.map((server) => (
|
||||
<SelectItem key={server.serverId} value={server.serverId}>
|
||||
{server.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
<SelectLabel>Servers ({servers?.length})</SelectLabel>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex flex-row gap-2 justify-between w-full max-sm:flex-col">
|
||||
<div className="flex flex-col gap-1">
|
||||
<CardTitle className="text-xl">Deployments</CardTitle>
|
||||
<CardDescription>See all the 5 Server Setup</CardDescription>
|
||||
</div>
|
||||
<div className="flex flex-row gap-2">
|
||||
<EditScript serverId={server?.serverId || ""} />
|
||||
<DialogAction
|
||||
title={"Setup Server?"}
|
||||
description="This will setup the server and all associated data"
|
||||
onClick={async () => {
|
||||
await mutateAsync({
|
||||
serverId: server?.serverId || "",
|
||||
})
|
||||
.then(async () => {
|
||||
refetch();
|
||||
toast.success("Server setup successfully");
|
||||
})
|
||||
.catch(() => {
|
||||
toast.error("Error configuring server");
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Button isLoading={isLoading}>Setup Server</Button>
|
||||
</DialogAction>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4 min-h-[30vh]">
|
||||
{server?.deployments?.length === 0 ? (
|
||||
<div className="flex w-full flex-col items-center justify-center gap-3 pt-10">
|
||||
<RocketIcon className="size-8 text-muted-foreground" />
|
||||
<span className="text-base text-muted-foreground">
|
||||
No deployments found
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col gap-4">
|
||||
{deployments?.map((deployment) => (
|
||||
<div
|
||||
key={deployment.deploymentId}
|
||||
className="flex items-center justify-between rounded-lg border p-4 gap-2"
|
||||
>
|
||||
<div className="flex flex-col">
|
||||
<span className="flex items-center gap-4 font-medium capitalize text-foreground">
|
||||
{deployment.status}
|
||||
|
||||
<StatusTooltip
|
||||
status={deployment?.status}
|
||||
className="size-2.5"
|
||||
/>
|
||||
</span>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{deployment.title}
|
||||
</span>
|
||||
{deployment.description && (
|
||||
<span className="break-all text-sm text-muted-foreground">
|
||||
{deployment.description}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col items-end gap-2">
|
||||
<div className="text-sm capitalize text-muted-foreground">
|
||||
<DateTooltip date={deployment.createdAt} />
|
||||
</div>
|
||||
|
||||
<Button
|
||||
onClick={() => {
|
||||
setActiveLog(deployment.logPath);
|
||||
}}
|
||||
>
|
||||
View
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<ShowDeployment
|
||||
open={activeLog !== null}
|
||||
onClose={() => setActiveLog(null)}
|
||||
logPath={activeLog}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,189 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
CardDescription,
|
||||
CardContent,
|
||||
} from "@/components/ui/card";
|
||||
import { Loader2, PcCase, RefreshCw } from "lucide-react";
|
||||
import { api } from "@/utils/api";
|
||||
import { useState } from "react";
|
||||
import { Label } from "@/components/ui/label";
|
||||
|
||||
import {
|
||||
Select,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
} from "@/components/ui/select";
|
||||
import { StatusRow } from "../gpu-support";
|
||||
import { AlertBlock } from "@/components/shared/alert-block";
|
||||
|
||||
export const Verify = () => {
|
||||
const { data: servers } = api.server.all.useQuery();
|
||||
const [serverId, setServerId] = useState<string>(
|
||||
servers?.[0]?.serverId || "",
|
||||
);
|
||||
const { data, refetch, error, isLoading, isError } =
|
||||
api.server.validate.useQuery(
|
||||
{ serverId },
|
||||
{
|
||||
enabled: !!serverId,
|
||||
},
|
||||
);
|
||||
const [isRefreshing, setIsRefreshing] = useState(false);
|
||||
|
||||
const { data: server } = api.server.one.useQuery(
|
||||
{
|
||||
serverId,
|
||||
},
|
||||
{
|
||||
enabled: !!serverId,
|
||||
},
|
||||
);
|
||||
|
||||
return (
|
||||
<CardContent className="p-0">
|
||||
<div className="flex flex-col gap-4">
|
||||
<Card className="bg-background">
|
||||
<CardHeader className="flex flex-row items-center justify-between flex-wrap gap-2">
|
||||
<div className="flex flex-col gap-2 w-full">
|
||||
<Label>Select a server</Label>
|
||||
<Select onValueChange={setServerId} defaultValue={serverId}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a server" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{servers?.map((server) => (
|
||||
<SelectItem key={server.serverId} value={server.serverId}>
|
||||
{server.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
<SelectLabel>Servers ({servers?.length})</SelectLabel>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex flex-row gap-2 justify-between w-full max-sm:flex-col">
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<PcCase className="size-5" />
|
||||
<CardTitle className="text-xl">Setup Validation</CardTitle>
|
||||
</div>
|
||||
<CardDescription>
|
||||
Check if your server is ready for deployment
|
||||
</CardDescription>
|
||||
</div>
|
||||
<Button
|
||||
isLoading={isRefreshing}
|
||||
onClick={async () => {
|
||||
setIsRefreshing(true);
|
||||
await refetch();
|
||||
setIsRefreshing(false);
|
||||
}}
|
||||
>
|
||||
<RefreshCw className="size-4" />
|
||||
Refresh
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 w-full">
|
||||
{isError && (
|
||||
<AlertBlock type="error" className="w-full">
|
||||
{error.message}
|
||||
</AlertBlock>
|
||||
)}
|
||||
</div>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="flex flex-col gap-4 min-h-[25vh]">
|
||||
{isLoading ? (
|
||||
<div className="flex items-center justify-center text-muted-foreground py-4">
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
<span>Checking Server configuration</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid w-full gap-4">
|
||||
<div className="border rounded-lg p-4">
|
||||
<h3 className="text-lg font-semibold mb-1">Status</h3>
|
||||
<p className="text-sm text-muted-foreground mb-4">
|
||||
Shows the server configuration status
|
||||
</p>
|
||||
<div className="grid gap-2.5">
|
||||
<StatusRow
|
||||
label="Docker Installed"
|
||||
isEnabled={data?.docker?.enabled}
|
||||
description={
|
||||
data?.docker?.enabled
|
||||
? `Installed: ${data?.docker?.version}`
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
<StatusRow
|
||||
label="RClone Installed"
|
||||
isEnabled={data?.rclone?.enabled}
|
||||
description={
|
||||
data?.rclone?.enabled
|
||||
? `Installed: ${data?.rclone?.version}`
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
<StatusRow
|
||||
label="Nixpacks Installed"
|
||||
isEnabled={data?.nixpacks?.enabled}
|
||||
description={
|
||||
data?.nixpacks?.enabled
|
||||
? `Installed: ${data?.nixpacks?.version}`
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
<StatusRow
|
||||
label="Buildpacks Installed"
|
||||
isEnabled={data?.buildpacks?.enabled}
|
||||
description={
|
||||
data?.buildpacks?.enabled
|
||||
? `Installed: ${data?.buildpacks?.version}`
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
<StatusRow
|
||||
label="Docker Swarm Initialized"
|
||||
isEnabled={data?.isSwarmInstalled}
|
||||
description={
|
||||
data?.isSwarmInstalled
|
||||
? "Initialized"
|
||||
: "Not Initialized"
|
||||
}
|
||||
/>
|
||||
<StatusRow
|
||||
label="Dokploy Network Created"
|
||||
isEnabled={data?.isDokployNetworkInstalled}
|
||||
description={
|
||||
data?.isDokployNetworkInstalled
|
||||
? "Created"
|
||||
: "Not Created"
|
||||
}
|
||||
/>
|
||||
<StatusRow
|
||||
label="Main Directory Created"
|
||||
isEnabled={data?.isMainDirectoryInstalled}
|
||||
description={
|
||||
data?.isMainDirectoryInstalled
|
||||
? "Created"
|
||||
: "Not Created"
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</CardContent>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,366 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Puzzle } from "lucide-react";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useState } from "react";
|
||||
import { defineStepper } from "@stepperize/react";
|
||||
import React from "react";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { AlertBlock } from "@/components/shared/alert-block";
|
||||
import { CreateServer } from "./create-server";
|
||||
import { CreateSSHKey } from "./create-ssh-key";
|
||||
import { Setup } from "./setup";
|
||||
import { Verify } from "./verify";
|
||||
import {
|
||||
Database,
|
||||
Globe,
|
||||
GitMerge,
|
||||
Code,
|
||||
Users,
|
||||
Code2,
|
||||
Plug,
|
||||
} from "lucide-react";
|
||||
import ConfettiExplosion from "react-confetti-explosion";
|
||||
|
||||
interface Props {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const { useStepper, steps, Scoped } = defineStepper(
|
||||
{
|
||||
id: "requisites",
|
||||
title: "Requisites",
|
||||
description: "Check your requisites",
|
||||
},
|
||||
{
|
||||
id: "create-ssh-key",
|
||||
title: "SSH Key",
|
||||
description: "Create your ssh key",
|
||||
},
|
||||
{
|
||||
id: "connect-server",
|
||||
title: "Connect",
|
||||
description: "Connect",
|
||||
},
|
||||
{ id: "setup", title: "Setup", description: "Setup your server" },
|
||||
{ id: "verify", title: "Verify", description: "Verify your server" },
|
||||
{ id: "complete", title: "Complete", description: "Checkout complete" },
|
||||
);
|
||||
|
||||
export const WelcomeSuscription = ({ children }: Props) => {
|
||||
const [showConfetti, setShowConfetti] = useState(false);
|
||||
const stepper = useStepper();
|
||||
const [isOpen, setIsOpen] = useState(true);
|
||||
const { push } = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
const confettiShown = localStorage.getItem("hasShownConfetti");
|
||||
if (!confettiShown) {
|
||||
setShowConfetti(true);
|
||||
localStorage.setItem("hasShownConfetti", "true");
|
||||
}
|
||||
}, [showConfetti]);
|
||||
|
||||
return (
|
||||
<Dialog open={isOpen}>
|
||||
<DialogContent className="max-h-screen overflow-y-auto sm:max-w-7xl min-h-[75vh]">
|
||||
{showConfetti ?? "Flaso"}
|
||||
<div className="flex justify-center items-center w-full">
|
||||
{showConfetti && (
|
||||
<ConfettiExplosion
|
||||
duration={3000}
|
||||
force={0.3}
|
||||
particleSize={12}
|
||||
particleCount={300}
|
||||
className="z-[9999]"
|
||||
zIndex={9999}
|
||||
width={1500}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-2xl text-center">
|
||||
Welcome To Dokploy Cloud 🎉
|
||||
</DialogTitle>
|
||||
<DialogDescription className="text-center">
|
||||
Thank you for choosing Dokploy Cloud, before you start you need to
|
||||
configure your remote server
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="grid gap-4">
|
||||
<div className="flex justify-between">
|
||||
<h2 className="text-lg font-semibold">Steps</h2>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Step {stepper.current.index + 1} of {steps.length}
|
||||
</span>
|
||||
<div />
|
||||
</div>
|
||||
</div>
|
||||
<Scoped>
|
||||
<nav aria-label="Checkout Steps" className="group my-4">
|
||||
<ol
|
||||
className="flex items-center justify-between gap-2"
|
||||
aria-orientation="horizontal"
|
||||
>
|
||||
{stepper.all.map((step, index, array) => (
|
||||
<React.Fragment key={step.id}>
|
||||
<li className="flex items-center gap-4 flex-shrink-0">
|
||||
<Button
|
||||
type="button"
|
||||
role="tab"
|
||||
variant={
|
||||
index <= stepper.current.index
|
||||
? "default"
|
||||
: "secondary"
|
||||
}
|
||||
aria-current={
|
||||
stepper.current.id === step.id ? "step" : undefined
|
||||
}
|
||||
aria-posinset={index + 1}
|
||||
aria-setsize={steps.length}
|
||||
aria-selected={stepper.current.id === step.id}
|
||||
className="flex size-10 items-center justify-center rounded-full"
|
||||
onClick={() => stepper.goTo(step.id)}
|
||||
>
|
||||
{index + 1}
|
||||
</Button>
|
||||
<span className="text-sm font-medium">{step.title}</span>
|
||||
</li>
|
||||
{index < array.length - 1 && (
|
||||
<Separator
|
||||
className={`flex-1 ${
|
||||
index < stepper.current.index
|
||||
? "bg-primary"
|
||||
: "bg-muted"
|
||||
}`}
|
||||
/>
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</ol>
|
||||
</nav>
|
||||
{stepper.switch({
|
||||
requisites: () => (
|
||||
<div className="flex flex-col gap-2 border p-4 rounded-lg">
|
||||
<span className="text-primary text-base font-bold">
|
||||
Before getting started, please follow the steps below to
|
||||
ensure the best experience:
|
||||
</span>
|
||||
<div>
|
||||
<p className="text-primary text-sm font-medium">
|
||||
Supported Distributions:
|
||||
</p>
|
||||
<ul className="list-inside list-disc pl-4 text-sm text-muted-foreground mt-4">
|
||||
<li>Ubuntu 24.04 LTS</li>
|
||||
<li>Ubuntu 23.10</li>
|
||||
<li>Ubuntu 22.04 LTS</li>
|
||||
<li>Ubuntu 20.04 LTS</li>
|
||||
<li>Ubuntu 18.04 LTS</li>
|
||||
<li>Debian 12</li>
|
||||
<li>Debian 11</li>
|
||||
<li>Debian 10</li>
|
||||
<li>Fedora 40</li>
|
||||
<li>CentOS 9</li>
|
||||
<li>CentOS 8</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-primary text-sm font-medium">
|
||||
You will need to purchase or rent a Virtual Private Server
|
||||
(VPS) to proceed, we recommend to use one of these
|
||||
providers since has been heavily tested.
|
||||
</p>
|
||||
<ul className="list-inside list-disc pl-4 text-sm text-muted-foreground mt-4">
|
||||
<li>
|
||||
<a
|
||||
href="https://www.hostinger.com/vps-hosting?REFERRALCODE=1SIUMAURICI97"
|
||||
className="text-link underline"
|
||||
>
|
||||
Hostinger - Get 20% Discount
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://m.do.co/c/db24efd43f35"
|
||||
className="text-link underline"
|
||||
>
|
||||
DigitalOcean - Get $200 Credits
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://hetzner.cloud/?ref=vou4fhxJ1W2D"
|
||||
className="text-link underline"
|
||||
>
|
||||
Hetzner - Get €20 Credits
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://www.vultr.com/?ref=9679828"
|
||||
className="text-link underline"
|
||||
>
|
||||
Vultr
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://www.linode.com/es/pricing/#compute-shared"
|
||||
className="text-link underline"
|
||||
>
|
||||
Linode
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<AlertBlock className="mt-4 px-4">
|
||||
You are free to use whatever provider, but we recommend to
|
||||
use one of the above, to avoid issues.
|
||||
</AlertBlock>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
"create-ssh-key": () => <CreateSSHKey />,
|
||||
"connect-server": () => <CreateServer stepper={stepper} />,
|
||||
setup: () => <Setup />,
|
||||
verify: () => <Verify />,
|
||||
complete: () => {
|
||||
const features = [
|
||||
{
|
||||
title: "Scalable Deployments",
|
||||
description:
|
||||
"Deploy and scale your applications effortlessly to handle any workload.",
|
||||
icon: <Database className="text-primary" />,
|
||||
},
|
||||
{
|
||||
title: "Automated Backups",
|
||||
description: "Protect your data with automatic backups",
|
||||
icon: <Database className="text-primary" />,
|
||||
},
|
||||
{
|
||||
title: "Open Source Templates",
|
||||
description:
|
||||
"Big list of common open source templates in one-click",
|
||||
icon: <Puzzle className="text-primary" />,
|
||||
},
|
||||
{
|
||||
title: "Custom Domains",
|
||||
description:
|
||||
"Link your own domains to your applications for a professional presence.",
|
||||
icon: <Globe className="text-primary" />,
|
||||
},
|
||||
{
|
||||
title: "CI/CD Integration",
|
||||
description:
|
||||
"Implement continuous integration and deployment workflows to streamline development.",
|
||||
icon: <GitMerge className="text-primary" />,
|
||||
},
|
||||
{
|
||||
title: "Database Management",
|
||||
description:
|
||||
"Efficiently manage your databases with intuitive tools.",
|
||||
icon: <Database className="text-primary" />,
|
||||
},
|
||||
{
|
||||
title: "Team Collaboration",
|
||||
description:
|
||||
"Collaborate with your team on shared projects with customizable permissions.",
|
||||
icon: <Users className="text-primary" />,
|
||||
},
|
||||
{
|
||||
title: "Multi-language Support",
|
||||
description:
|
||||
"Deploy applications in multiple programming languages to suit your needs.",
|
||||
icon: <Code2 className="text-primary" />,
|
||||
},
|
||||
{
|
||||
title: "API Access",
|
||||
description:
|
||||
"Integrate and manage your applications via robust and well-documented APIs.",
|
||||
icon: <Plug className="text-primary" />,
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex flex-col gap-2">
|
||||
<h2 className="text-xl font-semibold">You're All Set!</h2>
|
||||
<p className=" text-muted-foreground">
|
||||
Did you know you can deploy any number of applications
|
||||
that your server can handle?
|
||||
</p>
|
||||
<p className="text-muted-foreground">
|
||||
Here are some of the things you can do with Dokploy
|
||||
Cloud:
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6">
|
||||
{features.map((feature, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex flex-col items-start p-4 bg-card rounded-lg shadow-md hover:shadow-lg transition-shadow"
|
||||
>
|
||||
<div className="text-3xl mb-2">{feature.icon}</div>
|
||||
<h3 className="text-lg font-medium mb-1">
|
||||
{feature.title}
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
})}
|
||||
</Scoped>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<div className="flex items-center justify-between w-full">
|
||||
{!stepper.isLast && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() => {
|
||||
setIsOpen(false);
|
||||
}}
|
||||
>
|
||||
Skip for now
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<div className="flex items-center gap-2 w-full justify-end">
|
||||
<Button
|
||||
onClick={stepper.prev}
|
||||
disabled={stepper.isFirst}
|
||||
variant="secondary"
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (stepper.isLast) {
|
||||
setIsOpen(false);
|
||||
push("/dashboard/projects");
|
||||
} else {
|
||||
stepper.next();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{stepper.isLast ? "Complete" : "Next"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
@@ -35,7 +35,8 @@
|
||||
"test": "vitest --config __test__/vitest.config.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@reactour/tour": "3.7.0",
|
||||
"react-confetti-explosion":"2.1.2",
|
||||
"@stepperize/react": "4.0.1",
|
||||
"@codemirror/lang-json": "^6.0.1",
|
||||
"@codemirror/lang-yaml": "^6.1.1",
|
||||
"@codemirror/language": "^6.10.1",
|
||||
|
||||
@@ -4,7 +4,6 @@ import { SearchCommand } from "@/components/dashboard/search-command";
|
||||
import { Toaster } from "@/components/ui/sonner";
|
||||
import { Languages } from "@/lib/languages";
|
||||
import { api } from "@/utils/api";
|
||||
import { TourProvider } from "@reactour/tour";
|
||||
import type { NextPage } from "next";
|
||||
import { appWithTranslation } from "next-i18next";
|
||||
import { ThemeProvider } from "next-themes";
|
||||
@@ -16,21 +15,6 @@ import type { ReactElement, ReactNode } from "react";
|
||||
|
||||
const inter = Inter({ subsets: ["latin"] });
|
||||
|
||||
export const steps = [
|
||||
{
|
||||
selector: ".first-step",
|
||||
content: "This is the first Step",
|
||||
},
|
||||
{
|
||||
selector: ".second-step",
|
||||
content: "This is the second Step",
|
||||
},
|
||||
{
|
||||
selector: ".third-step",
|
||||
content: "This is the third Step",
|
||||
},
|
||||
];
|
||||
|
||||
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
|
||||
getLayout?: (page: ReactElement) => ReactNode;
|
||||
// session: Session | null;
|
||||
@@ -65,19 +49,17 @@ const MyApp = ({
|
||||
/>
|
||||
)}
|
||||
|
||||
<TourProvider steps={steps}>
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
forcedTheme={Component.theme}
|
||||
>
|
||||
<Toaster richColors />
|
||||
<SearchCommand />
|
||||
{getLayout(<Component {...pageProps} />)}
|
||||
</ThemeProvider>
|
||||
</TourProvider>
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
forcedTheme={Component.theme}
|
||||
>
|
||||
<Toaster richColors />
|
||||
<SearchCommand />
|
||||
{getLayout(<Component {...pageProps} />)}
|
||||
</ThemeProvider>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
updateSSHKeyById,
|
||||
} from "@dokploy/server";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { desc, eq } from "drizzle-orm";
|
||||
|
||||
export const sshRouter = createTRPCRouter({
|
||||
create: protectedProcedure
|
||||
@@ -71,6 +71,7 @@ export const sshRouter = createTRPCRouter({
|
||||
all: protectedProcedure.query(async ({ ctx }) => {
|
||||
return await db.query.sshKeys.findMany({
|
||||
...(IS_CLOUD && { where: eq(sshKeys.adminId, ctx.user.adminId) }),
|
||||
orderBy: desc(sshKeys.createdAt),
|
||||
});
|
||||
// TODO: Remove this line when the cloud version is ready
|
||||
}),
|
||||
|
||||
@@ -81,7 +81,7 @@ export const stripeRouter = createTRPCRouter({
|
||||
adminId: admin.adminId,
|
||||
},
|
||||
allow_promotion_codes: true,
|
||||
success_url: `${WEBSITE_URL}/dashboard/settings/billing`,
|
||||
success_url: `${WEBSITE_URL}/dashboard/settings/servers?success=true`,
|
||||
cancel_url: `${WEBSITE_URL}/dashboard/settings/billing`,
|
||||
});
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ export const serverSetup = async (serverId: string) => {
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
await updateDeploymentStatus(deployment.deploymentId, "error");
|
||||
writeStream.write(err);
|
||||
writeStream.write(`${err} ❌\n`);
|
||||
writeStream.close();
|
||||
}
|
||||
};
|
||||
|
||||
318
pnpm-lock.yaml
generated
318
pnpm-lock.yaml
generated
@@ -178,9 +178,9 @@ importers:
|
||||
'@radix-ui/react-tooltip':
|
||||
specifier: ^1.0.7
|
||||
version: 1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
'@reactour/tour':
|
||||
specifier: 3.7.0
|
||||
version: 3.7.0(react@18.2.0)
|
||||
'@stepperize/react':
|
||||
specifier: 4.0.1
|
||||
version: 4.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
'@stripe/stripe-js':
|
||||
specifier: 4.8.0
|
||||
version: 4.8.0
|
||||
@@ -301,6 +301,9 @@ importers:
|
||||
react:
|
||||
specifier: 18.2.0
|
||||
version: 18.2.0
|
||||
react-confetti-explosion:
|
||||
specifier: 2.1.2
|
||||
version: 2.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
react-dom:
|
||||
specifier: 18.2.0
|
||||
version: 18.2.0(react@18.2.0)
|
||||
@@ -863,6 +866,12 @@ packages:
|
||||
'@emnapi/runtime@1.3.1':
|
||||
resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==}
|
||||
|
||||
'@emotion/is-prop-valid@0.7.3':
|
||||
resolution: {integrity: sha512-uxJqm/sqwXw3YPA5GXX365OBcJGFtxUVkB6WyezqFHlNe9jqUWH5ur2O2M8dGBz61kn1g3ZBlzUunFQXQIClhA==}
|
||||
|
||||
'@emotion/memoize@0.7.1':
|
||||
resolution: {integrity: sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==}
|
||||
|
||||
'@esbuild-kit/core-utils@3.3.2':
|
||||
resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==}
|
||||
|
||||
@@ -2874,26 +2883,6 @@ packages:
|
||||
peerDependencies:
|
||||
react: ^18.2.0
|
||||
|
||||
'@reactour/mask@1.1.0':
|
||||
resolution: {integrity: sha512-GkJMLuTs3vTsm4Ryq2uXcE4sMzRP1p4xSd6juSOMqbHa7IVD/UiLCLqJWHR9xGSQPbYhpZAZAORUG5cS0U5tBA==}
|
||||
peerDependencies:
|
||||
react: 16.x || 17.x || 18.x
|
||||
|
||||
'@reactour/popover@1.2.0':
|
||||
resolution: {integrity: sha512-1JMykZ+MmDmRlEVC5+DwlvK1exwV5bFHtiSFwVXnoPZmsSfwId6SLyjo9H6bybeuNtNEzviKdsF/ZBC1UQbDqg==}
|
||||
peerDependencies:
|
||||
react: 16.x || 17.x || 18.x
|
||||
|
||||
'@reactour/tour@3.7.0':
|
||||
resolution: {integrity: sha512-p0USaOBc5fcNBS5ZiQ2lsmztAhIGCUfx913Zw14FbEM8bhSXpR1F2JD0alVj9Ya1N+pnTNYatf14rSNGJsEnCg==}
|
||||
peerDependencies:
|
||||
react: 16.x || 17.x || 18.x
|
||||
|
||||
'@reactour/utils@0.5.0':
|
||||
resolution: {integrity: sha512-yQs5Nm/Dg1xRM7d/S/UILBV5OInrTgrjGzgc81/RP5khqdO5KnpOaC46yF83kDtCalte8X3RCwp+F2YA509k1w==}
|
||||
peerDependencies:
|
||||
react: 16.x || 17.x || 18.x
|
||||
|
||||
'@redis/bloom@1.2.0':
|
||||
resolution: {integrity: sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==}
|
||||
peerDependencies:
|
||||
@@ -3003,11 +2992,6 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rooks/use-mutation-observer@4.11.2':
|
||||
resolution: {integrity: sha512-vpsdrZdr6TkB1zZJcHx+fR1YC/pHs2BaqcuYiEGjBVbwY5xcC49+h0hAUtQKHth3oJqXfIX/Ng8S7s5HFHdM/A==}
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
|
||||
'@selderee/plugin-htmlparser2@0.11.0':
|
||||
resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==}
|
||||
|
||||
@@ -3022,6 +3006,12 @@ packages:
|
||||
resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@stepperize/react@4.0.1':
|
||||
resolution: {integrity: sha512-LAOcfi3d2mM/Jn740Xy35qsuTwmoLIuitvWZTZRURYeGsc7a6sIKAkk3+L1joZGkLFvf5q4I6V7LxWWfB5hDvg==}
|
||||
peerDependencies:
|
||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
|
||||
'@stripe/stripe-js@4.8.0':
|
||||
resolution: {integrity: sha512-+4Cb0bVHlV4BJXxkJ3cCLSLuWxm3pXKtgcRacox146EuugjCzRRII5T5gUMgL4HpzrBLVwVxjKaZqntNWAXawQ==}
|
||||
engines: {node: '>=12.16'}
|
||||
@@ -3985,6 +3975,12 @@ packages:
|
||||
uWebSockets.js:
|
||||
optional: true
|
||||
|
||||
css-jss@10.10.0:
|
||||
resolution: {integrity: sha512-YyMIS/LsSKEGXEaVJdjonWe18p4vXLo8CMA4FrW/kcaEyqdIGKCFXao31gbJddXEdIxSXFFURWrenBJPlKTgAA==}
|
||||
|
||||
css-vendor@2.0.8:
|
||||
resolution: {integrity: sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==}
|
||||
|
||||
css.escape@1.5.1:
|
||||
resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
|
||||
|
||||
@@ -4754,6 +4750,9 @@ packages:
|
||||
resolution: {integrity: sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==}
|
||||
engines: {node: '>=10.18'}
|
||||
|
||||
hyphenate-style-name@1.1.0:
|
||||
resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==}
|
||||
|
||||
i18next-fs-backend@2.3.2:
|
||||
resolution: {integrity: sha512-LIwUlkqDZnUI8lnUxBnEj8K/FrHQTT/Sc+1rvDm9E8YvvY5YxzoEAASNx+W5M9DfD5s77lI5vSAFWeTp26B/3Q==}
|
||||
|
||||
@@ -4878,6 +4877,9 @@ packages:
|
||||
is-hexadecimal@1.0.4:
|
||||
resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==}
|
||||
|
||||
is-in-browser@1.1.3:
|
||||
resolution: {integrity: sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==}
|
||||
|
||||
is-ip@4.0.0:
|
||||
resolution: {integrity: sha512-4B4XA2HEIm/PY+OSpeMBXr8pGWBYbXuHgjMAqrwbLO3CPTCAd9ArEJzBUKGZtk9viY6+aSfadGnWyjY3ydYZkw==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
@@ -4969,6 +4971,48 @@ packages:
|
||||
resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==}
|
||||
engines: {node: '>=12', npm: '>=6'}
|
||||
|
||||
jss-plugin-camel-case@10.10.0:
|
||||
resolution: {integrity: sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw==}
|
||||
|
||||
jss-plugin-compose@10.10.0:
|
||||
resolution: {integrity: sha512-F5kgtWpI2XfZ3Z8eP78tZEYFdgTIbpA/TMuX3a8vwrNolYtN1N4qJR/Ob0LAsqIwCMLojtxN7c7Oo/+Vz6THow==}
|
||||
|
||||
jss-plugin-default-unit@10.10.0:
|
||||
resolution: {integrity: sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ==}
|
||||
|
||||
jss-plugin-expand@10.10.0:
|
||||
resolution: {integrity: sha512-ymT62W2OyDxBxr7A6JR87vVX9vTq2ep5jZLIdUSusfBIEENLdkkc0lL/Xaq8W9s3opUq7R0sZQpzRWELrfVYzA==}
|
||||
|
||||
jss-plugin-extend@10.10.0:
|
||||
resolution: {integrity: sha512-sKYrcMfr4xxigmIwqTjxNcHwXJIfvhvjTNxF+Tbc1NmNdyspGW47Ey6sGH8BcQ4FFQhLXctpWCQSpDwdNmXSwg==}
|
||||
|
||||
jss-plugin-global@10.10.0:
|
||||
resolution: {integrity: sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A==}
|
||||
|
||||
jss-plugin-nested@10.10.0:
|
||||
resolution: {integrity: sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA==}
|
||||
|
||||
jss-plugin-props-sort@10.10.0:
|
||||
resolution: {integrity: sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg==}
|
||||
|
||||
jss-plugin-rule-value-function@10.10.0:
|
||||
resolution: {integrity: sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g==}
|
||||
|
||||
jss-plugin-rule-value-observable@10.10.0:
|
||||
resolution: {integrity: sha512-ZLMaYrR3QE+vD7nl3oNXuj79VZl9Kp8/u6A1IbTPDcuOu8b56cFdWRZNZ0vNr8jHewooEeq2doy8Oxtymr2ZPA==}
|
||||
|
||||
jss-plugin-template@10.10.0:
|
||||
resolution: {integrity: sha512-ocXZBIOJOA+jISPdsgkTs8wwpK6UbsvtZK5JI7VUggTD6LWKbtoxUzadd2TpfF+lEtlhUmMsCkTRNkITdPKa6w==}
|
||||
|
||||
jss-plugin-vendor-prefixer@10.10.0:
|
||||
resolution: {integrity: sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg==}
|
||||
|
||||
jss-preset-default@10.10.0:
|
||||
resolution: {integrity: sha512-GL175Wt2FGhjE+f+Y3aWh+JioL06/QWFgZp53CbNNq6ZkVU0TDplD8Bxm9KnkotAYn3FlplNqoW5CjyLXcoJ7Q==}
|
||||
|
||||
jss@10.10.0:
|
||||
resolution: {integrity: sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw==}
|
||||
|
||||
jwa@1.4.1:
|
||||
resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==}
|
||||
|
||||
@@ -5827,6 +5871,12 @@ packages:
|
||||
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
|
||||
hasBin: true
|
||||
|
||||
react-confetti-explosion@2.1.2:
|
||||
resolution: {integrity: sha512-4UzDFBajAGXmF9TSJoRMO2QOBCIXc66idTxH8l7Mkul48HLGtk+tMzK9HYDYsy7Zmw5sEGchi2fbn4AJUuLrZw==}
|
||||
peerDependencies:
|
||||
react: ^18.x
|
||||
react-dom: ^18.x
|
||||
|
||||
react-copy-to-clipboard@5.1.0:
|
||||
resolution: {integrity: sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==}
|
||||
peerDependencies:
|
||||
@@ -5837,6 +5887,9 @@ packages:
|
||||
peerDependencies:
|
||||
react: ^15.3.0 || 16 || 17 || 18
|
||||
|
||||
react-display-name@0.2.5:
|
||||
resolution: {integrity: sha512-I+vcaK9t4+kypiSgaiVWAipqHRXYmZIuAiS8vzFvXHHXVigg/sMKwlRgLy6LH2i3rmP+0Vzfl5lFsFRwF1r3pg==}
|
||||
|
||||
react-dom@18.2.0:
|
||||
resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
|
||||
peerDependencies:
|
||||
@@ -5884,6 +5937,11 @@ packages:
|
||||
react-is@18.3.1:
|
||||
resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
|
||||
|
||||
react-jss@10.10.0:
|
||||
resolution: {integrity: sha512-WLiq84UYWqNBF6579/uprcIUnM1TSywYq6AIjKTTTG5ziJl9Uy+pwuvpN3apuyVwflMbD60PraeTKT7uWH9XEQ==}
|
||||
peerDependencies:
|
||||
react: '>=16.8.6'
|
||||
|
||||
react-promise-suspense@0.3.4:
|
||||
resolution: {integrity: sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==}
|
||||
|
||||
@@ -6040,9 +6098,6 @@ packages:
|
||||
reselect@5.1.1:
|
||||
resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==}
|
||||
|
||||
resize-observer-polyfill@1.5.1:
|
||||
resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==}
|
||||
|
||||
resolve-alpn@1.2.1:
|
||||
resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==}
|
||||
|
||||
@@ -6162,6 +6217,9 @@ packages:
|
||||
resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==}
|
||||
hasBin: true
|
||||
|
||||
shallow-equal@1.2.1:
|
||||
resolution: {integrity: sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==}
|
||||
|
||||
sharp@0.33.5:
|
||||
resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
@@ -6373,6 +6431,10 @@ packages:
|
||||
react: '>=16.8.0 <19'
|
||||
react-dom: '>=16.8.0 <19'
|
||||
|
||||
symbol-observable@1.2.0:
|
||||
resolution: {integrity: sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
tailwind-merge@2.4.0:
|
||||
resolution: {integrity: sha512-49AwoOQNKdqKPd9CViyH5wJoSKsCDjUlzL8DxuGp3P1FsGY36NJDAa18jLZcaHAUUuTj+JB8IAo8zWgBNvBF7A==}
|
||||
|
||||
@@ -6426,6 +6488,12 @@ packages:
|
||||
resolution: {integrity: sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
theming@3.3.0:
|
||||
resolution: {integrity: sha512-u6l4qTJRDaWZsqa8JugaNt7Xd8PPl9+gonZaIe28vAhqgHMIG/DOyFPqiKN/gQLQYj05tHv+YQdNILL4zoiAVA==}
|
||||
engines: {node: '>=8'}
|
||||
peerDependencies:
|
||||
react: '>=16.3'
|
||||
|
||||
thenify-all@1.6.0:
|
||||
resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
|
||||
engines: {node: '>=0.8'}
|
||||
@@ -6452,6 +6520,9 @@ packages:
|
||||
tiny-invariant@1.3.3:
|
||||
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
|
||||
|
||||
tiny-warning@1.0.3:
|
||||
resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
|
||||
|
||||
tinybench@2.8.0:
|
||||
resolution: {integrity: sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==}
|
||||
|
||||
@@ -7146,6 +7217,12 @@ snapshots:
|
||||
tslib: 2.6.3
|
||||
optional: true
|
||||
|
||||
'@emotion/is-prop-valid@0.7.3':
|
||||
dependencies:
|
||||
'@emotion/memoize': 0.7.1
|
||||
|
||||
'@emotion/memoize@0.7.1': {}
|
||||
|
||||
'@esbuild-kit/core-utils@3.3.2':
|
||||
dependencies:
|
||||
esbuild: 0.18.20
|
||||
@@ -8859,29 +8936,6 @@ snapshots:
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
|
||||
'@reactour/mask@1.1.0(react@18.2.0)':
|
||||
dependencies:
|
||||
'@reactour/utils': 0.5.0(react@18.2.0)
|
||||
react: 18.2.0
|
||||
|
||||
'@reactour/popover@1.2.0(react@18.2.0)':
|
||||
dependencies:
|
||||
'@reactour/utils': 0.5.0(react@18.2.0)
|
||||
react: 18.2.0
|
||||
|
||||
'@reactour/tour@3.7.0(react@18.2.0)':
|
||||
dependencies:
|
||||
'@reactour/mask': 1.1.0(react@18.2.0)
|
||||
'@reactour/popover': 1.2.0(react@18.2.0)
|
||||
'@reactour/utils': 0.5.0(react@18.2.0)
|
||||
react: 18.2.0
|
||||
|
||||
'@reactour/utils@0.5.0(react@18.2.0)':
|
||||
dependencies:
|
||||
'@rooks/use-mutation-observer': 4.11.2(react@18.2.0)
|
||||
react: 18.2.0
|
||||
resize-observer-polyfill: 1.5.1
|
||||
|
||||
'@redis/bloom@1.2.0(@redis/client@1.6.0)':
|
||||
dependencies:
|
||||
'@redis/client': 1.6.0
|
||||
@@ -8956,10 +9010,6 @@ snapshots:
|
||||
'@rollup/rollup-win32-x64-msvc@4.19.1':
|
||||
optional: true
|
||||
|
||||
'@rooks/use-mutation-observer@4.11.2(react@18.2.0)':
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
|
||||
'@selderee/plugin-htmlparser2@0.11.0':
|
||||
dependencies:
|
||||
domhandler: 5.0.3
|
||||
@@ -8971,6 +9021,11 @@ snapshots:
|
||||
|
||||
'@sindresorhus/merge-streams@2.3.0': {}
|
||||
|
||||
'@stepperize/react@4.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
|
||||
'@stripe/stripe-js@4.8.0': {}
|
||||
|
||||
'@swagger-api/apidom-ast@1.0.0-alpha.9':
|
||||
@@ -10270,6 +10325,17 @@ snapshots:
|
||||
|
||||
crossws@0.2.4: {}
|
||||
|
||||
css-jss@10.10.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
jss: 10.10.0
|
||||
jss-preset-default: 10.10.0
|
||||
|
||||
css-vendor@2.0.8:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
is-in-browser: 1.1.3
|
||||
|
||||
css.escape@1.5.1: {}
|
||||
|
||||
cssesc@3.0.0: {}
|
||||
@@ -11049,6 +11115,8 @@ snapshots:
|
||||
|
||||
hyperdyperid@1.2.0: {}
|
||||
|
||||
hyphenate-style-name@1.1.0: {}
|
||||
|
||||
i18next-fs-backend@2.3.2: {}
|
||||
|
||||
i18next@23.16.5:
|
||||
@@ -11156,6 +11224,8 @@ snapshots:
|
||||
|
||||
is-hexadecimal@1.0.4: {}
|
||||
|
||||
is-in-browser@1.1.3: {}
|
||||
|
||||
is-ip@4.0.0:
|
||||
dependencies:
|
||||
ip-regex: 5.0.0
|
||||
@@ -11241,6 +11311,98 @@ snapshots:
|
||||
ms: 2.1.3
|
||||
semver: 7.6.2
|
||||
|
||||
jss-plugin-camel-case@10.10.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
hyphenate-style-name: 1.1.0
|
||||
jss: 10.10.0
|
||||
|
||||
jss-plugin-compose@10.10.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
jss: 10.10.0
|
||||
tiny-warning: 1.0.3
|
||||
|
||||
jss-plugin-default-unit@10.10.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
jss: 10.10.0
|
||||
|
||||
jss-plugin-expand@10.10.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
jss: 10.10.0
|
||||
|
||||
jss-plugin-extend@10.10.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
jss: 10.10.0
|
||||
tiny-warning: 1.0.3
|
||||
|
||||
jss-plugin-global@10.10.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
jss: 10.10.0
|
||||
|
||||
jss-plugin-nested@10.10.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
jss: 10.10.0
|
||||
tiny-warning: 1.0.3
|
||||
|
||||
jss-plugin-props-sort@10.10.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
jss: 10.10.0
|
||||
|
||||
jss-plugin-rule-value-function@10.10.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
jss: 10.10.0
|
||||
tiny-warning: 1.0.3
|
||||
|
||||
jss-plugin-rule-value-observable@10.10.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
jss: 10.10.0
|
||||
symbol-observable: 1.2.0
|
||||
|
||||
jss-plugin-template@10.10.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
jss: 10.10.0
|
||||
tiny-warning: 1.0.3
|
||||
|
||||
jss-plugin-vendor-prefixer@10.10.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
css-vendor: 2.0.8
|
||||
jss: 10.10.0
|
||||
|
||||
jss-preset-default@10.10.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
jss: 10.10.0
|
||||
jss-plugin-camel-case: 10.10.0
|
||||
jss-plugin-compose: 10.10.0
|
||||
jss-plugin-default-unit: 10.10.0
|
||||
jss-plugin-expand: 10.10.0
|
||||
jss-plugin-extend: 10.10.0
|
||||
jss-plugin-global: 10.10.0
|
||||
jss-plugin-nested: 10.10.0
|
||||
jss-plugin-props-sort: 10.10.0
|
||||
jss-plugin-rule-value-function: 10.10.0
|
||||
jss-plugin-rule-value-observable: 10.10.0
|
||||
jss-plugin-template: 10.10.0
|
||||
jss-plugin-vendor-prefixer: 10.10.0
|
||||
|
||||
jss@10.10.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
csstype: 3.1.3
|
||||
is-in-browser: 1.1.3
|
||||
tiny-warning: 1.0.3
|
||||
|
||||
jwa@1.4.1:
|
||||
dependencies:
|
||||
buffer-equal-constant-time: 1.0.1
|
||||
@@ -12077,6 +12239,13 @@ snapshots:
|
||||
strip-json-comments: 2.0.1
|
||||
optional: true
|
||||
|
||||
react-confetti-explosion@2.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
|
||||
dependencies:
|
||||
lodash: 4.17.21
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
react-jss: 10.10.0(react@18.2.0)
|
||||
|
||||
react-copy-to-clipboard@5.1.0(react@18.2.0):
|
||||
dependencies:
|
||||
copy-to-clipboard: 3.3.3
|
||||
@@ -12089,6 +12258,8 @@ snapshots:
|
||||
prop-types: 15.8.1
|
||||
react: 18.2.0
|
||||
|
||||
react-display-name@0.2.5: {}
|
||||
|
||||
react-dom@18.2.0(react@18.2.0):
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
@@ -12127,6 +12298,21 @@ snapshots:
|
||||
|
||||
react-is@18.3.1: {}
|
||||
|
||||
react-jss@10.10.0(react@18.2.0):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.0
|
||||
'@emotion/is-prop-valid': 0.7.3
|
||||
css-jss: 10.10.0
|
||||
hoist-non-react-statics: 3.3.2
|
||||
is-in-browser: 1.1.3
|
||||
jss: 10.10.0
|
||||
jss-preset-default: 10.10.0
|
||||
prop-types: 15.8.1
|
||||
react: 18.2.0
|
||||
shallow-equal: 1.2.1
|
||||
theming: 3.3.0(react@18.2.0)
|
||||
tiny-warning: 1.0.3
|
||||
|
||||
react-promise-suspense@0.3.4:
|
||||
dependencies:
|
||||
fast-deep-equal: 2.0.1
|
||||
@@ -12296,8 +12482,6 @@ snapshots:
|
||||
|
||||
reselect@5.1.1: {}
|
||||
|
||||
resize-observer-polyfill@1.5.1: {}
|
||||
|
||||
resolve-alpn@1.2.1: {}
|
||||
|
||||
resolve-from@4.0.0: {}
|
||||
@@ -12423,6 +12607,8 @@ snapshots:
|
||||
inherits: 2.0.4
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
shallow-equal@1.2.1: {}
|
||||
|
||||
sharp@0.33.5:
|
||||
dependencies:
|
||||
color: 4.2.3
|
||||
@@ -12692,6 +12878,8 @@ snapshots:
|
||||
- '@types/react'
|
||||
- debug
|
||||
|
||||
symbol-observable@1.2.0: {}
|
||||
|
||||
tailwind-merge@2.4.0: {}
|
||||
|
||||
tailwindcss-animate@1.0.7(tailwindcss@3.4.7):
|
||||
@@ -12771,6 +12959,14 @@ snapshots:
|
||||
|
||||
text-extensions@2.4.0: {}
|
||||
|
||||
theming@3.3.0(react@18.2.0):
|
||||
dependencies:
|
||||
hoist-non-react-statics: 3.3.2
|
||||
prop-types: 15.8.1
|
||||
react: 18.2.0
|
||||
react-display-name: 0.2.5
|
||||
tiny-warning: 1.0.3
|
||||
|
||||
thenify-all@1.6.0:
|
||||
dependencies:
|
||||
thenify: 3.3.1
|
||||
@@ -12796,6 +12992,8 @@ snapshots:
|
||||
|
||||
tiny-invariant@1.3.3: {}
|
||||
|
||||
tiny-warning@1.0.3: {}
|
||||
|
||||
tinybench@2.8.0: {}
|
||||
|
||||
tinypool@0.8.4: {}
|
||||
|
||||
Reference in New Issue
Block a user