@konfuzio/document-validation-ui 0.1.14 → 0.1.16-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/README.md +12 -0
  2. package/cypress.config.js +13 -0
  3. package/dist/css/app.css +1 -1
  4. package/dist/index.html +1 -1
  5. package/dist/js/app.js +1 -1
  6. package/dist/js/app.js.map +1 -1
  7. package/dist/js/chunk-vendors.js +3 -3
  8. package/dist/js/chunk-vendors.js.map +1 -1
  9. package/package.json +5 -1
  10. package/src/api.js +53 -23
  11. package/src/assets/images/DraggableIcon.vue +14 -0
  12. package/src/assets/images/GridIcon.vue +16 -0
  13. package/src/assets/images/MagicWandIcon.vue +16 -0
  14. package/src/assets/images/NotFoundIcon.vue +16 -0
  15. package/src/assets/images/ServerImage.vue +19 -9
  16. package/src/assets/images/SettingsIcon.vue +14 -0
  17. package/src/assets/images/SplitZigZag.vue +47 -14
  18. package/src/assets/images/StarIcon.vue +16 -0
  19. package/src/assets/scss/ann_set_table_options.scss +26 -0
  20. package/src/assets/scss/annotation_details.scss +86 -71
  21. package/src/assets/scss/choose_label_set_modal.scss +1 -1
  22. package/src/assets/scss/document_annotations.scss +242 -229
  23. package/src/assets/scss/document_category.scss +12 -7
  24. package/src/assets/scss/document_dashboard.scss +7 -2
  25. package/src/assets/scss/document_edit.scss +151 -173
  26. package/src/assets/scss/document_name.scss +0 -2
  27. package/src/assets/scss/document_thumbnails.scss +1 -1
  28. package/src/assets/scss/document_toolbar.scss +23 -1
  29. package/src/assets/scss/document_top_bar.scss +40 -1
  30. package/src/assets/scss/edit_page_thumbnail.scss +53 -0
  31. package/src/assets/scss/multi_ann_table_overlay.scss +38 -0
  32. package/src/assets/scss/new_annotation.scss +17 -3
  33. package/src/assets/scss/scrolling_document.scss +1 -1
  34. package/src/assets/scss/theme.scss +801 -0
  35. package/src/assets/scss/variables.scss +5 -663
  36. package/src/components/App.cy.js +7 -0
  37. package/src/components/App.vue +98 -11
  38. package/src/components/DocumentAnnotations/AnnotationActionButtons.vue +168 -0
  39. package/src/components/DocumentAnnotations/AnnotationContent.vue +50 -84
  40. package/src/components/DocumentAnnotations/AnnotationDetails.vue +37 -12
  41. package/src/components/DocumentAnnotations/AnnotationRow.vue +244 -199
  42. package/src/components/DocumentAnnotations/AnnotationSetActionButtons.vue +89 -0
  43. package/src/components/DocumentAnnotations/ChooseLabelSetModal.vue +4 -2
  44. package/src/components/DocumentAnnotations/DocumentAnnotations.cy.js +295 -0
  45. package/src/components/DocumentAnnotations/DocumentAnnotations.vue +195 -146
  46. package/src/components/DocumentAnnotations/DocumentLabel.vue +46 -9
  47. package/src/components/DocumentAnnotations/EmptyAnnotation.vue +59 -88
  48. package/src/components/DocumentAnnotations/ExtractingData.vue +18 -6
  49. package/src/components/DocumentAnnotations/MultiAnnotationTableOverlay.vue +337 -0
  50. package/src/components/DocumentAnnotations/index.js +1 -1
  51. package/src/components/DocumentCategory.vue +89 -65
  52. package/src/components/DocumentDashboard.vue +59 -48
  53. package/src/components/DocumentEdit/DocumentEdit.vue +302 -105
  54. package/src/components/DocumentEdit/EditConfirmationModal.vue +55 -0
  55. package/src/components/DocumentEdit/EditPageThumbnail.vue +114 -0
  56. package/src/components/DocumentEdit/EditPages.vue +60 -103
  57. package/src/components/DocumentEdit/EditSidebar.vue +101 -48
  58. package/src/components/DocumentEdit/{SplitOverview.vue → RenameAndCategorize.vue} +15 -13
  59. package/src/components/DocumentEdit/SidebarButtons.vue +53 -0
  60. package/src/components/DocumentEdit/SplitInfoBar.vue +21 -0
  61. package/src/components/DocumentEdit/index.js +1 -1
  62. package/src/components/{DocumentError.vue → DocumentModals/DocumentErrorModal.vue} +9 -8
  63. package/src/components/{NotOptimizedViewportModal.vue → DocumentModals/NotOptimizedViewportModal.vue} +2 -2
  64. package/src/components/DocumentPage/ActionBar.vue +3 -3
  65. package/src/components/DocumentPage/AnnSetTableOptions.vue +110 -0
  66. package/src/components/DocumentPage/BoxSelection.vue +4 -1
  67. package/src/components/DocumentPage/DocumentPage.vue +92 -68
  68. package/src/components/DocumentPage/DocumentToolbar.vue +105 -16
  69. package/src/components/DocumentPage/DummyPage.vue +9 -7
  70. package/src/components/DocumentPage/MultiAnnSelection.vue +96 -27
  71. package/src/components/DocumentPage/NewAnnotation.vue +31 -35
  72. package/src/components/DocumentPage/ScrollingDocument.vue +46 -5
  73. package/src/components/DocumentPage/ScrollingPage.vue +5 -6
  74. package/src/components/DocumentThumbnails/DocumentThumbnails.cy.js +64 -0
  75. package/src/components/DocumentThumbnails/DocumentThumbnails.vue +53 -13
  76. package/src/components/DocumentTopBar/DocumentName.vue +16 -4
  77. package/src/components/DocumentTopBar/DocumentTopBar.vue +86 -15
  78. package/src/components/DocumentTopBar/DocumentTopBarButtons.vue +99 -72
  79. package/src/components/DocumentTopBar/KeyboardActionsDescription.vue +6 -3
  80. package/src/components/DocumentsList/DocumentsList.vue +6 -2
  81. package/src/components/index.js +1 -0
  82. package/src/constants.js +2 -1
  83. package/src/icons.js +45 -0
  84. package/src/locales/de.json +48 -21
  85. package/src/locales/en.json +37 -11
  86. package/src/locales/es.json +41 -13
  87. package/src/main.js +5 -66
  88. package/src/store/category.js +20 -36
  89. package/src/store/display.js +74 -1
  90. package/src/store/document.js +305 -109
  91. package/src/store/edit.js +160 -61
  92. package/src/store/project.js +46 -16
  93. package/src/store/selection.js +42 -10
  94. package/src/utils/utils.js +36 -0
  95. package/dist/css/chunk-vendors.css +0 -5
  96. package/src/.DS_Store +0 -0
  97. package/src/assets/scss/categorize_modal.scss +0 -45
  98. package/src/assets/scss/main.scss +0 -24
  99. package/src/components/DocumentAnnotations/ActionButtons.vue +0 -250
  100. package/src/components/DocumentAnnotations/CategorizeModal.vue +0 -219
  101. package/src/components/DocumentAnnotations/RejectedLabels.vue +0 -96
  102. package/src/components/DocumentPage/MultiAnnotationTablePopup.vue +0 -253
@@ -1,33 +1,48 @@
1
1
  <template>
2
- <div class="labels-sidebar">
2
+ <div id="labels-sidebar">
3
3
  <!-- When extracting annotations after editing -->
4
- <div v-if="recalculatingAnnotations">
4
+ <div v-if="recalculatingAnnotations" class="extracting-data">
5
5
  <ExtractingData />
6
6
  </div>
7
7
 
8
8
  <!-- When document data is still loading -->
9
- <div v-else-if="!annotationSets || loading">
10
- <div v-for="n in numberOfLoadingAnnotations" :key="n">
9
+ <div v-else-if="!annotationSets || loading" class="document-annotations-loading">
10
+ <div v-for="n in numberOfLoadingAnnotations" :key="n" class="loading-annotation-set">
11
11
  <LoadingAnnotations />
12
12
  </div>
13
13
  </div>
14
14
 
15
15
  <!-- When there's no annotations in the label -->
16
- <div v-else-if="annotationSets.length === 0">
17
- <CategorizeModal v-if="!publicView" />
16
+ <div v-else-if="annotationSets.length === 0" class="empty-annotation-sets">
18
17
  <EmptyState />
19
18
  </div>
20
19
 
21
- <div
22
- v-else
23
- :class="[
24
- 'annotation-set-list',
25
- missingAnnotations.length && !publicView && 'showing-rejected',
26
- ]"
27
- >
28
- <CategorizeModal v-if="!publicView" />
20
+ <div v-else ref="annotationList" :class="['annotation-set-list']">
29
21
  <div
30
- v-for="(annotationSet, indexGroup) in annotationSets"
22
+ v-if="Object.entries(annotationSetsInTable()).length > 0"
23
+ class="annotation-set-group"
24
+ >
25
+ <div class="label-set-header">
26
+ <div class="label-set-name">{{ $t("table") }}</div>
27
+ </div>
28
+ <div
29
+ v-for="(tableSet, index) in Object.values(annotationSetsInTable())"
30
+ :key="index"
31
+ class="ann-set-table"
32
+ @click="openAnnotationSetTable(tableSet)"
33
+ >
34
+ <div class="ann-set-table-icon">
35
+ <GridIcon /><span class="ann-set-number">{{
36
+ tableSet.length
37
+ }}</span>
38
+ </div>
39
+ <span class="ann-set-table-label-set-name">{{
40
+ tableSet[0].label_set.name
41
+ }}</span>
42
+ </div>
43
+ </div>
44
+ <div
45
+ v-for="(annotationSet, indexGroup) in annotationSetsToShowInList()"
31
46
  :key="indexGroup"
32
47
  class="annotation-set-group"
33
48
  >
@@ -39,19 +54,29 @@
39
54
  )}`
40
55
  }}
41
56
  </div>
42
- <div class="labelset-action-buttons">
43
- <ActionButtons
44
- :reject-all-empty-btn="true"
45
- :annotation-set="annotationSet"
46
- :accept-all-btn="true"
47
- @reject-all-empty="
48
- rejectMissingAnnotations(null, null, annotationSet, true)
57
+ <div
58
+ v-if="annotationSet.labels.length !== 0"
59
+ class="labelset-action-buttons"
60
+ >
61
+ <AnnotationSetActionButtons
62
+ :number-of-empty-labels-in-annotation-set="
63
+ emptyLabelsLength(annotationSet)
64
+ "
65
+ :number-of-pending-annotations-in-annotation-set="
66
+ annotationsWithPendingReviewLength(annotationSet)
49
67
  "
50
- @hover-annotation-set-to-reject="
51
- handleHoverAnnotationSet(annotationSet, 'reject')
68
+ @mark-all-empty-missing="
69
+ markAnnotationsAsMissing(null, null, annotationSet, true)
70
+ "
71
+ @hover-annotation-set-to-mark-missing="
72
+ handleHoverAnnotationSet(annotationSet, 'missing')
73
+ "
74
+ @leave-annotation-set-to-mark-missing="
75
+ handleHoverAnnotationSet(null)
76
+ "
77
+ @accept-all-pending-annotations="
78
+ acceptPendingAnnotationsInAnnotationSet(annotationSet)
52
79
  "
53
- @leave-annotation-set-to-reject="handleHoverAnnotationSet(null)"
54
- @accept-group="acceptGroup(annotationSet)"
55
80
  @hover-annotation-set-to-accept="
56
81
  handleHoverAnnotationSet(annotationSet, 'accept')
57
82
  "
@@ -60,24 +85,34 @@
60
85
  </div>
61
86
  </div>
62
87
 
63
- <div v-for="label in annotationSet.labels" :key="label.id">
64
- <div v-if="labelNotRejected(annotationSet, label)" class="labels">
65
- <DocumentLabel
66
- :label="label"
67
- :annotation-set="annotationSet"
68
- :index-group="indexGroup"
69
- @handle-reject="rejectMissingAnnotations"
70
- />
88
+ <div v-if="annotationSet.labels.length > 0">
89
+ <div v-for="label in annotationSet.labels" :key="label.id">
90
+ <div
91
+ v-if="!(label.annotations.length === 0 && publicView)"
92
+ class="labels"
93
+ >
94
+ <DocumentLabel
95
+ :label="label"
96
+ :annotation-set="annotationSet"
97
+ :index-group="indexGroup"
98
+ @handle-missing-annotation="markAnnotationsAsMissing"
99
+ />
100
+ </div>
71
101
  </div>
72
102
  </div>
73
- </div>
74
- </div>
75
103
 
76
- <div
77
- v-if="!publicView && missingAnnotations.length"
78
- class="rejected-labels-list"
79
- >
80
- <RejectedLabels :missing-annotations="missingAnnotations" />
104
+ <div v-if="annotationSet.labels.length === 0" class="no-labels">
105
+ <span> {{ $t("no_labels_in_set") }}</span>
106
+ <span v-if="!publicView" v-html="$t('link_to_add_labels')"></span>
107
+ </div>
108
+
109
+ <div
110
+ v-else-if="!annotationSetHasAnnotations(annotationSet) && publicView"
111
+ class="no-labels"
112
+ >
113
+ <span> {{ $t("no_annotations_in_annotation_set") }}</span>
114
+ </div>
115
+ </div>
81
116
  </div>
82
117
  </div>
83
118
  </template>
@@ -85,11 +120,10 @@
85
120
  import { mapGetters, mapState } from "vuex";
86
121
  import EmptyState from "./EmptyState";
87
122
  import ExtractingData from "./ExtractingData";
88
- import ActionButtons from "./ActionButtons";
123
+ import AnnotationSetActionButtons from "./AnnotationSetActionButtons";
89
124
  import DocumentLabel from "./DocumentLabel";
90
- import RejectedLabels from "./RejectedLabels";
91
125
  import LoadingAnnotations from "./LoadingAnnotations";
92
- import CategorizeModal from "./CategorizeModal";
126
+ import GridIcon from "../../assets/images/GridIcon";
93
127
 
94
128
  /**
95
129
  * This component loads all annotations for one document
@@ -98,11 +132,10 @@ export default {
98
132
  components: {
99
133
  EmptyState,
100
134
  ExtractingData,
101
- ActionButtons,
135
+ AnnotationSetActionButtons,
102
136
  DocumentLabel,
103
- RejectedLabels,
104
137
  LoadingAnnotations,
105
- CategorizeModal,
138
+ GridIcon,
106
139
  },
107
140
  data() {
108
141
  return {
@@ -112,6 +145,7 @@ export default {
112
145
  };
113
146
  },
114
147
  computed: {
148
+ ...mapState("display", ["showAnnSetTable"]),
115
149
  ...mapState("document", [
116
150
  "documentId",
117
151
  "recalculatingAnnotations",
@@ -123,9 +157,17 @@ export default {
123
157
  "loading",
124
158
  "labels",
125
159
  "selectedDocument",
160
+ "splittingSuggestions",
126
161
  ]),
127
162
  ...mapGetters("category", ["category"]),
128
- ...mapGetters("document", ["numberOfAnnotationSetGroup"]),
163
+ ...mapGetters("document", [
164
+ "numberOfAnnotationSetGroup",
165
+ "emptyLabelsLength",
166
+ "annotationsWithPendingReviewLength",
167
+ "annotationSetsToShowInList",
168
+ "annotationSetsInTable",
169
+ "isDocumentReviewed",
170
+ ]),
129
171
  isAnnotationBeingEdited() {
130
172
  return this.editAnnotation && this.editAnnotation.id;
131
173
  },
@@ -137,7 +179,6 @@ export default {
137
179
  }
138
180
  },
139
181
  acceptAnnotation(newValue, oldValue) {
140
- // TODO: rework this to be more generic
141
182
  if (!newValue && oldValue) {
142
183
  this.focusOnNextAnnotation();
143
184
  this.jumpToNextAnnotation = false;
@@ -151,23 +192,17 @@ export default {
151
192
  window.removeEventListener("keydown", this.keyDownHandler);
152
193
  },
153
194
  methods: {
154
- showMissingAnnotations() {
155
- if (
156
- (this.publicView &&
157
- this.selectedDocument &&
158
- this.selectedDocument.is_reviewed) ||
159
- !this.publicView
160
- ) {
161
- return true;
162
- } else {
163
- return false;
164
- }
195
+ annotationSetHasAnnotations(annotationSet) {
196
+ const found = annotationSet.labels.find(
197
+ (label) => label.annotations.length > 0
198
+ );
199
+
200
+ return found;
165
201
  },
166
202
 
167
203
  focusOnNextAnnotation() {
168
- const annotations = Array.from(
169
- document.getElementsByClassName("annotation-value")
170
- );
204
+ const annotations = this.createArray("keyboard-nav");
205
+
171
206
  if (annotations[this.count]) {
172
207
  annotations[this.count].click();
173
208
  } else {
@@ -209,31 +244,36 @@ export default {
209
244
  }
210
245
  },
211
246
 
247
+ exitEditMode() {
248
+ this.count = 0;
249
+ this.$store.dispatch("document/resetEditAnnotation");
250
+ this.$store.dispatch("selection/disableSelection");
251
+ this.$store.dispatch("document/endLoading");
252
+ },
253
+
254
+ createArray(className) {
255
+ return Array.from(
256
+ this.$refs.annotationList.getElementsByClassName(className)
257
+ );
258
+ },
259
+
212
260
  keyDownHandler(event) {
213
261
  // only allow keyboard navigation if we are not in public view mode
214
- if (this.publicView) return;
262
+ if (this.publicView || this.isDocumentReviewed) return;
215
263
 
216
- // get out of edit mode and navigation
264
+ // Exit edit mode and navigation
217
265
  if (event.key === "Escape") {
218
- this.count = 0;
219
- this.$store.dispatch("document/resetEditAnnotation");
220
- this.$store.dispatch("selection/disableSelection");
221
- this.$store.dispatch("document/endLoading");
266
+ this.exitEditMode();
222
267
  return;
223
268
  }
224
269
 
225
270
  // Not allow starting edit mode with ArrowUp key
226
271
  if (event.key === "ArrowUp" && !this.isAnnotationBeingEdited) return;
272
+ // Get all the annotation elements
273
+ let annotations = this.createArray("keyboard-nav");
227
274
 
228
- // Create an array from the elements selected
229
- // for easier management of data
230
- const annotations = Array.from(
231
- document.getElementsByClassName("annotation-value")
232
- );
233
275
  // Get clicked element to get the index
234
- const clickedAnnotations = Array.from(
235
- document.getElementsByClassName("clicked")
236
- );
276
+ const clickedAnnotations = this.createArray("clicked-ann");
237
277
 
238
278
  // get index of currently active element
239
279
  const currentAnnIndex = annotations.findIndex(
@@ -242,10 +282,10 @@ export default {
242
282
 
243
283
  // navigate with the arrow up or down keys
244
284
  if (event.key === "ArrowDown") {
285
+ // Check if we are focusing on the Finish Review button
245
286
  if (this.count >= annotations.length) {
246
- const finishBtn = Array.from(
247
- document.getElementsByClassName("finish-review-btn")
248
- );
287
+ const finishBtn = this.createArray("finish-review-btn");
288
+
249
289
  finishBtn[0].focus();
250
290
  this.$store.dispatch("document/resetEditAnnotation");
251
291
  this.count = 0;
@@ -263,12 +303,24 @@ export default {
263
303
  this.count = currentAnnIndex + 1;
264
304
  }
265
305
 
266
- annotations[this.count].click();
306
+ const nextElement = annotations[this.count];
307
+ if (nextElement.className.includes("label-group")) {
308
+ // open group and then click on annotation
309
+ // index is the same since group is removed from keyboard nav
310
+ nextElement.click();
311
+ this.$nextTick(() => {
312
+ annotations = this.createArray("keyboard-nav");
313
+ annotations[this.count].click();
314
+ this.scrollToFocusedAnnotationFromKeyHandler();
315
+ this.count++;
316
+ });
317
+ } else if (annotations[this.count]) {
318
+ annotations[this.count].click();
319
+ this.scrollToFocusedAnnotationFromKeyHandler();
320
+ this.count++;
321
+ }
267
322
 
268
323
  // scroll to current annotation if not empty
269
- this.scrollToFocusedAnnotationFromKeyHandler();
270
-
271
- this.count++;
272
324
  } else if (event.key === "ArrowUp") {
273
325
  // Check if the event happened on the first element from the array
274
326
  // If so, reset count to 0
@@ -285,12 +337,27 @@ export default {
285
337
  this.count = currentAnnIndex - 1;
286
338
  }
287
339
 
288
- annotations[this.count].click();
289
-
290
- // scroll to current annotation if not empty
291
- this.scrollToFocusedAnnotationFromKeyHandler();
292
-
293
- this.count--;
340
+ const previousElement = annotations[this.count];
341
+ if (previousElement.className.includes("label-group")) {
342
+ // open group and then click on annotation
343
+ // index is the same since group is removed from keyboard nav
344
+ previousElement.click();
345
+ this.$nextTick(() => {
346
+ annotations = this.createArray("keyboard-nav");
347
+ // since we are going backwards, we need to go to the last annotation of group
348
+ const currentAnnIndex = annotations.findIndex(
349
+ (el) => el === clickedAnnotations[0]
350
+ );
351
+ this.count = currentAnnIndex - 1;
352
+ annotations[this.count].click();
353
+ this.scrollToFocusedAnnotationFromKeyHandler();
354
+ this.count--;
355
+ });
356
+ } else if (annotations[this.count]) {
357
+ annotations[this.count].click();
358
+ this.scrollToFocusedAnnotationFromKeyHandler();
359
+ this.count--;
360
+ }
294
361
  } else {
295
362
  // Check for ENTER or DELETE
296
363
  // Accept annotation
@@ -311,9 +378,9 @@ export default {
311
378
  annotations[currentAnnIndex].className.includes("label-empty") &&
312
379
  annotations[currentAnnIndex].className.includes("clicked")
313
380
  ) {
314
- // Reject annotation
381
+ // Mark annotation as missing
315
382
  if (this.editAnnotation.id === annotations[currentAnnIndex].id) {
316
- this.rejectMissingAnnotations();
383
+ this.markAnnotationsAsMissing();
317
384
  }
318
385
  this.jumpToNextAnnotation = true;
319
386
  } else {
@@ -322,45 +389,13 @@ export default {
322
389
  }
323
390
  },
324
391
 
325
- labelNotRejected(annotationSet, label) {
326
- // Check if the combined label and label set have been rejected
327
- // or if the document is in public mode
328
- if (
329
- this.missingAnnotations.length === 0 ||
330
- !this.showMissingAnnotations()
331
- ) {
332
- return true;
333
- } else {
334
- let found;
335
-
336
- if (annotationSet && annotationSet.id) {
337
- found = this.missingAnnotations.filter(
338
- (el) =>
339
- el.label === label.id && el.annotation_set === annotationSet.id
340
- );
341
- } else {
342
- found = this.missingAnnotations.filter(
343
- (el) =>
344
- el.label === label.id &&
345
- el.label_set === annotationSet.label_set.id
346
- );
347
- }
348
-
349
- if (found.length !== 0) {
350
- return false;
351
- } else {
352
- return true;
353
- }
354
- }
355
- },
356
-
357
- rejectMissingAnnotations(label, labelSet, annotationSet, rejectAll) {
358
- let rejected;
392
+ markAnnotationsAsMissing(label, labelSet, annotationSet, markAllMissing) {
393
+ let missing;
359
394
 
360
- if (label && labelSet && !rejectAll) {
361
- // if single rejection is triggered by clicking the button
395
+ if (label && labelSet && !markAllMissing) {
396
+ // if annotation is marked as missing by clicking the button
362
397
 
363
- rejected = [
398
+ missing = [
364
399
  {
365
400
  document: parseInt(this.documentId),
366
401
  label: label,
@@ -369,24 +404,26 @@ export default {
369
404
  },
370
405
  ];
371
406
  } else if (this.editAnnotation && this.editAnnotation.id !== null) {
372
- // if single rejection is triggered from "delete" key
407
+ // if annotation is marked as missing from "delete" key
373
408
 
374
- rejected = {
375
- document: parseInt(this.documentId),
376
- label: this.editAnnotation.label,
377
- label_set: this.editAnnotation.labelSet,
378
- annotation_set: this.editAnnotation.annotationSet,
379
- };
380
- } else if (annotationSet && rejectAll) {
381
- // reject all labels in annotation set
409
+ missing = [
410
+ {
411
+ document: parseInt(this.documentId),
412
+ label: this.editAnnotation.label,
413
+ label_set: this.editAnnotation.labelSet,
414
+ annotation_set: this.editAnnotation.annotationSet,
415
+ },
416
+ ];
417
+ } else if (annotationSet && markAllMissing) {
418
+ // mark all annotations as missing in annotation set
382
419
 
383
420
  const allEmptyLabels = annotationSet.labels.filter(
384
421
  (label) => label.annotations.length === 0
385
422
  );
386
423
 
387
- // Check if any of the empty annotations was already rejected individually
424
+ // Check if any of the empty annotations was already marked as missing individually
388
425
  // and remove them
389
- const toReject = [];
426
+ const toMarkAsMissing = [];
390
427
 
391
428
  allEmptyLabels.map((label) => {
392
429
  const found = this.missingAnnotations.find(
@@ -397,11 +434,11 @@ export default {
397
434
  );
398
435
 
399
436
  if (!found) {
400
- toReject.push(label);
437
+ toMarkAsMissing.push(label);
401
438
  }
402
439
  });
403
440
 
404
- rejected = toReject.map((label) => {
441
+ missing = toMarkAsMissing.map((label) => {
405
442
  return {
406
443
  document: parseInt(this.documentId),
407
444
  label: label.id,
@@ -411,10 +448,10 @@ export default {
411
448
  });
412
449
  }
413
450
 
414
- this.$store.dispatch("document/setRejectedMissingAnnotations", rejected);
451
+ this.$store.dispatch("document/setAnnotationsMarkedAsMissing", missing);
415
452
 
416
453
  this.$store
417
- .dispatch("document/addMissingAnnotations", rejected)
454
+ .dispatch("document/addMissingAnnotations", missing)
418
455
  .then((response) => {
419
456
  if (response) {
420
457
  this.jumpToNextAnnotation = true;
@@ -430,7 +467,9 @@ export default {
430
467
  });
431
468
  })
432
469
  .finally(() => {
433
- this.$store.dispatch("document/setRejectedMissingAnnotations", null);
470
+ this.$store.dispatch("document/setAnnotationsMarkedAsMissing", null);
471
+ this.$store.dispatch("document/resetEditAnnotation");
472
+ this.$store.dispatch("selection/disableSelection");
434
473
  });
435
474
  },
436
475
 
@@ -449,7 +488,7 @@ export default {
449
488
  this.$store.dispatch("document/setHoveredAnnotationSet", hovered);
450
489
  },
451
490
 
452
- acceptGroup(annotationSet) {
491
+ acceptPendingAnnotationsInAnnotationSet(annotationSet) {
453
492
  const annotationsToAccept = [];
454
493
 
455
494
  annotationSet.labels.map((label) => {
@@ -480,6 +519,16 @@ export default {
480
519
  });
481
520
  }
482
521
  },
522
+
523
+ openAnnotationSetTable(tableSet) {
524
+ this.$store.dispatch("selection/disableSelection");
525
+ this.$store.dispatch("document/resetEditAnnotation");
526
+ if (this.showAnnSetTable && this.showAnnSetTable === tableSet) {
527
+ this.$store.dispatch("display/toggleAnnSetTable", tableSet);
528
+ } else {
529
+ this.$store.dispatch("display/showAnnSetTable", tableSet);
530
+ }
531
+ },
483
532
  },
484
533
  };
485
534
  </script>
@@ -1,7 +1,10 @@
1
1
  <template>
2
2
  <div class="label">
3
- <div v-if="enableGroupingFeature && isMultipleAnnotations">
4
- <div class="label-group" @click.stop="toggleGroup">
3
+ <div v-if="enableGroupingFeature && nonMultipleAnnotationsExtracted">
4
+ <div
5
+ :class="['label-group', !showAnnotationsGroup && 'keyboard-nav']"
6
+ @click.stop="toggleGroup"
7
+ >
5
8
  <div class="label-group-left">
6
9
  <b-icon
7
10
  :icon="showAnnotationsGroup ? 'angle-up' : 'angle-down'"
@@ -12,14 +15,14 @@
12
15
  </div>
13
16
  </div>
14
17
  <div class="label-group-right">
15
- <div class="label-annotations-pending">
18
+ <div v-if="!publicView" class="label-annotations-pending" >
16
19
  {{
17
20
  `${
18
21
  label.annotations.length - acceptedAnnotationsGroupCounter
19
22
  } ${$t("annotations_pending")}`
20
23
  }}
21
24
  </div>
22
- <div class="label-annotations-accepted">
25
+ <div v-if="!publicView" class="label-annotations-accepted">
23
26
  {{
24
27
  `${acceptedAnnotationsGroupCounter} ${$t("annotations_accepted")}`
25
28
  }}
@@ -36,7 +39,7 @@
36
39
  />
37
40
  </div>
38
41
  </div>
39
- <div v-else-if="!enableGroupingFeature && hasAnnotations">
42
+ <div v-else-if="hasAnnotations">
40
43
  <AnnotationRow
41
44
  v-for="annotation in label.annotations"
42
45
  :key="annotation.id"
@@ -66,15 +69,17 @@ export default {
66
69
  components: { AnnotationRow },
67
70
  props: {
68
71
  label: {
72
+ type: Object,
69
73
  required: true,
70
74
  },
71
75
  annotationSet: {
76
+ type: Object,
72
77
  required: true,
73
78
  },
74
79
  },
75
80
  data() {
76
81
  return {
77
- isMultipleAnnotations: false,
82
+ nonMultipleAnnotationsExtracted: false,
78
83
  acceptedAnnotationsGroupCounter: 0,
79
84
  showAnnotationsGroup: false,
80
85
  };
@@ -83,6 +88,8 @@ export default {
83
88
  ...mapState("document", [
84
89
  "sidebarAnnotationSelected",
85
90
  "enableGroupingFeature",
91
+ "hoveredAnnotationSet",
92
+ "publicView",
86
93
  ]),
87
94
  ...mapGetters("document", ["numberOfAcceptedAnnotationsInLabel"]),
88
95
  singleAnnotation() {
@@ -103,9 +110,18 @@ export default {
103
110
  !this.showAnnotationsGroup &&
104
111
  newSidebarAnnotationSelected
105
112
  ) {
113
+ let annotationSelected;
114
+
115
+ if (newSidebarAnnotationSelected.annotation) {
116
+ annotationSelected = newSidebarAnnotationSelected.annotation;
117
+ } else {
118
+ annotationSelected = newSidebarAnnotationSelected;
119
+ }
120
+
106
121
  const annotation = this.label.annotations.find(
107
- (ann) => ann.id === newSidebarAnnotationSelected.id
122
+ (ann) => ann.id === annotationSelected.id
108
123
  );
124
+
109
125
  if (annotation) {
110
126
  this.showAnnotationsGroup = true;
111
127
  this.$store.dispatch("document/setSidebarAnnotationSelected", null);
@@ -119,6 +135,16 @@ export default {
119
135
  }
120
136
  }
121
137
  },
138
+ hoveredAnnotationSet(newValue) {
139
+ // Check if there are some unrevised Annotations within the group
140
+ if (
141
+ newValue &&
142
+ newValue.type === "accept" &&
143
+ this.labelHasPendingAnnotations(newValue)
144
+ ) {
145
+ this.showAnnotationsGroup = true;
146
+ }
147
+ },
122
148
  },
123
149
  mounted() {
124
150
  this.updateValues();
@@ -131,12 +157,23 @@ export default {
131
157
  this.showAnnotationsGroup = !this.showAnnotationsGroup;
132
158
  },
133
159
  updateValues() {
134
- this.isMultipleAnnotations = this.label.annotations.length > 1;
135
- if (this.isMultipleAnnotations) {
160
+ // more than 1 Annotation extracted for a non multiple Label
161
+ this.nonMultipleAnnotationsExtracted =
162
+ this.label.annotations.length > 1 &&
163
+ !this.label.has_multiple_top_candidates;
164
+
165
+ if (this.nonMultipleAnnotationsExtracted) {
136
166
  this.acceptedAnnotationsGroupCounter =
137
167
  this.numberOfAcceptedAnnotationsInLabel(this.label);
138
168
  }
139
169
  },
170
+ labelHasPendingAnnotations(hoveredSet) {
171
+ if (!hoveredSet) return;
172
+
173
+ const found = this.label.annotations.find((ann) => !ann.revised);
174
+
175
+ return this.annotationSet.id === hoveredSet.annotationSet.id && found;
176
+ },
140
177
  },
141
178
  };
142
179
  </script>