From ee50a2bcd5cfdc1b7476406e80b8daa6f14864f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=86=E8=90=8C=E9=97=B7=E6=B2=B9=E7=93=B6?= <253605712@qq.com> Date: Fri, 25 Jul 2025 18:06:03 +0800 Subject: [PATCH] feat: clear all annotation (#22878) Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- api/controllers/console/app/annotation.py | 11 ++++++ api/services/annotation_service.py | 24 ++++++++++++ .../index.tsx | 32 ++++++++++++++++ .../app/annotation/header-opts/index.tsx | 37 ++++++++++++++++++- web/i18n/en-US/app-annotation.ts | 3 +- web/i18n/ja-JP/app-annotation.ts | 3 +- web/i18n/zh-Hans/app-annotation.ts | 3 +- web/service/annotation.ts | 4 ++ 8 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 web/app/components/app/annotation/clear-all-annotations-confirm-modal/index.tsx diff --git a/api/controllers/console/app/annotation.py b/api/controllers/console/app/annotation.py index 0c0d48a81..c2ba88040 100644 --- a/api/controllers/console/app/annotation.py +++ b/api/controllers/console/app/annotation.py @@ -123,6 +123,17 @@ class AnnotationListApi(Resource): } return response, 200 + @setup_required + @login_required + @account_initialization_required + def delete(self, app_id): + if not current_user.is_editor: + raise Forbidden() + + app_id = str(app_id) + AppAnnotationService.clear_all_annotations(app_id) + return {"result": "success"}, 204 + class AnnotationExportApi(Resource): @setup_required diff --git a/api/services/annotation_service.py b/api/services/annotation_service.py index 26273e367..3239af998 100644 --- a/api/services/annotation_service.py +++ b/api/services/annotation_service.py @@ -440,3 +440,27 @@ class AppAnnotationService: "embedding_model_name": collection_binding_detail.model_name, }, } + + @classmethod + def clear_all_annotations(cls, app_id: str) -> dict: + app = ( + db.session.query(App) + .filter(App.id == app_id, App.tenant_id == current_user.current_tenant_id, App.status == "normal") + .first() + ) + + if not app: + raise NotFound("App not found") + + annotations_query = db.session.query(MessageAnnotation).filter(MessageAnnotation.app_id == app_id) + for annotation in annotations_query.yield_per(100): + annotation_hit_histories_query = db.session.query(AppAnnotationHitHistory).filter( + AppAnnotationHitHistory.annotation_id == annotation.id + ) + for annotation_hit_history in annotation_hit_histories_query.yield_per(100): + db.session.delete(annotation_hit_history) + + db.session.delete(annotation) + + db.session.commit() + return {"result": "success"} diff --git a/web/app/components/app/annotation/clear-all-annotations-confirm-modal/index.tsx b/web/app/components/app/annotation/clear-all-annotations-confirm-modal/index.tsx new file mode 100644 index 000000000..7316ee10a --- /dev/null +++ b/web/app/components/app/annotation/clear-all-annotations-confirm-modal/index.tsx @@ -0,0 +1,32 @@ +'use client' + +import type { FC } from 'react' +import React from 'react' +import { useTranslation } from 'react-i18next' +import Confirm from '@/app/components/base/confirm' + +type Props = { + isShow: boolean + onHide: () => void + onConfirm: () => void +} + +const ClearAllAnnotationsConfirmModal: FC = ({ + isShow, + onHide, + onConfirm, +}) => { + const { t } = useTranslation() + + return ( + + ) +} + +export default React.memo(ClearAllAnnotationsConfirmModal) diff --git a/web/app/components/app/annotation/header-opts/index.tsx b/web/app/components/app/annotation/header-opts/index.tsx index b076a35e2..dcf6176cc 100644 --- a/web/app/components/app/annotation/header-opts/index.tsx +++ b/web/app/components/app/annotation/header-opts/index.tsx @@ -1,9 +1,11 @@ 'use client' import type { FC } from 'react' import React, { Fragment, useEffect, useState } from 'react' +import ClearAllAnnotationsConfirmModal from '../clear-all-annotations-confirm-modal' import { useTranslation } from 'react-i18next' import { RiAddLine, + RiDeleteBinLine, RiMoreFill, } from '@remixicon/react' import { useContext } from 'use-context-selector' @@ -22,6 +24,7 @@ import { ChevronRight } from '@/app/components/base/icons/src/vender/line/arrows import I18n from '@/context/i18n' import { fetchExportAnnotationList } from '@/service/annotation' +import { clearAllAnnotations } from '@/service/annotation' import { LanguagesSupported } from '@/i18n-config/language' const CSV_HEADER_QA_EN = ['Question', 'Answer'] @@ -76,7 +79,21 @@ const HeaderOptions: FC = ({ }, [controlUpdateList]) const [showBulkImportModal, setShowBulkImportModal] = useState(false) - + const [showClearConfirm, setShowClearConfirm] = useState(false) + const handleClearAll = () => { + setShowClearConfirm(true) + } + const handleConfirmed = async () => { + try { + await clearAllAnnotations(appId) + onAdded() + } +catch (_) { + } + finally { + setShowClearConfirm(false) + } + } const Operations = () => { return (
@@ -125,6 +142,15 @@ const HeaderOptions: FC = ({ +
) } @@ -169,6 +195,15 @@ const HeaderOptions: FC = ({ /> ) } + { + showClearConfirm && ( + setShowClearConfirm(false)} + onConfirm={handleConfirmed} + /> + ) + } ) } diff --git a/web/i18n/en-US/app-annotation.ts b/web/i18n/en-US/app-annotation.ts index 43f24a761..c0a8008d9 100644 --- a/web/i18n/en-US/app-annotation.ts +++ b/web/i18n/en-US/app-annotation.ts @@ -16,7 +16,8 @@ const translation = { addAnnotation: 'Add Annotation', bulkImport: 'Bulk Import', bulkExport: 'Bulk Export', - clearAll: 'Clear All Annotation', + clearAll: 'Delete All', + clearAllConfirm: 'Delete all annotations?', }, }, editModal: { diff --git a/web/i18n/ja-JP/app-annotation.ts b/web/i18n/ja-JP/app-annotation.ts index 38b891d9d..7dbdfe018 100644 --- a/web/i18n/ja-JP/app-annotation.ts +++ b/web/i18n/ja-JP/app-annotation.ts @@ -18,7 +18,8 @@ const translation = { addAnnotation: '注釈を追加', bulkImport: '一括インポート', bulkExport: '一括エクスポート', - clearAll: 'すべての注釈をクリア', + clearAll: 'すべて削除', + clearAllConfirm: 'すべての寸法を削除?', }, }, editModal: { diff --git a/web/i18n/zh-Hans/app-annotation.ts b/web/i18n/zh-Hans/app-annotation.ts index 3a6cacf5b..44d075715 100644 --- a/web/i18n/zh-Hans/app-annotation.ts +++ b/web/i18n/zh-Hans/app-annotation.ts @@ -18,7 +18,8 @@ const translation = { addAnnotation: '添加标注', bulkImport: '批量导入', bulkExport: '批量导出', - clearAll: '删除所有标注', + clearAll: '删除所有', + clearAllConfirm: '删除所有标注?', }, }, editModal: { diff --git a/web/service/annotation.ts b/web/service/annotation.ts index 5096a4f58..9f025f8eb 100644 --- a/web/service/annotation.ts +++ b/web/service/annotation.ts @@ -63,3 +63,7 @@ export const delAnnotation = (appId: string, annotationId: string) => { export const fetchHitHistoryList = (appId: string, annotationId: string, params: Record) => { return get(`apps/${appId}/annotations/${annotationId}/hit-histories`, { params }) } + +export const clearAllAnnotations = (appId: string): Promise => { + return del(`apps/${appId}/annotations`) +}