@konfuzio/document-validation-ui 0.1.14 → 0.1.15

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 (101) hide show
  1. package/README.md +12 -0
  2. package/cypress.config.js +13 -0
  3. package/dist/css/app.css +1 -1
  4. package/dist/index.html +1 -1
  5. package/dist/js/app.js +1 -1
  6. package/dist/js/app.js.map +1 -1
  7. package/dist/js/chunk-vendors.js +3 -3
  8. package/dist/js/chunk-vendors.js.map +1 -1
  9. package/package.json +5 -1
  10. package/src/api.js +53 -23
  11. package/src/assets/images/DraggableIcon.vue +14 -0
  12. package/src/assets/images/GridIcon.vue +16 -0
  13. package/src/assets/images/MagicWandIcon.vue +16 -0
  14. package/src/assets/images/NotFoundIcon.vue +16 -0
  15. package/src/assets/images/ServerImage.vue +19 -9
  16. package/src/assets/images/SettingsIcon.vue +14 -0
  17. package/src/assets/images/SplitZigZag.vue +47 -14
  18. package/src/assets/images/StarIcon.vue +16 -0
  19. package/src/assets/scss/ann_set_table_options.scss +26 -0
  20. package/src/assets/scss/annotation_details.scss +86 -71
  21. package/src/assets/scss/choose_label_set_modal.scss +1 -1
  22. package/src/assets/scss/document_annotations.scss +242 -229
  23. package/src/assets/scss/document_category.scss +12 -7
  24. package/src/assets/scss/document_dashboard.scss +7 -2
  25. package/src/assets/scss/document_edit.scss +151 -173
  26. package/src/assets/scss/document_name.scss +0 -2
  27. package/src/assets/scss/document_thumbnails.scss +1 -1
  28. package/src/assets/scss/document_toolbar.scss +23 -1
  29. package/src/assets/scss/document_top_bar.scss +40 -1
  30. package/src/assets/scss/edit_page_thumbnail.scss +53 -0
  31. package/src/assets/scss/multi_ann_table_overlay.scss +38 -0
  32. package/src/assets/scss/new_annotation.scss +17 -3
  33. package/src/assets/scss/scrolling_document.scss +1 -1
  34. package/src/assets/scss/theme.scss +801 -0
  35. package/src/assets/scss/variables.scss +5 -663
  36. package/src/components/App.cy.js +7 -0
  37. package/src/components/App.vue +98 -11
  38. package/src/components/DocumentAnnotations/AnnotationActionButtons.vue +168 -0
  39. package/src/components/DocumentAnnotations/AnnotationContent.vue +50 -84
  40. package/src/components/DocumentAnnotations/AnnotationDetails.vue +37 -12
  41. package/src/components/DocumentAnnotations/AnnotationRow.vue +244 -199
  42. package/src/components/DocumentAnnotations/AnnotationSetActionButtons.vue +89 -0
  43. package/src/components/DocumentAnnotations/ChooseLabelSetModal.vue +4 -2
  44. package/src/components/DocumentAnnotations/DocumentAnnotations.cy.js +295 -0
  45. package/src/components/DocumentAnnotations/DocumentAnnotations.vue +195 -146
  46. package/src/components/DocumentAnnotations/DocumentLabel.vue +46 -9
  47. package/src/components/DocumentAnnotations/EmptyAnnotation.vue +59 -88
  48. package/src/components/DocumentAnnotations/ExtractingData.vue +18 -6
  49. package/src/components/DocumentAnnotations/MultiAnnotationTableOverlay.vue +337 -0
  50. package/src/components/DocumentAnnotations/index.js +1 -1
  51. package/src/components/DocumentCategory.vue +89 -65
  52. package/src/components/DocumentDashboard.vue +59 -48
  53. package/src/components/DocumentEdit/DocumentEdit.vue +302 -105
  54. package/src/components/DocumentEdit/EditConfirmationModal.vue +55 -0
  55. package/src/components/DocumentEdit/EditPageThumbnail.vue +114 -0
  56. package/src/components/DocumentEdit/EditPages.vue +60 -103
  57. package/src/components/DocumentEdit/EditSidebar.vue +101 -48
  58. package/src/components/DocumentEdit/{SplitOverview.vue → RenameAndCategorize.vue} +15 -13
  59. package/src/components/DocumentEdit/SidebarButtons.vue +53 -0
  60. package/src/components/DocumentEdit/SplitInfoBar.vue +21 -0
  61. package/src/components/DocumentEdit/index.js +1 -1
  62. package/src/components/{DocumentError.vue → DocumentModals/DocumentErrorModal.vue} +9 -8
  63. package/src/components/{NotOptimizedViewportModal.vue → DocumentModals/NotOptimizedViewportModal.vue} +2 -2
  64. package/src/components/DocumentPage/ActionBar.vue +3 -3
  65. package/src/components/DocumentPage/AnnSetTableOptions.vue +110 -0
  66. package/src/components/DocumentPage/BoxSelection.vue +4 -1
  67. package/src/components/DocumentPage/DocumentPage.vue +92 -68
  68. package/src/components/DocumentPage/DocumentToolbar.vue +105 -16
  69. package/src/components/DocumentPage/DummyPage.vue +9 -7
  70. package/src/components/DocumentPage/MultiAnnSelection.vue +96 -27
  71. package/src/components/DocumentPage/NewAnnotation.vue +31 -35
  72. package/src/components/DocumentPage/ScrollingDocument.vue +46 -5
  73. package/src/components/DocumentPage/ScrollingPage.vue +5 -6
  74. package/src/components/DocumentThumbnails/DocumentThumbnails.cy.js +64 -0
  75. package/src/components/DocumentThumbnails/DocumentThumbnails.vue +53 -13
  76. package/src/components/DocumentTopBar/DocumentName.vue +16 -4
  77. package/src/components/DocumentTopBar/DocumentTopBar.vue +86 -15
  78. package/src/components/DocumentTopBar/DocumentTopBarButtons.vue +99 -72
  79. package/src/components/DocumentTopBar/KeyboardActionsDescription.vue +6 -3
  80. package/src/components/DocumentsList/DocumentsList.vue +6 -2
  81. package/src/components/index.js +1 -0
  82. package/src/constants.js +2 -1
  83. package/src/icons.js +45 -0
  84. package/src/locales/de.json +48 -21
  85. package/src/locales/en.json +37 -11
  86. package/src/locales/es.json +41 -13
  87. package/src/main.js +5 -66
  88. package/src/store/category.js +20 -36
  89. package/src/store/display.js +74 -1
  90. package/src/store/document.js +305 -109
  91. package/src/store/edit.js +160 -61
  92. package/src/store/project.js +46 -16
  93. package/src/store/selection.js +42 -10
  94. package/src/utils/utils.js +36 -0
  95. package/dist/css/chunk-vendors.css +0 -5
  96. package/src/assets/scss/categorize_modal.scss +0 -45
  97. package/src/assets/scss/main.scss +0 -24
  98. package/src/components/DocumentAnnotations/ActionButtons.vue +0 -250
  99. package/src/components/DocumentAnnotations/CategorizeModal.vue +0 -219
  100. package/src/components/DocumentAnnotations/RejectedLabels.vue +0 -96
  101. package/src/components/DocumentPage/MultiAnnotationTablePopup.vue +0 -253
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div class="empty-annotation">
3
3
  <span
4
- v-if="!publicView"
4
+ v-if="!publicView && !isDocumentReviewed"
5
5
  :id="emptyAnnotationId()"
6
6
  ref="emptyAnnotation"
7
7
  :class="[
@@ -10,25 +10,39 @@
10
10
  editAnnotation &&
11
11
  editAnnotation.id === emptyAnnotationId() &&
12
12
  'error-editing',
13
- isEmptyAnnotationEditable() ? '' : 'label-empty',
14
- isAnnotationBeingEdited() && 'clicked',
13
+ !isEmptyAnnotationEditable() && !isMissingAnnotation && 'label-empty',
14
+ isAnnotationBeingEdited() && 'clicked-ann',
15
+ isMissingAnnotation && 'missing-annotation',
16
+ !isMissingAnnotation && 'keyboard-nav',
15
17
  ]"
16
18
  :contenteditable="isEmptyAnnotationEditable()"
17
19
  @keypress.enter="saveEmptyAnnotationChanges"
18
20
  @click="handleEditEmptyAnnotation"
19
21
  @focus="handleEditEmptyAnnotation"
20
- >
21
- <span v-if="span && span.offset_string && isEmptyAnnotationEditable()">
22
+ ><!-- eslint-disable vue/no-v-html -->
23
+ <span
24
+ v-if="isFindingAnnotation"
25
+ v-html="$t('draw_box_document', { label_name: label.name })"
26
+ >
27
+ </span>
28
+ <span v-else-if="isMissingAnnotation" class="not-found-text">
29
+ {{ $t("missing_from_document") }}
30
+ </span>
31
+ <span
32
+ v-else-if="span && span.offset_string && isEmptyAnnotationEditable()"
33
+ >
22
34
  {{ span.offset_string }}
23
35
  </span>
24
36
  <span v-else>
25
37
  {{ $t("no_data_found") }}
26
38
  </span>
39
+ <!--eslint-enable-->
27
40
  </span>
28
41
  </div>
29
42
  </template>
30
43
  <script>
31
44
  import { mapState, mapGetters } from "vuex";
45
+ import { isElementArray } from "../../utils/utils";
32
46
 
33
47
  /**
34
48
  * This component is responsible for managing empty annotations (labels with no annotations).
@@ -37,97 +51,71 @@ export default {
37
51
  name: "EmptyAnnotation",
38
52
  props: {
39
53
  label: {
54
+ type: Object,
40
55
  required: true,
41
56
  },
42
57
  annotationSet: {
58
+ type: Object,
43
59
  required: true,
44
60
  },
45
-
46
61
  span: {
62
+ type: Object,
63
+ default: null,
47
64
  required: false,
48
65
  },
49
66
  spanIndex: {
67
+ type: Number,
50
68
  required: false,
69
+ default: 0,
51
70
  },
52
- saveChanges: {
71
+ isMissingAnnotation: {
53
72
  type: Boolean,
54
- required: false,
73
+ required: true,
74
+ default: false,
55
75
  },
56
76
  },
57
- data() {
58
- return {
59
- isLoading: false,
60
- };
61
- },
62
77
  computed: {
63
- ...mapGetters("document", [
64
- "isAnnotationInEditMode",
65
- "getTextFromEntities",
66
- ]),
67
- ...mapGetters("selection", ["isValueArray"]),
78
+ ...mapGetters("document", ["isAnnotationInEditMode", "isDocumentReviewed"]),
68
79
  ...mapState("selection", ["spanSelection", "elementSelected"]),
69
80
  ...mapState("document", [
70
81
  "editAnnotation",
71
82
  "publicView",
72
- "selectedEntities",
73
83
  "showActionError",
74
84
  ]),
85
+ isFindingAnnotation() {
86
+ return (
87
+ this.editAnnotation &&
88
+ this.editAnnotation.id === this.emptyAnnotationId() &&
89
+ (!this.span || !this.span.offset_string)
90
+ );
91
+ },
75
92
  },
93
+
76
94
  watch: {
77
95
  span(newValue) {
78
96
  if (this.elementSelected === this.emptyAnnotationId() && newValue) {
79
- if (this.isValueArray(newValue))
97
+ if (isElementArray(newValue))
80
98
  newValue.map((span) => {
81
99
  if (span.offset_string) {
82
100
  span.offset_string =
83
101
  this.$refs.emptyAnnotation.textContent.trim();
84
102
  span.offset_string_original =
85
103
  this.$refs.emptyAnnotation.textContent.trim();
86
-
87
- this.setText(span.offset_string);
88
104
  }
89
105
  });
90
106
  }
91
107
  },
92
- editAnnotation(newAnnotation, oldAnnotation) {
93
- // verify if new annotation in edit mode is not this one and if this
94
- // one was selected before so we set the state to the previous one (like a cancel)
95
- if (oldAnnotation && oldAnnotation.id === this.emptyAnnotationId()) {
96
- this.cancelEmptyAnnotation(true);
97
- }
98
- },
99
- selectedEntities(newValue) {
100
- if (!newValue && this.isAnnotationBeingEdited(this.emptyAnnotationId())) {
101
- this.setText(
102
- this.$t("draw_box_document", { label_name: this.label.name })
103
- );
104
- return;
105
- }
106
-
107
- if (
108
- newValue &&
109
- this.editAnnotation &&
110
- this.emptyAnnotationId() === this.editAnnotation.id
111
- ) {
112
- const text = this.getTextFromEntities();
113
- this.setText(text);
114
- }
115
- },
116
108
  spanSelection(newValue) {
117
- if (this.elementSelected === this.emptyAnnotationId() && newValue) {
118
- const isSpanArray = Array.isArray(newValue);
109
+ if (!newValue) return;
119
110
 
120
- // Check if the bbox is empty
121
- if (
122
- (isSpanArray && !newValue[0].offset_string) ||
123
- (!isSpanArray && !newValue.offset_string)
124
- ) {
125
- this.$store.dispatch("document/resetEditAnnotation");
126
- this.$store.dispatch("selection/disableSelection");
127
- }
111
+ // Check if the bbox has no string
112
+ if (newValue[0] && !newValue[0].offset_string) {
113
+ this.$store.dispatch("document/resetEditAnnotation");
114
+ this.$store.dispatch("selection/disableSelection");
128
115
  }
129
116
  },
130
117
  },
118
+
131
119
  methods: {
132
120
  emptyAnnotationId() {
133
121
  if (!this.annotationSet || !this.label) return;
@@ -142,20 +130,25 @@ export default {
142
130
  return this.isAnnotationInEditMode(this.emptyAnnotationId());
143
131
  },
144
132
  handleEditEmptyAnnotation() {
145
- if (this.publicView) return;
133
+ if (
134
+ this.publicView ||
135
+ this.isDocumentReviewed ||
136
+ this.isMissingAnnotation
137
+ )
138
+ return;
146
139
 
147
140
  if (
148
141
  !this.publicView &&
149
- !this.isLoading &&
142
+ !this.isDocumentReviewed &&
150
143
  this.elementSelected !== this.emptyAnnotationId()
151
144
  ) {
152
- this.setText(
153
- this.$t("draw_box_document", { label_name: this.label.name })
154
- );
145
+ this.$store.dispatch("selection/disableSelection");
146
+ this.$store.dispatch("selection/setSelectedEntities", null);
155
147
  this.$store.dispatch(
156
148
  "selection/selectElement",
157
149
  this.emptyAnnotationId()
158
150
  );
151
+
159
152
  this.$store.dispatch("document/setEditAnnotation", {
160
153
  id: this.emptyAnnotationId(),
161
154
  index: this.spanIndex,
@@ -165,28 +158,10 @@ export default {
165
158
  });
166
159
  }
167
160
  },
168
- cancelEmptyAnnotation(wasOutsideClick = false) {
169
- if (wasOutsideClick) {
170
- this.setText(this.$t("no_data_found"));
171
- } else {
172
- this.$store.dispatch("selection/disableSelection");
173
- }
174
-
175
- this.isLoading = false;
176
- this.$store.dispatch("document/setSelectedEntities", null);
177
-
178
- if (this.$refs.emptyAnnotation) {
179
- this.$refs.emptyAnnotation.blur();
180
- }
181
- },
182
161
  isEmptyAnnotationEditable() {
183
- if (this.selectedEntities && this.selectedEntities.length > 0) {
184
- return (
185
- this.elementSelected === this.emptyAnnotationId() && !this.isLoading
186
- );
187
- } else if (
188
- this.spanSelection &&
189
- this.spanSelection[this.spanIndex] === 0
162
+ if (
163
+ (this.spanSelection && this.spanSelection[this.spanIndex] === 0) ||
164
+ this.isMissingAnnotation
190
165
  ) {
191
166
  return false;
192
167
  } else {
@@ -194,13 +169,12 @@ export default {
194
169
  this.elementSelected === this.emptyAnnotationId() &&
195
170
  this.spanSelection &&
196
171
  this.spanSelection[this.spanIndex] &&
197
- this.spanSelection[this.spanIndex].offset_string != null &&
198
- !this.isLoading
172
+ this.spanSelection[this.spanIndex].offset_string != null
199
173
  );
200
174
  }
201
175
  },
202
176
  saveEmptyAnnotationChanges(event) {
203
- if (this.publicView) return;
177
+ if (this.publicView || this.isDocumentReviewed) return;
204
178
 
205
179
  if (event) {
206
180
  event.preventDefault();
@@ -209,9 +183,6 @@ export default {
209
183
  // API call handled in parent component - AnnotationRow
210
184
  this.$emit("save-empty-annotation-changes");
211
185
  },
212
- setText(text) {
213
- this.$refs.emptyAnnotation.innerHTML = text;
214
- },
215
186
  },
216
187
  };
217
188
  </script>
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div class="data-extraction-container">
3
3
  <div class="loading-container">
4
- <ActionButtons
4
+ <AnnotationActionButtons
5
5
  :is-loading="true"
6
6
  :save-btn="false"
7
7
  :cancel-btn="false"
@@ -9,21 +9,33 @@
9
9
  </div>
10
10
  <div class="data-extraction-text">
11
11
  <p class="title">
12
- {{ $t("data_being_extracted") }}
12
+ <span v-if="redirectingUser"> {{ $t("wait_title") }}</span>
13
+ <span v-else>
14
+ {{ $t("data_being_extracted") }}
15
+ </span>
13
16
  </p>
14
17
  <div class="description">
15
- <p>{{ $t("analysing_document") }}</p>
16
- <p>{{ $t("few_minutes") }}</p>
18
+ <span v-if="redirectingUser">
19
+ <p>{{ $t("redirecting_to_documents_list") }}</p>
20
+ </span>
21
+ <span v-else>
22
+ <p>{{ $t("analysing_document") }}</p>
23
+ <p>{{ $t("few_minutes") }}</p>
24
+ </span>
17
25
  </div>
18
26
  </div>
19
27
  </div>
20
28
  </template>
21
29
  <script>
22
- import ActionButtons from "./ActionButtons";
30
+ import { mapState } from "vuex";
31
+ import AnnotationActionButtons from "./AnnotationActionButtons";
23
32
 
24
33
  export default {
25
34
  name: "ExtractingData",
26
- components: { ActionButtons }
35
+ components: { AnnotationActionButtons },
36
+ computed: {
37
+ ...mapState("edit", ["redirectingUser"]),
38
+ },
27
39
  };
28
40
  </script>
29
41
  <style scoped lang="scss" src="../../assets/scss/extracting_data.scss"></style>
@@ -0,0 +1,337 @@
1
+ <template>
2
+ <div
3
+ class="multi-ann-table-overlay"
4
+ :style="{
5
+ left: `${left}px`,
6
+ width: `${width === 0 ? '100%' : `${width}px`}`,
7
+ }"
8
+ >
9
+ <b-table
10
+ ref="table"
11
+ class="multi-ann-set-table dark-header header-32"
12
+ detail-icon="faScissors"
13
+ :data="rows"
14
+ :sticky-header="true"
15
+ :narrowed="true"
16
+ :bordered="false"
17
+ draggable-column
18
+ @columndragstart="columndragstart"
19
+ @columndrop="columndrop"
20
+ @columndragover="columndragover"
21
+ @columndragleave="columndragleave"
22
+ >
23
+ <b-table-column
24
+ v-for="(item, index) in isLoading ? [columns[0]] : columns"
25
+ :key="index"
26
+ :field="item.field"
27
+ :label="item.label.name"
28
+ >
29
+ <template #header="{ column }">
30
+ <b-dropdown
31
+ :ref="getDropdownReference(item)"
32
+ aria-role="list"
33
+ class="header-dropdown"
34
+ position="is-top-right"
35
+ :close-on-click="false"
36
+ scrollable
37
+ @active-change="(e) => onDropdownChange(item, e)"
38
+ >
39
+ <template #trigger="{ active }">
40
+ <DraggableIcon v-if="!isLoading" class="draggable" />
41
+ <span v-if="!isLoading" :class="active ? 'active' : ''"
42
+ >{{ column.label }}
43
+ </span>
44
+ <b-icon
45
+ v-if="!isLoading"
46
+ :icon="active ? 'angle-up' : 'angle-down'"
47
+ size="is-small"
48
+ class="arrow"
49
+ />
50
+ </template>
51
+
52
+ <div v-if="editingLabels.length === 0">
53
+ <b-dropdown-item aria-role="listitem" @click="editLabel(item)"
54
+ ><span>{{ $t("edit_label") }}</span></b-dropdown-item
55
+ >
56
+ <b-dropdown-item
57
+ aria-role="listitem"
58
+ class="delete-action"
59
+ @click="deleteColumn(item)"
60
+ >
61
+ <span>{{ $t("delete_label") }}</span></b-dropdown-item
62
+ >
63
+ </div>
64
+ <div v-else>
65
+ <b-dropdown-item
66
+ v-for="label in editingLabels"
67
+ :key="label.id"
68
+ aria-role="listitem"
69
+ :disabled="label.disabled"
70
+ ><span @click="!label.disabled && changeLabel(item, label)">{{
71
+ label.name
72
+ }}</span></b-dropdown-item
73
+ >
74
+ </div>
75
+ </b-dropdown>
76
+ </template>
77
+
78
+ <template #default="props">
79
+ <div class="annotations-table">
80
+ <b-skeleton v-if="isLoading" width="98%" height="90%" />
81
+ <AnnotationRow
82
+ v-if="!isLoading"
83
+ :annotation="props.row[item.field]"
84
+ :label="item.label"
85
+ :annotation-set="item.annotationSet"
86
+ :show-label="false"
87
+ :show-buttons="false"
88
+ :is-small="true"
89
+ :from-table="true"
90
+ />
91
+ </div>
92
+ </template>
93
+ </b-table-column>
94
+ </b-table>
95
+ </div>
96
+ </template>
97
+
98
+ <script>
99
+ import { mapState } from "vuex";
100
+ import AnnotationRow from "../DocumentAnnotations/AnnotationRow";
101
+ import DraggableIcon from "../../assets/images/DraggableIcon";
102
+
103
+ export default {
104
+ name: "MultiAnnotationTableOverlay",
105
+ components: {
106
+ AnnotationRow,
107
+ DraggableIcon,
108
+ },
109
+ props: {
110
+ left: {
111
+ type: Number,
112
+ required: false,
113
+ default: 0,
114
+ },
115
+ width: {
116
+ type: Number,
117
+ required: false,
118
+ default: 0,
119
+ },
120
+ },
121
+ data() {
122
+ return {
123
+ rows: [],
124
+ columns: [],
125
+ orderedAnnotations: [],
126
+ editingLabels: [],
127
+ openDropdown: null,
128
+ draggingColumnIndex: null,
129
+ isLoading: false,
130
+ };
131
+ },
132
+ computed: {
133
+ ...mapState("display", ["showAnnSetTable"]),
134
+ ...mapState("document", ["annotations"]),
135
+ },
136
+ watch: {
137
+ showAnnSetTable() {
138
+ this.handleColumns();
139
+ this.handleRows();
140
+ },
141
+ annotations() {
142
+ // if there's a change in the annotations content, we update the table
143
+ this.handleColumns();
144
+ this.handleRows();
145
+ },
146
+ columns(columns) {
147
+ if (!columns || (columns && columns.length === 0)) {
148
+ this.$store.dispatch("selection/disableSelection");
149
+ this.$store.dispatch("document/resetEditAnnotation");
150
+ this.$store.dispatch("display/showAnnSetTable", null);
151
+ }
152
+ },
153
+ },
154
+ mounted() {
155
+ this.handleColumns();
156
+ this.handleRows();
157
+ },
158
+ methods: {
159
+ getDropdownReference(column) {
160
+ return `editDropdown_${column.field}`;
161
+ },
162
+ handleColumns() {
163
+ this.columns = [];
164
+ const labelAlreadyExists = (label) => {
165
+ return (
166
+ this.columns.length > 0 &&
167
+ this.columns.find((a) => a.field === `${label.id}`) != undefined
168
+ );
169
+ };
170
+
171
+ this.showAnnSetTable.forEach((annotationSet) => {
172
+ annotationSet.labels.forEach((label) => {
173
+ if (!labelAlreadyExists(label) && label.annotations.length > 0) {
174
+ const column = {
175
+ field: `${label.id}`,
176
+ label: label,
177
+ annotationSet,
178
+ centered: false,
179
+ };
180
+ this.columns.push(column);
181
+ }
182
+ });
183
+ });
184
+ },
185
+
186
+ handleRows() {
187
+ this.rows = [];
188
+ this.orderedAnnotations = [];
189
+
190
+ this.showAnnSetTable.forEach((annotationSet) => {
191
+ let row = {};
192
+ let toAdd = false; // to not push empty labels
193
+
194
+ annotationSet.labels.forEach((label) => {
195
+ if (label.annotations.length > 0) {
196
+ row[label.id] = label.annotations[0];
197
+ this.orderedAnnotations.push(label.annotations[0]);
198
+ toAdd = true;
199
+ }
200
+ });
201
+ if (toAdd) {
202
+ this.rows.push(row);
203
+ }
204
+ });
205
+ },
206
+
207
+ async editLabel(column) {
208
+ this.$store
209
+ .dispatch(
210
+ "project/fetchLabelSetDetails",
211
+ column.annotationSet.label_set.id
212
+ )
213
+ .then(async (labelSet) => {
214
+ this.editingLabels = [];
215
+
216
+ labelSet.labels.forEach((label) => {
217
+ const dropdownLabel = {
218
+ ...label,
219
+ disabled:
220
+ this.columns.find((column) => column.label.id === label.id) !==
221
+ undefined,
222
+ };
223
+ this.editingLabels.push(dropdownLabel);
224
+ });
225
+ });
226
+ },
227
+
228
+ async changeLabel(column, label) {
229
+ this.isLoading = true;
230
+ this.closeDropdown(column);
231
+ for (let i = 0; i < this.rows.length; i++) {
232
+ const annotationToUpdate = this.rows[i][column.label.id];
233
+ await this.$store
234
+ .dispatch("document/updateAnnotation", {
235
+ annotationId: annotationToUpdate.id,
236
+ updatedValues: { label: label.id },
237
+ })
238
+ .catch((error) => {
239
+ this.$store.dispatch("document/createErrorMessage", {
240
+ error,
241
+ serverErrorMessage: this.$t("server_error"),
242
+ defaultErrorMessage: this.$t("edit_error"),
243
+ });
244
+ });
245
+ }
246
+ this.isLoading = false;
247
+ },
248
+
249
+ async deleteColumn(column) {
250
+ this.isLoading = true;
251
+ this.closeDropdown(column);
252
+
253
+ const annotationsToDelete = [];
254
+ for (let i = 0; i < this.rows.length; i++) {
255
+ const annotationToDelete = this.rows[i][column.label.id];
256
+ if (annotationToDelete && annotationToDelete.id) {
257
+ annotationsToDelete.push(annotationToDelete);
258
+ }
259
+ }
260
+
261
+ annotationsToDelete.forEach(async (annotationToDelete) => {
262
+ await this.$store
263
+ .dispatch("document/deleteAnnotation", {
264
+ annotationId: annotationToDelete.id,
265
+ })
266
+ .catch((error) => {
267
+ this.$store.dispatch("document/createErrorMessage", {
268
+ error,
269
+ serverErrorMessage: this.$t("server_error"),
270
+ defaultErrorMessage: this.$t("edit_error"),
271
+ });
272
+ });
273
+ });
274
+
275
+ this.isLoading = false;
276
+ },
277
+
278
+ onDropdownChange(column, open) {
279
+ this.editingLabels = [];
280
+ this.$store.dispatch("selection/disableSelection");
281
+ this.$store.dispatch("document/resetEditAnnotation");
282
+ if (open) {
283
+ if (
284
+ this.openDropdown &&
285
+ this.$refs[this.getDropdownReference(column)].length > 0
286
+ ) {
287
+ this.$refs[this.openDropdown][0].toggle();
288
+ }
289
+ this.openDropdown = this.getDropdownReference(column);
290
+ } else {
291
+ if (this.openDropdown === this.getDropdownReference(column)) {
292
+ this.openDropdown = null;
293
+ }
294
+ }
295
+ },
296
+
297
+ closeDropdown(column) {
298
+ if (
299
+ this.openDropdown &&
300
+ this.$refs[this.getDropdownReference(column)].length > 0
301
+ ) {
302
+ this.$refs[this.getDropdownReference(column)][0].toggle();
303
+ this.openDropdown = null;
304
+ }
305
+ },
306
+
307
+ columndragstart(payload) {
308
+ this.draggingColumnIndex = payload.index;
309
+ payload.event.dataTransfer.effectAllowed = "copy";
310
+ },
311
+ columndragover(payload) {
312
+ payload.event.dataTransfer.dropEffect = "copy";
313
+ payload.event.target.closest("th").classList.add("is-selected");
314
+ payload.event.preventDefault();
315
+ },
316
+ columndragleave(payload) {
317
+ payload.event.target.closest("th").classList.remove("is-selected");
318
+ payload.event.preventDefault();
319
+ },
320
+ async columndrop(payload) {
321
+ payload.event.target.closest("th").classList.remove("is-selected");
322
+ const droppedOnColumnIndex = payload.index;
323
+
324
+ const draggingColumn = this.columns[this.draggingColumnIndex];
325
+ const droppedColumn = this.columns[droppedOnColumnIndex];
326
+
327
+ await this.changeLabel(draggingColumn, droppedColumn.label);
328
+ await this.changeLabel(droppedColumn, draggingColumn.label);
329
+ },
330
+ },
331
+ };
332
+ </script>
333
+ <style
334
+ scoped
335
+ lang="scss"
336
+ src="../../assets/scss/multi_ann_table_overlay.scss"
337
+ ></style>
@@ -3,6 +3,6 @@ export { default as AnnotationContent } from "./AnnotationContent";
3
3
  export { default as EmptyAnnotation } from "./EmptyAnnotation";
4
4
  export { default as DocumentLabel } from "./DocumentLabel";
5
5
  export { default as AnnotationDetails } from "./AnnotationDetails";
6
- export { default as RejectedLabels } from "./RejectedLabels";
7
6
  export { default as ChooseLabelSetModal } from "./ChooseLabelSetModal";
8
7
  export { default as AnnotationRow } from "./AnnotationRow";
8
+ export { default as MultiAnnotationTableOverlay } from "./MultiAnnotationTableOverlay";