feat: add deployment endpoint
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
import { CopyButton } from "@/components/CopyButton";
|
||||
import type { Lang } from "shiki";
|
||||
import shiki from "shiki";
|
||||
|
||||
export async function CodeBlock(props: { code: string; lang: Lang }) {
|
||||
const highlighter = await shiki.getHighlighter({
|
||||
theme: "one-dark-pro",
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="relative w-full max-w-full text-sm">
|
||||
{/* max-w-[calc(32rem-1.5rem-1.5rem)] */}
|
||||
{/* <div className=""> */}
|
||||
<p
|
||||
// tabIndex={1}
|
||||
className="[&>pre]:p-4 rounded-sm "
|
||||
style={{
|
||||
overflowWrap: "break-word",
|
||||
}}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: highlighter.codeToHtml(props.code.trim(), {
|
||||
lang: props.lang,
|
||||
}),
|
||||
}}
|
||||
/>
|
||||
{/* </div> */}
|
||||
<CopyButton className="absolute right-2 top-2" text={props.code} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Copy } from "lucide-react";
|
||||
|
||||
export function CopyButton({
|
||||
className,
|
||||
...props
|
||||
}: {
|
||||
text: string;
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<Button
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(props.text);
|
||||
}}
|
||||
className={cn(" p-2 min-h-0 aspect-square", className)}
|
||||
>
|
||||
<Copy size={14} />
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
import { CodeBlock } from "@/components/CodeBlock";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { TableCell, TableRow } from "@/components/ui/table";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { getRelativeTime } from "@/lib/getRelativeTime";
|
||||
import type { findAllDeployments } from "@/server/findAllRuns";
|
||||
|
||||
const curlTemplate = `
|
||||
curl --request POST \
|
||||
--url <URL> \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{
|
||||
"deployment_id": "<ID>"
|
||||
}'
|
||||
`;
|
||||
|
||||
const jsTemplate = `
|
||||
const options = {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: '{"deployment_id":"<ID>"}'
|
||||
};
|
||||
|
||||
fetch('<URL>', options)
|
||||
.then(response => response.json())
|
||||
.then(response => console.log(response))
|
||||
.catch(err => console.error(err));
|
||||
`;
|
||||
|
||||
const jsTemplate_checkStatus = `
|
||||
const options = {
|
||||
method: 'GET',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
};
|
||||
|
||||
const run_id = '<RUN_ID>';
|
||||
|
||||
fetch('<URL>?run_id=' + run_id, options)
|
||||
.then(response => response.json())
|
||||
.then(response => console.log(response))
|
||||
.catch(err => console.error(err));
|
||||
`;
|
||||
|
||||
export function DeploymentDisplay({
|
||||
deployment,
|
||||
}: {
|
||||
deployment: Awaited<ReturnType<typeof findAllDeployments>>[0];
|
||||
}) {
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger asChild className="appearance-none hover:cursor-pointer">
|
||||
<TableRow>
|
||||
<TableCell className="capitalize">{deployment.environment}</TableCell>
|
||||
<TableCell className="font-medium">
|
||||
{deployment.version?.version}
|
||||
</TableCell>
|
||||
<TableCell className="font-medium">
|
||||
{deployment.machine?.name}
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
{getRelativeTime(deployment.updated_at)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="capitalize">
|
||||
{deployment.environment} Deployment
|
||||
</DialogTitle>
|
||||
<DialogDescription>Code for your deployment client</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Tabs defaultValue="js" className="w-full">
|
||||
<TabsList className="grid w-fit grid-cols-2">
|
||||
<TabsTrigger value="js">js</TabsTrigger>
|
||||
<TabsTrigger value="curl">curl</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent className="flex flex-col gap-2" value="js">
|
||||
<CodeBlock lang="js" code={formatCode(jsTemplate, deployment)} />
|
||||
<CodeBlock
|
||||
lang="js"
|
||||
code={formatCode(jsTemplate_checkStatus, deployment)}
|
||||
/>
|
||||
</TabsContent>
|
||||
<TabsContent value="curl">
|
||||
<CodeBlock
|
||||
lang="bash"
|
||||
code={formatCode(curlTemplate, deployment)}
|
||||
/>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
function formatCode(
|
||||
codeTemplate: string,
|
||||
deployment: Awaited<ReturnType<typeof findAllDeployments>>[0]
|
||||
) {
|
||||
return codeTemplate
|
||||
.replace(
|
||||
"<URL>",
|
||||
`${process.env.VERCEL_URL ?? "http://localhost:3000"}/api/run`
|
||||
)
|
||||
.replace("<ID>", deployment.id);
|
||||
}
|
||||
@@ -161,7 +161,7 @@ export const columns: ColumnDef<Machine>[] = [
|
||||
<DropdownMenuItem
|
||||
className="text-destructive"
|
||||
onClick={async () => {
|
||||
callServerWithToast(await deleteMachine(workflow.id));
|
||||
callServerPromise(deleteMachine(workflow.id));
|
||||
}}
|
||||
>
|
||||
Delete Machine
|
||||
@@ -176,15 +176,16 @@ export const columns: ColumnDef<Machine>[] = [
|
||||
},
|
||||
];
|
||||
|
||||
async function callServerWithToast(result: {
|
||||
message: string;
|
||||
error?: boolean;
|
||||
}) {
|
||||
if (result.error) {
|
||||
toast.error(result.message);
|
||||
} else {
|
||||
toast.success(result.message);
|
||||
}
|
||||
export async function callServerPromise<T>(result: Promise<T>) {
|
||||
return result
|
||||
.then((x) => {
|
||||
if ((x as { message: string })?.message !== undefined) {
|
||||
toast.success((x as { message: string }).message);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
toast.error(error.message);
|
||||
});
|
||||
}
|
||||
|
||||
export function MachineList({ data }: { data: Machine[] }) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { RunOutputs } from "./RunOutputs";
|
||||
import { useStore } from "@/components/MachinesWS";
|
||||
import { StatusBadge } from "@/components/StatusBadge";
|
||||
import {
|
||||
@@ -10,18 +11,9 @@ import {
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { TableCell, TableRow } from "@/components/ui/table";
|
||||
import { getRelativeTime } from "@/lib/getRelativeTime";
|
||||
import { type findAllRuns } from "@/server/findAllRuns";
|
||||
import { getRunsOutput } from "@/server/getRunsOutput";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export function RunDisplay({
|
||||
run,
|
||||
@@ -73,42 +65,6 @@ export function RunDisplay({
|
||||
);
|
||||
}
|
||||
|
||||
export function RunOutputs({ run_id }: { run_id: string }) {
|
||||
const [outputs, setOutputs] = useState<
|
||||
Awaited<ReturnType<typeof getRunsOutput>>
|
||||
>([]);
|
||||
|
||||
useEffect(() => {
|
||||
getRunsOutput(run_id).then((x) => setOutputs(x));
|
||||
}, [run_id]);
|
||||
|
||||
return (
|
||||
<Table>
|
||||
{/* <TableCaption>A list of your recent runs.</TableCaption> */}
|
||||
<TableHeader className="bg-background top-0 sticky">
|
||||
<TableRow>
|
||||
<TableHead className="w-[100px]">File</TableHead>
|
||||
<TableHead className="">Output</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{outputs?.map((run) => {
|
||||
const fileName = run.data.images[0].filename;
|
||||
// const filePath
|
||||
return (
|
||||
<TableRow key={run.id}>
|
||||
<TableCell>{fileName}</TableCell>
|
||||
<TableCell>
|
||||
<OutputRender run_id={run_id} filename={fileName} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
|
||||
export function OutputRender(props: { run_id: string; filename: string }) {
|
||||
if (props.filename.endsWith(".png")) {
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
"use client";
|
||||
|
||||
import { OutputRender } from "./RunDisplay";
|
||||
import { callServerPromise } from "@/components/MachineList";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { getRunsOutput } from "@/server/getRunsOutput";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export function RunOutputs({ run_id }: { run_id: string }) {
|
||||
const [outputs, setOutputs] =
|
||||
useState<Awaited<ReturnType<typeof getRunsOutput>>>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!run_id) return;
|
||||
// fetch(`/api/run?run_id=${run_id}`)
|
||||
// .then((x) => x.json())
|
||||
// .then((x) => setOutputs(x));
|
||||
callServerPromise(getRunsOutput(run_id).then((x) => setOutputs(x)));
|
||||
}, [run_id, outputs]);
|
||||
|
||||
return (
|
||||
<Table>
|
||||
{/* <TableCaption>A list of your recent runs.</TableCaption> */}
|
||||
<TableHeader className="bg-background top-0 sticky">
|
||||
<TableRow>
|
||||
<TableHead className="w-[100px]">File</TableHead>
|
||||
<TableHead className="">Output</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{outputs?.map((run) => {
|
||||
const fileName = run.data.images[0].filename;
|
||||
// const filePath
|
||||
return (
|
||||
<TableRow key={run.id}>
|
||||
<TableCell>{fileName}</TableCell>
|
||||
<TableCell>
|
||||
<OutputRender run_id={run_id} filename={fileName} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { findAllRuns } from "../server/findAllRuns";
|
||||
import { findAllDeployments, findAllRuns } from "../server/findAllRuns";
|
||||
import { DeploymentDisplay } from "./DeploymentDisplay";
|
||||
import { RunDisplay } from "./RunDisplay";
|
||||
import {
|
||||
Table,
|
||||
@@ -33,3 +34,27 @@ export async function RunsTable(props: { workflow_id: string }) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export async function DeploymentsTable(props: { workflow_id: string }) {
|
||||
const allRuns = await findAllDeployments(props.workflow_id);
|
||||
return (
|
||||
<div className="overflow-auto h-[400px] w-full">
|
||||
<Table className="">
|
||||
<TableCaption>A list of your deployments</TableCaption>
|
||||
<TableHeader className="bg-background top-0 sticky">
|
||||
<TableRow>
|
||||
<TableHead className=" w-[100px]">Environment</TableHead>
|
||||
<TableHead className=" w-[100px]">Version</TableHead>
|
||||
<TableHead className="">Machine</TableHead>
|
||||
<TableHead className=" text-right">Updated At</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{allRuns.map((run) => (
|
||||
<DeploymentDisplay deployment={run} key={run.id} />
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import { LoadingIcon } from "@/components/LoadingIcon";
|
||||
import { callServerPromise } from "@/components/MachineList";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -12,9 +19,10 @@ import {
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { createRun } from "@/server/createRun";
|
||||
import { createDeployments } from "@/server/curdDeploments";
|
||||
import type { getMachines } from "@/server/curdMachine";
|
||||
import type { findFirstTableWithVersion } from "@/server/findFirstTableWithVersion";
|
||||
import { Play } from "lucide-react";
|
||||
import { MoreVertical, Play } from "lucide-react";
|
||||
import { parseAsInteger, useQueryState } from "next-usequerystate";
|
||||
import { useState } from "react";
|
||||
|
||||
@@ -122,3 +130,70 @@ export function RunWorkflowButton({
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
export function CreateDeploymentButton({
|
||||
workflow,
|
||||
machines,
|
||||
}: {
|
||||
workflow: Awaited<ReturnType<typeof findFirstTableWithVersion>>;
|
||||
machines: Awaited<ReturnType<typeof getMachines>>;
|
||||
}) {
|
||||
const [version] = useQueryState("version", {
|
||||
defaultValue: workflow?.versions[0].version ?? 1,
|
||||
...parseAsInteger,
|
||||
});
|
||||
const [machine] = useQueryState("machine", {
|
||||
defaultValue: machines[0].id ?? "",
|
||||
});
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const workflow_version_id = workflow?.versions.find(
|
||||
(x) => x.version === version
|
||||
)?.id;
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button className="gap-2" disabled={isLoading} variant="outline">
|
||||
Deploy <MoreVertical size={14} /> {isLoading && <LoadingIcon />}
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="w-56">
|
||||
<DropdownMenuItem
|
||||
onClick={async () => {
|
||||
if (!workflow_version_id) return;
|
||||
|
||||
setIsLoading(true);
|
||||
await callServerPromise(
|
||||
createDeployments(
|
||||
workflow.id,
|
||||
workflow_version_id,
|
||||
machine,
|
||||
"production"
|
||||
)
|
||||
);
|
||||
setIsLoading(false);
|
||||
}}
|
||||
>
|
||||
Production
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={async () => {
|
||||
if (!workflow_version_id) return;
|
||||
|
||||
setIsLoading(true);
|
||||
await callServerPromise(
|
||||
createDeployments(
|
||||
workflow.id,
|
||||
workflow_version_id,
|
||||
machine,
|
||||
"staging"
|
||||
)
|
||||
);
|
||||
setIsLoading(false);
|
||||
}}
|
||||
>
|
||||
Staging
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/lib/utils";
|
||||
import * as React from "react";
|
||||
|
||||
const Card = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
@@ -14,8 +13,8 @@ const Card = React.forwardRef<
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Card.displayName = "Card"
|
||||
));
|
||||
Card.displayName = "Card";
|
||||
|
||||
const CardHeader = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
@@ -26,8 +25,8 @@ const CardHeader = React.forwardRef<
|
||||
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
CardHeader.displayName = "CardHeader"
|
||||
));
|
||||
CardHeader.displayName = "CardHeader";
|
||||
|
||||
const CardTitle = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
@@ -41,8 +40,8 @@ const CardTitle = React.forwardRef<
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
CardTitle.displayName = "CardTitle"
|
||||
));
|
||||
CardTitle.displayName = "CardTitle";
|
||||
|
||||
const CardDescription = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
@@ -53,16 +52,16 @@ const CardDescription = React.forwardRef<
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
CardDescription.displayName = "CardDescription"
|
||||
));
|
||||
CardDescription.displayName = "CardDescription";
|
||||
|
||||
const CardContent = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
||||
))
|
||||
CardContent.displayName = "CardContent"
|
||||
));
|
||||
CardContent.displayName = "CardContent";
|
||||
|
||||
const CardFooter = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
@@ -73,7 +72,14 @@ const CardFooter = React.forwardRef<
|
||||
className={cn("flex items-center p-6 pt-0", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
CardFooter.displayName = "CardFooter"
|
||||
));
|
||||
CardFooter.displayName = "CardFooter";
|
||||
|
||||
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
|
||||
export {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardFooter,
|
||||
CardTitle,
|
||||
CardDescription,
|
||||
CardContent,
|
||||
};
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
"use client"
|
||||
"use client";
|
||||
|
||||
import * as React from "react"
|
||||
import * as DialogPrimitive from "@radix-ui/react-dialog"
|
||||
import { X } from "lucide-react"
|
||||
import { cn } from "@/lib/utils";
|
||||
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
||||
import { X } from "lucide-react";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
const Dialog = DialogPrimitive.Root;
|
||||
|
||||
const Dialog = DialogPrimitive.Root
|
||||
const DialogTrigger = DialogPrimitive.Trigger;
|
||||
|
||||
const DialogTrigger = DialogPrimitive.Trigger
|
||||
const DialogPortal = DialogPrimitive.Portal;
|
||||
|
||||
const DialogPortal = DialogPrimitive.Portal
|
||||
|
||||
const DialogClose = DialogPrimitive.Close
|
||||
const DialogClose = DialogPrimitive.Close;
|
||||
|
||||
const DialogOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
||||
@@ -26,8 +25,8 @@ const DialogOverlay = React.forwardRef<
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
|
||||
));
|
||||
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
||||
|
||||
const DialogContent = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||
@@ -37,8 +36,9 @@ const DialogContent = React.forwardRef<
|
||||
<DialogOverlay />
|
||||
<DialogPrimitive.Content
|
||||
ref={ref}
|
||||
// grid tuning off grid for styling issue
|
||||
className={cn(
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||
"fixed left-[50%] top-[50%] z-50 w-full max-w-lg translate-x-[-50%] grid grid-cols-1 translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -50,8 +50,8 @@ const DialogContent = React.forwardRef<
|
||||
</DialogPrimitive.Close>
|
||||
</DialogPrimitive.Content>
|
||||
</DialogPortal>
|
||||
))
|
||||
DialogContent.displayName = DialogPrimitive.Content.displayName
|
||||
));
|
||||
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
||||
|
||||
const DialogHeader = ({
|
||||
className,
|
||||
@@ -64,8 +64,8 @@ const DialogHeader = ({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
DialogHeader.displayName = "DialogHeader"
|
||||
);
|
||||
DialogHeader.displayName = "DialogHeader";
|
||||
|
||||
const DialogFooter = ({
|
||||
className,
|
||||
@@ -78,8 +78,8 @@ const DialogFooter = ({
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
DialogFooter.displayName = "DialogFooter"
|
||||
);
|
||||
DialogFooter.displayName = "DialogFooter";
|
||||
|
||||
const DialogTitle = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Title>,
|
||||
@@ -93,8 +93,8 @@ const DialogTitle = React.forwardRef<
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogTitle.displayName = DialogPrimitive.Title.displayName
|
||||
));
|
||||
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
||||
|
||||
const DialogDescription = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Description>,
|
||||
@@ -105,8 +105,8 @@ const DialogDescription = React.forwardRef<
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogDescription.displayName = DialogPrimitive.Description.displayName
|
||||
));
|
||||
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
||||
|
||||
export {
|
||||
Dialog,
|
||||
@@ -119,4 +119,4 @@ export {
|
||||
DialogFooter,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user