feat: add opening directly from comfy deploy -> machines

This commit is contained in:
BennyKok
2024-01-23 09:33:53 +08:00
parent c0450b58d5
commit 52d6e07eeb
12 changed files with 808 additions and 405 deletions
+138 -138
View File
@@ -1,11 +1,11 @@
import { CodeBlock } from "@/components/CodeBlock";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { ScrollArea } from "@/components/ui/scroll-area";
import { TableRow } from "@/components/ui/table";
@@ -83,145 +83,145 @@ const run = await client.getRun(run_id);
`;
export function DeploymentDisplay({
deployment,
domain,
deployment,
domain,
}: {
deployment: Awaited<ReturnType<typeof findAllDeployments>>[0];
domain: string;
deployment: Awaited<ReturnType<typeof findAllDeployments>>[0];
domain: string;
}) {
const workflowInput = getInputsFromWorkflow(deployment.version);
const workflowInput = getInputsFromWorkflow(deployment.version);
if (deployment.environment === "public-share") {
return <SharePageDeploymentRow deployment={deployment} />;
}
if (deployment.environment === "public-share") {
return <SharePageDeploymentRow deployment={deployment} />;
}
return (
<Dialog>
<DialogTrigger asChild className="appearance-none hover:cursor-pointer">
<TableRow>
<DeploymentRow deployment={deployment} />
</TableRow>
</DialogTrigger>
<DialogContent className="max-w-3xl">
<DialogHeader>
<DialogTitle className="capitalize">
{deployment.environment} Deployment
</DialogTitle>
<DialogDescription>Code for your deployment client</DialogDescription>
</DialogHeader>
<ScrollArea className="max-h-[600px] pr-4">
<Tabs defaultValue="client" className="w-full gap-2 text-sm">
<TabsList className="grid w-fit grid-cols-3 mb-2">
<TabsTrigger value="client">Server Client</TabsTrigger>
<TabsTrigger value="js">NodeJS Fetch</TabsTrigger>
<TabsTrigger value="curl">CURL</TabsTrigger>
</TabsList>
<TabsContent className="flex flex-col gap-2 !mt-0" value="client">
<div>
Copy and paste the ComfyDeployClient form&nbsp;
<a
href="https://github.com/BennyKok/comfyui-deploy-next-example/blob/main/src/lib/comfy-deploy.ts"
className="text-blue-500 hover:underline"
target="_blank"
rel="noreferrer"
>
here
</a>
</div>
<CodeBlock
lang="js"
code={formatCode(
domain == "https://www.comfydeploy.com"
? jsClientSetupTemplateHostedVersion
: jsClientSetupTemplate,
deployment,
domain,
workflowInput,
)}
/>
Create a run via deployment id
<CodeBlock
lang="js"
code={formatCode(
workflowInput && workflowInput.length > 0
? jsClientCreateRunTemplate
: jsClientCreateRunNoInputsTemplate,
deployment,
domain,
workflowInput,
)}
/>
Check the status of the run, and retrieve the outputs
<CodeBlock
lang="js"
code={formatCode(
clientTemplate_checkStatus,
deployment,
domain,
)}
/>
</TabsContent>
<TabsContent className="flex flex-col gap-2 !mt-0" value="js">
Trigger the workflow
<CodeBlock
lang="js"
code={formatCode(jsTemplate, deployment, domain, workflowInput)}
/>
Check the status of the run, and retrieve the outputs
<CodeBlock
lang="js"
code={formatCode(jsTemplate_checkStatus, deployment, domain)}
/>
</TabsContent>
<TabsContent className="flex flex-col gap-2 !mt-2" value="curl">
<CodeBlock
lang="bash"
code={formatCode(curlTemplate, deployment, domain)}
/>
<CodeBlock
lang="bash"
code={formatCode(curlTemplate_checkStatus, deployment, domain)}
/>
</TabsContent>
</Tabs>
</ScrollArea>
</DialogContent>
</Dialog>
);
return (
<Dialog>
<DialogTrigger asChild className="appearance-none hover:cursor-pointer">
<TableRow>
<DeploymentRow deployment={deployment} />
</TableRow>
</DialogTrigger>
<DialogContent className="max-w-3xl">
<DialogHeader>
<DialogTitle className="capitalize">
{deployment.environment} Deployment
</DialogTitle>
<DialogDescription>Code for your deployment client</DialogDescription>
</DialogHeader>
<ScrollArea className="max-h-[600px] pr-4">
<Tabs defaultValue="client" className="w-full gap-2 text-sm">
<TabsList className="grid w-fit grid-cols-3 mb-2">
<TabsTrigger value="client">Server Client</TabsTrigger>
<TabsTrigger value="js">NodeJS Fetch</TabsTrigger>
<TabsTrigger value="curl">CURL</TabsTrigger>
</TabsList>
<TabsContent className="flex flex-col gap-2 !mt-0" value="client">
<div>
Copy and paste the ComfyDeployClient form&nbsp;
<a
href="https://github.com/BennyKok/comfyui-deploy-next-example/blob/main/src/lib/comfy-deploy.ts"
className="text-blue-500 hover:underline"
target="_blank"
rel="noreferrer"
>
here
</a>
</div>
<CodeBlock
lang="js"
code={formatCode(
domain == "https://www.comfydeploy.com"
? jsClientSetupTemplateHostedVersion
: jsClientSetupTemplate,
deployment,
domain,
workflowInput,
)}
/>
Create a run via deployment id
<CodeBlock
lang="js"
code={formatCode(
workflowInput && workflowInput.length > 0
? jsClientCreateRunTemplate
: jsClientCreateRunNoInputsTemplate,
deployment,
domain,
workflowInput,
)}
/>
Check the status of the run, and retrieve the outputs
<CodeBlock
lang="js"
code={formatCode(
clientTemplate_checkStatus,
deployment,
domain,
)}
/>
</TabsContent>
<TabsContent className="flex flex-col gap-2 !mt-0" value="js">
Trigger the workflow
<CodeBlock
lang="js"
code={formatCode(jsTemplate, deployment, domain, workflowInput)}
/>
Check the status of the run, and retrieve the outputs
<CodeBlock
lang="js"
code={formatCode(jsTemplate_checkStatus, deployment, domain)}
/>
</TabsContent>
<TabsContent className="flex flex-col gap-2 !mt-2" value="curl">
<CodeBlock
lang="bash"
code={formatCode(curlTemplate, deployment, domain)}
/>
<CodeBlock
lang="bash"
code={formatCode(curlTemplate_checkStatus, deployment, domain)}
/>
</TabsContent>
</Tabs>
</ScrollArea>
</DialogContent>
</Dialog>
);
}
function formatCode(
codeTemplate: string,
deployment: Awaited<ReturnType<typeof findAllDeployments>>[0],
domain: string,
inputs?: ReturnType<typeof getInputsFromWorkflow>,
inputsTabs?: number,
codeTemplate: string,
deployment: Awaited<ReturnType<typeof findAllDeployments>>[0],
domain: string,
inputs?: ReturnType<typeof getInputsFromWorkflow>,
inputsTabs?: number,
) {
if (inputs && inputs.length > 0) {
codeTemplate = codeTemplate.replace(
"inputs: {}",
`inputs: ${JSON.stringify(
Object.fromEntries(
inputs.map((x) => {
return [x?.input_id, ""];
}),
),
null,
2,
)
.split("\n")
.map((line, index) => (index === 0 ? line : ` ${line}`)) // Add two spaces indentation except for the first line
.join("\n")}`,
);
} else {
codeTemplate = codeTemplate.replace(
`
if (inputs && inputs.length > 0) {
codeTemplate = codeTemplate.replace(
"inputs: {}",
`inputs: ${JSON.stringify(
Object.fromEntries(
inputs.map((x) => {
return [x?.input_id, ""];
}),
),
null,
2,
)
.split("\n")
.map((line, index) => (index === 0 ? line : ` ${line}`)) // Add two spaces indentation except for the first line
.join("\n")}`,
);
} else {
codeTemplate = codeTemplate.replace(
`
inputs: {}`,
"",
);
}
return codeTemplate
.replace("<URL>", `${domain ?? "http://localhost:3000"}/api/run`)
.replace("<ID>", deployment.id)
.replace("<URLONLY>", domain ?? "http://localhost:3000");
"",
);
}
return codeTemplate
.replace("<URL>", `${domain ?? "http://localhost:3000"}/api/run`)
.replace("<ID>", deployment.id)
.replace("<URLONLY>", domain ?? "http://localhost:3000");
}
+76 -23
View File
@@ -41,7 +41,14 @@ import { checkStatus, createRun } from "@/server/createRun";
import { createDeployments } from "@/server/curdDeploments";
import type { getMachines } from "@/server/curdMachine";
import type { findFirstTableWithVersion } from "@/server/findFirstTableWithVersion";
import { Copy, ExternalLink, Info, MoreVertical, Play } from "lucide-react";
import {
Copy,
Edit,
ExternalLink,
Info,
MoreVertical,
Play,
} from "lucide-react";
import { parseAsInteger, useQueryState } from "next-usequerystate";
import { useEffect, useMemo, useState } from "react";
import { toast } from "sonner";
@@ -51,6 +58,8 @@ import { create } from "zustand";
import { workflowVersionInputsToZod } from "../lib/workflowVersionInputsToZod";
import { callServerPromise } from "./callServerPromise";
import fetcher from "./fetcher";
import { ButtonAction } from "@/components/ButtonActionLoader";
import { editWorkflowOnMachine } from "@/server/editWorkflowOnMachine";
export function VersionSelect({
workflow,
@@ -116,13 +125,13 @@ export function MachineSelect({
}
export function useSelectedMachine(
machines: Awaited<ReturnType<typeof getMachines>>,
machines: Awaited<ReturnType<typeof getMachines>>,
) {
const a = useQueryState("machine", {
defaultValue: machines?.[0]?.id ?? "",
});
const a = useQueryState("machine", {
defaultValue: machines?.[0]?.id ?? "",
});
return a;
return a;
}
type PublicRunStore = {
@@ -219,7 +228,7 @@ export function RunWorkflowButton({
const schema = useMemo(() => {
const workflow_version = getWorkflowVersionFromVersionIndex(
workflow,
version
version,
);
if (!workflow_version) return null;
@@ -233,7 +242,7 @@ export function RunWorkflowButton({
const val = Object.keys(values).length > 0 ? values : undefined;
const workflow_version_id = workflow?.versions.find(
(x) => x.version === version
(x) => x.version === version,
)?.id;
console.log(workflow_version_id);
if (!workflow_version_id) return;
@@ -248,7 +257,7 @@ export function RunWorkflowButton({
machine_id: machine,
inputs: val,
runOrigin: "manual",
})
}),
);
// console.log(res.json());
setIsLoading(false);
@@ -317,7 +326,7 @@ export function CreateDeploymentButton({
const [isLoading, setIsLoading] = useState(false);
const workflow_version_id = workflow?.versions.find(
(x) => x.version === version
(x) => x.version === version,
)?.id;
return (
<DropdownMenu>
@@ -337,8 +346,8 @@ export function CreateDeploymentButton({
workflow.id,
workflow_version_id,
machine,
"production"
)
"production",
),
);
setIsLoading(false);
}}
@@ -355,8 +364,8 @@ export function CreateDeploymentButton({
workflow.id,
workflow_version_id,
machine,
"staging"
)
"staging",
),
);
setIsLoading(false);
}}
@@ -368,6 +377,49 @@ export function CreateDeploymentButton({
);
}
export function OpenEditButton({
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] = useSelectedMachine(machines);
const workflow_version_id = workflow?.versions.find(
(x) => x.version == version,
)?.id;
const [isLoading, setIsLoading] = useState(false);
return (
workflow_version_id &&
machine && (
<Button
className="gap-2"
onClick={async () => {
setIsLoading(true);
const url = await callServerPromise(
editWorkflowOnMachine(workflow_version_id, machine),
);
if (url && typeof url !== "object") {
window.open(url, "_blank");
} else if (url && typeof url === "object" && url.error) {
console.error(url.error);
}
setIsLoading(false);
}}
// asChild
variant="outline"
>
Edit {isLoading ? <LoadingIcon /> : <Edit size={14} />}
</Button>
)
);
}
export function CopyWorkflowVersion({
workflow,
}: {
@@ -378,7 +430,7 @@ export function CopyWorkflowVersion({
...parseAsInteger,
});
const workflow_version = workflow?.versions.find(
(x) => x.version === version
(x) => x.version === version,
);
return (
<DropdownMenu>
@@ -402,7 +454,7 @@ export function CopyWorkflowVersion({
});
navigator.clipboard.writeText(
JSON.stringify(workflow_version?.workflow)
JSON.stringify(workflow_version?.workflow),
);
toast("Copied to clipboard");
}}
@@ -412,7 +464,7 @@ export function CopyWorkflowVersion({
<DropdownMenuItem
onClick={async () => {
navigator.clipboard.writeText(
JSON.stringify(workflow_version?.workflow_api)
JSON.stringify(workflow_version?.workflow_api),
);
toast("Copied to clipboard");
}}
@@ -426,7 +478,7 @@ export function CopyWorkflowVersion({
export function getWorkflowVersionFromVersionIndex(
workflow: Awaited<ReturnType<typeof findFirstTableWithVersion>>,
version: number
version: number,
) {
const workflow_version = workflow?.versions.find((x) => x.version == version);
@@ -452,7 +504,7 @@ export function ViewWorkflowDetailsButton({
isLoading: isNodesIndexLoading,
} = useSWR(
"https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/extension-node-map.json",
fetcher
fetcher,
);
const groupedByAuxName = useMemo(() => {
@@ -462,7 +514,7 @@ export function ViewWorkflowDetailsButton({
const workflow_version = getWorkflowVersionFromVersionIndex(
workflow,
version
version,
);
const api = workflow_version?.workflow_api;
@@ -473,7 +525,7 @@ export function ViewWorkflowDetailsButton({
.map(([_, value]) => {
const classType = value.class_type;
const classTypeData = Object.entries(data).find(([_, nodeArray]) =>
nodeArray[0].includes(classType)
nodeArray[0].includes(classType),
);
return classTypeData ? { node: value, classTypeData } : null;
})
@@ -503,7 +555,7 @@ export function ViewWorkflowDetailsButton({
node: z.infer<typeof workflowAPINodeType>[];
url: string;
}
>
>,
);
// console.log(groupedByAuxName);
@@ -544,7 +596,8 @@ export function ViewWorkflowDetailsButton({
<a
href={group.url}
target="_blank"
className="hover:underline" rel="noreferrer"
className="hover:underline"
rel="noreferrer"
>
{key}
<ExternalLink