feat(web): add workflow inputs code template
This commit is contained in:
		
							parent
							
								
									c2d67da7db
								
							
						
					
					
						commit
						91b8c4d702
					
				@ -9,6 +9,7 @@ import {
 | 
				
			|||||||
} from "@/components/ui/dialog";
 | 
					} from "@/components/ui/dialog";
 | 
				
			||||||
import { TableCell, TableRow } from "@/components/ui/table";
 | 
					import { TableCell, TableRow } from "@/components/ui/table";
 | 
				
			||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
 | 
					import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
 | 
				
			||||||
 | 
					import { getInputsFromWorkflow } from "@/lib/getInputsFromWorkflow";
 | 
				
			||||||
import { getRelativeTime } from "@/lib/getRelativeTime";
 | 
					import { getRelativeTime } from "@/lib/getRelativeTime";
 | 
				
			||||||
import type { findAllDeployments } from "@/server/findAllRuns";
 | 
					import type { findAllDeployments } from "@/server/findAllRuns";
 | 
				
			||||||
import { headers } from "next/headers";
 | 
					import { headers } from "next/headers";
 | 
				
			||||||
@ -29,28 +30,29 @@ curl --request GET \
 | 
				
			|||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const jsTemplate = `
 | 
					const jsTemplate = `
 | 
				
			||||||
fetch('<URL>', {
 | 
					const { run_id } = await fetch('<URL>', {
 | 
				
			||||||
  method: 'POST',
 | 
					  method: 'POST',
 | 
				
			||||||
  headers: {'Content-Type': 'application/json'},
 | 
					  headers: {
 | 
				
			||||||
 | 
					    'Content-Type': 'application/json',
 | 
				
			||||||
 | 
					    'Authorization': 'Bearer ' + process.env.COMFY_DEPLOY_API_KEY,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  body: JSON.stringify({
 | 
					  body: JSON.stringify({
 | 
				
			||||||
    deployment_id: '<ID>',
 | 
					    deployment_id: '<ID>',
 | 
				
			||||||
 | 
					    inputs: {}
 | 
				
			||||||
  }),
 | 
					  }),
 | 
				
			||||||
})
 | 
					}).then(response => response.json())
 | 
				
			||||||
  .then(response => response.json())
 | 
					 | 
				
			||||||
  .then(response => console.log(response))
 | 
					 | 
				
			||||||
  .catch(err => console.error(err));
 | 
					 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const jsTemplate_checkStatus = `
 | 
					const jsTemplate_checkStatus = `
 | 
				
			||||||
const run_id = '<RUN_ID>';
 | 
					const run_id = '<RUN_ID>';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fetch('<URL>?run_id=' + run_id, {
 | 
					const output = fetch('<URL>?run_id=' + run_id, {
 | 
				
			||||||
  method: 'GET',
 | 
					  method: 'GET',
 | 
				
			||||||
  headers: {'Content-Type': 'application/json'},
 | 
					  headers: {
 | 
				
			||||||
})
 | 
					    'Content-Type': 'application/json',
 | 
				
			||||||
  .then(response => response.json())
 | 
					    'Authorization': 'Bearer ' + process.env.COMFY_DEPLOY_API_KEY,
 | 
				
			||||||
  .then(response => console.log(response))
 | 
					  },
 | 
				
			||||||
  .catch(err => console.error(err));
 | 
					}).then(response => response.json())
 | 
				
			||||||
`;
 | 
					`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function DeploymentDisplay({
 | 
					export function DeploymentDisplay({
 | 
				
			||||||
@ -63,6 +65,8 @@ export function DeploymentDisplay({
 | 
				
			|||||||
  const protocol = headersList.get("x-forwarded-proto") || "";
 | 
					  const protocol = headersList.get("x-forwarded-proto") || "";
 | 
				
			||||||
  const domain = `${protocol}://${host}`;
 | 
					  const domain = `${protocol}://${host}`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const workflowInput = getInputsFromWorkflow(deployment.version);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Dialog>
 | 
					    <Dialog>
 | 
				
			||||||
      <DialogTrigger asChild className="appearance-none hover:cursor-pointer">
 | 
					      <DialogTrigger asChild className="appearance-none hover:cursor-pointer">
 | 
				
			||||||
@ -79,7 +83,7 @@ export function DeploymentDisplay({
 | 
				
			|||||||
          </TableCell>
 | 
					          </TableCell>
 | 
				
			||||||
        </TableRow>
 | 
					        </TableRow>
 | 
				
			||||||
      </DialogTrigger>
 | 
					      </DialogTrigger>
 | 
				
			||||||
      <DialogContent className="max-w-xl">
 | 
					      <DialogContent className="max-w-2xl">
 | 
				
			||||||
        <DialogHeader>
 | 
					        <DialogHeader>
 | 
				
			||||||
          <DialogTitle className="capitalize">
 | 
					          <DialogTitle className="capitalize">
 | 
				
			||||||
            {deployment.environment} Deployment
 | 
					            {deployment.environment} Deployment
 | 
				
			||||||
@ -95,7 +99,7 @@ export function DeploymentDisplay({
 | 
				
			|||||||
            Trigger the workflow
 | 
					            Trigger the workflow
 | 
				
			||||||
            <CodeBlock
 | 
					            <CodeBlock
 | 
				
			||||||
              lang="js"
 | 
					              lang="js"
 | 
				
			||||||
              code={formatCode(jsTemplate, deployment, domain)}
 | 
					              code={formatCode(jsTemplate, deployment, domain, workflowInput)}
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
            Check the status of the run, and retrieve the outputs
 | 
					            Check the status of the run, and retrieve the outputs
 | 
				
			||||||
            <CodeBlock
 | 
					            <CodeBlock
 | 
				
			||||||
@ -122,8 +126,32 @@ export function DeploymentDisplay({
 | 
				
			|||||||
function formatCode(
 | 
					function formatCode(
 | 
				
			||||||
  codeTemplate: string,
 | 
					  codeTemplate: string,
 | 
				
			||||||
  deployment: Awaited<ReturnType<typeof findAllDeployments>>[0],
 | 
					  deployment: Awaited<ReturnType<typeof findAllDeployments>>[0],
 | 
				
			||||||
  domain: string
 | 
					  domain: string,
 | 
				
			||||||
 | 
					  inputs?: ReturnType<typeof getInputsFromWorkflow>
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
 | 
					  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
 | 
					  return codeTemplate
 | 
				
			||||||
    .replace("<URL>", `${domain ?? "http://localhost:3000"}/api/run`)
 | 
					    .replace("<URL>", `${domain ?? "http://localhost:3000"}/api/run`)
 | 
				
			||||||
    .replace("<ID>", deployment.id);
 | 
					    .replace("<ID>", deployment.id);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,8 @@
 | 
				
			|||||||
"use client";
 | 
					"use client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { getInputsFromWorkflow } from "../lib/getInputsFromWorkflow";
 | 
				
			||||||
import { callServerPromise } from "./callServerPromise";
 | 
					import { callServerPromise } from "./callServerPromise";
 | 
				
			||||||
 | 
					import { customInputNodes } from "./customInputNodes";
 | 
				
			||||||
import { LoadingIcon } from "@/components/LoadingIcon";
 | 
					import { LoadingIcon } from "@/components/LoadingIcon";
 | 
				
			||||||
import { Badge } from "@/components/ui/badge";
 | 
					import { Badge } from "@/components/ui/badge";
 | 
				
			||||||
import { Button } from "@/components/ui/button";
 | 
					import { Button } from "@/components/ui/button";
 | 
				
			||||||
@ -206,10 +208,16 @@ export function CreateDeploymentButton({
 | 
				
			|||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const customInputNodes: Record<string, string> = {
 | 
					export function getWorkflowVersionFromVersionIndex(
 | 
				
			||||||
  ComfyUIDeployExternalText: "string",
 | 
					  workflow: Awaited<ReturnType<typeof findFirstTableWithVersion>>,
 | 
				
			||||||
  ComfyUIDeployExternalImage: "string - (public image url)",
 | 
					  version: number
 | 
				
			||||||
};
 | 
					) {
 | 
				
			||||||
 | 
					  const workflow_version = workflow?.versions.find(
 | 
				
			||||||
 | 
					    (x) => x.version === version
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return workflow_version;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function VersionDetails({
 | 
					export function VersionDetails({
 | 
				
			||||||
  workflow,
 | 
					  workflow,
 | 
				
			||||||
@ -220,22 +228,23 @@ export function VersionDetails({
 | 
				
			|||||||
    defaultValue: workflow?.versions[0].version ?? 1,
 | 
					    defaultValue: workflow?.versions[0].version ?? 1,
 | 
				
			||||||
    ...parseAsInteger,
 | 
					    ...parseAsInteger,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  const workflow_version = workflow?.versions.find(
 | 
					  const workflow_version = getWorkflowVersionFromVersionIndex(
 | 
				
			||||||
    (x) => x.version === version
 | 
					    workflow,
 | 
				
			||||||
 | 
					    version
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					  const inputs = getInputsFromWorkflow(workflow_version);
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className="mt-4">
 | 
					    <div className="mt-4">
 | 
				
			||||||
      Workflow Details
 | 
					      Workflow Details
 | 
				
			||||||
      <div className="border rounded-lg p-2">
 | 
					      <div className="border rounded-lg p-2">
 | 
				
			||||||
        {workflow_version?.workflow_api && (
 | 
					        {inputs && (
 | 
				
			||||||
          <div className="flex flex-col gap-2">
 | 
					          <div className="flex flex-col gap-2">
 | 
				
			||||||
            {Object.entries(workflow_version.workflow_api).map(
 | 
					            {inputs.map((value) => {
 | 
				
			||||||
              ([key, value]) => {
 | 
					 | 
				
			||||||
              if (!value.class_type) return <> </>;
 | 
					              if (!value.class_type) return <> </>;
 | 
				
			||||||
              const nodeType = customInputNodes[value.class_type];
 | 
					              const nodeType = customInputNodes[value.class_type];
 | 
				
			||||||
              if (nodeType) {
 | 
					              if (nodeType) {
 | 
				
			||||||
                  const input_id = value.inputs.input_id;
 | 
					                const input_id = value.input_id;
 | 
				
			||||||
                  const defaultValue = value.inputs.default_value;
 | 
					                const defaultValue = value.default_value;
 | 
				
			||||||
                return (
 | 
					                return (
 | 
				
			||||||
                  <div key={input_id}>
 | 
					                  <div key={input_id}>
 | 
				
			||||||
                    <Tooltip>
 | 
					                    <Tooltip>
 | 
				
			||||||
@ -244,7 +253,7 @@ export function VersionDetails({
 | 
				
			|||||||
                          <div>
 | 
					                          <div>
 | 
				
			||||||
                            {input_id}
 | 
					                            {input_id}
 | 
				
			||||||
                            {" : "}
 | 
					                            {" : "}
 | 
				
			||||||
                              {nodeType}
 | 
					                            <span className="text-orange-500">{nodeType}</span>
 | 
				
			||||||
                          </div>
 | 
					                          </div>
 | 
				
			||||||
                        </Badge>
 | 
					                        </Badge>
 | 
				
			||||||
                        {/* {nodeType}{" "} */}
 | 
					                        {/* {nodeType}{" "} */}
 | 
				
			||||||
@ -258,8 +267,7 @@ export function VersionDetails({
 | 
				
			|||||||
                );
 | 
					                );
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
              return <></>;
 | 
					              return <></>;
 | 
				
			||||||
              }
 | 
					            })}
 | 
				
			||||||
            )}
 | 
					 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        )}
 | 
					        )}
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								web/src/components/customInputNodes.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								web/src/components/customInputNodes.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					export const customInputNodes: Record<string, string> = {
 | 
				
			||||||
 | 
					  ComfyUIDeployExternalText: "string",
 | 
				
			||||||
 | 
					  ComfyUIDeployExternalImage: "string - (public image url)",
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										24
									
								
								web/src/lib/getInputsFromWorkflow.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								web/src/lib/getInputsFromWorkflow.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					import type { getWorkflowVersionFromVersionIndex } from "../components/VersionSelect";
 | 
				
			||||||
 | 
					import { customInputNodes } from "@/components/customInputNodes";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function getInputsFromWorkflow(
 | 
				
			||||||
 | 
					  workflow_version: ReturnType<typeof getWorkflowVersionFromVersionIndex>
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					  if (!workflow_version || !workflow_version.workflow_api) return null;
 | 
				
			||||||
 | 
					  return Object.entries(workflow_version.workflow_api)
 | 
				
			||||||
 | 
					    .map(([_, value]) => {
 | 
				
			||||||
 | 
					      if (!value.class_type) return undefined;
 | 
				
			||||||
 | 
					      const nodeType = customInputNodes[value.class_type];
 | 
				
			||||||
 | 
					      if (nodeType) {
 | 
				
			||||||
 | 
					        const input_id = value.inputs.input_id as string;
 | 
				
			||||||
 | 
					        const default_value = value.inputs.default_value as string;
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          class_type: value.class_type,
 | 
				
			||||||
 | 
					          input_id,
 | 
				
			||||||
 | 
					          default_value,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return undefined;
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .filter((item) => item !== undefined);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -8,7 +8,7 @@ export async function findAllRuns(workflow_id: string) {
 | 
				
			|||||||
    orderBy: desc(workflowRunsTable.created_at),
 | 
					    orderBy: desc(workflowRunsTable.created_at),
 | 
				
			||||||
    limit: 10,
 | 
					    limit: 10,
 | 
				
			||||||
    extras: {
 | 
					    extras: {
 | 
				
			||||||
      "number": sql<number>`row_number() over (order by created_at)`.as("number"),
 | 
					      number: sql<number>`row_number() over (order by created_at)`.as("number"),
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    with: {
 | 
					    with: {
 | 
				
			||||||
      machine: {
 | 
					      machine: {
 | 
				
			||||||
@ -36,11 +36,7 @@ export async function findAllDeployments(workflow_id: string) {
 | 
				
			|||||||
          name: true,
 | 
					          name: true,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      version: {
 | 
					 | 
				
			||||||
        columns: {
 | 
					 | 
				
			||||||
      version: true,
 | 
					      version: true,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user