@konfuzio/document-validation-ui 0.1.12-dev.0 → 0.1.12-dev.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@konfuzio/document-validation-ui",
3
- "version": "0.1.12-dev.0",
3
+ "version": "0.1.12-dev.2",
4
4
  "repository": "git://github.com:konfuzio-ai/document-validation-ui.git",
5
5
  "main": "dist/app.js",
6
6
  "scripts": {
@@ -253,7 +253,7 @@
253
253
  font-size: 14px;
254
254
  color: $primary;
255
255
 
256
- &.clicked {
256
+ &.clicked-ann {
257
257
  font-weight: 400;
258
258
  color: $text-lighter;
259
259
  }
@@ -6,12 +6,13 @@
6
6
  ref="contentEditable"
7
7
  :class="[
8
8
  'annotation-value',
9
+ 'keyboard-nav',
9
10
  isLoading && 'saving-changes',
10
11
  showActionError &&
11
12
  editAnnotation &&
12
13
  editAnnotation.id === annotation.id &&
13
14
  'error-editing',
14
- isAnnotationBeingEdited && 'clicked',
15
+ isAnnotationBeingEdited && 'clicked-ann',
15
16
  ]"
16
17
  role="textbox"
17
18
  :contenteditable="isAnnotationBeingEdited"
@@ -84,22 +85,10 @@ export default {
84
85
  },
85
86
 
86
87
  watch: {
87
- editAnnotation(newAnnotation, oldAnnotation) {
88
+ isAnnotationBeingEdited(newState, oldState) {
88
89
  // verify if new annotation in edit mode is not this one and if this
89
90
  // one was selected before so we set the state to the previous one (like a cancel)
90
-
91
- if (
92
- !newAnnotation &&
93
- oldAnnotation &&
94
- oldAnnotation.id === this.annotation.id
95
- ) {
96
- this.handleCancel(true);
97
- } else if (
98
- newAnnotation &&
99
- oldAnnotation &&
100
- newAnnotation.id === this.annotation.id &&
101
- newAnnotation.id !== oldAnnotation.id
102
- ) {
91
+ if (!newState && oldState) {
103
92
  this.handleCancel();
104
93
  }
105
94
  },
@@ -170,14 +159,8 @@ export default {
170
159
  }
171
160
  }
172
161
  },
173
- handleCancel(wasOutsideClick = false) {
174
- if (wasOutsideClick) {
175
- this.setText(this.span.offset_string);
176
- } else {
177
- this.$store.dispatch("selection/disableSelection");
178
- this.$store.dispatch("document/endLoading");
179
- }
180
-
162
+ handleCancel() {
163
+ this.setText(this.span.offset_string);
181
164
  this.isLoading = false;
182
165
  if (this.$refs.contentEditable) {
183
166
  this.$refs.contentEditable.blur();
@@ -352,12 +352,8 @@ export default {
352
352
  return label.annotations;
353
353
  });
354
354
 
355
- // Check if there are no annotations OR if there are annotations for the same label (grouped)
356
- if (
357
- annotations.length === 0 ||
358
- (this.label.annotations.length > 1 && this.enableGroupingFeature)
359
- )
360
- return;
355
+ // Check if there are no annotations
356
+ if (annotations.length === 0) return;
361
357
 
362
358
  const found = annotations.find(
363
359
  (ann) => ann.id === this.annotation.id && !ann.revised
@@ -17,7 +17,7 @@
17
17
  <EmptyState />
18
18
  </div>
19
19
 
20
- <div v-else :class="['annotation-set-list']">
20
+ <div v-else ref="annotationList" :class="['annotation-set-list']">
21
21
  <div
22
22
  v-if="Object.entries(annotationSetsInTable()).length > 0"
23
23
  class="annotation-set-group"
@@ -162,7 +162,6 @@ export default {
162
162
  }
163
163
  },
164
164
  acceptAnnotation(newValue, oldValue) {
165
- // TODO: rework this to be more generic
166
165
  if (!newValue && oldValue) {
167
166
  this.focusOnNextAnnotation();
168
167
  this.jumpToNextAnnotation = false;
@@ -177,9 +176,8 @@ export default {
177
176
  },
178
177
  methods: {
179
178
  focusOnNextAnnotation() {
180
- const annotations = Array.from(
181
- document.getElementsByClassName("annotation-value")
182
- );
179
+ const annotations = this.createArray("keyboard-nav");
180
+
183
181
  if (annotations[this.count]) {
184
182
  annotations[this.count].click();
185
183
  } else {
@@ -221,31 +219,36 @@ export default {
221
219
  }
222
220
  },
223
221
 
222
+ exitEditMode() {
223
+ this.count = 0;
224
+ this.$store.dispatch("document/resetEditAnnotation");
225
+ this.$store.dispatch("selection/disableSelection");
226
+ this.$store.dispatch("document/endLoading");
227
+ },
228
+
229
+ createArray(className) {
230
+ return Array.from(
231
+ this.$refs.annotationList.getElementsByClassName(className)
232
+ );
233
+ },
234
+
224
235
  keyDownHandler(event) {
225
236
  // only allow keyboard navigation if we are not in public view mode
226
237
  if (this.publicView || this.isDocumentReviewed) return;
227
238
 
228
- // get out of edit mode and navigation
239
+ // Exit edit mode and navigation
229
240
  if (event.key === "Escape") {
230
- this.count = 0;
231
- this.$store.dispatch("document/resetEditAnnotation");
232
- this.$store.dispatch("selection/disableSelection");
233
- this.$store.dispatch("document/endLoading");
241
+ this.exitEditMode();
234
242
  return;
235
243
  }
236
244
 
237
245
  // Not allow starting edit mode with ArrowUp key
238
246
  if (event.key === "ArrowUp" && !this.isAnnotationBeingEdited) return;
247
+ // Get all the annotation elements
248
+ let annotations = this.createArray("keyboard-nav");
239
249
 
240
- // Create an array from the elements selected
241
- // for easier management of data
242
- const annotations = Array.from(
243
- document.getElementsByClassName("annotation-value")
244
- );
245
250
  // Get clicked element to get the index
246
- const clickedAnnotations = Array.from(
247
- document.getElementsByClassName("clicked")
248
- );
251
+ const clickedAnnotations = this.createArray("clicked-ann");
249
252
 
250
253
  // get index of currently active element
251
254
  const currentAnnIndex = annotations.findIndex(
@@ -254,10 +257,10 @@ export default {
254
257
 
255
258
  // navigate with the arrow up or down keys
256
259
  if (event.key === "ArrowDown") {
260
+ // Check if we are focusing on the Finish Review button
257
261
  if (this.count >= annotations.length) {
258
- const finishBtn = Array.from(
259
- document.getElementsByClassName("finish-review-btn")
260
- );
262
+ const finishBtn = this.createArray("finish-review-btn");
263
+
261
264
  finishBtn[0].focus();
262
265
  this.$store.dispatch("document/resetEditAnnotation");
263
266
  this.count = 0;
@@ -275,24 +278,24 @@ export default {
275
278
  this.count = currentAnnIndex + 1;
276
279
  }
277
280
 
278
- // Skip missing annotations
279
- if (this.focusedAnnotationIsMarkedAsMissing(annotations, this.count)) {
280
- for (let i = this.count; i < annotations.length; i++) {
281
- if (!this.focusedAnnotationIsMarkedAsMissing(annotations, i)) {
282
- break;
283
- }
281
+ const nextElement = annotations[this.count];
282
+ if (nextElement.className.includes("label-group")) {
283
+ // open group and then click on annotation
284
+ // index is the same since group is removed from keyboard nav
285
+ nextElement.click();
286
+ this.$nextTick(() => {
287
+ annotations = this.createArray("keyboard-nav");
288
+ annotations[this.count].click();
289
+ this.scrollToFocusedAnnotationFromKeyHandler();
284
290
  this.count++;
285
- }
291
+ });
292
+ } else if (annotations[this.count]) {
293
+ annotations[this.count].click();
294
+ this.scrollToFocusedAnnotationFromKeyHandler();
295
+ this.count++;
286
296
  }
287
297
 
288
- if (!annotations[this.count]) return;
289
-
290
- annotations[this.count].click();
291
-
292
298
  // scroll to current annotation if not empty
293
- this.scrollToFocusedAnnotationFromKeyHandler();
294
-
295
- this.count++;
296
299
  } else if (event.key === "ArrowUp") {
297
300
  // Check if the event happened on the first element from the array
298
301
  // If so, reset count to 0
@@ -309,24 +312,27 @@ export default {
309
312
  this.count = currentAnnIndex - 1;
310
313
  }
311
314
 
312
- // Skip missing annotations
313
- if (this.focusedAnnotationIsMarkedAsMissing(annotations, this.count)) {
314
- for (let i = this.count; i < annotations.length; i--) {
315
- if (!this.focusedAnnotationIsMarkedAsMissing(annotations, i)) {
316
- break;
317
- }
315
+ const previousElement = annotations[this.count];
316
+ if (previousElement.className.includes("label-group")) {
317
+ // open group and then click on annotation
318
+ // index is the same since group is removed from keyboard nav
319
+ previousElement.click();
320
+ this.$nextTick(() => {
321
+ annotations = this.createArray("keyboard-nav");
322
+ // since we are going backwards, we need to go to the last annotation of group
323
+ const currentAnnIndex = annotations.findIndex(
324
+ (el) => el === clickedAnnotations[0]
325
+ );
326
+ this.count = currentAnnIndex - 1;
327
+ annotations[this.count].click();
328
+ this.scrollToFocusedAnnotationFromKeyHandler();
318
329
  this.count--;
319
- }
330
+ });
331
+ } else if (annotations[this.count]) {
332
+ annotations[this.count].click();
333
+ this.scrollToFocusedAnnotationFromKeyHandler();
334
+ this.count--;
320
335
  }
321
-
322
- if (!annotations[this.count]) return;
323
-
324
- annotations[this.count].click();
325
-
326
- // scroll to current annotation if not empty
327
- this.scrollToFocusedAnnotationFromKeyHandler();
328
-
329
- this.count--;
330
336
  } else {
331
337
  // Check for ENTER or DELETE
332
338
  // Accept annotation
@@ -358,10 +364,6 @@ export default {
358
364
  }
359
365
  },
360
366
 
361
- focusedAnnotationIsMarkedAsMissing(annotations, index) {
362
- return annotations[index].classList.value.includes("missing-annotation");
363
- },
364
-
365
367
  markAnnotationsAsMissing(label, labelSet, annotationSet, markAllMissing) {
366
368
  let missing;
367
369
 
@@ -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'"
@@ -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"
@@ -76,7 +79,7 @@ export default {
76
79
  },
77
80
  data() {
78
81
  return {
79
- isMultipleAnnotations: false,
82
+ nonMultipleAnnotationsExtracted: false,
80
83
  acceptedAnnotationsGroupCounter: 0,
81
84
  showAnnotationsGroup: false,
82
85
  };
@@ -85,6 +88,7 @@ export default {
85
88
  ...mapState("document", [
86
89
  "sidebarAnnotationSelected",
87
90
  "enableGroupingFeature",
91
+ "hoveredAnnotationSet",
88
92
  ]),
89
93
  ...mapGetters("document", ["numberOfAcceptedAnnotationsInLabel"]),
90
94
  singleAnnotation() {
@@ -121,6 +125,16 @@ export default {
121
125
  }
122
126
  }
123
127
  },
128
+ hoveredAnnotationSet(newValue) {
129
+ // Check if there are some unrevised Annotations within the group
130
+ if (
131
+ newValue &&
132
+ newValue.type === "accept" &&
133
+ this.labelHasPendingAnnotations(newValue)
134
+ ) {
135
+ this.showAnnotationsGroup = true;
136
+ }
137
+ },
124
138
  },
125
139
  mounted() {
126
140
  this.updateValues();
@@ -133,12 +147,23 @@ export default {
133
147
  this.showAnnotationsGroup = !this.showAnnotationsGroup;
134
148
  },
135
149
  updateValues() {
136
- this.isMultipleAnnotations = this.label.annotations.length > 1;
137
- if (this.isMultipleAnnotations) {
150
+ // more than 1 Annotation extracted for a non multiple Label
151
+ this.nonMultipleAnnotationsExtracted =
152
+ this.label.annotations.length > 1 &&
153
+ !this.label.has_multiple_top_candidates;
154
+
155
+ if (this.nonMultipleAnnotationsExtracted) {
138
156
  this.acceptedAnnotationsGroupCounter =
139
157
  this.numberOfAcceptedAnnotationsInLabel(this.label);
140
158
  }
141
159
  },
160
+ labelHasPendingAnnotations(hoveredSet) {
161
+ if (!hoveredSet) return;
162
+
163
+ const found = this.label.annotations.find((ann) => !ann.revised);
164
+
165
+ return this.annotationSet.id === hoveredSet.annotationSet.id && found;
166
+ },
142
167
  },
143
168
  };
144
169
  </script>
@@ -11,8 +11,9 @@
11
11
  editAnnotation.id === emptyAnnotationId() &&
12
12
  'error-editing',
13
13
  !isEmptyAnnotationEditable() && !isMissingAnnotation && 'label-empty',
14
- isAnnotationBeingEdited() && 'clicked',
14
+ isAnnotationBeingEdited() && 'clicked-ann',
15
15
  isMissingAnnotation && 'missing-annotation',
16
+ !isMissingAnnotation && 'keyboard-nav',
16
17
  ]"
17
18
  :contenteditable="isEmptyAnnotationEditable()"
18
19
  @keypress.enter="saveEmptyAnnotationChanges"
@@ -104,6 +104,33 @@ export default {
104
104
  if (!this.splitMode) {
105
105
  return this.categoryName(this.selectedDocument.category);
106
106
  } else {
107
+ const missingCategory = this.updatedDocument.find(
108
+ (item) => !item.category
109
+ );
110
+
111
+ // if there is just 1 category in the project,
112
+ // and one or more sub-documents has no category,
113
+ // assign the only category by default
114
+ if (this.projectHasSingleCategory() && missingCategory) {
115
+ const updatedValuesForDocuments = this.updatedDocument.map(
116
+ (document) => {
117
+ if (!document.category && this.categories) {
118
+ document.category = this.categories[0].id;
119
+ }
120
+
121
+ return document;
122
+ }
123
+ );
124
+
125
+ // update the store state
126
+ // so that if the changes are saved the data sent to the API is updated
127
+ // instead of only handling the category name in this component
128
+ this.$store.dispatch(
129
+ "edit/setUpdatedDocument",
130
+ updatedValuesForDocuments
131
+ );
132
+ }
133
+
107
134
  const categoryName = this.categoryName(
108
135
  this.updatedDocument[this.index].category
109
136
  );
@@ -1,14 +1,16 @@
1
1
  <template>
2
2
  <section class="document-error-modal">
3
- <b-modal v-model="isModalActive" :width="400">
3
+ <b-modal
4
+ v-model="isModalActive"
5
+ :width="400"
6
+ can-cancel="['x']"
7
+ :on-cancel="closeModal"
8
+ >
4
9
  <section class="modal-card-body">
5
10
  <div class="header">
6
11
  <div class="error-icon">
7
12
  <ErrorIcon class="icon" />
8
13
  </div>
9
- <div class="btn-container" type="button" @click="closeModal">
10
- <b-icon icon="xmark" class="close-btn" size="is-small" />
11
- </div>
12
14
  </div>
13
15
  <div class="content">
14
16
  <h3>{{ $t("document_error_title") }}</h3>
@@ -127,7 +127,7 @@ const margin = 12;
127
127
  const widthOfPopup = 205;
128
128
 
129
129
  import { mapGetters, mapState } from "vuex";
130
- import { ChooseLabelSetModal } from "../DocumentAnnotations";
130
+ import { MULTI_ANN_TABLE_FEATURE } from "../../constants";
131
131
 
132
132
  export default {
133
133
  props: {
@@ -271,7 +271,7 @@ export default {
271
271
  openAnnotationSetCreation() {
272
272
  this.$store.dispatch("display/showChooseLabelSetModal", {
273
273
  show: true,
274
- isMultipleAnnotations: true,
274
+ isMultipleAnnotations: MULTI_ANN_TABLE_FEATURE,
275
275
  finish: this.chooseLabelSet,
276
276
  });
277
277
  },
@@ -34,6 +34,7 @@ const state = {
34
34
  newAcceptedAnnotations: null,
35
35
  serverError: false,
36
36
  splittingSuggestions: null,
37
+ enableGroupingFeature: true,
37
38
  };
38
39
 
39
40
  const getters = {
@@ -247,14 +248,11 @@ const getters = {
247
248
  const labels = [];
248
249
  const processedAnnotationSets = annotationSets.map((annotationSet) => {
249
250
  const annotationSetLabels = annotationSet.labels.map((label) => {
250
- // filter label
251
- const filteredLabel = getters.annotationsInLabelFiltered(label);
252
-
253
251
  // add annotations to the document array
254
- annotations.push(...filteredLabel.annotations);
255
- labels.push(filteredLabel);
252
+ annotations.push(...label.annotations);
253
+ labels.push(label);
256
254
  // add labels to the labels array
257
- return filteredLabel;
255
+ return label;
258
256
  });
259
257
  annotationSet.labels = annotationSetLabels;
260
258
  return annotationSet;
@@ -475,12 +473,12 @@ const getters = {
475
473
  annotationsWithPendingReview.push(annotation);
476
474
  });
477
475
  }
478
- });
479
476
 
480
- // Check if we have grouped annotations by same label
481
- if (state.enableGroupingFeature && label.annotations.length < 2) {
482
- return annotationsWithPendingReview.length - label.annotations.length;
483
- }
477
+ // Check if we have grouped annotations by same label
478
+ if (state.enableGroupingFeature && label.annotations.length < 2) {
479
+ return annotationsWithPendingReview.length - label.annotations.length;
480
+ }
481
+ });
484
482
 
485
483
  return annotationsWithPendingReview.length;
486
484
  },