External dataset (#1485)

* fix: revert version

* feat: external collection

* import context

* external ui

* doc

* fix: ts

* clear invalid data

* feat: rename sub name

* fix: node if else edge remove

* fix: init

* api size

* fix: if else node refresh
This commit is contained in:
Archer
2024-05-15 10:19:51 +08:00
committed by GitHub
parent fb04889a31
commit cd876251b7
74 changed files with 1882 additions and 1353 deletions

View File

@@ -0,0 +1,14 @@
import Head from 'next/head';
import React from 'react';
const NextHead = ({ title, icon, desc }: { title?: string; icon?: string; desc?: string }) => {
return (
<Head>
<title>{title}</title>
{desc && <meta name="description" content={desc} />}
{icon && <link rel="icon" href={icon} />}
</Head>
);
};
export default NextHead;

View File

@@ -1,12 +1,12 @@
import { Box, Flex, FlexProps } from '@chakra-ui/react';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useTranslation } from 'next-i18next';
import React from 'react';
import { DatasetTypeMap } from '@fastgpt/global/core/dataset/constants';
import { useI18n } from '@/web/context/I18n';
const DatasetTypeTag = ({ type, ...props }: { type: `${DatasetTypeEnum}` } & FlexProps) => {
const { t } = useTranslation();
const DatasetTypeTag = ({ type, ...props }: { type: DatasetTypeEnum } & FlexProps) => {
const { datasetT } = useI18n();
const item = DatasetTypeMap[type] || DatasetTypeMap['dataset'];
@@ -22,7 +22,8 @@ const DatasetTypeTag = ({ type, ...props }: { type: `${DatasetTypeEnum}` } & Fle
{...props}
>
<MyIcon name={item.icon as any} w={'16px'} mr={2} color={'myGray.400'} />
<Box>{t(item.label)}</Box>
{/* @ts-ignore */}
<Box>{datasetT(item.label)}</Box>
</Flex>
);
};

View File

@@ -50,16 +50,11 @@ const ListItem = ({
}) => {
const { t } = useTranslation();
const { getZoom } = useReactFlow();
const onDelEdge = useContextSelector(WorkflowContext, (v) => v.onDelEdge);
const handleId = getHandleId(nodeId, 'source', getElseIFLabel(conditionIndex));
return (
<Box
ref={provided.innerRef}
{...provided.draggableProps}
style={{
...provided.draggableProps.style,
opacity: snapshot.isDragging ? 0.8 : 1
}}
>
const Render = useMemo(() => {
return (
<Flex
alignItems={'center'}
position={'relative'}
@@ -68,7 +63,10 @@ const ListItem = ({
>
<Container w={snapshot.isDragging ? '' : 'full'} className="nodrag">
<Flex mb={4} alignItems={'center'}>
{ifElseList.length > 1 && <DragIcon provided={provided} />}
<DragIcon
visibility={ifElseList.length > 1 ? 'visible' : 'hidden'}
provided={provided}
/>
<Box color={'black'} fontSize={'lg'} ml={2}>
{getElseIFLabel(conditionIndex)}
</Box>
@@ -109,6 +107,10 @@ const ListItem = ({
color={'myGray.400'}
onClick={() => {
onUpdateIfElseList(ifElseList.filter((_, index) => index !== conditionIndex));
onDelEdge({
nodeId,
sourceHandle: handleId
});
}}
/>
)}
@@ -185,21 +187,21 @@ const ListItem = ({
onChange={(e) => {
onUpdateIfElseList(
ifElseList.map((ifElse, index) => {
if (index === conditionIndex) {
return {
...ifElse,
list: ifElse.list.map((item, index) => {
if (index === i) {
return {
...item,
value: e
};
}
return item;
})
};
}
return ifElse;
return {
...ifElse,
list:
index === conditionIndex
? ifElse.list.map((item, index) => {
if (index === i) {
return {
...item,
value: e
};
}
return item;
})
: ifElse.list
};
})
);
}}
@@ -263,12 +265,38 @@ const ListItem = ({
{!snapshot.isDragging && (
<SourceHandle
nodeId={nodeId}
handleId={getHandleId(nodeId, 'source', getElseIFLabel(conditionIndex))}
handleId={handleId}
position={Position.Right}
translate={[18, 0]}
/>
)}
</Flex>
);
}, [
conditionIndex,
conditionItem.condition,
conditionItem.list,
getZoom,
handleId,
ifElseList,
nodeId,
onDelEdge,
onUpdateIfElseList,
provided,
snapshot.isDragging,
t
]);
return (
<Box
ref={provided.innerRef}
{...provided.draggableProps}
style={{
...provided.draggableProps.style,
opacity: snapshot.isDragging ? 0.8 : 1
}}
>
{Render}
</Box>
);
};
@@ -387,35 +415,39 @@ const ConditionValueInput = ({
return output.valueType;
}, [nodeList, variable]);
if (valueType === WorkflowIOValueTypeEnum.boolean) {
return (
<MySelect
list={[
{ label: 'True', value: 'true' },
{ label: 'False', value: 'false' }
]}
onchange={onChange}
value={value}
placeholder={'选择值'}
isDisabled={
condition === VariableConditionEnum.isEmpty ||
condition === VariableConditionEnum.isNotEmpty
}
/>
);
} else {
return (
<MyInput
value={value}
placeholder={'输入值'}
w={'100%'}
bg={'white'}
isDisabled={
condition === VariableConditionEnum.isEmpty ||
condition === VariableConditionEnum.isNotEmpty
}
onChange={(e) => onChange(e.target.value)}
/>
);
}
const Render = useMemo(() => {
if (valueType === WorkflowIOValueTypeEnum.boolean) {
return (
<MySelect
list={[
{ label: 'True', value: 'true' },
{ label: 'False', value: 'false' }
]}
onchange={onChange}
value={value}
placeholder={'选择值'}
isDisabled={
condition === VariableConditionEnum.isEmpty ||
condition === VariableConditionEnum.isNotEmpty
}
/>
);
} else {
return (
<MyInput
value={value}
placeholder={'输入值'}
w={'100%'}
bg={'white'}
isDisabled={
condition === VariableConditionEnum.isEmpty ||
condition === VariableConditionEnum.isNotEmpty
}
onChange={(e) => onChange(e.target.value)}
/>
);
}
}, [condition, onChange, value, valueType]);
return Render;
};

View File

@@ -1,4 +1,4 @@
import React, { useCallback, useMemo, useState } from 'react';
import React, { useCallback, useMemo } from 'react';
import NodeCard from '../render/NodeCard';
import { useTranslation } from 'next-i18next';
import { Box, Button, Flex } from '@chakra-ui/react';
@@ -9,7 +9,7 @@ import { IfElseListItemType } from '@fastgpt/global/core/workflow/template/syste
import { useContextSelector } from 'use-context-selector';
import { WorkflowContext } from '../../../context';
import Container from '../../components/Container';
import DndDrag, { Draggable, DropResult } from '@fastgpt/web/components/common/DndDrag/index';
import DndDrag, { Draggable } from '@fastgpt/web/components/common/DndDrag/index';
import { SourceHandle } from '../render/Handle';
import { getHandleId } from '@fastgpt/global/core/workflow/utils';
import ListItem from './ListItem';
@@ -19,6 +19,7 @@ const NodeIfElse = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
const { t } = useTranslation();
const { nodeId, inputs = [] } = data;
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
const elseHandleId = getHandleId(nodeId, 'source', IfElseResultEnum.ELSE);
const ifElseList = useMemo(
() =>
@@ -49,7 +50,7 @@ const NodeIfElse = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
<NodeCard selected={selected} maxW={'1000px'} {...data}>
<Box px={4} cursor={'default'}>
<DndDrag<IfElseListItemType>
onDragEndCb={(list) => onUpdateIfElseList(list)}
onDragEndCb={(list: IfElseListItemType[]) => onUpdateIfElseList(list)}
dataList={ifElseList}
renderClone={(provided, snapshot, rubric) => (
<ListItem
@@ -95,7 +96,7 @@ const NodeIfElse = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
</Box>
<SourceHandle
nodeId={nodeId}
handleId={getHandleId(nodeId, 'source', IfElseResultEnum.ELSE)}
handleId={elseHandleId}
position={Position.Right}
translate={[26, 0]}
/>

View File

@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useCallback, useState } from 'react';
import { getPublishList, postRevertVersion } from '@/web/core/app/versionApi';
import { useScrollPagination } from '@fastgpt/web/hooks/useScrollPagination';
import CustomRightDrawer from '@fastgpt/web/components/common/MyDrawer/CustomRightDrawer';
@@ -14,6 +14,8 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import { useRequest } from '@fastgpt/web/hooks/useRequest';
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type';
import { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
const PublishHistoriesSlider = () => {
const { t } = useTranslation();
@@ -45,29 +47,29 @@ const PublishHistoriesSlider = () => {
setIsShowVersionHistories(false);
});
const onPreview = useMemoizedFn((data: AppVersionSchemaType) => {
const onPreview = useCallback((data: AppVersionSchemaType) => {
setSelectedHistoryId(data._id);
initData({
nodes: data.nodes,
edges: data.edges
});
});
const onCloseSlider = useMemoizedFn(() => {
setSelectedHistoryId(undefined);
initData({
nodes: appDetail.modules,
edges: appDetail.edges
});
onClose();
});
}, []);
const onCloseSlider = useCallback(
(data: { nodes: StoreNodeItemType[]; edges: StoreEdgeItemType[] }) => {
setSelectedHistoryId(undefined);
initData(data);
onClose();
},
[appDetail]
);
const { mutate: onRevert, isLoading: isReverting } = useRequest({
mutationFn: async (data: AppVersionSchemaType) => {
if (!appId) return;
await postRevertVersion(appId, {
versionId: data._id,
editNodes: appDetail.modules,
editNodes: appDetail.modules, // old workflow
editEdges: appDetail.edges
});
@@ -77,7 +79,7 @@ const PublishHistoriesSlider = () => {
edges: data.edges
});
onCloseSlider();
onCloseSlider(data);
}
});
@@ -86,7 +88,12 @@ const PublishHistoriesSlider = () => {
return (
<>
<CustomRightDrawer
onClose={onCloseSlider}
onClose={() =>
onCloseSlider({
nodes: appDetail.modules,
edges: appDetail.edges
})
}
iconSrc="core/workflow/versionHistories"
title={t('core.workflow.publish.histories')}
maxW={'300px'}

View File

@@ -430,8 +430,8 @@ const WorkflowContextProvider = ({
const initData = useMemoizedFn(
async (e: { nodes: StoreNodeItemType[]; edges: StoreEdgeItemType[] }) => {
setNodes(e.nodes?.map((item) => storeNode2FlowNode({ item })));
setEdges(e.edges?.map((item) => storeEdgesRenderEdge({ edge: item })));
setNodes(e.nodes?.map((item) => storeNode2FlowNode({ item })) || []);
setEdges(e.edges?.map((item) => storeEdgesRenderEdge({ edge: item })) || []);
}
);