Skip to content

Commit

Permalink
feat: import comfyui
Browse files Browse the repository at this point in the history
  • Loading branch information
ikun97 authored and shanexi committed Sep 20, 2024
1 parent 0b8efb5 commit f21a01c
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 44 deletions.
2 changes: 1 addition & 1 deletion web/apps/web/src/components/app/export-dialog/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ export const ExportDialog = ({ id, name, children }: ExportDialogProps) => {
<Text size="sm" color="subtler">
{key.toLocaleUpperCase()}
</Text>
<div className="mt-1 gap-2">
<div className="flex flex-col mt-1 gap-2">
{Object.values(item).map(v => (
<Text size="lg" className="block break-words">
{v as string}
Expand Down
213 changes: 171 additions & 42 deletions web/apps/web/src/components/workflow/import-modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,46 @@ import {
DialogTitle,
Separator,
Heading,
AlertDialog,
AlertDialogContent,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogPortal,
Text,
} from '@shellagent/ui';
import { useRequest } from 'ahooks';
import { useBoolean, useRequest } from 'ahooks';
import { useState, useEffect } from 'react';
import { toast } from 'react-toastify';
import { ChevronDownIcon } from '@heroicons/react/16/solid';
import {
ExclamationTriangleIcon,
XMarkIcon,
} from '@heroicons/react/24/outline';

import FileUploader from '@/components/common/uploader';
import { APIFetch } from '@/services/base';
import { importFormComfyUI } from '@/services/workflow';
import { useWorkflowStore } from '@/stores/workflow/workflow-provider';
import { cn } from '@/utils/cn';
import { isEmpty } from 'lodash-es';

const ImportModal: React.FC<{
open: boolean;
onOpenChange: (open: boolean) => void;
}> = ({ open, onOpenChange }) => {
const [openTips, setOpenTips] = useBoolean(false);
const [isExpand, isExpandAction] = useBoolean(false);
const [fileUrl, setFileUrl] = useState<string | undefined>();
const [workflow, setWorkflow] = useState<Workflow | undefined>();
const { importWorkflow } = useWorkflowStore(state => ({
importWorkflow: state.importWorkflow,
}));
const { existedInfo, importWorkflow, setExistedInfo } = useWorkflowStore(
state => ({
existedInfo: state.existedInfo,
setExistedInfo: state.setExistedInfo,
importWorkflow: state.importWorkflow,
}),
);

useEffect(() => {
if (fileUrl) {
Expand Down Expand Up @@ -58,6 +79,18 @@ const ImportModal: React.FC<{
workflow: result.data,
comfyui: request?.[0]?.data,
});
setExistedInfo({
undefined_widgets: result.undefined_widgets,
non_existed_models: result.non_existed_models,
});
if (
!isEmpty(result.undefined_widgets) ||
!isEmpty(result.non_existed_models)
) {
setTimeout(() => {
setOpenTips.setTrue();
}, 1000);
}
toast.success(`Import Success!`, {
position: 'top-center',
autoClose: 1000,
Expand Down Expand Up @@ -108,45 +141,141 @@ const ImportModal: React.FC<{
}
};

const onCloseTips = () => {
setOpenTips.setFalse();
};

return (
<Dialog modal open={open} onOpenChange={onOpenChange}>
<DialogContent onClose={() => onOpenChange(false)} autoFocus={false}>
<DialogHeader>
<DialogTitle>
<Heading size="h2">Import from ComfyUI</Heading>
</DialogTitle>
</DialogHeader>
<Separator />
<DialogDescription className="px-3 pt-1 pb-3 grid gap-y-1.5 h-28 overflow-y-auto">
<FileUploader
onChange={onChange}
value={fileUrl || ''}
defaultValue={fileUrl || ''}
accept={{
'application/json': ['.json'],
}}
/>
</DialogDescription>
<Separator />
<DialogFooter className="gap-x-4">
<Button
type="button"
className="min-w-[92px] px-[24px]"
variant="outline"
onClick={() => onOpenChange(false)}>
Cancel
</Button>
<Button
type="button"
loading={loading}
className="min-w-[92px] px-[24px]"
disabled={!workflow}
onClick={handleConfirm}>
Confirm
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<>
<Dialog modal open={open} onOpenChange={onOpenChange}>
<DialogContent onClose={() => onOpenChange(false)} autoFocus={false}>
<DialogHeader>
<DialogTitle>
<Heading size="h2">Import from ComfyUI</Heading>
</DialogTitle>
</DialogHeader>
<Separator />
<DialogDescription className="px-3 pt-1 pb-3 grid gap-y-1.5 h-28 overflow-y-auto">
<FileUploader
onChange={onChange}
value={fileUrl || ''}
defaultValue={fileUrl || ''}
accept={{
'application/json': ['.json'],
}}
/>
</DialogDescription>
<Separator />
<DialogFooter className="gap-x-4">
<Button
type="button"
className="min-w-[92px] px-[24px]"
variant="outline"
onClick={() => onOpenChange(false)}>
Cancel
</Button>
<Button
type="button"
loading={loading}
className="min-w-[92px] px-[24px]"
disabled={!workflow}
onClick={handleConfirm}>
Confirm
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<AlertDialog open={openTips}>
<AlertDialogPortal>
<AlertDialogContent style={{ width: '380px' }}>
<AlertDialogHeader>
<AlertDialogTitle>
<div className="flex justify-between items-center">
<span className="rounded-full p-2 bg-surface-accent-yellow-subtler">
<ExclamationTriangleIcon className="w-6 h-6 text-warning" />
</span>
<div className="w-9 h-9 flex cursor-pointer justify-center items-center focus-visible:outline-0 rounded-full hover:bg-surface-hovered">
<XMarkIcon
className="w-6 h-6 text-icon-subtle"
onClick={onCloseTips}
/>
</div>
</div>
</AlertDialogTitle>
</AlertDialogHeader>
<AlertDialogDescription className="flex flex-col gap-1.5">
<Heading size="h2">Warning</Heading>
<Text size="sm" color="subtle">
The following items are missing.
<br />
Replace it with installed models/widgets, or contact us to add
it to the standard environment.
</Text>
<div
className="flex items-center cursor-pointer"
onClick={() => isExpandAction.toggle()}>
<Text size="sm" color="subtler">
{isExpand ? 'Show Less' : 'View Detail'}
</Text>
<ChevronDownIcon
className={cn('w-4 h-4 ml-1.5 text-subtler', {
'rotate-180': isExpand,
})}
/>
</div>
<div
className={cn(
'flex-1 rounded-lg border border-default p-3 w-[340px] max-h-60 overflow-x-hidden',
{
hidden: !isExpand,
},
)}>
{!isEmpty(existedInfo.non_existed_models) ? (
<div>
<Text size="sm" color="subtler">
Models
</Text>
<div className="flex flex-col mt-1 gap-2">
{existedInfo.non_existed_models?.map(v => (
<Text size="lg" className="block break-words">
{v as string}
</Text>
))}
</div>
</div>
) : null}
{!isEmpty(existedInfo.undefined_widgets) ? (
<div>
{!isEmpty(existedInfo.non_existed_models) ? (
<Separator className="my-3" />
) : null}
<Text size="sm" color="subtler">
Widgets
</Text>
<div className="mt-1 gap-2">
{existedInfo.undefined_widgets?.map(v => (
<Text size="lg" className="block break-words">
{v as string}
</Text>
))}
</div>
</div>
) : null}
</div>
</AlertDialogDescription>
<AlertDialogFooter>
<Button
loading={loading}
className="flex-1"
color="warning"
onClick={onCloseTips}>
Confirm
</Button>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialogPortal>
</AlertDialog>
</>
);
};

Expand Down
7 changes: 6 additions & 1 deletion web/apps/web/src/services/workflow/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,14 @@ export type ComfyUIRequest = {
data: object;
};

export type ExistedInfo = {
undefined_widgets?: Array<string>;
non_existed_models?: Array<string>;
}

export type ComfyuiResponse = {
success?: boolean;
data?: Workflow;
error_message?: string;
error_message_detail?: string;
};
} & ExistedInfo;
11 changes: 11 additions & 0 deletions web/apps/web/src/stores/workflow/workflow-store.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
GetWidgetListResponse,
RunWorkflowResponse,
EventStatusEnum,
ExistedInfo,
} from '@/services/workflow/type';
import {
genNodeData,
Expand Down Expand Up @@ -64,6 +65,7 @@ export type WorkflowState = {
};
resetData: Record<string, TValues>;
reloadSchemaMap: Record<string, boolean>;
existedInfo: ExistedInfo;
};

export type WorkflowAction = {
Expand All @@ -81,6 +83,7 @@ export type WorkflowAction = {
setNodeData: (params: { id: NodeId; data: TValues }) => void;
setFlowInstance: (instance: ReactFlowInstance) => void;
getWidgetList: (params: GetWidgetListRequest) => void;
setExistedInfo: (params: ExistedInfo) => void;
getWidgetSchema: (
params: GetWidgetSchemaRequest & { id?: string },
reload?: boolean,
Expand Down Expand Up @@ -134,6 +137,7 @@ export const initState: WorkflowState = {
resetData: {},
// reload
reloadSchemaMap: {},
existedInfo: {},
};

export const createWorkflowStore = () => {
Expand Down Expand Up @@ -526,6 +530,13 @@ export const createWorkflowStore = () => {
}),
);
},
setExistedInfo(params) {
set(
produce(state => {
state.existedInfo = params;
}),
);
},
})),
);
};

0 comments on commit f21a01c

Please sign in to comment.