From e5102eb132610eed9b616da65199156ffdc551a1 Mon Sep 17 00:00:00 2001 From: shaohuzhang1 Date: Wed, 18 Mar 2026 16:05:05 +0800 Subject: [PATCH] fix: The simple intelligent agent moves from one folder to another, and the previously set AI model and associated knowledge base will be cleared #4890 --- apps/application/serializers/application.py | 19 +++++++-- apps/application/urls.py | 1 + apps/application/views/application.py | 27 ++++++++++++ apps/locales/en_US/LC_MESSAGES/django.po | 5 ++- apps/locales/zh_CN/LC_MESSAGES/django.po | 5 ++- apps/locales/zh_Hant/LC_MESSAGES/django.po | 5 ++- ui/src/api/application/application.ts | 41 ++++++++++++++----- .../components/folder-tree/MoveToDialog.vue | 2 +- 8 files changed, 86 insertions(+), 19 deletions(-) diff --git a/apps/application/serializers/application.py b/apps/application/serializers/application.py index 0f770eea912..79e2262b356 100644 --- a/apps/application/serializers/application.py +++ b/apps/application/serializers/application.py @@ -699,9 +699,12 @@ def to_application(application, workspace_id, user_id, update_tool_map, folder_i file_clean_time=application.get('file_clean_time') or 180, file_upload_enable=application.get('file_upload_enable'), file_upload_setting=application.get('file_upload_setting'), - tool_ids=[update_tool_map.get(tool_id, tool_id) for tool_id in application.get('tool_ids', [])], - skill_tool_ids=[update_tool_map.get(tool_id, tool_id) for tool_id in application.get('skill_tool_ids', [])], - mcp_tool_ids=[update_tool_map.get(tool_id, tool_id) for tool_id in application.get('mcp_tool_ids', [])], + tool_ids=[update_tool_map.get(tool_id, tool_id) for tool_id in + application.get('tool_ids', [])], + skill_tool_ids=[update_tool_map.get(tool_id, tool_id) for tool_id in + application.get('skill_tool_ids', [])], + mcp_tool_ids=[update_tool_map.get(tool_id, tool_id) for tool_id in + application.get('mcp_tool_ids', [])], ) class StoreApplication(serializers.Serializer): @@ -926,7 +929,7 @@ def publish(self, instance, with_valid=True): work_flow_version.save() access_token = hashlib.md5( str(uuid.uuid7()).encode()).hexdigest()[ - 8:24] + 8:24] application_access_token = QuerySet(ApplicationAccessToken).filter( application_id=application.id).first() if application_access_token is None: @@ -987,6 +990,14 @@ def update_work_flow_model(instance): not view_knowledge_id_list.__contains__(knowledge_id)] node_data['knowledge_id_list'] = other_knowledge_id_list + knowledge_id_list + def move(self, folder_id: str): + self.is_valid(raise_exception=True) + application_id = self.data.get("application_id") + application = QuerySet(Application).get(id=application_id) + application.folder_id = folder_id + application.save() + return True + @transaction.atomic def edit(self, instance: Dict, with_valid=True): if with_valid: diff --git a/apps/application/urls.py b/apps/application/urls.py index 7e2569076b9..dca864b86fd 100644 --- a/apps/application/urls.py +++ b/apps/application/urls.py @@ -11,6 +11,7 @@ path('workspace//application//', views.ApplicationAPI.Page.as_view(), name='application_page'), path('workspace//application/', views.ApplicationAPI.Operate.as_view()), path('workspace//application//publish', views.ApplicationAPI.Publish.as_view()), + path('workspace//application//move/', views.ApplicationAPI.Move.as_view()), path('workspace//application//application_key', views.ApplicationKey.as_view()), path('workspace//application//application_stats', views.ApplicationStats.as_view()), path('workspace//application//application_token_usage', views.ApplicationStats.TokenUsageStatistics.as_view()), diff --git a/apps/application/views/application.py b/apps/application/views/application.py index 13cc6fe73db..ea2bf31dc26 100644 --- a/apps/application/views/application.py +++ b/apps/application/views/application.py @@ -225,6 +225,33 @@ def get(self, request: Request, workspace_id: str, application_id: str): data={'application_id': application_id, 'user_id': request.user.id, 'workspace_id': workspace_id, }).one()) + class Move(APIView): + authentication_classes = [TokenAuth] + + @extend_schema( + methods=['PUT'], + description=_("Move an application"), + summary=_("Move an application"), + operation_id=_("Move an application"), # type: ignore + parameters=ApplicationOperateAPI.get_parameters(), + request=None, + responses=result.DefaultResultSerializer, + tags=[_('Application')] # type: ignore + ) + @has_permissions(PermissionConstants.APPLICATION_EDIT.get_workspace_application_permission(), + PermissionConstants.APPLICATION_EDIT.get_workspace_permission_workspace_manage_role(), + ViewPermission([RoleConstants.USER.get_workspace_role()], + [PermissionConstants.APPLICATION.get_workspace_application_permission()], + CompareConstants.AND), + RoleConstants.WORKSPACE_MANAGE.get_workspace_role()) + @log(menu='Application', operate='Move an application', + get_operation_object=lambda r, k: get_application_operation_object(k.get('application_id'))) + def put(self, request: Request, workspace_id: str, application_id: str, folder_id: str): + return result.success( + ApplicationOperateSerializer( + data={'application_id': application_id, 'user_id': request.user.id, + 'workspace_id': workspace_id, }).move(folder_id)) + class Publish(APIView): authentication_classes = [TokenAuth] diff --git a/apps/locales/en_US/LC_MESSAGES/django.po b/apps/locales/en_US/LC_MESSAGES/django.po index 230c1afd40e..6d7e7490f31 100644 --- a/apps/locales/en_US/LC_MESSAGES/django.po +++ b/apps/locales/en_US/LC_MESSAGES/django.po @@ -9165,4 +9165,7 @@ msgid "Batch Remove Documents from Tag" msgstr "Batch Remove Documents from Tag" msgid "Document does not belong to current knowledge" -msgstr "Document does not belong to current knowledge" \ No newline at end of file +msgstr "Document does not belong to current knowledge" + +msgid "Move an application" +msgstr "Move an application" \ No newline at end of file diff --git a/apps/locales/zh_CN/LC_MESSAGES/django.po b/apps/locales/zh_CN/LC_MESSAGES/django.po index c84def98172..9827d4b61d5 100644 --- a/apps/locales/zh_CN/LC_MESSAGES/django.po +++ b/apps/locales/zh_CN/LC_MESSAGES/django.po @@ -9288,4 +9288,7 @@ msgid "Batch Remove Documents from Tag" msgstr "批量删除标签下的文档" msgid "Document does not belong to current knowledge" -msgstr "文档不属于当前知识库" \ No newline at end of file +msgstr "文档不属于当前知识库" + +msgid "Move an application" +msgstr "移动应用程序" \ No newline at end of file diff --git a/apps/locales/zh_Hant/LC_MESSAGES/django.po b/apps/locales/zh_Hant/LC_MESSAGES/django.po index 27f850329ff..9721ca9a7e4 100644 --- a/apps/locales/zh_Hant/LC_MESSAGES/django.po +++ b/apps/locales/zh_Hant/LC_MESSAGES/django.po @@ -9285,4 +9285,7 @@ msgid "Batch Remove Documents from Tag" msgstr "批量刪除標籤下的文件" msgid "Document does not belong to current knowledge" -msgstr "文件不屬於當前知識庫" \ No newline at end of file +msgstr "文件不屬於當前知識庫" + +msgid "Move an application" +msgstr "移動應用程序" \ No newline at end of file diff --git a/ui/src/api/application/application.ts b/ui/src/api/application/application.ts index 9592baae705..76b31e37830 100644 --- a/ui/src/api/application/application.ts +++ b/ui/src/api/application/application.ts @@ -63,6 +63,20 @@ const putApplication: ( ) => Promise> = (application_id, data, loading) => { return put(`${prefix.value}/${application_id}`, data, undefined, loading) } +/** + * 移动应用 + * @param application_id + * @param folder_id + * @param loading + * @returns + */ +const moveApplication: ( + application_id: string, + folder_id: string, + loading?: Ref, +) => Promise> = (application_id, folder_id, loading) => { + return put(`${prefix.value}/${application_id}/move/${folder_id}`, {}, undefined, loading) +} /** * 删除应用 @@ -233,17 +247,19 @@ const open: (application_id: string, loading?: Ref) => Promise Promise = ( - workspace_id, - model_id, - application_id, - data -) => { +const generate_prompt: ( + workspace_id: string, + model_id: string, + application_id: string, + data: any, +) => Promise = (workspace_id, model_id, application_id, data) => { const prefix = (window.MaxKB?.prefix ? window.MaxKB?.prefix : '/admin') + '/api' - return postStream(`${prefix}/workspace/${workspace_id}/application/${application_id}/model/${model_id}/prompt_generate`, data) + return postStream( + `${prefix}/workspace/${workspace_id}/application/${application_id}/model/${model_id}/prompt_generate`, + data, + ) } - /** * 对话 * chat_id: string @@ -401,8 +417,10 @@ const postUploadFile: ( return post(`/oss/file`, fd, undefined, loading) } - -const getFile: (application_id: string, params: any) => Promise> = (application_id, params) => { +const getFile: (application_id: string, params: any) => Promise> = ( + application_id, + params, +) => { return get(`/oss/get_url/${application_id}`, params) } export default { @@ -435,5 +453,6 @@ export default { generate_prompt, getTokenUsage, topQuestions, - getFile + getFile, + moveApplication, } diff --git a/ui/src/components/folder-tree/MoveToDialog.vue b/ui/src/components/folder-tree/MoveToDialog.vue index 1b65175ad97..f13ea415762 100644 --- a/ui/src/components/folder-tree/MoveToDialog.vue +++ b/ui/src/components/folder-tree/MoveToDialog.vue @@ -130,7 +130,7 @@ const submitHandle = async () => { dialogVisible.value = false }) } else if (props.source === SourceTypeEnum.APPLICATION) { - ApplicationApi.putApplication(detail.value.id, obj, loading).then((res) => { + ApplicationApi.moveApplication(detail.value.id, obj.folder_id, loading).then((res) => { MsgSuccess(t('common.saveSuccess')) emit('refresh', detail.value) dialogVisible.value = false