* fix if-else find variables (#92) * fix if-else find variables * change workflow output type * fix tooltip style * fix * 4.8 (#93) * api middleware * perf: app version histories * faq * perf: value type show * fix: ts * fix: Run the same node multiple times * feat: auto save workflow * perf: auto save workflow --------- Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com>
158 lines
4.6 KiB
TypeScript
158 lines
4.6 KiB
TypeScript
import React, { useCallback, useMemo } from 'react';
|
|
import { Box, Flex, IconButton, useTheme, useDisclosure, Button } from '@chakra-ui/react';
|
|
import { PluginItemSchema } from '@fastgpt/global/core/plugin/type';
|
|
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
|
import { useTranslation } from 'next-i18next';
|
|
import { useCopyData } from '@/web/common/hooks/useCopyData';
|
|
import dynamic from 'next/dynamic';
|
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
|
import MyTooltip from '@/components/MyTooltip';
|
|
import { flowNode2StoreNodes } from '@/components/core/workflow/utils';
|
|
import { putUpdatePlugin } from '@/web/core/plugin/api';
|
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
|
import MyMenu from '@fastgpt/web/components/common/MyMenu';
|
|
import {
|
|
getWorkflowStore,
|
|
useFlowProviderStore
|
|
} from '@/components/core/workflow/Flow/FlowProvider';
|
|
import {
|
|
checkWorkflowNodeAndConnection,
|
|
filterSensitiveNodesData
|
|
} from '@/web/core/workflow/utils';
|
|
|
|
const ImportSettings = dynamic(() => import('@/components/core/workflow/Flow/ImportSettings'));
|
|
|
|
type Props = { plugin: PluginItemSchema; onClose: () => void };
|
|
|
|
const Header = ({ plugin, onClose }: Props) => {
|
|
const theme = useTheme();
|
|
const { t } = useTranslation();
|
|
const { toast } = useToast();
|
|
const { copyData } = useCopyData();
|
|
const { edges, onUpdateNodeError } = useFlowProviderStore();
|
|
const { isOpen: isOpenImport, onOpen: onOpenImport, onClose: onCloseImport } = useDisclosure();
|
|
|
|
const flowData2StoreDataAndCheck = useCallback(async () => {
|
|
const { nodes } = await getWorkflowStore();
|
|
const checkResults = checkWorkflowNodeAndConnection({ nodes, edges });
|
|
if (!checkResults) {
|
|
const storeNodes = flowNode2StoreNodes({ nodes, edges });
|
|
|
|
return storeNodes;
|
|
} else {
|
|
checkResults.forEach((nodeId) => onUpdateNodeError(nodeId, true));
|
|
toast({
|
|
status: 'warning',
|
|
title: t('core.workflow.Check Failed')
|
|
});
|
|
}
|
|
}, [edges, onUpdateNodeError, t, toast]);
|
|
|
|
const { mutate: onclickSave, isLoading } = useRequest({
|
|
mutationFn: async () => {
|
|
const workflow = await flowData2StoreDataAndCheck();
|
|
if (workflow) {
|
|
await putUpdatePlugin({
|
|
id: plugin._id,
|
|
modules: workflow.nodes,
|
|
edges: workflow.edges
|
|
});
|
|
toast({
|
|
status: 'success',
|
|
title: t('common.Save Success')
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
const onCopy = useCallback(async () => {
|
|
const data = await flowData2StoreDataAndCheck();
|
|
if (data) {
|
|
copyData(
|
|
JSON.stringify(
|
|
{
|
|
nodes: filterSensitiveNodesData(data.nodes),
|
|
edges: data.edges
|
|
},
|
|
null,
|
|
2
|
|
),
|
|
t('app.Export Config Successful')
|
|
);
|
|
}
|
|
}, [copyData, flowData2StoreDataAndCheck, t]);
|
|
|
|
const Render = useMemo(() => {
|
|
return (
|
|
<>
|
|
<Flex
|
|
py={3}
|
|
px={[2, 5, 8]}
|
|
borderBottom={theme.borders.base}
|
|
alignItems={'center'}
|
|
userSelect={'none'}
|
|
>
|
|
<MyTooltip label={t('common.Back')} offset={[10, 10]}>
|
|
<IconButton
|
|
size={'smSquare'}
|
|
icon={<MyIcon name={'common/backLight'} w={'14px'} />}
|
|
variant={'whiteBase'}
|
|
aria-label={''}
|
|
onClick={() => {
|
|
onClose();
|
|
}}
|
|
/>
|
|
</MyTooltip>
|
|
<Box ml={[3, 5]} fontSize={['md', '2xl']} flex={1}>
|
|
{plugin.name}
|
|
</Box>
|
|
|
|
<MyMenu
|
|
Button={
|
|
<IconButton
|
|
mr={[3, 5]}
|
|
icon={<MyIcon name={'more'} w={'14px'} p={2} />}
|
|
aria-label={''}
|
|
size={'sm'}
|
|
variant={'whitePrimary'}
|
|
/>
|
|
}
|
|
menuList={[
|
|
{ label: t('app.Import Configs'), icon: 'common/importLight', onClick: onOpenImport },
|
|
{
|
|
label: t('app.Export Configs'),
|
|
icon: 'export',
|
|
onClick: onCopy
|
|
}
|
|
]}
|
|
/>
|
|
<Button
|
|
size={'sm'}
|
|
isLoading={isLoading}
|
|
leftIcon={<MyIcon name={'common/saveFill'} w={['14px', '16px']} />}
|
|
onClick={onclickSave}
|
|
>
|
|
{t('common.Save')}
|
|
</Button>
|
|
</Flex>
|
|
{isOpenImport && <ImportSettings onClose={onCloseImport} />}
|
|
</>
|
|
);
|
|
}, [
|
|
isLoading,
|
|
isOpenImport,
|
|
onClose,
|
|
onCloseImport,
|
|
onCopy,
|
|
onOpenImport,
|
|
onclickSave,
|
|
plugin.name,
|
|
t,
|
|
theme.borders.base
|
|
]);
|
|
|
|
return Render;
|
|
};
|
|
|
|
export default React.memo(Header);
|