mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-21 11:43:56 +00:00
Perf: delete app tip; fix: can't stop debug. (#2865)
* fix: variables check * remove log * perf: delete app tip * perf: remove node code * fix: can not stop debug * update version * update version intro * fix: per error * perf: apikey manager * Add permission check * update README
This commit is contained in:
@@ -55,7 +55,7 @@ https://github.com/labring/FastGPT/assets/15308462/7d3a38df-eb0e-4388-9250-2409b
|
||||
- [x] Code sandbox
|
||||
- [x] 循环调用
|
||||
- [x] 用户选择
|
||||
- [ ] 表单输入
|
||||
- [x] 表单输入
|
||||
|
||||
`2` 知识库能力
|
||||
- [x] 多库复用,混用
|
||||
|
@@ -24,8 +24,8 @@ STORE_LOG_LEVEL=warn
|
||||
|
||||
### 3. 修改镜像tag
|
||||
|
||||
- 更新 FastGPT 镜像 tag: v4.8.10-fix2
|
||||
- 更新 FastGPT 商业版镜像 tag: v4.8.10-fix
|
||||
- 更新 FastGPT 镜像 tag: v4.8.10
|
||||
- 更新 FastGPT 商业版镜像 tag: v4.8.10
|
||||
- Sandbox 镜像,可以不更新
|
||||
|
||||
## 4. 执行初始化
|
||||
|
@@ -80,9 +80,21 @@ weight: 813
|
||||
|
||||
### 3. 修改镜像 tag 并重启
|
||||
|
||||
- 更新 FastGPT 镜像 tag: v4.8.11-alpha
|
||||
- 更新 FastGPT 商业版镜像 tag: v4.8.11-alpha
|
||||
- 更新 FastGPT Sandbox 镜像 tag: v4.8.11-alpha
|
||||
- 更新 FastGPT 镜像 tag: v4.8.11-beta
|
||||
- 更新 FastGPT 商业版镜像 tag: v4.8.11-beta
|
||||
- 更新 FastGPT Sandbox 镜像 tag: v4.8.11-beta
|
||||
|
||||
### 4. 商业版初始化
|
||||
|
||||
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 `rootkey`;{{host}} 替换成**FastGPT 商业版域名**。
|
||||
|
||||
```bash
|
||||
curl --location --request POST 'https://{{host}}/api/admin/init/4811' \
|
||||
--header 'rootkey: {{rootkey}}' \
|
||||
--header 'Content-Type: application/json'
|
||||
```
|
||||
|
||||
会初始化成员组。
|
||||
|
||||
## V4.8.11 更新说明
|
||||
|
||||
|
@@ -5,11 +5,8 @@
|
||||
"app.Version name": "Version Name",
|
||||
"app.modules.click to update": "Click to Refresh",
|
||||
"app.modules.has new version": "New Version Available",
|
||||
"version_back": "Revert to Original State",
|
||||
"version_copy": "Duplicate",
|
||||
"app.version_current": "Current Version",
|
||||
"app.version_initial": "Initial Version",
|
||||
"version_initial_copy": "Duplicate - Original State",
|
||||
"app.version_name_tips": "Version name cannot be empty",
|
||||
"app.version_past": "Previously Published",
|
||||
"app.version_publish_tips": "This version will be saved to the team cloud, synchronized with the entire team, and update the app version on all release channels.",
|
||||
@@ -19,7 +16,7 @@
|
||||
"chat_logs_tips": "Logs will record the online, shared, and API (requires chatId) conversation records of this app.",
|
||||
"config_file_upload": "Click to Configure File Upload Rules",
|
||||
"confirm_copy_app_tip": "The system will create an app with the same configuration for you, but permissions will not be copied. Please confirm!",
|
||||
"confirm_del_app_tip": "Confirm to delete this app and all its conversation records?",
|
||||
"confirm_del_app_tip": "Are you sure you want to delete 【{{name}}】 and all of its chat history?",
|
||||
"confirm_delete_folder_tip": "Confirm to delete this folder? All apps and corresponding conversation records under it will be deleted. Please confirm!",
|
||||
"copy_one_app": "Create Duplicate",
|
||||
"create_copy_success": "Duplicate Created Successfully",
|
||||
@@ -132,6 +129,9 @@
|
||||
"variable.select type_desc": "You can define a global variable that does not need to be filled in by the user.\n\nThe value of this variable can come from the API interface, the Query of the shared link, or assigned through the [Variable Update] module.",
|
||||
"variable.textarea_type_desc": "Allows users to input up to 4000 characters in the dialogue box.",
|
||||
"version.Revert success": "Revert Successful",
|
||||
"version_back": "Revert to Original State",
|
||||
"version_copy": "Duplicate",
|
||||
"version_initial_copy": "Duplicate - Original State",
|
||||
"vision_model_title": "Enable Image Recognition",
|
||||
"week.Friday": "Friday",
|
||||
"week.Monday": "Monday",
|
||||
|
@@ -851,6 +851,7 @@
|
||||
"dataset.dataset_name": "Dataset Name",
|
||||
"dataset.deleteFolderTips": "Confirm to Delete This Folder and All Its Contained Datasets? Data Cannot Be Recovered After Deletion, Please Confirm!",
|
||||
"dataset.test.noResult": "No Search Results",
|
||||
"delete_api": "Are you sure you want to delete this API key? \nAfter deletion, the key will become invalid immediately and the corresponding conversation log will not be deleted. Please confirm!",
|
||||
"error.Create failed": "Create failed",
|
||||
"error.code_error": "Verification code error",
|
||||
"error.fileNotFound": "File not found~",
|
||||
@@ -1197,4 +1198,4 @@
|
||||
"verification": "Verification",
|
||||
"xx_search_result": "{{key}} Search Results",
|
||||
"yes": "Yes"
|
||||
}
|
||||
}
|
||||
|
@@ -32,7 +32,6 @@
|
||||
"dataset_quote_role_system_option_desc": "Historical records should be consistent first (recommended)",
|
||||
"dataset_quote_role_tip": "When set to System, the knowledge base reference content will be placed in the system message, which can ensure the continuity of the history record, but the constraint effect may not be good.\n\nWhen set to User, the knowledge base reference content will be placed in the user message, and the {{question}} variable location needs to be specified. \nIt will have a certain impact on the consistency of historical records, but usually the constraint effect is better.",
|
||||
"dataset_quote_role_user_option_desc": "Strong constraints take precedence",
|
||||
"delete_api": "Confirm delete this API key? The key will be invalid immediately after deletion, but the corresponding conversation logs will not be deleted. Please confirm!",
|
||||
"dynamic_input_description": "Receive the output value of the previous node as a variable, which can be used by Laf request parameters.",
|
||||
"dynamic_input_description_concat": "You can reference the output of other nodes as variables for text concatenation. Type / to invoke the variable list.",
|
||||
"edit_input": "Edit Input",
|
||||
@@ -186,4 +185,4 @@
|
||||
"workflow.Switch_success": "Switch Successful",
|
||||
"workflow.Team cloud": "Team Cloud",
|
||||
"workflow.exit_tips": "Your changes have not been saved. 'Exit directly' will not save your edits."
|
||||
}
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@
|
||||
"chat_logs_tips": "日志会记录该应用的在线、分享和 API(需填写 chatId)对话记录",
|
||||
"config_file_upload": "点击配置文件上传规则",
|
||||
"confirm_copy_app_tip": "系统将为您创建一个相同配置应用,但权限不会进行复制,请确认!",
|
||||
"confirm_del_app_tip": "确认删除该应用及其所有聊天记录?",
|
||||
"confirm_del_app_tip": "确认删除 【{{name}}】 及其所有聊天记录?",
|
||||
"confirm_delete_folder_tip": "确认删除该文件夹?将会删除它下面所有应用及对应的聊天记录,请确认!",
|
||||
"copy_one_app": "创建副本",
|
||||
"create_copy_success": "创建副本成功",
|
||||
|
@@ -68,15 +68,18 @@
|
||||
"code_error.system_error.community_version_num_limit": "超出开源版数量限制,请升级商业版: https://fastgpt.in",
|
||||
"code_error.team_error.ai_points_not_enough": "",
|
||||
"code_error.team_error.app_amount_not_enough": "应用数量已达上限~",
|
||||
"code_error.team_error.cannot_delete_default_group": "不能删除默认群组",
|
||||
"code_error.team_error.dataset_amount_not_enough": "知识库数量已达上限~",
|
||||
"code_error.team_error.dataset_size_not_enough": "知识库容量不足,请先扩容~",
|
||||
"code_error.team_error.group_name_duplicate": "群组名称重复",
|
||||
"code_error.team_error.group_name_empty": "群组名称不能为空",
|
||||
"code_error.team_error.group_not_exist": "群组不存在",
|
||||
"code_error.team_error.over_size": "error.team.overSize",
|
||||
"code_error.team_error.plugin_amount_not_enough": "插件数量已达上限~",
|
||||
"code_error.team_error.re_rank_not_enough": "无权使用检索重排~",
|
||||
"code_error.team_error.un_auth": "无权操作该团队",
|
||||
"code_error.team_error.website_sync_not_enough": "无权使用Web站点同步~",
|
||||
"code_error.team_error.group_name_duplicate": "群组名称重复",
|
||||
"code_error.team_error.user_not_active": "用户未接受或已离开团队",
|
||||
"code_error.team_error.website_sync_not_enough": "无权使用Web站点同步~",
|
||||
"code_error.token_error_code.403": "登录状态无效,请重新登录",
|
||||
"code_error.user_error.balance_not_enough": "账号余额不足~",
|
||||
"code_error.user_error.bin_visitor": "您的身份校验未通过",
|
||||
@@ -148,6 +151,7 @@
|
||||
"common.Params": "参数",
|
||||
"common.Password inconsistency": "两次密码不一致",
|
||||
"common.Permission": "权限",
|
||||
"common.Permission_tip": "个人权限大于群组权限",
|
||||
"common.Please Input Name": "请输入名称",
|
||||
"common.Read document": "查看文档",
|
||||
"common.Read intro": "查看说明",
|
||||
@@ -242,10 +246,6 @@
|
||||
"comon.Continue_Adding": "继续添加",
|
||||
"compliance.chat": "内容由第三方 AI 生成,无法确保真实准确,仅供参考",
|
||||
"compliance.dataset": "请确保您的内容严格遵守相关法律法规,避免包含任何违法或侵权的内容。请谨慎上传可能涉及敏感信息的资料。",
|
||||
"code_error.team_error.group_name_empty": "群组名称不能为空",
|
||||
"code_error.team_error.group_not_exist": "群组不存在",
|
||||
"code_error.team_error.cannot_delete_default_group": "不能删除默认群组",
|
||||
"common.Permission_tip": "个人权限大于群组权限",
|
||||
"confirm_choice": "确认选择",
|
||||
"contribute_app_template": "贡献模板",
|
||||
"core.Chat": "对话",
|
||||
@@ -856,6 +856,7 @@
|
||||
"dataset.dataset_name": "知识库名称",
|
||||
"dataset.deleteFolderTips": "确认删除该文件夹及其包含的所有知识库?删除后数据无法恢复,请确认!",
|
||||
"dataset.test.noResult": "搜索结果为空",
|
||||
"delete_api": "确认删除该API密钥?删除后该密钥立即失效,对应的对话日志不会删除,请确认!",
|
||||
"error.Create failed": "创建失败",
|
||||
"error.code_error": "验证码错误",
|
||||
"error.fileNotFound": "文件找不到了~",
|
||||
@@ -1198,9 +1199,9 @@
|
||||
"user.team.member.waiting": "待接受",
|
||||
"user.team.role.Admin": "管理员",
|
||||
"user.team.role.Owner": "创建者",
|
||||
"user.type": "类型",
|
||||
"user.team.role.writer": "可写成员",
|
||||
"user.team.role.Visitor": "访客",
|
||||
"user.team.role.writer": "可写成员",
|
||||
"user.type": "类型",
|
||||
"verification": "验证",
|
||||
"xx_search_result": "{{key}} 的搜索结果",
|
||||
"yes": "是"
|
||||
|
@@ -33,7 +33,6 @@
|
||||
"dataset_quote_role_system_option_desc": "历史记录连贯优先(推荐)",
|
||||
"dataset_quote_role_tip": "设置为 System 时,将会把知识库引用内容放置到 system 消息中,可以确保历史记录的连贯性,但约束效果可能不佳,需要多调试。\n设置为 User 时,将会把知识库引用内容放置到 user 消息中,并且需要指定 {{question}} 变量位置。会对历史记录连贯性有一定影响,但通常约束效果更优。",
|
||||
"dataset_quote_role_user_option_desc": "强约束优先",
|
||||
"delete_api": "确认删除该API密钥?删除后该密钥立即失效,对应的对话日志不会删除,请确认!",
|
||||
"dynamic_input_description": "接收前方节点的输出值作为变量,这些变量可以被 Laf 请求参数使用。",
|
||||
"dynamic_input_description_concat": "可以引用其他节点的输出,作为文本拼接的变量,输入 / 唤起变量列表",
|
||||
"edit_input": "编辑输入",
|
||||
@@ -187,4 +186,4 @@
|
||||
"workflow.Switch_success": "切换成功",
|
||||
"workflow.Team cloud": "团队云端",
|
||||
"workflow.exit_tips": "您的更改尚未保存,「直接退出」将不会保存您的编辑记录。"
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "app",
|
||||
"version": "4.8.10",
|
||||
"version": "4.8.11",
|
||||
"private": false,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
@@ -1,46 +1,31 @@
|
||||
### FastGPT V4.8.9
|
||||
### FastGPT V4.8.11 更新说明
|
||||
|
||||
#### 新功能说明
|
||||
1. 新增 - 表单输入节点,允许用户在工作流中让用户输入一些信息。
|
||||
2. 新增 - 循环运行节点,可传入数组进行批量调用,目前最多支持 50 长度的数组串行执行。
|
||||
3. 新增 - 自定义工具变量节点,可以为工具调用子流程完全自定义变量。在构建复杂 Agent 时有帮助。
|
||||
4. 新增 - 节点支持折叠。
|
||||
5. 新增 - 聊天记录滚动加载,不再只加载 30 条。
|
||||
6. 新增 - 工作流增加触摸板优先模式,可以通过工作流右下角按键进行切换。
|
||||
7. 新增 - 沙盒增加字符串转 base64 全局方法(全局变量 strToBase64)。
|
||||
8. 新增 - 支持 Openai o1 模型,需增加模型的 `defaultConfig` 配置,覆盖 `temperature`、`max_tokens` 和 `stream`配置,o1 不支持 stream 模式, 详细可重新拉取 `config.json` 配置文件查看。
|
||||
9. 新增 - AI 对话节点知识库引用,支持配置 role=system 和 role=user,已配置的过自定义提示词的节点将会保持 user 模式,其余用户将转成 system 模式。
|
||||
10. 新增 - 插件支持上传系统文件。
|
||||
11. 新增 - 子应用嵌套调用时,版本锁定。主应用未主动更新版本时,不会取最新版进行执行,保证主应用服务稳定。
|
||||
12. 新增 - 插件输出,支持指定字段作为工具响应。
|
||||
13. 新增 - 支持工作流嵌套子应用时,可以设置`非流模式`,同时简易模式也可以选择工作流作为插件了,简易模式调用子应用时,都将强制使用非流模式。
|
||||
14. 新增 - 调试模式下,子应用调用,支持返回详细运行数据。
|
||||
15. 新增 - 保留所有模式下子应用嵌套调用的日志。
|
||||
16. 新增 - 商业版支持团队成员组,后续将逐渐覆盖工作台和知识库权限。
|
||||
17. 优化 - 工作流嵌套层级限制 20 层,避免因编排不合理导致的无限死循环。
|
||||
18. 优化 - 工作流 handler 性能优化。
|
||||
19. 优化 - 工作流快捷键,避免调试测试时也会触发复制和回退。
|
||||
20. 修复 - 工作流工具调用中修改全局变量后,无法传递到后续流程。
|
||||
21. 优化 - 流输出,切换浏览器 Tab 后仍可以继续输出。
|
||||
22. 优化 - 完善外部文件知识库相关 API
|
||||
23. 修复 - 知识库选择权限问题。
|
||||
24. 修复 - 空 chatId 发起对话,首轮携带用户选择时会异常。
|
||||
25. 修复 - createDataset 接口,intro 为赋值。
|
||||
26. 修复 - 对话框渲染性能问题。
|
||||
27. 修复 - 工具调用历史记录存储不正确。
|
||||
|
||||
1. **文件上传**
|
||||
|
||||
支持在简易模式和工作流中上传文档,目前版本,主要以上传文档总结为主,如果需要通过工作流编排实现类似于内容提取、文档对比之类的功能,需要配合代码运行去使用。
|
||||
|
||||
- 在系统配置中可以开启文件上传,对话框中即可上传文件。文件包括文档和图片;是否可上传图片,不再依赖视觉模型决定,而是通过系统配置决定。
|
||||
- 简易模式下,会通过工具调用,由模型决定是否读取文档,所以尽可能选择支持工具调用的模型。
|
||||
- 工作流模式下,可以通过文档解析节点,手动获取解析结果进行后续流程。
|
||||
|
||||
| | |
|
||||
| --------------------------------------------------------- | --------------------------------------------------------- |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|
||||
2. **AI 对话模型,启用视觉模型**
|
||||
|
||||
之前有反馈,工作流中所有模型都会强制使用视觉模式,浪费了资源,目前可以手动关闭。开启后会自动获取对话框上传的图片和“用户问题”中的图片链接。
|
||||
|
||||

|
||||
|
||||
3. **清空对话引导**
|
||||
|
||||

|
||||
|
||||
#### 优化说明
|
||||
|
||||
1. 优化 - 对话框懒加载。
|
||||
2. 优化 - i18n 翻译。
|
||||
3. 优化 - 减少工具调用结果的存储,不再实际存储完整响应,避免超出存储限制。
|
||||
4. 优化 - QA 拆分支持自定义 chunk 大小,并优化 gpt4o-mini 拆分时,chunk 太大导致生成内容很少的问题。
|
||||
|
||||
#### 问题修复
|
||||
|
||||
1. 修复 - 删除应用后回到聊天选择最后一次对话的应用为删除的应用时提示无该应用问题。
|
||||
2. 修复 - 插件运行获取历史记录后无法更新到页面。
|
||||
3. 修复 - 插件默认值无法正常显示。
|
||||
4. 修复 - 工具调用温度和最大回复值未生效。
|
||||
5. 修复 - 知识库文件上传进度更新可能异常。
|
||||
6. 修复 - 知识库 rebuilding 时候,页面总是刷新到第一页。
|
||||
7. 修复 - 函数调用模式,assistant role 中,GPT 模型必须传入 content 参数。(不影响大部分模型,目前基本都改用用 ToolChoice 模式,FC 模式已弃用)。
|
||||
8. 修复 - docs: Repair and supplement document content xinference.md。
|
||||
9. 修复 - 知识库列表右下角类型的名称上下居中。
|
||||
10. 修复 - 知识库 list openapi 鉴权问题。
|
||||
|
@@ -24,7 +24,6 @@ import {
|
||||
putOpenApiKey
|
||||
} from '@/web/support/openapi/api';
|
||||
import type { EditApiKeyProps } from '@/global/support/openapi/api.d';
|
||||
import { useQuery, useMutation } from '@tanstack/react-query';
|
||||
import dayjs from 'dayjs';
|
||||
import { AddIcon } from '@chakra-ui/icons';
|
||||
import { useCopyData } from '@/web/common/hooks/useCopyData';
|
||||
@@ -33,7 +32,7 @@ import { useTranslation } from 'next-i18next';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import { getDocPath } from '@/web/common/system/doc';
|
||||
import MyMenu from '@fastgpt/web/components/common/MyMenu';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
@@ -61,13 +60,10 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => {
|
||||
|
||||
const { ConfirmModal, openConfirm } = useConfirm({
|
||||
type: 'delete',
|
||||
content: t('workflow:delete_api')
|
||||
content: t('common:delete_api')
|
||||
});
|
||||
|
||||
const { mutate: onclickRemove, isLoading: isDeleting } = useMutation({
|
||||
mutationFn: async (id: string) => {
|
||||
return delOpenApiById(id);
|
||||
},
|
||||
const { runAsync: onclickRemove } = useRequest2(delOpenApiById, {
|
||||
onSuccess() {
|
||||
refetch();
|
||||
}
|
||||
@@ -75,9 +71,12 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => {
|
||||
|
||||
const {
|
||||
data: apiKeys = [],
|
||||
isLoading: isGetting,
|
||||
refetch
|
||||
} = useQuery(['getOpenApiKeys', appId], () => getOpenApiKeys({ appId }));
|
||||
loading: isGetting,
|
||||
run: refetch
|
||||
} = useRequest2(() => getOpenApiKeys({ appId }), {
|
||||
manual: false,
|
||||
refreshDeps: [appId]
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setBaseUrl(feConfigs?.customApiDomain || `${location.origin}/api`);
|
||||
@@ -85,7 +84,7 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => {
|
||||
|
||||
return (
|
||||
<MyBox
|
||||
isLoading={isGetting || isDeleting}
|
||||
isLoading={isGetting}
|
||||
display={'flex'}
|
||||
flexDirection={'column'}
|
||||
h={'100%'}
|
||||
|
@@ -52,8 +52,7 @@ const Account = ({ currentTab }: { currentTab: TabEnum }) => {
|
||||
}
|
||||
]
|
||||
: []),
|
||||
// ...(feConfigs?.show_pay && userInfo?.team?.permission.hasWritePer
|
||||
...(feConfigs?.show_pay || userInfo?.team?.permission.hasWritePer
|
||||
...(feConfigs?.show_pay && userInfo?.team?.permission.hasManagePer
|
||||
? [
|
||||
{
|
||||
icon: 'support/bill/payRecordLight',
|
||||
@@ -62,8 +61,7 @@ const Account = ({ currentTab }: { currentTab: TabEnum }) => {
|
||||
}
|
||||
]
|
||||
: []),
|
||||
|
||||
...(feConfigs?.show_promotion
|
||||
...(feConfigs?.show_promotion && userInfo?.team?.permission.isOwner
|
||||
? [
|
||||
{
|
||||
icon: 'support/account/promotionLight',
|
||||
@@ -72,7 +70,7 @@ const Account = ({ currentTab }: { currentTab: TabEnum }) => {
|
||||
}
|
||||
]
|
||||
: []),
|
||||
...(userInfo?.team?.permission.hasWritePer
|
||||
...(userInfo?.team?.permission.hasManagePer
|
||||
? [
|
||||
{
|
||||
icon: 'support/outlink/apikeyLight',
|
||||
|
@@ -1,64 +0,0 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||
import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema';
|
||||
import { FastGPTProUrl } from '@fastgpt/service/common/system/constants';
|
||||
import { POST } from '@fastgpt/service/common/api/plusRequest';
|
||||
import { MongoTeam } from '@fastgpt/service/support/user/team/teamSchema';
|
||||
import { MongoMemberGroupModel } from '@fastgpt/service/support/permission/memberGroup/memberGroupSchema';
|
||||
import { delay } from '@fastgpt/global/common/system/utils';
|
||||
import { DefaultGroupName } from '@fastgpt/global/support/user/team/group/constant';
|
||||
|
||||
/*
|
||||
1. 给每个 team 创建一个默认的 group
|
||||
*/
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
await connectToDatabase();
|
||||
await authCert({ req, authRoot: true });
|
||||
|
||||
const teamList = await MongoTeam.find({}, '_id');
|
||||
console.log('Total team', teamList.length);
|
||||
let success = 0;
|
||||
|
||||
async function createGroup(teamId: string) {
|
||||
try {
|
||||
await MongoMemberGroupModel.updateOne(
|
||||
{
|
||||
teamId,
|
||||
name: DefaultGroupName
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
teamId: teamId,
|
||||
name: DefaultGroupName
|
||||
}
|
||||
},
|
||||
{
|
||||
upsert: true
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
await delay(500);
|
||||
return createGroup(teamId);
|
||||
}
|
||||
}
|
||||
for await (const team of teamList) {
|
||||
await createGroup(team._id);
|
||||
console.log(++success);
|
||||
}
|
||||
|
||||
jsonRes(res, {
|
||||
message: 'success'
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
jsonRes(res, {
|
||||
code: 500,
|
||||
error
|
||||
});
|
||||
}
|
||||
}
|
@@ -413,32 +413,7 @@ export const useWorkflow = () => {
|
||||
});
|
||||
|
||||
/* node */
|
||||
const handleRemoveNode = useMemoizedFn((nodeId: string) => {
|
||||
// If the node has child nodes, remove the child nodes
|
||||
const childNodes = nodes.filter((n) => n.data.parentNodeId === nodeId);
|
||||
if (childNodes.length > 0) {
|
||||
const childNodeIds = childNodes.map((node) => node.id);
|
||||
const childEdges = edges.filter(
|
||||
(edge) => childNodeIds.includes(edge.source) || childNodeIds.includes(edge.target)
|
||||
);
|
||||
|
||||
onNodesChange(
|
||||
childNodes.map<NodeRemoveChange>((node) => ({
|
||||
type: 'remove',
|
||||
id: node.id
|
||||
}))
|
||||
);
|
||||
onEdgesChange(
|
||||
childEdges.map<EdgeRemoveChange>((edge) => ({
|
||||
type: 'remove',
|
||||
id: edge.id
|
||||
}))
|
||||
);
|
||||
}
|
||||
onNodesChange([{ type: 'remove', id: nodeId }]);
|
||||
|
||||
return;
|
||||
});
|
||||
const handleSelectNode = useMemoizedFn((change: NodeSelectionChange) => {
|
||||
// If the node is not selected and the Ctrl key is pressed, select the node
|
||||
if (change.selected === false && isDowningCtrl) {
|
||||
@@ -618,9 +593,8 @@ export const useWorkflow = () => {
|
||||
|
||||
useKeyPress(['Delete', 'Backspace'], (e) => {
|
||||
if (!mouseInCanvas) return;
|
||||
const selectedNodes = nodes.filter((node) => node.selected);
|
||||
const selectedEdges = edges.filter((edge) => edge.selected);
|
||||
|
||||
const selectedNodes = nodes.filter((node) => node.selected);
|
||||
if (selectedNodes.length > 0) {
|
||||
for (const node of selectedNodes) {
|
||||
if (node.data.forbidDelete) {
|
||||
@@ -631,13 +605,27 @@ export const useWorkflow = () => {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Computed deleted node and its edges
|
||||
const removedNodeId = node.id;
|
||||
handleRemoveNode(removedNodeId);
|
||||
const edgesToRemove = edges.filter(
|
||||
const removedNodeEdges = edges.filter(
|
||||
(edge) => edge.source === removedNodeId || edge.target === removedNodeId
|
||||
);
|
||||
|
||||
const childNodes = nodes.filter((n) => n.data.parentNodeId === removedNodeId);
|
||||
const childNodeIds = childNodes.map((node) => node.id);
|
||||
const childEdges = edges.filter(
|
||||
(edge) => childNodeIds.includes(edge.source) || childNodeIds.includes(edge.target)
|
||||
);
|
||||
|
||||
// Delete
|
||||
onNodesChange(
|
||||
[removedNodeId, ...childNodeIds].map((nodeId) => ({
|
||||
type: 'remove',
|
||||
id: nodeId
|
||||
}))
|
||||
);
|
||||
onEdgesChange(
|
||||
edgesToRemove.map((edge) => ({
|
||||
[...removedNodeEdges, ...childEdges].map((edge) => ({
|
||||
type: 'remove',
|
||||
id: edge.id
|
||||
}))
|
||||
@@ -645,6 +633,8 @@ export const useWorkflow = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// Delete selected edges
|
||||
const selectedEdges = edges.filter((edge) => edge.selected);
|
||||
if (selectedEdges.length > 0) {
|
||||
onEdgesChange(
|
||||
selectedEdges.map((edge) => ({
|
||||
|
@@ -606,10 +606,10 @@ const NodeDebugResponse = React.memo(function NodeDebugResponse({
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
const onStopNodeDebug = useContextSelector(WorkflowContext, (v) => v.onStopNodeDebug);
|
||||
const onNextNodeDebug = useContextSelector(WorkflowContext, (v) => v.onNextNodeDebug);
|
||||
const workflowDebugData = useContextSelector(WorkflowContext, (v) => v.workflowDebugData);
|
||||
const { onChangeNode, onStopNodeDebug, onNextNodeDebug, workflowDebugData } = useContextSelector(
|
||||
WorkflowContext,
|
||||
(v) => v
|
||||
);
|
||||
|
||||
const { openConfirm, ConfirmModal } = useConfirm({
|
||||
content: t('common:core.workflow.Confirm stop debug')
|
||||
@@ -741,11 +741,9 @@ const NodeDebugResponse = React.memo(function NodeDebugResponse({
|
||||
)}
|
||||
</Card>
|
||||
)}
|
||||
<ConfirmModal />
|
||||
</>
|
||||
) : null;
|
||||
}, [
|
||||
ConfirmModal,
|
||||
debugResult,
|
||||
nodeId,
|
||||
onChangeNode,
|
||||
@@ -753,8 +751,13 @@ const NodeDebugResponse = React.memo(function NodeDebugResponse({
|
||||
onStopNodeDebug,
|
||||
openConfirm,
|
||||
t,
|
||||
workflowDebugData?.nextRunNodes
|
||||
workflowDebugData
|
||||
]);
|
||||
|
||||
return <>{RenderStatus}</>;
|
||||
return (
|
||||
<>
|
||||
{RenderStatus}
|
||||
<ConfirmModal />
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
@@ -160,7 +160,7 @@ const AppContextProvider = ({ children }: { children: ReactNode }) => {
|
||||
});
|
||||
|
||||
const { openConfirm: openConfirmDel, ConfirmModal: ConfirmDelModal } = useConfirm({
|
||||
content: t('app:confirm_del_app_tip'),
|
||||
content: t('app:confirm_del_app_tip', { name: appDetail.name }),
|
||||
type: 'delete'
|
||||
});
|
||||
const { runAsync: deleteApp } = useRequest2(
|
||||
|
@@ -365,7 +365,7 @@ const ListItem = () => {
|
||||
undefined,
|
||||
app.type === AppTypeEnum.folder
|
||||
? t('app:confirm_delete_folder_tip')
|
||||
: t('app:confirm_del_app_tip')
|
||||
: t('app:confirm_del_app_tip', { name: app.name })
|
||||
)()
|
||||
}
|
||||
]
|
||||
|
@@ -82,7 +82,7 @@ const Dataset = () => {
|
||||
|
||||
const RenderSearchInput = useMemo(
|
||||
() => (
|
||||
<InputGroup maxW={['auto', '250px']} pr={[0, 4]}>
|
||||
<InputGroup maxW={['auto', '250px']}>
|
||||
<InputLeftElement h={'full'} alignItems={'center'} display={'flex'}>
|
||||
<MyIcon color={'myGray.600'} name={'common/searchLight'} w={'1rem'} />
|
||||
</InputLeftElement>
|
||||
@@ -100,6 +100,7 @@ const Dataset = () => {
|
||||
),
|
||||
[searchKey, setSearchKey, t]
|
||||
);
|
||||
|
||||
return (
|
||||
<MyBox
|
||||
isLoading={myDatasets.length === 0 && isFetchingDatasets}
|
||||
@@ -110,7 +111,7 @@ const Dataset = () => {
|
||||
>
|
||||
<Flex pt={[4, 6]} pl={3} pr={[3, 10]}>
|
||||
<Flex flexGrow={1} flexDirection="column">
|
||||
<Flex alignItems={'flex-start'} justifyContent={'space-between'}>
|
||||
<Flex alignItems={'center'} justifyContent={'space-between'}>
|
||||
<ParentPaths
|
||||
paths={paths}
|
||||
FirstPathDom={
|
||||
@@ -138,54 +139,56 @@ const Dataset = () => {
|
||||
{isPc && RenderSearchInput}
|
||||
|
||||
{userInfo?.team?.permission.hasWritePer && (
|
||||
<MyMenu
|
||||
offset={[0, 10]}
|
||||
width={120}
|
||||
iconSize="2rem"
|
||||
iconRadius="6px"
|
||||
placement="bottom-end"
|
||||
Button={
|
||||
<Button variant={'primary'} px="0">
|
||||
<Flex alignItems={'center'} px={5}>
|
||||
<AddIcon mr={2} />
|
||||
<Box>{t('common:common.Create New')}</Box>
|
||||
</Flex>
|
||||
</Button>
|
||||
}
|
||||
menuList={[
|
||||
{
|
||||
children: [
|
||||
{
|
||||
icon: 'core/dataset/commonDatasetColor',
|
||||
label: t('dataset:common_dataset'),
|
||||
description: t('dataset:common_dataset_desc'),
|
||||
onClick: () => setCreateDatasetType(DatasetTypeEnum.dataset)
|
||||
},
|
||||
{
|
||||
icon: 'core/dataset/websiteDatasetColor',
|
||||
label: t('dataset:website_dataset'),
|
||||
description: t('dataset:website_dataset_desc'),
|
||||
onClick: () => setCreateDatasetType(DatasetTypeEnum.websiteDataset)
|
||||
},
|
||||
{
|
||||
icon: 'core/dataset/externalDatasetColor',
|
||||
label: t('dataset:external_file'),
|
||||
description: t('dataset:external_file_dataset_desc'),
|
||||
onClick: () => setCreateDatasetType(DatasetTypeEnum.externalFile)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
icon: FolderIcon,
|
||||
label: t('common:Folder'),
|
||||
onClick: () => setEditFolderData({})
|
||||
}
|
||||
]
|
||||
<Box pl={[0, 4]}>
|
||||
<MyMenu
|
||||
offset={[0, 10]}
|
||||
width={120}
|
||||
iconSize="2rem"
|
||||
iconRadius="6px"
|
||||
placement="bottom-end"
|
||||
Button={
|
||||
<Button variant={'primary'} px="0">
|
||||
<Flex alignItems={'center'} px={5}>
|
||||
<AddIcon mr={2} />
|
||||
<Box>{t('common:common.Create New')}</Box>
|
||||
</Flex>
|
||||
</Button>
|
||||
}
|
||||
]}
|
||||
/>
|
||||
menuList={[
|
||||
{
|
||||
children: [
|
||||
{
|
||||
icon: 'core/dataset/commonDatasetColor',
|
||||
label: t('dataset:common_dataset'),
|
||||
description: t('dataset:common_dataset_desc'),
|
||||
onClick: () => setCreateDatasetType(DatasetTypeEnum.dataset)
|
||||
},
|
||||
{
|
||||
icon: 'core/dataset/websiteDatasetColor',
|
||||
label: t('dataset:website_dataset'),
|
||||
description: t('dataset:website_dataset_desc'),
|
||||
onClick: () => setCreateDatasetType(DatasetTypeEnum.websiteDataset)
|
||||
},
|
||||
{
|
||||
icon: 'core/dataset/externalDatasetColor',
|
||||
label: t('dataset:external_file'),
|
||||
description: t('dataset:external_file_dataset_desc'),
|
||||
onClick: () => setCreateDatasetType(DatasetTypeEnum.externalFile)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
icon: FolderIcon,
|
||||
label: t('common:Folder'),
|
||||
onClick: () => setEditFolderData({})
|
||||
}
|
||||
]
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
|
Reference in New Issue
Block a user