@konfuzio/document-validation-ui 0.1.59 → 0.2.0-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.
Files changed (68) hide show
  1. package/cypress.config.js +6 -6
  2. package/dist/css/app.css +1 -1
  3. package/dist/index.html +1 -1
  4. package/dist/js/app.js +1 -1
  5. package/dist/js/app.js.map +1 -1
  6. package/dist/js/chunk-vendors.js +66 -23
  7. package/dist/js/chunk-vendors.js.map +1 -1
  8. package/jest.config.js +22 -2
  9. package/package.json +32 -38
  10. package/src/assets/scss/ann_set_table_options.scss +4 -4
  11. package/src/assets/scss/annotation_action_buttons.scss +29 -7
  12. package/src/assets/scss/annotation_details.scss +9 -9
  13. package/src/assets/scss/choose_label_set_modal.scss +5 -5
  14. package/src/assets/scss/document_action_bar.scss +3 -3
  15. package/src/assets/scss/document_annotations.scss +45 -45
  16. package/src/assets/scss/document_category.scss +8 -8
  17. package/src/assets/scss/document_dashboard.scss +6 -1
  18. package/src/assets/scss/document_edit.scss +30 -30
  19. package/src/assets/scss/document_error.scss +6 -6
  20. package/src/assets/scss/document_name.scss +6 -6
  21. package/src/assets/scss/document_page.scss +3 -3
  22. package/src/assets/scss/document_search_bar.scss +7 -7
  23. package/src/assets/scss/document_set_chooser.scss +3 -3
  24. package/src/assets/scss/document_thumbnails.scss +7 -7
  25. package/src/assets/scss/document_toolbar.scss +10 -10
  26. package/src/assets/scss/document_top_bar.scss +11 -11
  27. package/src/assets/scss/document_viewport_modal.scss +3 -3
  28. package/src/assets/scss/documents_list.scss +11 -12
  29. package/src/assets/scss/edit_page_thumbnail.scss +6 -6
  30. package/src/assets/scss/empty_state.scss +4 -4
  31. package/src/assets/scss/error_page.scss +2 -2
  32. package/src/assets/scss/extracting_data.scss +3 -3
  33. package/src/assets/scss/multi_ann_table_overlay.scss +3 -3
  34. package/src/assets/scss/multi_ann_table_popup.scss +1 -1
  35. package/src/assets/scss/new_annotation.scss +25 -19
  36. package/src/assets/scss/scrolling_document.scss +1 -1
  37. package/src/assets/scss/theme.scss +64 -52
  38. package/src/assets/scss/variables.scss +2 -0
  39. package/src/components/App.vue +9 -14
  40. package/src/components/DocumentAnnotations/AnnotationActionButtons.vue +31 -7
  41. package/src/components/DocumentAnnotations/AnnotationContent.vue +25 -52
  42. package/src/components/DocumentAnnotations/AnnotationRow.vue +108 -51
  43. package/src/components/DocumentAnnotations/DocumentAnnotations.vue +12 -6
  44. package/src/components/DocumentAnnotations/DocumentLabel.vue +12 -122
  45. package/src/components/DocumentAnnotations/EmptyAnnotation.vue +31 -70
  46. package/src/components/DocumentDashboard.vue +12 -17
  47. package/src/components/DocumentEdit/EditPages.vue +51 -46
  48. package/src/components/DocumentEdit/EditSidebar.vue +0 -9
  49. package/src/components/DocumentPage/{NewAnnotation.vue → AnnotationPopup.vue} +123 -94
  50. package/src/components/DocumentPage/BoxSelection.vue +16 -49
  51. package/src/components/DocumentPage/DocumentPage.vue +56 -153
  52. package/src/components/DocumentPage/DocumentToolbar.vue +0 -1
  53. package/src/components/DocumentPage/PlaceholderSelection.vue +51 -0
  54. package/src/components/DocumentPage/SpanSelection.vue +259 -0
  55. package/src/components/DocumentThumbnails/LoadingThumbnail.vue +3 -6
  56. package/src/components/DocumentTopBar/DocumentTopBar.vue +4 -2
  57. package/src/constants.js +1 -7
  58. package/src/i18n.js +2 -5
  59. package/src/locales/de.json +2 -1
  60. package/src/locales/en.json +2 -1
  61. package/src/locales/es.json +2 -1
  62. package/src/main.js +14 -16
  63. package/src/store/display.js +33 -22
  64. package/src/store/document.js +131 -10
  65. package/src/store/index.js +5 -8
  66. package/src/store/selection.js +152 -76
  67. package/src/assets/scss/imports.scss +0 -1
  68. package/src/components/DocumentPage/EditAnnotation.vue +0 -372
@@ -1,10 +1,25 @@
1
1
  <!-- eslint-disable vue/no-v-html -->
2
2
  <template>
3
- <div class="annotation-popup" :style="{ left: `${left}px`, top: `${top}px` }">
4
- <div v-if="!textFromEntities" class="popup-input">
5
- <b-icon icon="spinner" class="fa-spin loading-icon-size spinner" />
3
+ <div
4
+ class="annotation-popup"
5
+ :style="{
6
+ left: `${left}px`,
7
+ top: `${top}px`,
8
+ height: `${heightOfPopup}px`,
9
+ }"
10
+ >
11
+ <div v-if="!editAnnotation">
12
+ <div v-if="spanLoading" class="popup-input">
13
+ <b-icon icon="spinner" class="fa-spin loading-icon-size spinner" />
14
+ </div>
15
+ <input
16
+ v-else
17
+ v-model="textFromEntities"
18
+ class="popup-input"
19
+ type="text"
20
+ :disabled="true"
21
+ />
6
22
  </div>
7
- <input v-else v-model="textFromEntities" class="popup-input" type="text" />
8
23
  <b-dropdown
9
24
  v-model="selectedSet"
10
25
  :disabled="!textFromEntities"
@@ -27,17 +42,19 @@
27
42
  ]"
28
43
  type="is-text"
29
44
  >
30
- {{
31
- selectedSet
32
- ? `${selectedSet.label_set.name} ${
33
- selectedSet.id
34
- ? numberOfAnnotationSetGroup(selectedSet)
35
- : `${numberOfLabelSetGroup(selectedSet.label_set)} (${$t(
36
- "new"
37
- )})`
38
- }`
39
- : $t("select_annotation_set")
40
- }}
45
+ <span class="input-text">
46
+ {{
47
+ selectedSet
48
+ ? `${selectedSet.label_set.name} ${
49
+ selectedSet.id
50
+ ? numberOfAnnotationSetGroup(selectedSet)
51
+ : `${numberOfLabelSetGroup(selectedSet.label_set)} (${$t(
52
+ "new"
53
+ )})`
54
+ }`
55
+ : $t("select_annotation_set")
56
+ }}</span
57
+ >
41
58
  <span class="caret-icon">
42
59
  <b-icon icon="angle-down" size="is-small" class="caret" />
43
60
  </span>
@@ -72,7 +89,6 @@
72
89
  size="is-large"
73
90
  position="is-bottom"
74
91
  class="bottom-aligned"
75
- :close-delay="5000"
76
92
  >
77
93
  <template #content>
78
94
  <div
@@ -99,13 +115,13 @@
99
115
  ]"
100
116
  type="is-text"
101
117
  >
102
- {{
118
+ <span class="input-text">{{
103
119
  selectedLabel
104
120
  ? selectedLabel.name
105
121
  : labels && labels.length === 0
106
122
  ? $t("no_labels_to_choose")
107
123
  : $t("select_label")
108
- }}
124
+ }}</span>
109
125
  <span class="caret-icon">
110
126
  <b-icon icon="angle-down" size="is-small" class="caret" />
111
127
  </span>
@@ -144,15 +160,12 @@
144
160
  * This component is used to show a popup
145
161
  * for creating a new annotation.
146
162
  */
147
- const heightOfPopup = 192;
148
- const margin = 12;
149
- const widthOfPopup = 205;
150
163
 
151
164
  import { mapGetters, mapState } from "vuex";
152
165
 
153
166
  export default {
154
167
  props: {
155
- newAnnotation: {
168
+ spans: {
156
169
  required: true,
157
170
  type: Array,
158
171
  },
@@ -171,6 +184,9 @@ export default {
171
184
  },
172
185
  data() {
173
186
  return {
187
+ heightOfPopup: 192,
188
+ margin: 12,
189
+ widthOfPopup: 205,
174
190
  selectedLabel: null,
175
191
  selectedSet: null,
176
192
  labels: null,
@@ -180,51 +196,48 @@ export default {
180
196
  };
181
197
  },
182
198
  computed: {
183
- ...mapState("document", ["annotationSets", "documentId"]),
199
+ ...mapState("document", ["annotationSets", "documentId", "editAnnotation"]),
184
200
  ...mapGetters("document", [
185
201
  "numberOfAnnotationSetGroup",
186
202
  "numberOfLabelSetGroup",
187
203
  "labelsFilteredForAnnotationCreation",
188
204
  ]),
189
205
  ...mapState("display", ["showBranding"]),
190
- ...mapGetters("display", ["clientToBbox"]),
191
- ...mapState("selection", ["spanSelection", "selection"]),
206
+ ...mapGetters("display", ["clientToBbox", "bboxToRect"]),
207
+ ...mapState("selection", ["spanSelection", "selection", "spanLoading"]),
192
208
  top() {
193
209
  if (this.selection && this.selection.end) {
194
- const top = this.selection.end.y + margin;
210
+ const top = this.selection.end.y + this.margin;
195
211
  //check if the popup will not go off the container on the top
196
- return top + heightOfPopup < this.containerHeight
212
+ return top + this.heightOfPopup < this.containerHeight
197
213
  ? top
198
- : this.selection.end.y - heightOfPopup;
214
+ : this.selection.end.y - this.heightOfPopup;
199
215
  } else {
200
- const top = this.newAnnotation[0].scaled.y - heightOfPopup; // subtract the height of the popup plus some margin
216
+ const normalizedSpan = this.bboxToRect(this.page, this.spans[0]);
217
+ const top = normalizedSpan.y - this.heightOfPopup; // subtract the height of the popup plus some margin
201
218
 
202
219
  //check if the popup will not go off the container on the top
203
- return this.newAnnotation[0].scaled.y > heightOfPopup
220
+ return normalizedSpan.y > this.heightOfPopup
204
221
  ? top
205
- : this.newAnnotation[0].scaled.y +
206
- this.newAnnotation[0].scaled.height +
207
- margin;
222
+ : normalizedSpan.y + normalizedSpan.height + this.margin;
208
223
  }
209
224
  },
210
225
  left() {
211
226
  if (this.selection && this.selection.start && this.selection.end) {
212
227
  const left = this.selection.start.x;
213
228
  //check if the popup will not go off the container on the right
214
- return left + widthOfPopup < this.containerWidth
229
+ return left + this.widthOfPopup < this.containerWidth
215
230
  ? left
216
- : this.containerWidth - widthOfPopup;
217
- return this.selection.start.x;
231
+ : this.containerWidth - this.widthOfPopup;
218
232
  } else {
233
+ const normalizedSpan = this.bboxToRect(this.page, this.spans[0]);
219
234
  const left =
220
- this.newAnnotation[0].scaled.x +
221
- this.newAnnotation[0].scaled.width / 2 -
222
- widthOfPopup / 2; // add the entity half width to be centered and then subtract half the width of the popup
235
+ normalizedSpan.x + normalizedSpan.width / 2 - this.widthOfPopup / 2; // add the entity half width to be centered and then subtract half the width of the popup
223
236
 
224
237
  //check if the popup will not go off the container
225
- if (left + widthOfPopup > this.containerWidth) {
238
+ if (left + this.widthOfPopup > this.containerWidth) {
226
239
  // on the right side
227
- return this.containerWidth - widthOfPopup;
240
+ return this.containerWidth - this.widthOfPopup;
228
241
  } else {
229
242
  // on the left side
230
243
  return left > 0 ? left : 0;
@@ -232,10 +245,8 @@ export default {
232
245
  }
233
246
  },
234
247
  textFromEntities() {
235
- if (!this.spanSelection) return;
236
-
237
248
  let text = "";
238
- this.spanSelection.forEach((span) => {
249
+ this.spans.forEach((span) => {
239
250
  text = `${text} ${span.offset_string}`;
240
251
  });
241
252
 
@@ -243,17 +254,23 @@ export default {
243
254
  },
244
255
  },
245
256
  watch: {
246
- selectedSet(newValue) {
257
+ selectedSet(newValue, oldValue) {
247
258
  this.selectedLabel = null;
248
259
  this.labels = this.labelsFilteredForAnnotationCreation(newValue);
249
- if (this.labels.length === 1) {
260
+ if (oldValue === null && this.editAnnotation) {
261
+ this.selectedLabel = this.editAnnotation.label;
262
+ } else if (this.labels.length === 1) {
250
263
  this.selectedLabel = this.labels[0];
251
264
  }
252
265
  },
253
266
  },
254
267
  mounted() {
255
268
  this.setsList = this.orderedSetList([...this.annotationSets]);
256
- if (this.setsList.length === 1) {
269
+
270
+ if (this.editAnnotation) {
271
+ this.heightOfPopup = 142;
272
+ this.selectedSet = this.editAnnotation.annotationSet;
273
+ } else if (this.setsList.length === 1) {
257
274
  this.selectedSet = this.setsList[0];
258
275
  }
259
276
 
@@ -262,7 +279,7 @@ export default {
262
279
  document.body.addEventListener("click", this.clickOutside);
263
280
  }, 200);
264
281
  },
265
- destroyed() {
282
+ unmounted() {
266
283
  document.body.removeEventListener("click", this.clickOutside);
267
284
  },
268
285
  methods: {
@@ -283,61 +300,73 @@ export default {
283
300
  return setsList;
284
301
  },
285
302
  close() {
286
- this.$store.dispatch("selection/setSelectedEntities", null);
287
- this.$store.dispatch("selection/endSelection");
303
+ if (this.editAnnotation) {
304
+ this.$store.dispatch("document/resetEditAnnotation");
305
+ }
306
+ this.$store.dispatch("selection/disableSelection");
288
307
  this.$emit("close");
289
308
  },
290
309
  save() {
291
- this.loading = true;
292
- const span = this.newAnnotation.flatMap((ann) => {
293
- return {
294
- ...ann.original,
295
- offset_string: ann.original.offset_string,
296
- };
297
- });
310
+ if (this.editAnnotation) {
311
+ this.loading = true;
312
+ this.$store.dispatch("document/setEditAnnotation", {
313
+ id: this.editAnnotation.id,
314
+ index: this.editAnnotation.index,
315
+ label: this.selectedLabel,
316
+ labelSet: this.selectedSet.label_set,
317
+ annotationSet: this.selectedSet,
318
+ pageNumber: this.editAnnotation.pageNumber,
319
+ });
298
320
 
299
- let selection_bbox = null;
321
+ document.getElementById("save-ann").click();
300
322
 
301
- if (this.selection && this.selection.start && this.selection.end) {
302
- selection_bbox = this.clientToBbox(
303
- this.page,
304
- this.selection.start,
305
- this.selection.end
306
- );
307
- }
323
+ return;
324
+ } else {
325
+ this.loading = true;
308
326
 
309
- const annotationToCreate = {
310
- document: this.documentId,
311
- span: span,
312
- label: this.selectedLabel.id,
313
- is_correct: true,
314
- revised: false,
315
- };
327
+ let selection_bbox = null;
316
328
 
317
- if (selection_bbox) {
318
- annotationToCreate.selection_bbox = selection_bbox;
319
- }
329
+ if (this.selection && this.selection.start && this.selection.end) {
330
+ selection_bbox = this.clientToBbox(
331
+ this.page,
332
+ this.selection.start,
333
+ this.selection.end
334
+ );
335
+ }
320
336
 
321
- if (this.selectedSet.id) {
322
- annotationToCreate.annotation_set = this.selectedSet.id;
323
- } else {
324
- annotationToCreate.label_set = this.selectedSet.label_set.id;
325
- }
326
- this.$store
327
- .dispatch("document/createAnnotation", {
328
- annotation: annotationToCreate,
329
- })
330
- .catch((error) => {
331
- this.$store.dispatch("document/createErrorMessage", {
332
- error,
333
- serverErrorMessage: this.$t("server_error"),
334
- defaultErrorMessage: this.$t("error_creating_annotation"),
337
+ const annotationToCreate = {
338
+ document: this.documentId,
339
+ span: this.spans,
340
+ label: this.selectedLabel.id,
341
+ is_correct: true,
342
+ revised: false,
343
+ };
344
+
345
+ if (selection_bbox) {
346
+ annotationToCreate.selection_bbox = selection_bbox;
347
+ }
348
+
349
+ if (this.selectedSet.id) {
350
+ annotationToCreate.annotation_set = this.selectedSet.id;
351
+ } else {
352
+ annotationToCreate.label_set = this.selectedSet.label_set.id;
353
+ }
354
+ this.$store
355
+ .dispatch("document/createAnnotation", {
356
+ annotation: annotationToCreate,
357
+ })
358
+ .catch((error) => {
359
+ this.$store.dispatch("document/createErrorMessage", {
360
+ error,
361
+ serverErrorMessage: this.$t("server_error"),
362
+ defaultErrorMessage: this.$t("error_creating_annotation"),
363
+ });
364
+ })
365
+ .finally(() => {
366
+ this.close();
367
+ this.loading = false;
335
368
  });
336
- })
337
- .finally(() => {
338
- this.close();
339
- this.loading = false;
340
- });
369
+ }
341
370
  },
342
371
  chooseLabelSet(labelSet) {
343
372
  // check if there's already a new entry for that label set to be created
@@ -13,11 +13,6 @@
13
13
  ref="boxTransformer"
14
14
  :config="transformerConfig"
15
15
  />
16
- <v-rect
17
- v-if="selection.placeholderBox"
18
- ref="placeholderSelection"
19
- :config="placeholderConfig"
20
- />
21
16
  </v-group>
22
17
  </template>
23
18
 
@@ -56,21 +51,7 @@ export default {
56
51
  draggable: true,
57
52
  };
58
53
  },
59
- placeholderConfig() {
60
- return {
61
- x: this.selection.placeholderBox.x,
62
- y: this.selection.placeholderBox.y,
63
- width: this.selection.placeholderBox.width,
64
- height: this.selection.placeholderBox.height,
65
- fill: "transparent",
66
- stroke: "#41af85",
67
- strokeWidth: 3,
68
- globalCompositeOperation: "multiply",
69
- shadowForStrokeEnabled: false,
70
- name: "placeholderSelection",
71
- draggable: false,
72
- };
73
- },
54
+
74
55
  transformerConfig() {
75
56
  return {
76
57
  borderEnabled: false,
@@ -87,7 +68,8 @@ export default {
87
68
  "elementSelected",
88
69
  "spanSelection",
89
70
  ]),
90
- ...mapGetters("display", ["clientToBbox"]),
71
+ ...mapState("document", ["editAnnotation"]),
72
+ ...mapGetters("display", ["clientToBbox", "scaledEntities"]),
91
73
  ...mapGetters("selection", ["isSelectionValid", "entitiesOnSelection"]),
92
74
  },
93
75
  watch: {
@@ -106,19 +88,19 @@ export default {
106
88
  },
107
89
  methods: {
108
90
  handleSelection() {
109
- if (!this.elementSelected) {
110
- const box = this.clientToBbox(
111
- this.page,
112
- this.selection.start,
113
- this.selection.end
114
- );
115
- this.$emit(
116
- "createAnnotations",
117
- this.entitiesOnSelection(box, this.page)
118
- );
119
- } else {
120
- this.getBoxSelectionContent();
121
- }
91
+ const box = this.clientToBbox(
92
+ this.page,
93
+ this.selection.start,
94
+ this.selection.end
95
+ );
96
+
97
+ this.$store.dispatch("selection/entitySelection", {
98
+ entities: this.scaledEntities(
99
+ this.entitiesOnSelection(box, this.page),
100
+ this.page
101
+ ),
102
+ selection: box,
103
+ });
122
104
  },
123
105
  updateTransformer() {
124
106
  // here we need to manually attach or detach Transformer node
@@ -152,21 +134,6 @@ export default {
152
134
  transformerNode.getLayer().batchDraw();
153
135
  },
154
136
 
155
- getBoxSelectionContent() {
156
- if (!this.isSelecting) {
157
- const box = this.clientToBbox(
158
- this.page,
159
- this.selection.start,
160
- this.selection.end
161
- );
162
- this.$emit("selectEntities", this.entitiesOnSelection(box, this.page));
163
- this.$store.dispatch("selection/getTextFromBboxes", {
164
- box,
165
- entities: false,
166
- });
167
- }
168
- },
169
-
170
137
  /**
171
138
  * This method is used for both transforms and drags since it just
172
139
  * retrieves the rect's new attributes from the event and uses those