@konfuzio/document-validation-ui 0.1.5 → 0.1.6-multi-ann-set-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/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/.DS_Store +0 -0
- package/src/assets/images/DraggableIcon.vue +14 -0
- package/src/assets/images/GridIcon.vue +16 -0
- package/src/assets/images/MagicWandIcon.vue +16 -0
- package/src/assets/images/NotFoundIcon.vue +16 -0
- package/src/assets/images/SettingsIcon.vue +14 -0
- package/src/assets/images/SplitZigZag.vue +47 -14
- package/src/assets/images/StarIcon.vue +16 -0
- package/src/assets/scss/ann_set_table_options.scss +26 -0
- package/src/assets/scss/annotation_details.scss +85 -73
- package/src/assets/scss/document_annotations.scss +54 -57
- package/src/assets/scss/document_category.scss +0 -1
- package/src/assets/scss/document_dashboard.scss +7 -2
- package/src/assets/scss/document_edit.scss +90 -46
- package/src/assets/scss/main.scss +725 -7
- package/src/assets/scss/multi_ann_table_overlay.scss +38 -0
- package/src/assets/scss/splitting_confirmation_modal.scss +41 -0
- package/src/assets/scss/variables.scss +2 -657
- package/src/components/App.vue +9 -3
- package/src/components/DocumentAnnotations/AnnotationActionButtons.vue +171 -0
- package/src/components/DocumentAnnotations/AnnotationContent.vue +5 -3
- package/src/components/DocumentAnnotations/AnnotationDetails.vue +28 -7
- package/src/components/DocumentAnnotations/AnnotationRow.vue +133 -41
- package/src/components/DocumentAnnotations/AnnotationSetActionButtons.vue +86 -0
- package/src/components/DocumentAnnotations/CategorizeModal.vue +28 -2
- package/src/components/DocumentAnnotations/DocumentAnnotations.vue +121 -97
- package/src/components/DocumentAnnotations/EmptyAnnotation.vue +21 -5
- package/src/components/DocumentAnnotations/ExtractingData.vue +3 -3
- package/src/components/DocumentAnnotations/index.js +0 -1
- package/src/components/DocumentCategory.vue +13 -5
- package/src/components/DocumentDashboard.vue +17 -6
- package/src/components/DocumentEdit/DocumentEdit.vue +208 -68
- package/src/components/DocumentEdit/EditConfirmationModal.vue +54 -0
- package/src/components/DocumentEdit/EditPages.vue +29 -18
- package/src/components/DocumentEdit/EditSidebar.vue +92 -45
- package/src/components/DocumentEdit/SidebarButtons.vue +53 -0
- package/src/components/DocumentEdit/SplitInfoBar.vue +19 -0
- package/src/components/DocumentEdit/SplitOverview.vue +4 -5
- package/src/components/{DocumentError.vue → DocumentModals/DocumentErrorModal.vue} +3 -4
- package/src/components/{NotOptimizedViewportModal.vue → DocumentModals/NotOptimizedViewportModal.vue} +2 -2
- package/src/components/DocumentModals/SplittingSuggestionsModal.vue +120 -0
- package/src/components/DocumentPage/ActionBar.vue +3 -3
- package/src/components/DocumentPage/AnnSetTableOptions.vue +107 -0
- package/src/components/DocumentPage/DocumentPage.vue +39 -10
- package/src/components/DocumentPage/DocumentToolbar.vue +6 -2
- package/src/components/DocumentPage/MultiAnnSelection.vue +90 -2
- package/src/components/DocumentPage/MultiAnnotationTableOverlay.vue +274 -0
- package/src/components/DocumentPage/MultiAnnotationTablePopup.vue +19 -46
- package/src/components/DocumentPage/NewAnnotation.vue +1 -1
- package/src/components/DocumentPage/ScrollingDocument.vue +43 -4
- package/src/components/DocumentPage/ScrollingPage.vue +4 -5
- package/src/components/DocumentThumbnails/DocumentThumbnails.vue +14 -11
- package/src/components/DocumentTopBar/DocumentName.vue +6 -1
- package/src/components/DocumentTopBar/DocumentTopBar.vue +9 -9
- package/src/components/DocumentTopBar/DocumentTopBarButtons.vue +38 -32
- package/src/components/DocumentTopBar/KeyboardActionsDescription.vue +9 -3
- package/src/components/DocumentsList/DocumentsList.vue +11 -2
- package/src/locales/de.json +23 -6
- package/src/locales/en.json +24 -6
- package/src/locales/es.json +23 -6
- package/src/store/category.js +1 -1
- package/src/store/display.js +51 -0
- package/src/store/document.js +181 -24
- package/src/store/edit.js +71 -48
- package/src/store/project.js +14 -14
- package/src/utils/utils.js +13 -0
- package/src/components/DocumentAnnotations/ActionButtons.vue +0 -257
- package/src/components/DocumentAnnotations/RejectedLabels.vue +0 -96
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
ref="pdfContainer"
|
|
4
4
|
:class="[
|
|
5
5
|
'pdf-page-container',
|
|
6
|
-
(categorizeModalIsActive ||
|
|
6
|
+
(categorizeModalIsActive ||
|
|
7
|
+
editMode ||
|
|
8
|
+
publicView ||
|
|
9
|
+
documentIsReviewed) &&
|
|
10
|
+
'default-cursor',
|
|
7
11
|
page.number === currentPage && 'current-page',
|
|
8
12
|
]"
|
|
9
13
|
>
|
|
@@ -23,6 +27,8 @@
|
|
|
23
27
|
@close="closePopups"
|
|
24
28
|
/>
|
|
25
29
|
|
|
30
|
+
<AnnSetTableOptions v-if="showAnnSetTable" :page="page" />
|
|
31
|
+
|
|
26
32
|
<v-stage
|
|
27
33
|
v-if="image && scale"
|
|
28
34
|
ref="stage"
|
|
@@ -42,7 +48,7 @@
|
|
|
42
48
|
}"
|
|
43
49
|
/>
|
|
44
50
|
<template v-if="pageInVisibleRange && !editMode">
|
|
45
|
-
<v-group v-if="!publicView" ref="entities">
|
|
51
|
+
<v-group v-if="!publicView || !documentIsReviewed" ref="entities">
|
|
46
52
|
<v-rect
|
|
47
53
|
v-for="(entity, index) in scaledEntities"
|
|
48
54
|
:key="index"
|
|
@@ -70,7 +76,13 @@
|
|
|
70
76
|
</template>
|
|
71
77
|
</template>
|
|
72
78
|
</v-layer>
|
|
73
|
-
<v-layer
|
|
79
|
+
<v-layer
|
|
80
|
+
v-if="
|
|
81
|
+
showFocusedAnnotation &&
|
|
82
|
+
!isSelecting &&
|
|
83
|
+
documentAnnotationSelected.labelName !== ''
|
|
84
|
+
"
|
|
85
|
+
>
|
|
74
86
|
<v-label
|
|
75
87
|
:key="`label${documentAnnotationSelected.id}`"
|
|
76
88
|
:config="{
|
|
@@ -125,6 +137,7 @@ import BoxSelection from "./BoxSelection";
|
|
|
125
137
|
import MultiAnnSelection from "./MultiAnnSelection";
|
|
126
138
|
import NewAnnotation from "./NewAnnotation";
|
|
127
139
|
import MultiAnnotationTablePopup from "./MultiAnnotationTablePopup";
|
|
140
|
+
import AnnSetTableOptions from "./AnnSetTableOptions";
|
|
128
141
|
|
|
129
142
|
export default {
|
|
130
143
|
name: "DocumentPage",
|
|
@@ -133,6 +146,7 @@ export default {
|
|
|
133
146
|
MultiAnnSelection,
|
|
134
147
|
NewAnnotation,
|
|
135
148
|
MultiAnnotationTablePopup,
|
|
149
|
+
AnnSetTableOptions,
|
|
136
150
|
},
|
|
137
151
|
|
|
138
152
|
props: {
|
|
@@ -151,7 +165,7 @@ export default {
|
|
|
151
165
|
},
|
|
152
166
|
|
|
153
167
|
computed: {
|
|
154
|
-
...mapState("display", ["currentPage"]),
|
|
168
|
+
...mapState("display", ["currentPage", "showAnnSetTable"]),
|
|
155
169
|
|
|
156
170
|
showFocusedAnnotation() {
|
|
157
171
|
return (
|
|
@@ -258,6 +272,7 @@ export default {
|
|
|
258
272
|
"selectedDocument",
|
|
259
273
|
"publicView",
|
|
260
274
|
"selectedEntities",
|
|
275
|
+
"documentIsReviewed",
|
|
261
276
|
]),
|
|
262
277
|
...mapState("edit", ["editMode"]),
|
|
263
278
|
...mapGetters("display", ["visiblePageRange", "bboxToRect"]),
|
|
@@ -311,7 +326,13 @@ export default {
|
|
|
311
326
|
},
|
|
312
327
|
|
|
313
328
|
onMouseDown(event) {
|
|
314
|
-
if (
|
|
329
|
+
if (
|
|
330
|
+
this.categorizeModalIsActive ||
|
|
331
|
+
this.editMode ||
|
|
332
|
+
this.publicView ||
|
|
333
|
+
this.documentIsReviewed
|
|
334
|
+
)
|
|
335
|
+
return;
|
|
315
336
|
|
|
316
337
|
this.closePopups();
|
|
317
338
|
|
|
@@ -329,9 +350,6 @@ export default {
|
|
|
329
350
|
) {
|
|
330
351
|
return;
|
|
331
352
|
}
|
|
332
|
-
if (this.publicView) {
|
|
333
|
-
return;
|
|
334
|
-
}
|
|
335
353
|
|
|
336
354
|
// anything else, we start selecting
|
|
337
355
|
|
|
@@ -379,7 +397,13 @@ export default {
|
|
|
379
397
|
},
|
|
380
398
|
|
|
381
399
|
handleClickedEntity(entity) {
|
|
382
|
-
if (
|
|
400
|
+
if (
|
|
401
|
+
!entity ||
|
|
402
|
+
this.categorizeModalIsActive ||
|
|
403
|
+
this.publicView ||
|
|
404
|
+
this.documentIsReviewed
|
|
405
|
+
)
|
|
406
|
+
return;
|
|
383
407
|
|
|
384
408
|
// Check if we are creating a new Annotation
|
|
385
409
|
// or if we are editing an existing or empty one
|
|
@@ -417,7 +441,12 @@ export default {
|
|
|
417
441
|
},
|
|
418
442
|
|
|
419
443
|
onElementEnter() {
|
|
420
|
-
if (
|
|
444
|
+
if (
|
|
445
|
+
!this.categorizeModalIsActive &&
|
|
446
|
+
!this.publicView &&
|
|
447
|
+
!this.editMode &&
|
|
448
|
+
!this.documentIsReviewed
|
|
449
|
+
) {
|
|
421
450
|
this.$refs.stage.$el.style.cursor = "pointer";
|
|
422
451
|
}
|
|
423
452
|
},
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
class="top-aligned"
|
|
10
10
|
>
|
|
11
11
|
<div
|
|
12
|
-
v-if="!editMode && !publicView"
|
|
12
|
+
v-if="!editMode && !publicView && !documentIsReviewed"
|
|
13
13
|
:class="[
|
|
14
14
|
'icons icons-left',
|
|
15
15
|
editModeDisabled && 'edit-mode-disabled',
|
|
@@ -22,7 +22,10 @@
|
|
|
22
22
|
<span class="edit-text">{{ $t("edit") }}</span>
|
|
23
23
|
</div>
|
|
24
24
|
</b-tooltip>
|
|
25
|
-
<div
|
|
25
|
+
<div
|
|
26
|
+
v-if="!editMode && !publicView && !documentIsReviewed"
|
|
27
|
+
class="toolbar-divider"
|
|
28
|
+
/>
|
|
26
29
|
<div class="icons icons-right">
|
|
27
30
|
<div class="fit-zoom icon" @click.prevent.stop="fitAuto">
|
|
28
31
|
<FitZoomIcon />
|
|
@@ -74,6 +77,7 @@ export default {
|
|
|
74
77
|
"selectedDocument",
|
|
75
78
|
"recalculatingAnnotations",
|
|
76
79
|
"publicView",
|
|
80
|
+
"documentIsReviewed",
|
|
77
81
|
]),
|
|
78
82
|
...mapGetters("document", ["documentCannotBeEdited"]),
|
|
79
83
|
},
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
<script>
|
|
46
46
|
import { mapGetters, mapState, mapActions } from "vuex";
|
|
47
47
|
import { ChooseLabelSetModal } from "../DocumentAnnotations";
|
|
48
|
+
import { table_reference_api } from "../../store/document";
|
|
48
49
|
|
|
49
50
|
export default {
|
|
50
51
|
props: {
|
|
@@ -114,6 +115,7 @@ export default {
|
|
|
114
115
|
};
|
|
115
116
|
},
|
|
116
117
|
...mapState("selection", ["selection", "isSelecting"]),
|
|
118
|
+
...mapState("document", ["documentId"]),
|
|
117
119
|
...mapGetters("display", ["clientToBbox"]),
|
|
118
120
|
...mapGetters("document", ["entitiesOnSelection"]),
|
|
119
121
|
},
|
|
@@ -134,10 +136,10 @@ export default {
|
|
|
134
136
|
hasModalCard: true,
|
|
135
137
|
trapFocus: true,
|
|
136
138
|
canCancel: false,
|
|
137
|
-
customClass: "invisible-parent-modal",
|
|
139
|
+
customClass: "dv-ui-theme invisible-parent-modal",
|
|
138
140
|
props: { isMultipleAnnotations: true },
|
|
139
141
|
events: {
|
|
140
|
-
labelSet: this.
|
|
142
|
+
labelSet: this.submitAnnotations,
|
|
141
143
|
},
|
|
142
144
|
});
|
|
143
145
|
},
|
|
@@ -156,6 +158,48 @@ export default {
|
|
|
156
158
|
this.$emit("finished", tableSelection);
|
|
157
159
|
},
|
|
158
160
|
|
|
161
|
+
async submitAnnotations(labelSet) {
|
|
162
|
+
const columns = labelSet.labels.map((label) => {
|
|
163
|
+
return {
|
|
164
|
+
field: `${label.id}`,
|
|
165
|
+
label: label.name,
|
|
166
|
+
centered: true,
|
|
167
|
+
};
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const orderedEntities = this.processRows(columns);
|
|
171
|
+
|
|
172
|
+
const annotations = [];
|
|
173
|
+
|
|
174
|
+
orderedEntities.forEach((orderedEntity) => {
|
|
175
|
+
annotations.push({
|
|
176
|
+
document: this.documentId,
|
|
177
|
+
span: orderedEntity.spans,
|
|
178
|
+
label: orderedEntity.label_id,
|
|
179
|
+
is_correct: true,
|
|
180
|
+
revised: false,
|
|
181
|
+
label_set: labelSet.id,
|
|
182
|
+
set_reference: orderedEntity.row_index,
|
|
183
|
+
origin: table_reference_api,
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
this.$store
|
|
188
|
+
.dispatch("document/createAnnotation", annotations)
|
|
189
|
+
.then(() => {
|
|
190
|
+
this.$store.dispatch("selection/disableSelection");
|
|
191
|
+
this.$emit("finished");
|
|
192
|
+
})
|
|
193
|
+
.catch((error) => {
|
|
194
|
+
this.$store.dispatch("document/createErrorMessage", {
|
|
195
|
+
error,
|
|
196
|
+
serverErrorMessage: this.$t("server_error"),
|
|
197
|
+
defaultErrorMessage: this.$t("error_creating_multi_ann"),
|
|
198
|
+
});
|
|
199
|
+
this.$emit("finished");
|
|
200
|
+
});
|
|
201
|
+
},
|
|
202
|
+
|
|
159
203
|
onButtonEnter() {
|
|
160
204
|
this.$emit("buttonEnter");
|
|
161
205
|
},
|
|
@@ -296,6 +340,50 @@ export default {
|
|
|
296
340
|
|
|
297
341
|
this.entities = cols;
|
|
298
342
|
},
|
|
343
|
+
|
|
344
|
+
processRows(columns) {
|
|
345
|
+
const orderedEntities = []; // this will match the order of entities in the table so we have a way of tracking them once we submit
|
|
346
|
+
let rowIndex = 0;
|
|
347
|
+
|
|
348
|
+
Object.entries(this.entities).forEach(([key, groupedEntity]) => {
|
|
349
|
+
let row = null;
|
|
350
|
+
columns.forEach((column, index) => {
|
|
351
|
+
let spans = [];
|
|
352
|
+
if (
|
|
353
|
+
Object.entries(groupedEntity)[index] &&
|
|
354
|
+
Object.entries(groupedEntity)[index].length > 0
|
|
355
|
+
) {
|
|
356
|
+
spans = Object.entries(groupedEntity)[index][1];
|
|
357
|
+
}
|
|
358
|
+
const entityExists = spans.length > 0;
|
|
359
|
+
|
|
360
|
+
let textContent = "";
|
|
361
|
+
|
|
362
|
+
spans.forEach((entity) => {
|
|
363
|
+
textContent = `${textContent} ${entity.offset_string}`;
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
row = {
|
|
367
|
+
...row,
|
|
368
|
+
[column.field]: textContent,
|
|
369
|
+
};
|
|
370
|
+
if (entityExists) {
|
|
371
|
+
const customEntity = {
|
|
372
|
+
spans: [...spans],
|
|
373
|
+
label_id: column.field,
|
|
374
|
+
row_index: rowIndex,
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
orderedEntities.push(customEntity);
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
if (row !== null) {
|
|
381
|
+
rowIndex++;
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
return orderedEntities;
|
|
385
|
+
},
|
|
386
|
+
|
|
299
387
|
...mapActions("selection", ["moveSelection"]),
|
|
300
388
|
},
|
|
301
389
|
};
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="multi-ann-table-overlay">
|
|
3
|
+
<b-table
|
|
4
|
+
ref="table"
|
|
5
|
+
class="multi-ann-set-table dark-header header-32"
|
|
6
|
+
detail-icon="faScissors"
|
|
7
|
+
:data="rows"
|
|
8
|
+
:sticky-header="true"
|
|
9
|
+
:narrowed="true"
|
|
10
|
+
:bordered="false"
|
|
11
|
+
draggable-column
|
|
12
|
+
@columndragstart="columndragstart"
|
|
13
|
+
@columndrop="columndrop"
|
|
14
|
+
@columndragover="columndragover"
|
|
15
|
+
@columndragleave="columndragleave"
|
|
16
|
+
>
|
|
17
|
+
<b-table-column
|
|
18
|
+
v-for="(item, index) in columns"
|
|
19
|
+
:key="index"
|
|
20
|
+
:field="item.field"
|
|
21
|
+
:label="item.label.name"
|
|
22
|
+
>
|
|
23
|
+
<template #header="{ column }">
|
|
24
|
+
<b-dropdown
|
|
25
|
+
:ref="getDropdownReference(item)"
|
|
26
|
+
aria-role="list"
|
|
27
|
+
class="header-dropdown"
|
|
28
|
+
position="is-top-left"
|
|
29
|
+
:close-on-click="false"
|
|
30
|
+
@active-change="(e) => onDropdownChange(item, e)"
|
|
31
|
+
>
|
|
32
|
+
<template #trigger="{ active }">
|
|
33
|
+
<DraggableIcon class="draggable" />
|
|
34
|
+
<span :class="active ? 'active' : ''">{{ column.label }} </span>
|
|
35
|
+
<b-icon
|
|
36
|
+
:icon="active ? 'angle-up' : 'angle-down'"
|
|
37
|
+
size="is-small"
|
|
38
|
+
class="arrow"
|
|
39
|
+
/>
|
|
40
|
+
</template>
|
|
41
|
+
|
|
42
|
+
<div v-if="editingLabels.length === 0">
|
|
43
|
+
<b-dropdown-item aria-role="listitem" @click="editLabel(item)"
|
|
44
|
+
><span>{{ $t("edit_label") }}</span></b-dropdown-item
|
|
45
|
+
>
|
|
46
|
+
<b-dropdown-item
|
|
47
|
+
aria-role="listitem"
|
|
48
|
+
class="delete-action"
|
|
49
|
+
@click="deleteColumn(item)"
|
|
50
|
+
>
|
|
51
|
+
<span>{{ $t("delete_label") }}</span></b-dropdown-item
|
|
52
|
+
>
|
|
53
|
+
</div>
|
|
54
|
+
<div v-else>
|
|
55
|
+
<b-dropdown-item
|
|
56
|
+
v-for="label in editingLabels"
|
|
57
|
+
:key="label.id"
|
|
58
|
+
aria-role="listitem"
|
|
59
|
+
:disabled="label.disabled"
|
|
60
|
+
><span @click="changeLabel(item, label)">{{
|
|
61
|
+
label.name
|
|
62
|
+
}}</span></b-dropdown-item
|
|
63
|
+
>
|
|
64
|
+
</div>
|
|
65
|
+
</b-dropdown>
|
|
66
|
+
</template>
|
|
67
|
+
|
|
68
|
+
<template #default="props">
|
|
69
|
+
<div class="annotations-table">
|
|
70
|
+
<AnnotationRow
|
|
71
|
+
:annotation="props.row[item.field]"
|
|
72
|
+
:label="item.label"
|
|
73
|
+
:annotation-set="item.annotationSet"
|
|
74
|
+
:show-label="false"
|
|
75
|
+
:show-buttons="false"
|
|
76
|
+
:is-small="true"
|
|
77
|
+
:from-table="true"
|
|
78
|
+
/>
|
|
79
|
+
</div>
|
|
80
|
+
</template>
|
|
81
|
+
</b-table-column>
|
|
82
|
+
</b-table>
|
|
83
|
+
</div>
|
|
84
|
+
</template>
|
|
85
|
+
|
|
86
|
+
<script>
|
|
87
|
+
import { mapState } from "vuex";
|
|
88
|
+
import AnnotationRow from "../DocumentAnnotations/AnnotationRow";
|
|
89
|
+
import DraggableIcon from "../../assets/images/DraggableIcon";
|
|
90
|
+
|
|
91
|
+
export default {
|
|
92
|
+
name: "MultiAnnotationTablePopup",
|
|
93
|
+
components: {
|
|
94
|
+
AnnotationRow,
|
|
95
|
+
DraggableIcon,
|
|
96
|
+
},
|
|
97
|
+
data() {
|
|
98
|
+
return {
|
|
99
|
+
rows: [],
|
|
100
|
+
columns: [],
|
|
101
|
+
orderedAnnotations: [],
|
|
102
|
+
editingLabels: [],
|
|
103
|
+
openDropdown: null,
|
|
104
|
+
draggingColumnIndex: null,
|
|
105
|
+
};
|
|
106
|
+
},
|
|
107
|
+
computed: {
|
|
108
|
+
...mapState("display", ["showAnnSetTable"]),
|
|
109
|
+
},
|
|
110
|
+
watch: {
|
|
111
|
+
showAnnSetTable() {
|
|
112
|
+
this.handleColumns();
|
|
113
|
+
this.handleRows();
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
mounted() {
|
|
117
|
+
this.handleColumns();
|
|
118
|
+
this.handleRows();
|
|
119
|
+
},
|
|
120
|
+
methods: {
|
|
121
|
+
getDropdownReference(column) {
|
|
122
|
+
return `editDropdown_${column.field}`;
|
|
123
|
+
},
|
|
124
|
+
handleColumns() {
|
|
125
|
+
this.columns = [];
|
|
126
|
+
const labelAlreadyExists = (label) => {
|
|
127
|
+
return (
|
|
128
|
+
this.columns.length > 0 &&
|
|
129
|
+
this.columns.find((a) => a.field === `${label.id}`) != undefined
|
|
130
|
+
);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
this.showAnnSetTable.forEach((annotationSet) => {
|
|
134
|
+
annotationSet.labels.forEach((label) => {
|
|
135
|
+
if (!labelAlreadyExists(label) && label.annotations.length > 0) {
|
|
136
|
+
const column = {
|
|
137
|
+
field: `${label.id}`,
|
|
138
|
+
label: label,
|
|
139
|
+
annotationSet,
|
|
140
|
+
centered: false,
|
|
141
|
+
};
|
|
142
|
+
this.columns.push(column);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
handleRows() {
|
|
149
|
+
this.rows = [];
|
|
150
|
+
this.orderedAnnotations = [];
|
|
151
|
+
|
|
152
|
+
this.showAnnSetTable.forEach((annotationSet) => {
|
|
153
|
+
let row = {};
|
|
154
|
+
|
|
155
|
+
annotationSet.labels.forEach((label) => {
|
|
156
|
+
if (label.annotations.length > 0) {
|
|
157
|
+
row[label.id] = label.annotations[0];
|
|
158
|
+
this.orderedAnnotations.push(label.annotations[0]);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
this.rows.push(row);
|
|
162
|
+
});
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
async editLabel(column) {
|
|
166
|
+
this.$store
|
|
167
|
+
.dispatch(
|
|
168
|
+
"project/fetchLabelSetDetails",
|
|
169
|
+
column.annotationSet.label_set.id
|
|
170
|
+
)
|
|
171
|
+
.then(async (labelSet) => {
|
|
172
|
+
this.editingLabels = [];
|
|
173
|
+
|
|
174
|
+
labelSet.labels.forEach((label) => {
|
|
175
|
+
const dropdownLabel = {
|
|
176
|
+
...label,
|
|
177
|
+
disabled:
|
|
178
|
+
this.columns.find((column) => column.label.id === label.id) !==
|
|
179
|
+
undefined,
|
|
180
|
+
};
|
|
181
|
+
this.editingLabels.push(dropdownLabel);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
async changeLabel(column, label) {
|
|
187
|
+
for (let i = 0; i < this.rows.length; i++) {
|
|
188
|
+
const annotationToUpdate = this.rows[i][column.label.id];
|
|
189
|
+
await this.$store
|
|
190
|
+
.dispatch("document/updateAnnotation", {
|
|
191
|
+
annotationId: annotationToUpdate.id,
|
|
192
|
+
updatedValues: { label: label.id },
|
|
193
|
+
})
|
|
194
|
+
.catch((error) => {
|
|
195
|
+
this.$store.dispatch("document/createErrorMessage", {
|
|
196
|
+
error,
|
|
197
|
+
serverErrorMessage: this.$t("server_error"),
|
|
198
|
+
defaultErrorMessage: this.$t("edit_error"),
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
this.closeDropdown(column);
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
async deleteColumn(column) {
|
|
206
|
+
for (let i = 0; i < this.rows.length; i++) {
|
|
207
|
+
const annotationToDelete = this.rows[i][column.label.id];
|
|
208
|
+
await this.$store
|
|
209
|
+
.dispatch("document/deleteAnnotation", {
|
|
210
|
+
annotationId: annotationToDelete.id,
|
|
211
|
+
})
|
|
212
|
+
.catch((error) => {
|
|
213
|
+
this.$store.dispatch("document/createErrorMessage", {
|
|
214
|
+
error,
|
|
215
|
+
serverErrorMessage: this.$t("server_error"),
|
|
216
|
+
defaultErrorMessage: this.$t("edit_error"),
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
this.closeDropdown(column);
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
onDropdownChange(column, open) {
|
|
224
|
+
this.editingLabels = [];
|
|
225
|
+
if (open) {
|
|
226
|
+
if (this.openDropdown) {
|
|
227
|
+
this.$refs[this.openDropdown][0].toggle();
|
|
228
|
+
}
|
|
229
|
+
this.openDropdown = this.getDropdownReference(column);
|
|
230
|
+
} else {
|
|
231
|
+
if (this.openDropdown === this.getDropdownReference(column)) {
|
|
232
|
+
this.openDropdown = null;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
closeDropdown(column) {
|
|
238
|
+
if (this.openDropdown) {
|
|
239
|
+
this.$refs[this.getDropdownReference(column)][0].toggle();
|
|
240
|
+
this.openDropdown = null;
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
columndragstart(payload) {
|
|
245
|
+
this.draggingColumnIndex = payload.index;
|
|
246
|
+
payload.event.dataTransfer.effectAllowed = "copy";
|
|
247
|
+
},
|
|
248
|
+
columndragover(payload) {
|
|
249
|
+
payload.event.dataTransfer.dropEffect = "copy";
|
|
250
|
+
payload.event.target.closest("th").classList.add("is-selected");
|
|
251
|
+
payload.event.preventDefault();
|
|
252
|
+
},
|
|
253
|
+
columndragleave(payload) {
|
|
254
|
+
payload.event.target.closest("th").classList.remove("is-selected");
|
|
255
|
+
payload.event.preventDefault();
|
|
256
|
+
},
|
|
257
|
+
async columndrop(payload) {
|
|
258
|
+
payload.event.target.closest("th").classList.remove("is-selected");
|
|
259
|
+
const droppedOnColumnIndex = payload.index;
|
|
260
|
+
|
|
261
|
+
const draggingColumn = this.columns[this.draggingColumnIndex];
|
|
262
|
+
const droppedColumn = this.columns[droppedOnColumnIndex];
|
|
263
|
+
|
|
264
|
+
await this.changeLabel(draggingColumn, droppedColumn.label);
|
|
265
|
+
await this.changeLabel(droppedColumn, draggingColumn.label);
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
</script>
|
|
270
|
+
<style
|
|
271
|
+
scoped
|
|
272
|
+
lang="scss"
|
|
273
|
+
src="../../assets/scss/multi_ann_table_overlay.scss"
|
|
274
|
+
></style>
|
|
@@ -156,63 +156,36 @@ export default {
|
|
|
156
156
|
}
|
|
157
157
|
},
|
|
158
158
|
async submitAnnotations() {
|
|
159
|
-
let errorMessageShown = false;
|
|
160
|
-
let previousAnnotationSetId = null;
|
|
161
|
-
let previousRowIndex = 0;
|
|
162
|
-
|
|
163
159
|
this.$store.dispatch("display/showDocumentActionBar", {
|
|
164
160
|
show: true,
|
|
165
161
|
loading: false,
|
|
166
162
|
action: true,
|
|
167
163
|
});
|
|
168
164
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const groupedEntity = this.orderedEntities[i];
|
|
172
|
-
|
|
173
|
-
const annotationToCreate = {
|
|
165
|
+
this.orderedEntities.forEach((orderedEntity) => {
|
|
166
|
+
annotations.push({
|
|
174
167
|
document: this.documentId,
|
|
175
|
-
span:
|
|
176
|
-
label:
|
|
168
|
+
span: orderedEntity.spans,
|
|
169
|
+
label: orderedEntity.label_id,
|
|
177
170
|
is_correct: true,
|
|
178
171
|
revised: false,
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
previousAnnotationSetId = null;
|
|
184
|
-
}
|
|
185
|
-
previousRowIndex = groupedEntity.row_index;
|
|
186
|
-
|
|
187
|
-
if (previousAnnotationSetId) {
|
|
188
|
-
annotationToCreate.annotation_set = previousAnnotationSetId;
|
|
189
|
-
} else {
|
|
190
|
-
annotationToCreate.label_set = this.labelSet.id;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
await this.$store
|
|
194
|
-
.dispatch("document/createAnnotation", annotationToCreate)
|
|
195
|
-
.then((response) => {
|
|
196
|
-
if (response) {
|
|
197
|
-
// set ann set id to use on the next labels on the same row
|
|
198
|
-
previousAnnotationSetId = response.data.annotation_set;
|
|
199
|
-
}
|
|
200
|
-
})
|
|
201
|
-
.catch((error) => {
|
|
202
|
-
if (!errorMessageShown) {
|
|
203
|
-
this.$store.dispatch("document/createErrorMessage", {
|
|
204
|
-
error,
|
|
205
|
-
serverErrorMessage: this.$t("server_error"),
|
|
206
|
-
defaultErrorMessage: this.$t("error_creating_multi_ann"),
|
|
207
|
-
});
|
|
172
|
+
label_set: labelSet.id,
|
|
173
|
+
set_reference: orderedEntity.row_index,
|
|
174
|
+
});
|
|
175
|
+
});
|
|
208
176
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
177
|
+
this.$store
|
|
178
|
+
.dispatch("document/createAnnotation", annotations)
|
|
179
|
+
.then(() => {
|
|
180
|
+
this.$emit("close");
|
|
181
|
+
})
|
|
182
|
+
.catch((error) => {
|
|
183
|
+
this.$store.dispatch("document/createErrorMessage", {
|
|
184
|
+
error,
|
|
185
|
+
serverErrorMessage: this.$t("server_error"),
|
|
186
|
+
defaultErrorMessage: this.$t("error_creating_multi_ann"),
|
|
213
187
|
});
|
|
214
|
-
|
|
215
|
-
this.$emit("close");
|
|
188
|
+
});
|
|
216
189
|
},
|
|
217
190
|
deleteRow(index) {
|
|
218
191
|
this.rows.splice(index, 1);
|
|
@@ -274,7 +274,7 @@ export default {
|
|
|
274
274
|
trapFocus: true,
|
|
275
275
|
canCancel: false,
|
|
276
276
|
onCancel: this.disableLabelSetModalShowing,
|
|
277
|
-
customClass: "invisible-parent-modal",
|
|
277
|
+
customClass: "dv-ui-theme invisible-parent-modal",
|
|
278
278
|
events: {
|
|
279
279
|
labelSet: this.chooseLabelSet,
|
|
280
280
|
close: this.disableLabelSetModalShowing,
|