feat: add opening directly from comfy deploy -> machines
This commit is contained in:
@@ -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
|
||||
<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
|
||||
<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");
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user