@konfuzio/document-validation-ui 0.1.22-dev.0 → 0.1.22-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.22-dev.0",
3
+ "version": "0.1.22-dev.2",
4
4
  "repository": "git://github.com:konfuzio-ai/document-validation-ui.git",
5
5
  "main": "dist/app.js",
6
6
  "scripts": {
@@ -51,6 +51,7 @@
51
51
 
52
52
  .annotation-set-group {
53
53
  .label-set-header {
54
+ cursor: pointer;
54
55
  display: flex;
55
56
  align-items: center;
56
57
  justify-content: space-between;
@@ -66,6 +67,14 @@
66
67
  font-size: 14px;
67
68
  line-height: 20px;
68
69
  color: $text;
70
+ display: flex;
71
+ align-items: center;
72
+ gap: 8px;
73
+
74
+ .icon {
75
+ width: 12px;
76
+ height: 12px;
77
+ }
69
78
  }
70
79
  }
71
80
 
@@ -300,32 +300,22 @@ export default {
300
300
  ) {
301
301
  clearTimeout(this.annotationAnimationTimeout);
302
302
 
303
- let timeout;
304
-
305
- if (!newSidebarAnnotationSelected.trigger) {
306
- timeout = 600;
307
- } else {
308
- timeout = 1200;
309
- }
310
-
311
303
  this.isSelected = true;
312
304
  // remove annotation selection after some time
313
305
  this.annotationAnimationTimeout = setTimeout(() => {
314
306
  this.$store.dispatch("document/setSidebarAnnotationSelected", null);
315
307
  this.isSelected = false;
316
- }, timeout);
308
+ }, 1200);
317
309
 
318
310
  // Check if sidebarAnnotationSelected changed from a click or hover
319
- if (newSidebarAnnotationSelected.trigger === "click") {
320
- const runAnimation = () => {
321
- this.$el.scrollIntoView({
322
- behavior: "smooth",
323
- block: "center",
324
- inline: "nearest",
325
- });
326
- };
327
- runAnimation();
328
- }
311
+ const runAnimation = () => {
312
+ this.$el.scrollIntoView({
313
+ behavior: "smooth",
314
+ block: "center",
315
+ inline: "nearest",
316
+ });
317
+ };
318
+ runAnimation();
329
319
  }
330
320
  },
331
321
  editAnnotation(newValue) {
@@ -49,12 +49,22 @@
49
49
  </div>
50
50
  </div>
51
51
  <div
52
- v-for="(annotationSet, indexGroup) in annotationSetsToShowInList()"
52
+ v-for="(annotationSet, indexGroup) in annotationSets"
53
53
  :key="indexGroup"
54
- class="annotation-set-group"
54
+ :class="[
55
+ 'annotation-set-group',
56
+ !annotationSetsAccordion[indexGroup] === true &&
57
+ 'annotation-set-collapsed',
58
+ ]"
55
59
  >
56
- <div class="label-set-header">
60
+ <div class="label-set-header" @click="toggleAccordion(indexGroup)">
57
61
  <div class="label-set-name">
62
+ <b-icon
63
+ :icon="
64
+ annotationSetsAccordion[indexGroup] ? 'angle-up' : 'angle-down'
65
+ "
66
+ >
67
+ </b-icon>
58
68
  {{
59
69
  `${annotationSet.label_set.name} ${numberOfAnnotationSetGroup(
60
70
  annotationSet
@@ -66,6 +76,7 @@
66
76
  class="labelset-action-buttons"
67
77
  >
68
78
  <AnnotationSetActionButtons
79
+ v-if="annotationSetsAccordion[indexGroup] === true"
69
80
  :number-of-empty-labels-in-annotation-set="
70
81
  emptyLabels(annotationSet).length
71
82
  "
@@ -92,34 +103,38 @@
92
103
  </div>
93
104
  </div>
94
105
 
95
- <div v-if="annotationSet.labels.length > 0">
96
- <div v-for="label in annotationSet.labels" :key="label.id">
97
- <div
98
- v-if="!(label.annotations.length === 0 && publicView)"
99
- class="labels"
100
- >
101
- <DocumentLabel
102
- :label="label"
103
- :annotation-set="annotationSet"
104
- :index-group="indexGroup"
105
- @handle-missing-annotation="markAnnotationsAsMissing"
106
- />
106
+ <b-collapse :open="annotationSetsAccordion[indexGroup] === true">
107
+ <div v-if="annotationSet.labels.length > 0">
108
+ <div v-for="label in annotationSet.labels" :key="label.id">
109
+ <div
110
+ v-if="!(label.annotations.length === 0 && publicView)"
111
+ class="labels"
112
+ >
113
+ <DocumentLabel
114
+ :label="label"
115
+ :annotation-set="annotationSet"
116
+ :index-group="indexGroup"
117
+ @handle-missing-annotation="markAnnotationsAsMissing"
118
+ />
119
+ </div>
107
120
  </div>
108
121
  </div>
109
- </div>
110
122
 
111
- <div v-if="annotationSet.labels.length === 0" class="no-labels">
112
- <span> {{ $t("no_labels_in_set") }}</span>
113
- <!-- eslint-disable-next-line vue/no-v-html -->
114
- <span v-if="isDocumentEditable" v-html="$t('link_to_add_labels')" />
115
- </div>
123
+ <div v-if="annotationSet.labels.length === 0" class="no-labels">
124
+ <span> {{ $t("no_labels_in_set") }}</span>
125
+ <!-- eslint-disable-next-line vue/no-v-html -->
126
+ <span v-if="isDocumentEditable" v-html="$t('link_to_add_labels')" />
127
+ </div>
116
128
 
117
- <div
118
- v-else-if="!annotationSetHasAnnotations(annotationSet) && publicView"
119
- class="no-labels"
120
- >
121
- <span> {{ $t("no_annotations_in_annotation_set") }}</span>
122
- </div>
129
+ <div
130
+ v-else-if="
131
+ !annotationSetHasAnnotations(annotationSet) && publicView
132
+ "
133
+ class="no-labels"
134
+ >
135
+ <span> {{ $t("no_annotations_in_annotation_set") }}</span>
136
+ </div>
137
+ </b-collapse>
123
138
  </div>
124
139
  </div>
125
140
  </div>
@@ -150,6 +165,7 @@ export default {
150
165
  count: 0,
151
166
  jumpToNextAnnotation: false,
152
167
  numberOfLoadingAnnotations: 3,
168
+ annotationSetsAccordion: [],
153
169
  };
154
170
  },
155
171
  computed: {
@@ -166,15 +182,16 @@ export default {
166
182
  "labels",
167
183
  "selectedDocument",
168
184
  "splittingSuggestions",
185
+ "sidebarAnnotationSelected",
169
186
  ]),
170
187
  ...mapGetters("category", ["category"]),
171
188
  ...mapGetters("document", [
172
189
  "numberOfAnnotationSetGroup",
173
190
  "emptyLabels",
174
191
  "notCorrectAnnotations",
175
- "annotationSetsToShowInList",
176
192
  "annotationSetsInTable",
177
193
  "isDocumentReviewed",
194
+ "annotationSetOfAnnotation",
178
195
  ]),
179
196
  isAnnotationBeingEdited() {
180
197
  return this.editAnnotation && this.editAnnotation.id;
@@ -195,6 +212,70 @@ export default {
195
212
  this.jumpToNextAnnotation = false;
196
213
  }
197
214
  },
215
+ annotationSets(newAnnotationSets, oldAnnotationSets) {
216
+ if (newAnnotationSets) {
217
+ const newAnnotationSetsAccordion = [];
218
+ const annotationSetsOpened = [];
219
+ const annotationSetsCreated = [];
220
+ if (oldAnnotationSets) {
221
+ // when annotation sets changed, restore old state
222
+ // and check if new ones were created to be open by default
223
+
224
+ this.annotationSetsAccordion.forEach((isOpen, index) => {
225
+ if (isOpen) {
226
+ annotationSetsOpened.push(oldAnnotationSets[index]);
227
+ }
228
+ });
229
+
230
+ newAnnotationSets.forEach((newAnnotationSet) => {
231
+ const existed = oldAnnotationSets.find(
232
+ (oldAnnotationSet) =>
233
+ oldAnnotationSet.id &&
234
+ newAnnotationSet.id &&
235
+ oldAnnotationSet.id === newAnnotationSet.id
236
+ );
237
+ if (!existed && newAnnotationSet.id !== null) {
238
+ annotationSetsCreated.push(newAnnotationSet);
239
+ }
240
+ });
241
+ }
242
+
243
+ newAnnotationSets.forEach((newAnnotationSet, index) => {
244
+ const wasOpen = annotationSetsOpened.find(
245
+ (annotationSetOpened) =>
246
+ annotationSetOpened.id &&
247
+ newAnnotationSet.id &&
248
+ newAnnotationSet.id === annotationSetOpened.id
249
+ );
250
+
251
+ if (wasOpen) {
252
+ newAnnotationSetsAccordion[index] = wasOpen !== undefined;
253
+ } else {
254
+ const wasCreated = annotationSetsCreated.find(
255
+ (annotationSetCreated) =>
256
+ annotationSetCreated.id &&
257
+ newAnnotationSet.id &&
258
+ newAnnotationSet.id === annotationSetCreated.id
259
+ );
260
+ newAnnotationSetsAccordion[index] = wasCreated !== undefined;
261
+ }
262
+ });
263
+ this.annotationSetsAccordion = newAnnotationSetsAccordion;
264
+ }
265
+ },
266
+ sidebarAnnotationSelected(annotation) {
267
+ if (annotation) {
268
+ const annotationSet = this.annotationSetOfAnnotation(annotation);
269
+ if (annotationSet) {
270
+ const index = this.annotationSets.findIndex(
271
+ (annotationSetToFind) => annotationSetToFind.id === annotationSet.id
272
+ );
273
+ const newAnnotationSetsAccordion = [...this.annotationSetsAccordion];
274
+ newAnnotationSetsAccordion[index] = true;
275
+ this.annotationSetsAccordion = newAnnotationSetsAccordion;
276
+ }
277
+ }
278
+ },
198
279
  },
199
280
  created() {
200
281
  window.addEventListener("keydown", this.keyDownHandler);
@@ -203,6 +284,18 @@ export default {
203
284
  window.removeEventListener("keydown", this.keyDownHandler);
204
285
  },
205
286
  methods: {
287
+ toggleAccordion(index) {
288
+ const newAnnotationSetsAccordion = [...this.annotationSetsAccordion];
289
+ newAnnotationSetsAccordion[index] = !newAnnotationSetsAccordion[index];
290
+ this.annotationSetsAccordion = newAnnotationSetsAccordion;
291
+ },
292
+ openAllAccordions() {
293
+ const newAnnotationSetsAccordion = [...this.annotationSetsAccordion];
294
+ newAnnotationSetsAccordion.forEach((_, index) => {
295
+ newAnnotationSetsAccordion[index] = true;
296
+ });
297
+ this.annotationSetsAccordion = newAnnotationSetsAccordion;
298
+ },
206
299
  annotationSetHasAnnotations(annotationSet) {
207
300
  const found = annotationSet.labels.find(
208
301
  (label) => label.annotations.length > 0
@@ -280,6 +373,10 @@ export default {
280
373
 
281
374
  // Not allow starting edit mode with ArrowUp key
282
375
  if (event.key === "ArrowUp" && !this.isAnnotationBeingEdited) return;
376
+
377
+ // open accordions
378
+ this.openAllAccordions();
379
+
283
380
  // Get all the annotation elements
284
381
  let annotations = this.createArray("keyboard-nav");
285
382
 
@@ -297,7 +394,9 @@ export default {
297
394
  if (this.count >= annotations.length) {
298
395
  const finishBtn = this.createArray("finish-review-btn");
299
396
 
300
- finishBtn[0].focus();
397
+ if (finishBtn && finishBtn[0]) {
398
+ finishBtn[0].focus();
399
+ }
301
400
  this.$store.dispatch("document/resetEditAnnotation");
302
401
  this.count = 0;
303
402
  if (event.key === "Enter" && !finishBtn.disabled) {
@@ -71,8 +71,8 @@
71
71
  v-if="!isAnnotationInEditMode(annotation.id)"
72
72
  :key="'ann' + annotation.id + '-' + index"
73
73
  :config="annotationRect(bbox, annotation.id)"
74
- @click="handleFocusedAnnotation(annotation, 'click')"
75
- @mouseenter="handleFocusedAnnotation(annotation)"
74
+ @click="handleFocusedAnnotation(annotation)"
75
+ @mouseenter="onElementEnter(annotation, bbox)"
76
76
  @mouseleave="onElementLeave"
77
77
  />
78
78
  </template>
@@ -284,6 +284,7 @@ export default {
284
284
  "isDocumentReadyToBeReviewed",
285
285
  "entitiesOnSelection",
286
286
  "isDocumentReviewed",
287
+ "labelOfAnnotation",
287
288
  ]),
288
289
  },
289
290
  watch: {
@@ -396,17 +397,9 @@ export default {
396
397
  });
397
398
  },
398
399
 
399
- handleFocusedAnnotation(annotation, trigger) {
400
- this.$store.dispatch("document/setSidebarAnnotationSelected", {
401
- annotation,
402
- trigger,
403
- });
404
-
405
- if (trigger && trigger === "click") {
406
- this.closePopups(true);
407
- } else {
408
- this.onElementEnter();
409
- }
400
+ handleFocusedAnnotation(annotation) {
401
+ this.$store.dispatch("document/setSidebarAnnotationSelected", annotation);
402
+ this.closePopups(true);
410
403
  },
411
404
 
412
405
  handleClickedEntity(entity) {
@@ -454,7 +447,7 @@ export default {
454
447
  }
455
448
  },
456
449
 
457
- onElementEnter() {
450
+ onElementEnter(annotation = null, span = null) {
458
451
  if (
459
452
  !this.categorizeModalIsActive &&
460
453
  !this.publicView &&
@@ -463,10 +456,23 @@ export default {
463
456
  ) {
464
457
  this.$refs.stage.$el.style.cursor = "pointer";
465
458
  }
459
+
460
+ if (annotation) {
461
+ const label = this.labelOfAnnotation(annotation);
462
+ if (label) {
463
+ this.$store.dispatch("document/setDocumentAnnotationSelected", {
464
+ annotation,
465
+ label,
466
+ span,
467
+ scrollTo: false,
468
+ });
469
+ }
470
+ }
466
471
  },
467
472
 
468
473
  onElementLeave() {
469
474
  this.$refs.stage.$el.style.cursor = "inherit";
475
+ this.$store.dispatch("document/disableDocumentAnnotationSelected");
470
476
  },
471
477
 
472
478
  /**
@@ -247,6 +247,50 @@ const getters = {
247
247
  return annotations;
248
248
  },
249
249
 
250
+ /* Get annotation set for a given annotation */
251
+ annotationSetOfAnnotation: (state) => (annotationToFind) => {
252
+ let foundAnnotationSet = null;
253
+ state.annotationSets.forEach((annotationSet) => {
254
+ annotationSet.labels.forEach((label) => {
255
+ label.annotations.forEach((annotation) => {
256
+ if (annotation.id === annotationToFind.id) {
257
+ foundAnnotationSet = annotationSet;
258
+ return;
259
+ }
260
+ });
261
+ if (foundAnnotationSet) {
262
+ return;
263
+ }
264
+ });
265
+ if (foundAnnotationSet) {
266
+ return;
267
+ }
268
+ });
269
+ return foundAnnotationSet;
270
+ },
271
+
272
+ /* Get label for a given annotation */
273
+ labelOfAnnotation: (state) => (annotationToFind) => {
274
+ let foundLabel = null;
275
+ state.annotationSets.forEach((annotationSet) => {
276
+ annotationSet.labels.forEach((label) => {
277
+ label.annotations.forEach((annotation) => {
278
+ if (annotation.id === annotationToFind.id) {
279
+ foundLabel = label;
280
+ return;
281
+ }
282
+ });
283
+ if (foundLabel) {
284
+ return;
285
+ }
286
+ });
287
+ if (foundLabel) {
288
+ return;
289
+ }
290
+ });
291
+ return foundLabel;
292
+ },
293
+
250
294
  /* Process annotations and extract labels and sets */
251
295
  processAnnotationSets: (state, getters) => (annotationSets) => {
252
296
  // group annotations for sidebar