@konfuzio/document-validation-ui 0.1.21 → 0.1.22-dev.1
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/dist/css/app.css +1 -1
- package/dist/index.html +1 -1
- package/dist/js/app.js +1 -1
- package/dist/js/app.js.map +1 -1
- package/package.json +1 -1
- package/src/assets/scss/document_annotations.scss +9 -0
- package/src/components/DocumentAnnotations/AnnotationRow.vue +9 -19
- package/src/components/DocumentAnnotations/DocumentAnnotations.vue +128 -29
- package/src/components/DocumentPage/DocumentPage.vue +5 -13
- package/src/store/document.js +22 -0
package/package.json
CHANGED
|
@@ -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
|
-
},
|
|
308
|
+
}, 1200);
|
|
317
309
|
|
|
318
310
|
// Check if sidebarAnnotationSelected changed from a click or hover
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
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
|
|
52
|
+
v-for="(annotationSet, indexGroup) in annotationSets"
|
|
53
53
|
:key="indexGroup"
|
|
54
|
-
class="
|
|
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
|
-
<
|
|
96
|
-
<div v-
|
|
97
|
-
<div
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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]
|
|
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
|
|
75
|
-
@mouseenter="
|
|
74
|
+
@click="handleFocusedAnnotation(annotation)"
|
|
75
|
+
@mouseenter="onElementEnter"
|
|
76
76
|
@mouseleave="onElementLeave"
|
|
77
77
|
/>
|
|
78
78
|
</template>
|
|
@@ -396,17 +396,9 @@ export default {
|
|
|
396
396
|
});
|
|
397
397
|
},
|
|
398
398
|
|
|
399
|
-
handleFocusedAnnotation(annotation
|
|
400
|
-
this.$store.dispatch("document/setSidebarAnnotationSelected",
|
|
401
|
-
|
|
402
|
-
trigger,
|
|
403
|
-
});
|
|
404
|
-
|
|
405
|
-
if (trigger && trigger === "click") {
|
|
406
|
-
this.closePopups(true);
|
|
407
|
-
} else {
|
|
408
|
-
this.onElementEnter();
|
|
409
|
-
}
|
|
399
|
+
handleFocusedAnnotation(annotation) {
|
|
400
|
+
this.$store.dispatch("document/setSidebarAnnotationSelected", annotation);
|
|
401
|
+
this.closePopups(true);
|
|
410
402
|
},
|
|
411
403
|
|
|
412
404
|
handleClickedEntity(entity) {
|
package/src/store/document.js
CHANGED
|
@@ -247,6 +247,28 @@ 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
|
+
|
|
250
272
|
/* Process annotations and extract labels and sets */
|
|
251
273
|
processAnnotationSets: (state, getters) => (annotationSets) => {
|
|
252
274
|
// group annotations for sidebar
|