mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-22 12:20:34 +00:00
perf: workflow&plugins json config import and export (#2592)
This commit is contained in:
@@ -5,6 +5,7 @@ export const iconPaths = {
|
||||
visible: () => import('./icons/visible.svg'),
|
||||
change: () => import('./icons/change.svg'),
|
||||
chatSend: () => import('./icons/chatSend.svg'),
|
||||
configmap: () => import('./icons/configmap.svg'),
|
||||
closeSolid: () => import('./icons/closeSolid.svg'),
|
||||
collectionLight: () => import('./icons/collectionLight.svg'),
|
||||
collectionSolid: () => import('./icons/collectionSolid.svg'),
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" >
|
||||
<path
|
||||
d="M4.25845 0.738983C4.25845 0.606996 4.15146 0.5 4.01947 0.5C2.11725 0.5 0.575195 2.04205 0.575195 3.94428V12.0557C0.575195 13.9579 2.11725 15.5 4.01947 15.5H12.1309C14.0331 15.5 15.5752 13.9579 15.5752 12.0557V3.94428C15.5752 2.04205 14.0331 0.5 12.1309 0.5H10.4017C9.98744 0.5 9.65166 0.835786 9.65166 1.25C9.65166 1.66421 9.98744 2 10.4017 2H12.1309C13.2047 2 14.0752 2.87048 14.0752 3.94428V12.0557C14.0752 13.1295 13.2047 14 12.1309 14H4.01947C2.94568 14 2.0752 13.1295 2.0752 12.0557V3.94428C2.0752 2.87048 2.94568 2 4.01947 2C4.15146 2 4.25845 1.893 4.25845 1.76102V0.738983Z" />
|
||||
<path
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
4
packages/web/components/common/Icon/icons/configmap.svg
Normal file
4
packages/web/components/common/Icon/icons/configmap.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13 3.63151C12.8097 3.61563 12.5318 3.61309 12.0118 3.61309H8.8C7.94442 3.61309 7.35921 3.61378 6.90608 3.64853C6.46289 3.68252 6.23164 3.7446 6.0695 3.82215C5.68754 4.00483 5.38889 4.29054 5.20585 4.62774C5.13457 4.75906 5.07214 4.95341 5.03711 5.35592C5.00088 5.7721 5 6.31265 5 7.11879V16.8811C5 17.6873 5.00088 18.2278 5.03711 18.644C5.07214 19.0465 5.13457 19.2409 5.20585 19.3722C5.38889 19.7094 5.68754 19.9951 6.0695 20.1778C6.23164 20.2553 6.46289 20.3174 6.90608 20.3514C7.35921 20.3861 7.94442 20.3868 8.8 20.3868H11.3166V20.3831H12.0402C12.5935 20.3831 13.0421 20.8317 13.0421 21.385C13.0421 21.9383 12.5935 22.3868 12.0402 22.3868H8.76082C7.95401 22.3868 7.29182 22.3869 6.75314 22.3455C6.19582 22.3028 5.68616 22.2114 5.20656 21.982C4.45954 21.6247 3.84031 21.0488 3.44811 20.3263C3.19241 19.8552 3.09135 19.3541 3.04464 18.8174C2.99997 18.3042 2.99999 17.6761 3 16.9243V7.07562C2.99999 6.32377 2.99997 5.69569 3.04464 5.18249C3.09135 4.64583 3.19241 4.1447 3.44811 3.67363C3.84031 2.95108 4.45955 2.37518 5.20656 2.0179C5.68616 1.78851 6.19582 1.69713 6.75314 1.65438C7.29183 1.61307 7.95404 1.61308 8.76087 1.61309L12.1104 1.61306C12.7488 1.6128 13.2216 1.61261 13.6775 1.71536C13.9143 1.76871 14.1455 1.84257 14.3684 1.93605C14.3845 1.94245 14.4004 1.94926 14.4162 1.95646C14.5556 2.01705 14.6916 2.08538 14.8235 2.16124C15.2292 2.3946 15.5693 2.71422 16.0188 3.13657L19.3536 6.26681C19.7996 6.68508 20.1428 7.00687 20.3953 7.39362C20.4782 7.52058 20.5532 7.65209 20.6199 7.78747C20.6275 7.8022 20.6347 7.81715 20.6416 7.8323C20.7445 8.04841 20.8265 8.27406 20.8859 8.50648C21.0007 8.95522 21.0004 9.42011 21 10.0095L21.0001 12.9707C21.0001 13.524 20.5515 13.9725 19.9982 13.9725C19.4449 13.9725 18.9964 13.524 18.9964 12.9707V12.2471H19V10.1115C19 9.65934 18.9973 9.41026 18.985 9.24521L15.5694 9.24522C15.3159 9.24524 15.0723 9.24526 14.8667 9.2295C14.6429 9.21233 14.3802 9.1721 14.1145 9.04503C13.7438 8.86773 13.4306 8.57903 13.2301 8.20974C13.0834 7.93947 13.0369 7.67016 13.0174 7.44655C12.9999 7.24586 13 7.01037 13 6.77572L13 3.63151ZM15 4.92332V6.74331C15 6.99036 15.0007 7.13329 15.007 7.23432L15.0197 7.23535C15.1393 7.24453 15.3045 7.24521 15.6 7.24521H17.4736L15 4.92332Z" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.6589 16.1948C17.9477 15.0725 19.5415 15.0725 19.8304 16.1948C19.9868 16.8028 20.6122 17.1639 21.217 16.9953C22.3333 16.6843 23.1303 18.0647 22.3028 18.8759C21.8544 19.3155 21.8544 20.0375 22.3028 20.4771C23.1303 21.2883 22.3333 22.6687 21.217 22.3577C20.6122 22.1891 19.9868 22.5502 19.8304 23.1582C19.5415 24.2805 17.9477 24.2805 17.6589 23.1582C17.5024 22.5502 16.8771 22.1891 16.2722 22.3577C15.1559 22.6687 14.3589 21.2883 15.1865 20.4771C15.6348 20.0375 15.6348 19.3155 15.1865 18.8759C14.3589 18.0647 15.1559 16.6843 16.2722 16.9953C16.8771 17.1639 17.5024 16.8028 17.6589 16.1948ZM20.1433 19.6765C20.1433 20.449 19.5171 21.0752 18.7446 21.0752C17.9721 21.0752 17.3459 20.449 17.3459 19.6765C17.3459 18.904 17.9721 18.2778 18.7446 18.2778C19.5171 18.2778 20.1433 18.904 20.1433 19.6765Z" />
|
||||
</svg>
|
After Width: | Height: | Size: 3.1 KiB |
@@ -1 +1,4 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1689491332665" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5892" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M393.2 701.7c-8.2 0-16.4-3.1-22.6-9.4-12.5-12.5-12.5-32.8 0-45.3l115.3-115.3c14-14 36.9-14 50.9 0L652.1 647c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0l-95.5-95.5-95.5 95.5c-6.2 6.2-14.4 9.4-22.6 9.4z" fill="" p-id="5893"></path><path d="M511.3 921.1c-17.7 0-32-14.3-32-32v-276c0-17.7 14.3-32 32-32s32 14.3 32 32v276c0 17.6-14.3 32-32 32z" fill="" p-id="5894"></path><path d="M732.7 784.9c-17.7 0-32-14.3-32-32s14.3-32 32-32c90.6 0 164.3-73.7 164.3-164.3 0-82.9-61.9-153-144-163.1l-22.7-2.8-4.7-22.4c-20.8-99.9-110.1-172.4-212.4-172.4-102.2 0-191.5 72.5-212.4 172.4l-4.7 22.4-22.7 2.8c-82.1 10.1-144 80.2-144 163.1 0 90.6 73.7 164.3 164.3 164.3 17.7 0 32 14.3 32 32s-14.3 32-32 32c-61 0-118.3-23.8-161.5-66.9-43.1-43.1-66.9-100.5-66.9-161.5 0-107.6 75.2-199.7 178.2-222.8 15.8-53.8 47.7-102.2 91.3-138.1 50.1-41.2 113.4-63.9 178.3-63.9s128.3 22.7 178.3 63.9c43.6 35.9 75.5 84.3 91.3 138.1C885.9 356.8 961 448.9 961 556.5c0 61-23.8 118.3-66.9 161.5-43.1 43.1-100.4 66.9-161.4 66.9z" fill="" p-id="5895"></path></svg>
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.9689 12.7335C13.8022 12.6748 15.2703 11.1701 15.2703 9.32256C15.2703 7.72206 14.1686 6.37888 12.6821 6.01009C12.1325 3.93852 10.2445 2.41187 8.00003 2.41187C5.75552 2.41187 3.86757 3.93852 3.31794 6.01009C1.83149 6.37888 0.729736 7.72206 0.729736 9.32256C0.729736 11.1827 2.2179 12.6952 4.06858 12.7345V12.7353H4.33524C4.70343 12.7353 5.00191 12.4368 5.00191 12.0686C5.00191 11.7004 4.70343 11.402 4.33524 11.402H4.14248C2.99405 11.402 2.06307 10.471 2.06307 9.32256C2.06307 8.34915 2.73317 7.52893 3.63901 7.30419L4.40444 7.11428L4.60668 6.35202C5.00513 4.85028 6.37523 3.7452 8.00003 3.7452C9.62484 3.7452 10.9949 4.85028 11.3934 6.35202L11.5956 7.11428L12.361 7.30419C13.2669 7.52893 13.937 8.34915 13.937 9.32256C13.937 10.4672 13.0121 11.3958 11.8689 11.4019L11.7009 11.402C11.3327 11.402 11.0342 11.7004 11.0342 12.0686C11.0342 12.4368 11.3327 12.7353 11.7009 12.7353H11.9689V12.7335Z" />
|
||||
<path d="M6.17498 8.73195L7.50552 7.40141C7.52051 7.38484 7.53633 7.36902 7.5529 7.35403L7.60322 7.30371L7.6041 7.30283C7.82262 7.08431 8.17682 7.08417 8.39551 7.30241C8.39595 7.30284 8.39638 7.30327 8.39682 7.30371L8.44704 7.35393C8.46368 7.36899 8.47957 7.38487 8.49462 7.40151L9.82417 8.73107C10.0433 8.95021 10.0433 9.30552 9.82417 9.52466C9.60503 9.74381 9.24972 9.74381 9.03058 9.52466L8.66669 9.16077V13.0339C8.66669 13.402 8.36821 13.7005 8.00002 13.7005C7.63183 13.7005 7.33336 13.402 7.33336 13.0339V9.15724L6.96682 9.52378C6.74816 9.74244 6.39364 9.74244 6.17498 9.52378C5.95632 9.30512 5.95632 8.95061 6.17498 8.73195Z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.6 KiB |
@@ -23,6 +23,7 @@ export type Props = {
|
||||
trigger?: 'hover' | 'click';
|
||||
iconSize?: string;
|
||||
iconRadius?: string;
|
||||
menuItemStyles?: MenuItemProps;
|
||||
placement?: PlacementWithLogical;
|
||||
menuList: {
|
||||
label?: string;
|
||||
@@ -45,7 +46,15 @@ const MyMenu = ({
|
||||
Button,
|
||||
menuList,
|
||||
iconRadius,
|
||||
placement = 'bottom-start'
|
||||
placement = 'bottom-start',
|
||||
menuItemStyles = {
|
||||
borderRadius: 'sm',
|
||||
py: 2,
|
||||
px: 3,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
fontSize: 'sm'
|
||||
}
|
||||
}: Props) => {
|
||||
const typeMapStyle: Record<MenuItemType, MenuItemProps> = {
|
||||
primary: {
|
||||
@@ -75,14 +84,6 @@ const MyMenu = ({
|
||||
}
|
||||
}
|
||||
};
|
||||
const menuItemStyles: MenuItemProps = {
|
||||
borderRadius: 'sm',
|
||||
py: 2,
|
||||
px: 3,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
fontSize: 'sm'
|
||||
};
|
||||
|
||||
const { isPc } = useSystem();
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
@@ -167,7 +168,7 @@ const MyMenu = ({
|
||||
<MenuItem
|
||||
key={index}
|
||||
{...menuItemStyles}
|
||||
onClickCapture={(e) => {
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setIsOpen(false);
|
||||
child.onClick && child.onClick();
|
||||
@@ -185,12 +186,16 @@ const MyMenu = ({
|
||||
mr={3}
|
||||
/>
|
||||
)}
|
||||
<Box>
|
||||
<Box color={child.description ? 'myGray.900' : 'inherit'} fontSize={'sm'}>
|
||||
<Box w={'100%'}>
|
||||
<Box
|
||||
w={'100%'}
|
||||
color={child.description ? 'myGray.900' : 'inherit'}
|
||||
fontSize={'sm'}
|
||||
>
|
||||
{child.label}
|
||||
</Box>
|
||||
{child.description && (
|
||||
<Box color={'myGray.500'} fontSize={'mini'}>
|
||||
<Box color={'myGray.500'} fontSize={'mini'} w={'100%'}>
|
||||
{child.description}
|
||||
</Box>
|
||||
)}
|
||||
|
@@ -48,6 +48,7 @@
|
||||
"export_config_successful": "Config copied, please check for important data",
|
||||
"export_configs": "Export Configs",
|
||||
"feedback_count": "User Feedback",
|
||||
"file_recover": "The file will overwrite the current content",
|
||||
"file_upload": "file_upload",
|
||||
"file_upload_tip": "After it is enabled, you can upload documents/pictures. Documents are kept for 7 days and pictures for 15 days. Use of this feature may incur additional charges. To ensure the user experience, select an AI model with a large context length when using this function.",
|
||||
"go_to_chat": "To chat",
|
||||
@@ -56,6 +57,7 @@
|
||||
"image_upload_tip": "Be sure to select a visual model that can handle the picture",
|
||||
"import_configs": "Import Configs",
|
||||
"import_configs_failed": "Failed to import configs, please ensure configs are valid!",
|
||||
"import_configs_success": "Import successful",
|
||||
"interval": {
|
||||
"12_hours": "every 12 hours",
|
||||
"2_hours": "every 2 hours",
|
||||
@@ -86,6 +88,8 @@
|
||||
},
|
||||
"move_app": "Move app",
|
||||
"no": "no",
|
||||
"not_json_file": "Please select a JSON file",
|
||||
"or_drag_JSON": "Or drag in a JSON file",
|
||||
"paste_config": "Paste Config",
|
||||
"plugin_cost_per_times": "{{cost}}/per time",
|
||||
"plugin_dispatch": "Plugins",
|
||||
|
@@ -227,6 +227,7 @@
|
||||
"confirm": {
|
||||
"Common Tip": "Operation confirmation"
|
||||
},
|
||||
"copy_to_clipboard": "copy to clipboard",
|
||||
"course": {
|
||||
"Read Course": "Read course"
|
||||
},
|
||||
@@ -238,6 +239,7 @@
|
||||
"too_many_request": "Too many requests, please try again later.",
|
||||
"unKnow": "An unexpected error occurred~"
|
||||
},
|
||||
"export_to_json": "Export to JSON",
|
||||
"failed": "fail",
|
||||
"folder": {
|
||||
"Drag Tip": "Drag me",
|
||||
@@ -257,6 +259,7 @@
|
||||
"jsonEditor": {
|
||||
"Parse error": "JSON may be incorrect, please check carefully"
|
||||
},
|
||||
"json_config": "JSON configuration",
|
||||
"link": {
|
||||
"UnValid": "Invalid link"
|
||||
},
|
||||
@@ -289,6 +292,7 @@
|
||||
},
|
||||
"undo_tip": "unde ctrl z",
|
||||
"undo_tip_mac": "undo ⌘ z ",
|
||||
"upload_file": "Upload files",
|
||||
"zoomin_tip": "zoomIn ctrl -",
|
||||
"zoomin_tip_mac": "zoomIn ⌘ -",
|
||||
"zoomout_tip": "zoomOut ctrl +",
|
||||
|
@@ -48,6 +48,7 @@
|
||||
"export_config_successful": "已复制配置,自动过滤部分敏感信息,请注意检查是否仍有敏感数据",
|
||||
"export_configs": "导出配置",
|
||||
"feedback_count": "用户反馈",
|
||||
"file_recover": "文件将覆盖当前内容",
|
||||
"file_upload": "文件上传",
|
||||
"file_upload_tip": "开启后,可以上传文档/图片。文档保留7天,图片保留15天。使用该功能可能产生较多额外费用。为保证使用体验,使用该功能时,请选择上下文长度较大的AI模型。",
|
||||
"go_to_chat": "去对话",
|
||||
@@ -56,6 +57,7 @@
|
||||
"image_upload_tip": "请确保选择可处理图片的视觉模型",
|
||||
"import_configs": "导入配置",
|
||||
"import_configs_failed": "导入配置失败,请确保配置正常!",
|
||||
"import_configs_success": "导入成功",
|
||||
"interval": {
|
||||
"12_hours": "每12小时",
|
||||
"2_hours": "每2小时",
|
||||
@@ -85,7 +87,9 @@
|
||||
"unit": "号"
|
||||
},
|
||||
"move_app": "移动应用",
|
||||
"not_json_file": "请选择JSON文件",
|
||||
"paste_config": "粘贴配置",
|
||||
"or_drag_JSON": "或拖入JSON文件",
|
||||
"plugin_cost_per_times": "{{cost}}/次",
|
||||
"plugin_dispatch": "插件调用",
|
||||
"plugin_dispatch_tip": "给模型附加额外的能力,具体调用哪些插件,将由模型自主决定。\n若选择了插件,知识库调用将自动作为一个特殊的插件。",
|
||||
|
@@ -112,6 +112,7 @@
|
||||
"common": {
|
||||
"Action": "操作",
|
||||
"Add": "添加",
|
||||
"copy_to_clipboard": "复制到剪贴板",
|
||||
"Add New": "新增",
|
||||
"Add Success": "添加成功",
|
||||
"All": "全部",
|
||||
@@ -122,6 +123,7 @@
|
||||
"Confirm": "确认",
|
||||
"Confirm Create": "确认创建",
|
||||
"Confirm Import": "确认导入",
|
||||
"export_to_json": "导出为 JSON",
|
||||
"Confirm Move": "移动到这",
|
||||
"Confirm Update": "确认更新",
|
||||
"Confirm to leave the page": "确认离开该页面?",
|
||||
@@ -193,6 +195,7 @@
|
||||
"Save Success": "保存成功",
|
||||
"Save_and_exit": "保存并退出",
|
||||
"Search": "搜索",
|
||||
"json_config": "JSON 配置",
|
||||
"Select File Failed": "选择文件异常",
|
||||
"Select template": "选择模板",
|
||||
"Set Avatar": "点击设置头像",
|
||||
@@ -289,6 +292,7 @@
|
||||
},
|
||||
"undo_tip": "撤销 ctrl z",
|
||||
"undo_tip_mac": "撤销 ⌘ z ",
|
||||
"upload_file": "上传文件",
|
||||
"zoomin_tip": "缩小 ctrl -",
|
||||
"zoomin_tip_mac": "缩小 ⌘ -",
|
||||
"zoomout_tip": "放大 ctrl +",
|
||||
|
@@ -14,6 +14,9 @@ import { useCopyData } from '@/web/common/hooks/useCopyData';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import MyTag from '@fastgpt/web/components/common/Tag/index';
|
||||
import { publishStatusStyle } from '../constants';
|
||||
import MyPopover from '@fastgpt/web/components/common/MyPopover';
|
||||
import { fileDownload } from '@/web/common/file/utils';
|
||||
import { AppChatConfigType } from '@fastgpt/global/core/app/type';
|
||||
|
||||
const ImportSettings = dynamic(() => import('./Flow/ImportSettings'));
|
||||
|
||||
@@ -26,32 +29,16 @@ const AppCard = ({
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { appT } = useI18n();
|
||||
const { copyData } = useCopyData();
|
||||
const { feConfigs } = useSystemStore();
|
||||
|
||||
const { appDetail, onOpenInfoEdit, onOpenTeamTagModal, onDelApp, currentTab } =
|
||||
useContextSelector(AppContext, (v) => v);
|
||||
const { historiesDefaultData, flowData2StoreDataAndCheck, onSaveWorkflow, isSaving } =
|
||||
useContextSelector(WorkflowContext, (v) => v);
|
||||
const { historiesDefaultData, onSaveWorkflow, isSaving } = useContextSelector(
|
||||
WorkflowContext,
|
||||
(v) => v
|
||||
);
|
||||
|
||||
const { isOpen: isOpenImport, onOpen: onOpenImport, onClose: onCloseImport } = useDisclosure();
|
||||
const onExportWorkflow = useCallback(async () => {
|
||||
const data = flowData2StoreDataAndCheck();
|
||||
if (data) {
|
||||
copyData(
|
||||
JSON.stringify(
|
||||
{
|
||||
nodes: filterSensitiveNodesData(data.nodes),
|
||||
edges: data.edges,
|
||||
chatConfig: appDetail.chatConfig
|
||||
},
|
||||
null,
|
||||
2
|
||||
),
|
||||
appT('export_config_successful')
|
||||
);
|
||||
}
|
||||
}, [appDetail.chatConfig, appT, copyData, flowData2StoreDataAndCheck]);
|
||||
|
||||
const InfoMenu = useCallback(
|
||||
({ children }: { children: React.ReactNode }) => {
|
||||
@@ -84,9 +71,11 @@ const AppCard = ({
|
||||
onClick: onOpenImport
|
||||
},
|
||||
{
|
||||
label: appT('export_configs'),
|
||||
icon: 'export',
|
||||
onClick: onExportWorkflow
|
||||
label: ExportPopover({
|
||||
chatConfig: appDetail.chatConfig,
|
||||
appName: appDetail.name
|
||||
}),
|
||||
onClick: () => {}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -124,6 +113,8 @@ const AppCard = ({
|
||||
);
|
||||
},
|
||||
[
|
||||
appDetail.chatConfig,
|
||||
appDetail.name,
|
||||
appDetail.permission.hasWritePer,
|
||||
appDetail.permission.isOwner,
|
||||
appT,
|
||||
@@ -131,7 +122,6 @@ const AppCard = ({
|
||||
feConfigs?.show_team_chat,
|
||||
historiesDefaultData,
|
||||
onDelApp,
|
||||
onExportWorkflow,
|
||||
onOpenImport,
|
||||
onOpenInfoEdit,
|
||||
onOpenTeamTagModal,
|
||||
@@ -192,4 +182,98 @@ const AppCard = ({
|
||||
return Render;
|
||||
};
|
||||
|
||||
function ExportPopover({
|
||||
chatConfig,
|
||||
appName
|
||||
}: {
|
||||
chatConfig: AppChatConfigType;
|
||||
appName: string;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const { copyData } = useCopyData();
|
||||
const { flowData2StoreDataAndCheck } = useContextSelector(WorkflowContext, (v) => v);
|
||||
const data = flowData2StoreDataAndCheck();
|
||||
const onExportWorkflow = useCallback(async () => {
|
||||
const data = flowData2StoreDataAndCheck();
|
||||
if (data) {
|
||||
copyData(
|
||||
JSON.stringify(
|
||||
{
|
||||
nodes: filterSensitiveNodesData(data.nodes),
|
||||
edges: data.edges,
|
||||
chatConfig: chatConfig
|
||||
},
|
||||
null,
|
||||
2
|
||||
),
|
||||
t('app:export_config_successful')
|
||||
);
|
||||
}
|
||||
}, [chatConfig, copyData, flowData2StoreDataAndCheck, t]);
|
||||
|
||||
return (
|
||||
<MyPopover
|
||||
placement={'right-start'}
|
||||
offset={[-5, 20]}
|
||||
hasArrow={false}
|
||||
trigger={'hover'}
|
||||
w={'8.6rem'}
|
||||
Trigger={
|
||||
<Flex align={'center'} w={'100%'}>
|
||||
<Avatar src={'export'} borderRadius={'sm'} w={'1rem'} mr={3} />
|
||||
{t('app:export_configs')}
|
||||
</Flex>
|
||||
}
|
||||
>
|
||||
{({ onClose }) => (
|
||||
<Box p={1}>
|
||||
<Flex
|
||||
py={'0.38rem'}
|
||||
px={1}
|
||||
color={'myGray.600'}
|
||||
_hover={{
|
||||
bg: 'myGray.05',
|
||||
color: 'primary.600'
|
||||
}}
|
||||
borderRadius={'xs'}
|
||||
onClick={onExportWorkflow}
|
||||
>
|
||||
<MyIcon name={'copy'} w={'1rem'} mr={2} />
|
||||
<Box fontSize={'mini'}>{t('common:common.copy_to_clipboard')}</Box>
|
||||
</Flex>
|
||||
<Flex
|
||||
py={'0.38rem'}
|
||||
px={1}
|
||||
color={'myGray.600'}
|
||||
_hover={{
|
||||
bg: 'myGray.05',
|
||||
color: 'primary.600'
|
||||
}}
|
||||
borderRadius={'xs'}
|
||||
onClick={() => {
|
||||
if (!data) return;
|
||||
fileDownload({
|
||||
text: JSON.stringify(
|
||||
{
|
||||
nodes: filterSensitiveNodesData(data.nodes),
|
||||
edges: data.edges,
|
||||
chatConfig: chatConfig
|
||||
},
|
||||
null,
|
||||
2
|
||||
),
|
||||
type: 'application/json;charset=utf-8',
|
||||
filename: `${appName}.json`
|
||||
});
|
||||
}}
|
||||
>
|
||||
<MyIcon name={'configmap'} w={'1rem'} mr={2} />
|
||||
<Box fontSize={'mini'}>{t('common:common.export_to_json')}</Box>
|
||||
</Flex>
|
||||
</Box>
|
||||
)}
|
||||
</MyPopover>
|
||||
);
|
||||
}
|
||||
|
||||
export default AppCard;
|
||||
|
@@ -1,11 +1,14 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Textarea, Button, ModalBody, ModalFooter } from '@chakra-ui/react';
|
||||
import React, { DragEvent, useCallback, useMemo, useState } from 'react';
|
||||
import { Textarea, Button, ModalBody, ModalFooter, Flex, Box } from '@chakra-ui/react';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../context';
|
||||
import { useI18n } from '@/web/context/I18n';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useSelectFile } from '@/web/common/file/hooks/useSelectFile';
|
||||
import { useSystem } from '@fastgpt/web/hooks/useSystem';
|
||||
type Props = {
|
||||
onClose: () => void;
|
||||
};
|
||||
@@ -13,46 +16,161 @@ type Props = {
|
||||
const ImportSettings = ({ onClose }: Props) => {
|
||||
const { appT } = useI18n();
|
||||
const { toast } = useToast();
|
||||
const { File, onOpen } = useSelectFile({
|
||||
fileType: 'json',
|
||||
multiple: false
|
||||
});
|
||||
const { isPc } = useSystem();
|
||||
const initData = useContextSelector(WorkflowContext, (v) => v.initData);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const [value, setValue] = useState('');
|
||||
const { t } = useTranslation();
|
||||
const handleDragEnter = useCallback((e: DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
setIsDragging(true);
|
||||
}, []);
|
||||
|
||||
const handleDragLeave = useCallback((e: DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
setIsDragging(false);
|
||||
}, []);
|
||||
const handleDrop = useCallback(async (e: DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
const file = e.dataTransfer.files[0];
|
||||
readJSONFile(file);
|
||||
setIsDragging(false);
|
||||
}, []);
|
||||
|
||||
const readJSONFile = useCallback(
|
||||
(file: File) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
if (!file.name.endsWith('.json')) {
|
||||
toast({
|
||||
title: t('app:not_json_file'),
|
||||
status: 'error'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (e.target) {
|
||||
const res = JSON.parse(e.target.result as string);
|
||||
setValue(JSON.stringify(res, null, 2));
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
},
|
||||
[t, toast]
|
||||
);
|
||||
|
||||
const onSelectFile = useCallback(
|
||||
async (e: File[]) => {
|
||||
const file = e[0];
|
||||
readJSONFile(file);
|
||||
console.log(file);
|
||||
},
|
||||
[readJSONFile]
|
||||
);
|
||||
return (
|
||||
<MyModal
|
||||
isOpen
|
||||
w={'600px'}
|
||||
onClose={onClose}
|
||||
iconSrc="/imgs/modal/params.svg"
|
||||
title={appT('import_configs')}
|
||||
title={
|
||||
<Flex align={'center'} ml={-3}>
|
||||
<MyIcon name={'common/importLight'} color={'primary.600'} w={'1.25rem'} mr={'0.62rem'} />
|
||||
<Box lineHeight={'1.25rem'}>{appT('import_configs')}</Box>
|
||||
</Flex>
|
||||
}
|
||||
>
|
||||
<ModalBody>
|
||||
<Textarea
|
||||
placeholder={appT('paste_config')}
|
||||
defaultValue={value}
|
||||
rows={16}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
/>
|
||||
<ModalBody py={'2rem'} px={'3.25rem'}>
|
||||
<File onSelect={onSelectFile} />
|
||||
{isDragging ? (
|
||||
<Flex
|
||||
align={'center'}
|
||||
justify={'center'}
|
||||
w={'31rem'}
|
||||
h={'21.25rem'}
|
||||
borderRadius={'md'}
|
||||
border={'1px dashed'}
|
||||
borderColor={'myGray.400'}
|
||||
onDragEnter={handleDragEnter}
|
||||
onDragOver={(e) => e.preventDefault()}
|
||||
onDrop={handleDrop}
|
||||
onDragLeave={handleDragLeave}
|
||||
>
|
||||
<Flex align={'center'} justify={'center'} flexDir={'column'} gap={'0.62rem'}>
|
||||
<MyIcon name={'configmap'} w={'1.5rem'} color={'myGray.500'} />
|
||||
<Box color={'myGray.600'} fontSize={'mini'}>
|
||||
{t('app:file_recover')}
|
||||
</Box>
|
||||
</Flex>
|
||||
</Flex>
|
||||
) : (
|
||||
<Box w={'31rem'} minH={'21.25rem'}>
|
||||
<Flex justify={'space-between'} align={'center'} pb={2}>
|
||||
<Box fontSize={'sm'} color={'myGray.900'} fontWeight={'500'}>
|
||||
{t('common:common.json_config')}
|
||||
</Box>
|
||||
<Button onClick={onOpen} variant={'whiteBase'} p={0}>
|
||||
<Flex px={'0.88rem'} py={'0.44rem'} color={'myGray.600'} fontSize={'mini'}>
|
||||
<MyIcon name={'file/uploadFile'} w={'1rem'} mr={'0.38rem'} />
|
||||
{t('common:common.upload_file')}
|
||||
</Flex>
|
||||
</Button>
|
||||
</Flex>
|
||||
<Box
|
||||
onDragEnter={handleDragEnter}
|
||||
onDragOver={(e) => e.preventDefault()}
|
||||
onDrop={handleDrop}
|
||||
onDragLeave={handleDragLeave}
|
||||
>
|
||||
<Textarea
|
||||
bg={'myGray.50'}
|
||||
border={'1px solid'}
|
||||
borderRadius={'md'}
|
||||
borderColor={'myGray.200'}
|
||||
h={'15.125rem'}
|
||||
value={value}
|
||||
placeholder={
|
||||
isPc
|
||||
? t('app:paste_config') + '\n' + t('app:or_drag_JSON')
|
||||
: t('app:paste_config')
|
||||
}
|
||||
defaultValue={value}
|
||||
rows={16}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
/>
|
||||
</Box>
|
||||
<Flex justify={'flex-end'} pt={5}>
|
||||
<Button
|
||||
p={0}
|
||||
onClick={() => {
|
||||
if (!value) {
|
||||
return onClose();
|
||||
}
|
||||
try {
|
||||
const data = JSON.parse(value);
|
||||
initData(data);
|
||||
onClose();
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: appT('import_configs_failed')
|
||||
});
|
||||
}
|
||||
toast({
|
||||
title: t('app:import_configs_success'),
|
||||
status: 'success'
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Flex px={5} py={2} fontWeight={'500'}>
|
||||
{t('common:common.Save')}
|
||||
</Flex>
|
||||
</Button>
|
||||
</Flex>
|
||||
</Box>
|
||||
)}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
variant="whiteBase"
|
||||
onClick={() => {
|
||||
if (!value) {
|
||||
return onClose();
|
||||
}
|
||||
try {
|
||||
const data = JSON.parse(value);
|
||||
initData(data);
|
||||
onClose();
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: appT('import_configs_failed')
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t('common:common.Confirm')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</MyModal>
|
||||
);
|
||||
};
|
||||
|
Reference in New Issue
Block a user