From 8e8e6f1fd0d2e08bf2bd96690d394b9359880612 Mon Sep 17 00:00:00 2001 From: Prab Dhaliwal Date: Mon, 14 Dec 2020 21:58:53 -0500 Subject: [PATCH] Add clear annotations and bulk delete functionality --- app/api/views.py | 11 ++++ .../annotation/ClearAnnotationsButton.vue | 41 +++++++++++++++ .../containers/annotation/EntityItemBox.vue | 25 +++++---- .../documents/DocumentBulkDeletionButton.vue | 51 +++++++++++++++++++ frontend/i18n/en/generic.js | 1 + frontend/i18n/en/projects/dataset.js | 2 + frontend/pages/projects/_id/dataset/index.vue | 5 +- frontend/services/annotation.service.js | 4 ++ frontend/services/document.service.js | 4 ++ frontend/store/documents.js | 26 +++++++++- 10 files changed, 157 insertions(+), 13 deletions(-) create mode 100644 frontend/components/containers/annotation/ClearAnnotationsButton.vue create mode 100644 frontend/components/containers/documents/DocumentBulkDeletionButton.vue diff --git a/app/api/views.py b/app/api/views.py index 44d6f081..b45e984e 100644 --- a/app/api/views.py +++ b/app/api/views.py @@ -184,6 +184,12 @@ class DocumentList(generics.ListCreateAPIView): project = get_object_or_404(Project, pk=self.kwargs['project_id']) serializer.save(project=project) + def delete(self, request, *args, **kwargs): + project = get_object_or_404(Project, pk=self.kwargs['project_id']) + queryset = project.documents + queryset.all().delete() + return Response(status=status.HTTP_204_NO_CONTENT) + class DocumentDetail(generics.RetrieveUpdateDestroyAPIView): queryset = Document.objects.all() @@ -220,6 +226,11 @@ class AnnotationList(generics.ListCreateAPIView): def perform_create(self, serializer): serializer.save(document_id=self.kwargs['doc_id'], user=self.request.user) + + def delete(self, request, *args, **kwargs): + queryset = self.get_queryset() + queryset.all().delete() + return Response(status=status.HTTP_204_NO_CONTENT) @staticmethod def check_single_class_classification(project_id, doc_id, user): diff --git a/frontend/components/containers/annotation/ClearAnnotationsButton.vue b/frontend/components/containers/annotation/ClearAnnotationsButton.vue new file mode 100644 index 00000000..7dabb43d --- /dev/null +++ b/frontend/components/containers/annotation/ClearAnnotationsButton.vue @@ -0,0 +1,41 @@ + + + diff --git a/frontend/components/containers/annotation/EntityItemBox.vue b/frontend/components/containers/annotation/EntityItemBox.vue index bab9c557..58c46505 100644 --- a/frontend/components/containers/annotation/EntityItemBox.vue +++ b/frontend/components/containers/annotation/EntityItemBox.vue @@ -1,22 +1,27 @@ diff --git a/frontend/i18n/en/generic.js b/frontend/i18n/en/generic.js index e3d0b0eb..309f098c 100644 --- a/frontend/i18n/en/generic.js +++ b/frontend/i18n/en/generic.js @@ -10,6 +10,7 @@ export default { upload: 'Upload', add: 'Add', delete: 'Delete', + deleteAll: 'Delete All', search: 'Search', name: 'Name', import: 'Import', diff --git a/frontend/i18n/en/projects/dataset.js b/frontend/i18n/en/projects/dataset.js index ac8cccd1..9f82f26c 100644 --- a/frontend/i18n/en/projects/dataset.js +++ b/frontend/i18n/en/projects/dataset.js @@ -15,5 +15,7 @@ export default { exportDataMessage: 'Select a file format', deleteDocumentsTitle: 'Delete Document', deleteDocumentsMessage: 'Are you sure you want to delete these documents from this project?', + deleteBulkDocumentsTitle: 'Delete All Documents', + deleteBulkDocumentsMessage: 'Are you sure you want to delete all documents from this project?', pageText: '{0}-{1} of {2}' } diff --git a/frontend/pages/projects/_id/dataset/index.vue b/frontend/pages/projects/_id/dataset/index.vue index b4fb874a..82f13995 100644 --- a/frontend/pages/projects/_id/dataset/index.vue +++ b/frontend/pages/projects/_id/dataset/index.vue @@ -3,6 +3,7 @@ + @@ -12,6 +13,7 @@ import DocumentList from '@/components/containers/documents/DocumentList' import DocumentActionMenu from '@/components/containers/documents/DocumentActionMenu' import DocumentDeletionButton from '@/components/containers/documents/DocumentDeletionButton' +import DocumentBulkDeletionButton from '@/components/containers/documents/DocumentBulkDeletionButton' export default { layout: 'project', @@ -19,7 +21,8 @@ export default { components: { DocumentList, DocumentActionMenu, - DocumentDeletionButton + DocumentDeletionButton, + DocumentBulkDeletionButton }, validate({ params, query }) { diff --git a/frontend/services/annotation.service.js b/frontend/services/annotation.service.js index 919b84e3..fa29d6db 100644 --- a/frontend/services/annotation.service.js +++ b/frontend/services/annotation.service.js @@ -17,6 +17,10 @@ class AnnotationService { return this.request.delete(`/projects/${projectId}/docs/${docId}/annotations/${annotationId}`) } + clearAnnotations(projectId, docid) { + return this.request.delete(`/projects/${projectId}/docs/${docid}/annotations`) + } + updateAnnotation(projectId, docId, annotationId, payload) { return this.request.patch(`/projects/${projectId}/docs/${docId}/annotations/${annotationId}`, payload) } diff --git a/frontend/services/document.service.js b/frontend/services/document.service.js index 8f72d8f0..e73b1a60 100644 --- a/frontend/services/document.service.js +++ b/frontend/services/document.service.js @@ -13,6 +13,10 @@ class DocumentService { return this.request.post(`/projects/${projectId}/docs`, payload) } + deleteAllDocuments(projectId) { + return this.request.delete(`/projects/${projectId}/docs`) + } + deleteDocument(projectId, docId) { return this.request.delete(`/projects/${projectId}/docs/${docId}`) } diff --git a/frontend/store/documents.js b/frontend/store/documents.js index 141afe42..36ce5f64 100644 --- a/frontend/store/documents.js +++ b/frontend/store/documents.js @@ -31,7 +31,6 @@ export const getters = { return state.items[state.current] } } - export const mutations = { setCurrent(state, payload) { state.current = payload @@ -67,6 +66,9 @@ export const mutations = { deleteAnnotation(state, annotationId) { state.items[state.current].annotations = state.items[state.current].annotations.filter(item => item.id !== annotationId) }, + clearAnnotations(state) { + state.items[state.current].annotations = [] + }, updateAnnotation(state, payload) { const item = state.items[state.current].annotations.find(item => item.id === payload.id) Object.assign(item, payload) @@ -88,7 +90,6 @@ export const mutations = { export const actions = { getDocumentList({ commit, state }, payload) { commit('setLoading', true) - // payload = Object.assign(payload, state.searchOptions) return DocumentService.getDocumentList(payload) .then((response) => { commit('setDocumentList', response.data.results) @@ -146,6 +147,17 @@ export const actions = { alert(error) }) }, + deleteAllDocuments({ commit, state }, projectId) { + DocumentService.deleteAllDocuments(projectId) + .then((response) => { + commit('setDocumentList', []) + commit('setTotalItems', 0) + commit('resetSelected') + }) + .catch((error) => { + alert(error) + }) + }, deleteDocument({ commit, state }, projectId) { for (const document of state.selected) { DocumentService.deleteDocument(projectId, document.id) @@ -188,6 +200,16 @@ export const actions = { alert(error) }) }, + clearAnnotations({ commit, state }, projectId) { + const documentId = state.items[state.current].id + AnnotationService.clearAnnotations(projectId, documentId) + .then((response) => { + commit('clearAnnotations') + }) + .catch((error) => { + alert(error) + }) + }, approve({ commit, getters }, payload) { const documentId = getters.currentDoc.id const data = {