@konfuzio/document-validation-ui 0.1.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.
Files changed (131) hide show
  1. package/.eslintrc.js +11 -0
  2. package/.prettierrc.json +1 -0
  3. package/LICENSE +21 -0
  4. package/README.md +13 -0
  5. package/dist/css/app.0c8973f8.css +1 -0
  6. package/dist/css/chunk-vendors.053b6b6e.css +5 -0
  7. package/dist/favicon.ico +0 -0
  8. package/dist/index.html +1 -0
  9. package/dist/js/app.17fe48c4.js +2 -0
  10. package/dist/js/app.17fe48c4.js.map +1 -0
  11. package/dist/js/chunk-vendors.a48fca3f.js +47 -0
  12. package/dist/js/chunk-vendors.a48fca3f.js.map +1 -0
  13. package/jest.config.js +4 -0
  14. package/package.json +60 -0
  15. package/src/.DS_Store +0 -0
  16. package/src/api.js +49 -0
  17. package/src/assets/images/AcceptedCheckMark.vue +8 -0
  18. package/src/assets/images/AcceptedUser.vue +8 -0
  19. package/src/assets/images/ActionIcon.vue +60 -0
  20. package/src/assets/images/ArrowDownKey.vue +11 -0
  21. package/src/assets/images/ArrowUpKey.vue +11 -0
  22. package/src/assets/images/CategoryIconImg.vue +13 -0
  23. package/src/assets/images/CheckMark.vue +8 -0
  24. package/src/assets/images/EditDocIcon.vue +12 -0
  25. package/src/assets/images/EmptyStateImg.vue +129 -0
  26. package/src/assets/images/ErrorIcon.vue +28 -0
  27. package/src/assets/images/EyeIcon.vue +11 -0
  28. package/src/assets/images/FileNameNotSavedImage.vue +26 -0
  29. package/src/assets/images/FileNameSavedImage.vue +14 -0
  30. package/src/assets/images/FitZoomIcon.vue +16 -0
  31. package/src/assets/images/KeyboardIcon.vue +16 -0
  32. package/src/assets/images/MinusIcon.vue +13 -0
  33. package/src/assets/images/NotOptimizedIllustration.vue +651 -0
  34. package/src/assets/images/PlusIcon.vue +13 -0
  35. package/src/assets/images/QuestionMark.vue +12 -0
  36. package/src/assets/images/ServerImage.vue +63 -0
  37. package/src/assets/images/SplitLines.vue +18 -0
  38. package/src/assets/images/SplitZigZag.vue +16 -0
  39. package/src/assets/images/StatusImg.vue +14 -0
  40. package/src/assets/images/UserIcon.vue +8 -0
  41. package/src/assets/scss/annotation_details.scss +126 -0
  42. package/src/assets/scss/categorize_modal.scss +42 -0
  43. package/src/assets/scss/choose_label_set_modal.scss +62 -0
  44. package/src/assets/scss/document_action_bar.scss +37 -0
  45. package/src/assets/scss/document_annotations.scss +472 -0
  46. package/src/assets/scss/document_category.scss +80 -0
  47. package/src/assets/scss/document_dashboard.scss +47 -0
  48. package/src/assets/scss/document_dataset_status.scss +46 -0
  49. package/src/assets/scss/document_edit.scss +431 -0
  50. package/src/assets/scss/document_error.scss +81 -0
  51. package/src/assets/scss/document_handover.scss +200 -0
  52. package/src/assets/scss/document_name.scss +62 -0
  53. package/src/assets/scss/document_page.scss +8 -0
  54. package/src/assets/scss/document_thumbnails.scss +41 -0
  55. package/src/assets/scss/document_toolbar.scss +89 -0
  56. package/src/assets/scss/document_top_bar.scss +139 -0
  57. package/src/assets/scss/document_viewport_modal.scss +25 -0
  58. package/src/assets/scss/documents_list.scss +130 -0
  59. package/src/assets/scss/empty_state.scss +34 -0
  60. package/src/assets/scss/extracting_data.scss +35 -0
  61. package/src/assets/scss/imports.scss +1 -0
  62. package/src/assets/scss/main.scss +24 -0
  63. package/src/assets/scss/multi_ann_table_popup.scss +12 -0
  64. package/src/assets/scss/new_annotation.scss +86 -0
  65. package/src/assets/scss/scrolling_document.scss +19 -0
  66. package/src/assets/scss/variables.scss +696 -0
  67. package/src/components/App.vue +112 -0
  68. package/src/components/DocumentAnnotations/ActionButtons.vue +237 -0
  69. package/src/components/DocumentAnnotations/AnnotationContent.vue +249 -0
  70. package/src/components/DocumentAnnotations/AnnotationDetails.vue +292 -0
  71. package/src/components/DocumentAnnotations/AnnotationRow.vue +616 -0
  72. package/src/components/DocumentAnnotations/CategorizeModal.vue +159 -0
  73. package/src/components/DocumentAnnotations/ChooseLabelSetModal.vue +155 -0
  74. package/src/components/DocumentAnnotations/DocumentAnnotations.vue +502 -0
  75. package/src/components/DocumentAnnotations/DocumentLabel.vue +148 -0
  76. package/src/components/DocumentAnnotations/EmptyAnnotation.vue +222 -0
  77. package/src/components/DocumentAnnotations/EmptyState.vue +21 -0
  78. package/src/components/DocumentAnnotations/ExtractingData.vue +29 -0
  79. package/src/components/DocumentAnnotations/LoadingAnnotations.vue +43 -0
  80. package/src/components/DocumentAnnotations/LoadingLabels.vue +43 -0
  81. package/src/components/DocumentAnnotations/RejectedLabels.vue +96 -0
  82. package/src/components/DocumentAnnotations/index.js +8 -0
  83. package/src/components/DocumentCategory.vue +156 -0
  84. package/src/components/DocumentDashboard.vue +159 -0
  85. package/src/components/DocumentEdit/DocumentEdit.vue +279 -0
  86. package/src/components/DocumentEdit/EditPages.vue +213 -0
  87. package/src/components/DocumentEdit/EditSidebar.vue +118 -0
  88. package/src/components/DocumentEdit/SplitOverview.vue +182 -0
  89. package/src/components/DocumentEdit/index.js +4 -0
  90. package/src/components/DocumentError.vue +53 -0
  91. package/src/components/DocumentPage/ActionBar.vue +48 -0
  92. package/src/components/DocumentPage/BoxSelection.vue +149 -0
  93. package/src/components/DocumentPage/DocumentPage.vue +517 -0
  94. package/src/components/DocumentPage/DocumentToolbar.vue +145 -0
  95. package/src/components/DocumentPage/DummyPage.vue +53 -0
  96. package/src/components/DocumentPage/MultiAnnSelection.vue +302 -0
  97. package/src/components/DocumentPage/MultiAnnotationTablePopup.vue +253 -0
  98. package/src/components/DocumentPage/NewAnnotation.vue +283 -0
  99. package/src/components/DocumentPage/ScrollingDocument.vue +108 -0
  100. package/src/components/DocumentPage/ScrollingPage.vue +184 -0
  101. package/src/components/DocumentPage/index.js +5 -0
  102. package/src/components/DocumentThumbnails/DocumentThumbnails.vue +92 -0
  103. package/src/components/DocumentThumbnails/LoadingThumbnail.vue +25 -0
  104. package/src/components/DocumentThumbnails/index.js +1 -0
  105. package/src/components/DocumentTopBar/DocumentDatasetStatus.vue +103 -0
  106. package/src/components/DocumentTopBar/DocumentHandover.vue +202 -0
  107. package/src/components/DocumentTopBar/DocumentName.vue +224 -0
  108. package/src/components/DocumentTopBar/DocumentTopBar.vue +144 -0
  109. package/src/components/DocumentTopBar/DocumentTopBarButtons.vue +148 -0
  110. package/src/components/DocumentTopBar/KeyboardActionsDescription.vue +71 -0
  111. package/src/components/DocumentTopBar/index.js +5 -0
  112. package/src/components/DocumentsList/DocumentsList.vue +126 -0
  113. package/src/components/DocumentsList/index.js +1 -0
  114. package/src/components/ErrorMessage.vue +40 -0
  115. package/src/components/NotOptimizedViewportModal.vue +54 -0
  116. package/src/constants.js +4 -0
  117. package/src/directives/scroll.js +28 -0
  118. package/src/i18n.js +23 -0
  119. package/src/locales/de.json +114 -0
  120. package/src/locales/en.json +114 -0
  121. package/src/locales/es.json +113 -0
  122. package/src/main.js +87 -0
  123. package/src/store/category.js +193 -0
  124. package/src/store/display.js +238 -0
  125. package/src/store/document.js +1057 -0
  126. package/src/store/edit.js +210 -0
  127. package/src/store/index.js +22 -0
  128. package/src/store/project.js +95 -0
  129. package/src/store/selection.js +179 -0
  130. package/src/utils/utils.js +3 -0
  131. package/vue.config.js +13 -0
@@ -0,0 +1,302 @@
1
+ <template>
2
+ <v-group>
3
+ <v-rect
4
+ ref="multiAnnBoxSelection"
5
+ :config="tableConfig"
6
+ :stroke-scale-enabled="false"
7
+ @dragstart="changeStart"
8
+ @dragend="onChange"
9
+ @transformstart="changeStart"
10
+ @transformend="onChange"
11
+ />
12
+ <v-transformer ref="multiAnnBoxTransformer" :config="transformerConfig" />
13
+ <v-label
14
+ v-if="showButton"
15
+ :config="buttonConfig"
16
+ @mouseenter="onButtonEnter"
17
+ @mouseleave="onButtonLeave"
18
+ >
19
+ <v-tag
20
+ :config="{
21
+ fill: '#7B61FF',
22
+ cornerRadius: 4,
23
+ name: 'tag',
24
+ }"
25
+ />
26
+ <v-text
27
+ :config="{
28
+ align: 'right',
29
+ width: buttonWidth,
30
+ ellipsis: true,
31
+ wrap: 'none',
32
+ padding: 8,
33
+ text: $t('new_multi_ann_title'),
34
+ fill: 'white',
35
+ fontSize: 14,
36
+ cursor: 'pointer',
37
+ name: 'multiAnnButton',
38
+ }"
39
+ @click="openMultiAnnotationModal"
40
+ />
41
+ </v-label>
42
+ </v-group>
43
+ </template>
44
+
45
+ <script>
46
+ import { mapGetters, mapState, mapActions } from "vuex";
47
+ import { ChooseLabelSetModal } from "../DocumentAnnotations";
48
+
49
+ export default {
50
+ props: {
51
+ page: {
52
+ required: true,
53
+ type: Object,
54
+ },
55
+ },
56
+ data() {
57
+ const BUTTON_HEIGHT = 36;
58
+ const BUTTON_WIDTH = this.$i18n.locale === "de" ? 238 : 187;
59
+ return {
60
+ buttonWidth: BUTTON_WIDTH,
61
+ buttonHeight: BUTTON_HEIGHT,
62
+ isEditing: false,
63
+ showTable: false,
64
+ entities: [],
65
+ };
66
+ },
67
+ computed: {
68
+ showButton() {
69
+ return !this.isSelecting && !this.isEditing;
70
+ },
71
+ transformerConfig() {
72
+ return {
73
+ borderEnabled: false,
74
+ rotateEnabled: false,
75
+ ignoreStroke: true,
76
+ keepRatio: false,
77
+ anchorStroke: "#7B61FF",
78
+ anchorSize: 6,
79
+ };
80
+ },
81
+ tableConfig() {
82
+ return {
83
+ x: this.selection.start.x,
84
+ y: this.selection.start.y,
85
+ width: this.selection.end.x - this.selection.start.x,
86
+ height: this.selection.end.y - this.selection.start.y,
87
+ fill: this.isSelecting ? "#7B61FFB3" : "#7B61FF33",
88
+ stroke: this.isSelecting ? "transparent" : "#7B61FFB3",
89
+ strokeWidth: 1,
90
+ globalCompositeOperation: "multiply",
91
+ shadowForStrokeEnabled: false,
92
+ name: "multiAnnBoxSelection",
93
+ draggable: true,
94
+ };
95
+ },
96
+ buttonConfig() {
97
+ let x = this.selection.end.x;
98
+ let y = this.selection.end.y;
99
+ const marginTop = 4;
100
+
101
+ // check if selection was made from right to left
102
+ if (x < this.selection.start.x) {
103
+ x = this.selection.start.x;
104
+ }
105
+ if (y < this.selection.start.y) {
106
+ y = this.selection.start.y;
107
+ }
108
+
109
+ return {
110
+ x: x - this.buttonWidth,
111
+ y: y + marginTop,
112
+ height: this.buttonHeight,
113
+ width: this.buttonWidth,
114
+ };
115
+ },
116
+ ...mapState("selection", ["selection", "isSelecting"]),
117
+ ...mapGetters("display", ["clientToBbox"]),
118
+ ...mapGetters("document", ["entitiesOnSelection"]),
119
+ },
120
+ watch: {
121
+ isSelecting(newValue, oldValue) {
122
+ // if it ends selection
123
+ if (!newValue && oldValue) {
124
+ this.calculateEntities();
125
+ this.updateTransformer();
126
+ }
127
+ },
128
+ },
129
+ methods: {
130
+ openMultiAnnotationModal() {
131
+ this.$buefy.modal.open({
132
+ parent: this.$parent,
133
+ component: ChooseLabelSetModal,
134
+ hasModalCard: true,
135
+ trapFocus: true,
136
+ canCancel: false,
137
+ customClass: "invisible-parent-modal",
138
+ props: { isMultipleAnnotations: true },
139
+ events: {
140
+ labelSet: this.chooseLabelSet,
141
+ },
142
+ });
143
+ },
144
+ chooseLabelSet(labelSet) {
145
+ const tableSelection = {
146
+ labelSet,
147
+ position: {
148
+ x: this.selection.start.x,
149
+ y: this.selection.start.y,
150
+ width: this.selection.end.x - this.selection.start.x,
151
+ height: this.selection.end.y - this.selection.start.y,
152
+ },
153
+ entities: this.entities,
154
+ };
155
+ this.$store.dispatch("selection/disableSelection");
156
+ this.$emit("finished", tableSelection);
157
+ },
158
+
159
+ onButtonEnter() {
160
+ this.$emit("buttonEnter");
161
+ },
162
+
163
+ onButtonLeave() {
164
+ this.$emit("buttonLeave");
165
+ },
166
+ changeStart() {
167
+ this.isEditing = true;
168
+ },
169
+ /**
170
+ * This method is used for both transforms and drags since it just
171
+ * retrieves the rect's new attributes from the event and uses those
172
+ * to set the new selection state.
173
+ */
174
+ onChange(event) {
175
+ this.isEditing = false;
176
+
177
+ const { x, y, scaleX, scaleY, skewX, width, height } = event.target.attrs;
178
+ const realWidth = width * scaleX;
179
+ const realHeight = height * scaleY;
180
+ let start;
181
+ let end;
182
+
183
+ // we need to figure out if there's skewing going on, to fix start/end points
184
+ // (other cases appear to fix themselves automatically)
185
+ if (skewX >= 0) {
186
+ start = { x, y };
187
+ end = {
188
+ x: start.x + realWidth,
189
+ y: start.y + realHeight,
190
+ };
191
+ } else {
192
+ end = { x, y };
193
+ start = { x: end.x - realWidth, y: end.y - realHeight };
194
+ }
195
+
196
+ this.moveSelection({ start, end });
197
+
198
+ // reset node's everything after transform (we don't want to deal with that,
199
+ // just with regular x/y/width/height)
200
+ const node = this.$refs.multiAnnBoxSelection.getNode();
201
+ node.skewX(0);
202
+ node.skewY(0);
203
+ node.rotation(0);
204
+ node.scaleX(1);
205
+ node.scaleY(1);
206
+
207
+ this.calculateEntities();
208
+ this.updateTransformer();
209
+ },
210
+
211
+ updateTransformer() {
212
+ // here we need to manually attach or detach Transformer node
213
+ const transformer = this.$refs.multiAnnBoxTransformer;
214
+
215
+ // maybe we're out of sync and the transformer is not available, just return
216
+ if (!transformer) {
217
+ return;
218
+ }
219
+
220
+ const transformerNode = transformer.getNode();
221
+ const stage = transformerNode.getStage();
222
+ const selectedNode = stage.findOne(".multiAnnBoxSelection");
223
+
224
+ // do nothing if selected node is already attached
225
+ if (selectedNode === transformerNode.node()) {
226
+ return;
227
+ }
228
+
229
+ if (selectedNode) {
230
+ // attach to another node
231
+ transformerNode.nodes([selectedNode]);
232
+ } else {
233
+ // remove transformer
234
+ transformerNode.nodes([]);
235
+ }
236
+
237
+ transformerNode.getLayer().batchDraw();
238
+ },
239
+
240
+ calculateEntities() {
241
+ const box = this.clientToBbox(
242
+ this.page,
243
+ this.selection.start,
244
+ this.selection.end
245
+ );
246
+ const entities = this.entitiesOnSelection(box, this.page);
247
+
248
+ const offset = 4;
249
+ if (entities.length === 0) {
250
+ return;
251
+ }
252
+
253
+ const rows = [...new Set(entities.map((o) => o["top"]))];
254
+ rows.sort();
255
+
256
+ let joinRow = 0;
257
+ const jointRows = [];
258
+
259
+ // group entities that are near each other on Y axis
260
+ rows.forEach((row) => {
261
+ if (row - joinRow > offset) {
262
+ joinRow = row;
263
+ jointRows.push(row);
264
+ }
265
+ });
266
+
267
+ let cols = {};
268
+ jointRows.forEach((row) => {
269
+ const entityRow = [];
270
+ entities.forEach((item) => {
271
+ if (item.top === row || Math.abs(item.top - row) <= offset) {
272
+ entityRow.push(item);
273
+ }
274
+ });
275
+ entityRow.sort((a, b) => a.x0 - b.x0);
276
+
277
+ const finalRow = {};
278
+ let previousEntity = null;
279
+
280
+ // group entities that are near each other on X axis
281
+ entityRow.forEach((entity) => {
282
+ let xGroup = entity.x0;
283
+ if (previousEntity && previousEntity.x1 + offset > entity.x0) {
284
+ // compare to previous one
285
+ finalRow[previousEntity.xGroup].push(entity);
286
+ xGroup = previousEntity.xGroup;
287
+ } else {
288
+ finalRow[entity.x0] = [entity];
289
+ }
290
+ previousEntity = entity;
291
+ previousEntity.xGroup = xGroup;
292
+ });
293
+
294
+ cols[row] = finalRow;
295
+ });
296
+
297
+ this.entities = cols;
298
+ },
299
+ ...mapActions("selection", ["moveSelection"]),
300
+ },
301
+ };
302
+ </script>
@@ -0,0 +1,253 @@
1
+ <template>
2
+ <div
3
+ class="multi-ann-table-popup"
4
+ :style="{
5
+ left: `${tablePosition.x}px`,
6
+ top: `${tablePosition.y - 22}px`,
7
+ width: `${tablePosition.width}px`,
8
+ height: `${tablePosition.height}px`,
9
+ maxWidth: `${pageSize.width}px`,
10
+ maxHeight: `${pageSize.height}px`,
11
+ }"
12
+ >
13
+ <b-table
14
+ ref="table"
15
+ class="full-height"
16
+ detail-icon="faScissors"
17
+ :data="rows"
18
+ :columns="columns"
19
+ :narrowed="true"
20
+ :bordered="true"
21
+ draggable-column
22
+ @columndragstart="columndragstart"
23
+ @columndrop="columndrop"
24
+ @columndragover="columndragover"
25
+ @columndragleave="columndragleave"
26
+ >
27
+ </b-table>
28
+ </div>
29
+ </template>
30
+
31
+ <script>
32
+ import { mapState } from "vuex";
33
+
34
+ export default {
35
+ name: "MultiAnnotationTablePopup",
36
+
37
+ props: {
38
+ tablePosition: {
39
+ required: true,
40
+ type: Object,
41
+ default: null,
42
+ },
43
+ pageSize: {
44
+ required: true,
45
+ type: Object,
46
+ default: null,
47
+ },
48
+ labelSet: {
49
+ required: true,
50
+ type: Object,
51
+ default: null,
52
+ },
53
+ groupedEntities: {
54
+ required: true,
55
+ type: Object,
56
+ default: null,
57
+ },
58
+ },
59
+ data() {
60
+ const columns = this.labelSet.labels.map((label) => {
61
+ return {
62
+ field: `${label.id}`,
63
+ label: label.name,
64
+ centered: true,
65
+ };
66
+ });
67
+ return {
68
+ rows: [],
69
+ columns,
70
+ counter: 0,
71
+ draggingColumn: null,
72
+ draggingColumnIndex: null,
73
+ orderedEntities: [],
74
+ };
75
+ },
76
+ computed: {
77
+ ...mapState("document", ["documentId"]),
78
+ },
79
+ mounted() {
80
+ this.handleRows();
81
+ setTimeout(() => {
82
+ // prevent click propagation when opening the popup
83
+ document.body.addEventListener("click", this.clickOutside);
84
+ this.$refs.table.$el.scrollIntoView({
85
+ behavior: "smooth",
86
+ block: "nearest",
87
+ inline: "center",
88
+ });
89
+ }, 200);
90
+
91
+ // show action bar
92
+ this.$store.dispatch("display/showDocumentActionBar", {
93
+ show: true,
94
+ text: this.$t("drag_drop_columns_multi_ann"),
95
+ icon: "drag",
96
+ loading: false,
97
+ action: () => {
98
+ this.submitAnnotations();
99
+ this.$emit("close");
100
+ },
101
+ });
102
+ },
103
+ destroyed() {
104
+ this.$store.dispatch("display/showDocumentActionBar", { show: false });
105
+ this.$store.dispatch("selection/disableSelection");
106
+ document.body.removeEventListener("click", this.clickOutside);
107
+ },
108
+ methods: {
109
+ handleRows() {
110
+ this.rows = [];
111
+ this.orderedEntities = []; // this will match the order of entities in the table so we have a way of tracking them once we submit
112
+ let rowIndex = 0;
113
+
114
+ Object.entries(this.groupedEntities).forEach(([key, groupedEntity]) => {
115
+ let row = null;
116
+ this.columns.forEach((column, index) => {
117
+ let spans = [];
118
+ if (
119
+ Object.entries(groupedEntity)[index] &&
120
+ Object.entries(groupedEntity)[index].length > 0
121
+ ) {
122
+ spans = Object.entries(groupedEntity)[index][1];
123
+ }
124
+ const entityExists = spans.length > 0;
125
+
126
+ let textContent = "";
127
+
128
+ spans.forEach((entity) => {
129
+ textContent = `${textContent} ${entity.offset_string}`;
130
+ });
131
+
132
+ row = {
133
+ ...row,
134
+ [column.field]: textContent,
135
+ };
136
+ if (entityExists) {
137
+ const customEntity = {
138
+ spans: [...spans],
139
+ label_id: column.field,
140
+ row_index: rowIndex,
141
+ };
142
+
143
+ this.orderedEntities.push(customEntity);
144
+ }
145
+ });
146
+ if (row !== null) {
147
+ rowIndex++;
148
+ }
149
+ this.rows.push(row);
150
+ });
151
+ },
152
+
153
+ clickOutside(event) {
154
+ if (!(this.$el == event.target || this.$el.contains(event.target))) {
155
+ this.$emit("close");
156
+ }
157
+ },
158
+ async submitAnnotations() {
159
+ let errorMessageShown = false;
160
+ let previousAnnotationSetId = null;
161
+ let previousRowIndex = 0;
162
+
163
+ this.$store.dispatch("display/showDocumentActionBar", {
164
+ show: true,
165
+ loading: false,
166
+ action: true,
167
+ });
168
+
169
+ // traditional for to await for every request
170
+ for (let i = 0; i < this.orderedEntities.length; i++) {
171
+ const groupedEntity = this.orderedEntities[i];
172
+
173
+ const annotationToCreate = {
174
+ document: this.documentId,
175
+ span: groupedEntity.spans,
176
+ label: groupedEntity.label_id,
177
+ is_correct: true,
178
+ revised: false,
179
+ };
180
+
181
+ if (groupedEntity.row_index !== previousRowIndex) {
182
+ // if line changed then reset annotation set
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
+ });
208
+
209
+ // set to true to only show 1 error
210
+ // the first time it appears
211
+ errorMessageShown = true;
212
+ }
213
+ });
214
+ }
215
+ this.$emit("close");
216
+ },
217
+ deleteRow(index) {
218
+ this.rows.splice(index, 1);
219
+ },
220
+
221
+ //#region Column Drag
222
+ columndragstart(payload) {
223
+ this.draggingColumn = payload.column;
224
+ this.draggingColumnIndex = payload.index;
225
+ payload.event.dataTransfer.effectAllowed = "copy";
226
+ },
227
+ columndragover(payload) {
228
+ payload.event.dataTransfer.dropEffect = "copy";
229
+ payload.event.target.closest("th").classList.add("is-selected");
230
+ payload.event.preventDefault();
231
+ },
232
+ columndragleave(payload) {
233
+ payload.event.target.closest("th").classList.remove("is-selected");
234
+ payload.event.preventDefault();
235
+ },
236
+ columndrop(payload) {
237
+ payload.event.target.closest("th").classList.remove("is-selected");
238
+ const droppedOnColumnIndex = payload.index;
239
+
240
+ const column = this.columns[this.draggingColumnIndex];
241
+ this.columns.splice(this.draggingColumnIndex, 1);
242
+ this.columns.splice(droppedOnColumnIndex, 0, column);
243
+ this.handleRows();
244
+ },
245
+ //#endregion
246
+ },
247
+ };
248
+ </script>
249
+ <style
250
+ scoped
251
+ lang="scss"
252
+ src="../../assets/scss/multi_ann_table_popup.scss"
253
+ ></style>