@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
@@ -9,30 +9,24 @@ const state = {
9
9
  pageNumber: null,
10
10
  start: null,
11
11
  end: null,
12
- custom: false, // if the box was created by user in document or it comes from an annotation
13
- placeholderBox: null, // show a not editable placeholder box
14
12
  },
15
13
  isSelecting: false,
16
- spanSelection: null,
17
- elementSelected: null, // selected element id
18
- selectedEntities: null,
14
+ spanSelection: [],
15
+ placeholderSelection: [],
16
+ selectedEntities: [],
17
+ spanLoading: false,
19
18
  };
20
19
 
21
20
  const getters = {
22
- isElementSelected: (state) => {
23
- return state.elementSelected;
24
- },
25
- isSelecting: (state) => {
26
- return state.isSelecting;
27
- },
28
21
  isSelectionValid: (state) => {
29
22
  /**
30
23
  * `endSelection` will reset everything in case of invalid selection.
31
24
  * Check the existence of `selection.end` before requesting the
32
25
  * content from the backend.
33
26
  * */
34
- return state.selection && state.selection.end;
27
+ return state.selection && state.selection.end != null;
35
28
  },
29
+
36
30
  getSelectionForPage: (state) => (pageNumber) => {
37
31
  if (state.selection.pageNumber === pageNumber) {
38
32
  return state.selection;
@@ -52,19 +46,24 @@ const getters = {
52
46
  box.y1 >= entity.y1
53
47
  );
54
48
  },
49
+ spanSelectionsForPage: (state) => (page) => {
50
+ return state.spanSelection.filter(
51
+ (span) => page.number === span.page_index + 1
52
+ );
53
+ },
54
+ placeholderSelectionForPage: (state) => (page) => {
55
+ return state.placeholderSelection.filter(
56
+ (span) => page.number === span.page_index + 1
57
+ );
58
+ },
55
59
  };
56
60
 
57
61
  const actions = {
58
- selectElement: ({ commit }, value) => {
59
- commit("RESET_SELECTION");
60
- commit("SET_SPAN_SELECTION", null);
61
- commit("ELEMENT_SELECTED", value);
62
- },
63
-
64
62
  disableSelection: ({ commit }) => {
65
- commit("ELEMENT_SELECTED", null);
66
63
  commit("RESET_SELECTION");
67
- commit("SET_SPAN_SELECTION", null);
64
+ commit("SET_SELECTED_ENTITIES", []);
65
+ commit("SET_SPAN_SELECTION", []);
66
+ commit("SET_PLACEHOLDER_SELECTION", []);
68
67
  },
69
68
 
70
69
  startSelection: ({ commit }, { pageNumber, start }) => {
@@ -81,8 +80,6 @@ const actions = {
81
80
  if (xDiff > 5 && yDiff > 5) {
82
81
  commit("MOVE_SELECTION", points);
83
82
  }
84
-
85
- commit("SET_SELECTED_ENTITIES", null);
86
83
  },
87
84
 
88
85
  endSelection: ({ commit, state }, end) => {
@@ -113,78 +110,138 @@ const actions = {
113
110
  }
114
111
  },
115
112
 
116
- setSelection: ({ commit }, { span, selection }) => {
117
- commit("SET_SELECTION", selection);
118
- commit("SET_SPAN_SELECTION", span);
119
- },
120
-
121
113
  setSelectedEntities: ({ commit }, entities) => {
122
114
  commit("SET_SELECTED_ENTITIES", entities);
123
115
  },
124
116
 
125
- getTextFromBboxes: ({ commit, rootState }, { box, entities }) => {
126
- let span;
117
+ getTextFromBboxes: ({ commit, rootState }, span) => {
118
+ commit("SET_SPAN_LOADING", true);
119
+ return new Promise((resolve, reject) => {
120
+ HTTP.post(`documents/${rootState.document.documentId}/bbox/`, {
121
+ span,
122
+ })
123
+ .then((response) => {
124
+ if (response.data.span.length && response.data.span.length > 0) {
125
+ /**
126
+ * If we have a non-empty bboxes list, we assume there
127
+ * is text here on the backend, so we just set
128
+ * spanSelection to the response.
129
+ */
130
+ resolve(response.data.span);
131
+ } else {
132
+ /**
133
+ * Otherwise, we assume the backend can't identify text
134
+ * on this area, so we set our bbox into spanSelection
135
+ * ready to be passed back to the backend when creating
136
+ * an annotation on this empty area, adding the offset_string
137
+ * attribute, ready to be filled.
138
+ */
139
+ resolve(span);
140
+ }
141
+ })
142
+ .catch((error) => {
143
+ alert("Could not fetch the selected text from the backend");
144
+ reject(error);
145
+ })
146
+ .finally(() => {
147
+ commit("SET_SPAN_LOADING", false);
148
+ });
149
+ });
150
+ },
127
151
 
128
- if (entities) {
129
- span = box.flatMap((s) => {
130
- return s.original;
152
+ entitySelection: ({ commit, dispatch, state }, { entities, selection }) => {
153
+ if (entities.length === 0) {
154
+ if (selection) {
155
+ dispatch("getTextFromBboxes", [selection]).then((spans) => {
156
+ commit("SET_SPAN_SELECTION", spans);
157
+ });
158
+ } else {
159
+ commit("RESET_SELECTION");
160
+ commit("SET_SPAN_SELECTION", []);
161
+ }
162
+ commit("SET_SELECTED_ENTITIES", []);
163
+ } else {
164
+ commit("SET_SELECTED_ENTITIES", entities);
165
+
166
+ dispatch("document/setAnnotationId", null, {
167
+ root: true,
168
+ });
169
+ let span;
170
+ if (entities) {
171
+ span = entities.flatMap((s) => {
172
+ return s.original;
173
+ });
174
+ } else {
175
+ span = [entities];
176
+ }
177
+ commit("SET_SPAN_SELECTION", span);
178
+ dispatch("getTextFromBboxes", span).then((spans) => {
179
+ commit("SET_SPAN_SELECTION", spans);
131
180
  });
181
+ }
182
+ },
183
+
184
+ entityClick: ({ commit, dispatch, state }, entity) => {
185
+ // Check if we are creating a new Annotation
186
+ // or if we are removing a previously selected entity
187
+ // or editing empty one
188
+ const found = state.selectedEntities.find(
189
+ (entityToFind) =>
190
+ entity.scaled.width === entityToFind.scaled.width &&
191
+ entity.original.offset_string === entityToFind.original.offset_string
192
+ );
193
+
194
+ let entities = state.selectedEntities;
195
+ if (found) {
196
+ entities = [
197
+ ...state.selectedEntities.filter(
198
+ (entityToFilter) =>
199
+ entityToFilter.scaled.width !== entity.scaled.width &&
200
+ entityToFilter.original.offset_string !==
201
+ entity.original.offset_string
202
+ ),
203
+ ];
132
204
  } else {
133
- span = [box];
205
+ entities.push(entity);
134
206
  }
135
207
 
136
- return HTTP.post(`documents/${rootState.document.documentId}/bbox/`, {
137
- span,
138
- })
139
- .then((response) => {
140
- if (response.data.span.length && response.data.span.length > 0) {
141
- /**
142
- * If we have a non-empty bboxes list, we assume there
143
- * is text here on the backend, so we just set
144
- * spanSelection to the response.
145
- */
146
- commit("SET_SPAN_SELECTION", response.data.span);
147
- } else {
148
- /**
149
- * Otherwise, we assume the backend can't identify text
150
- * on this area, so we set our bbox into spanSelection
151
- * ready to be passed back to the backend when creating
152
- * an annotation on this empty area, adding the offset_string
153
- * attribute, ready to be filled.
154
- */
155
- commit("SET_SPAN_SELECTION", span);
156
- }
157
- })
158
- .catch((error) => {
159
- alert("Could not fetch the selected text from the backend");
208
+ if (entities.length === 0) {
209
+ commit("SET_SELECTED_ENTITIES", []);
210
+ commit("SET_SPAN_SELECTION", []);
211
+ } else {
212
+ commit("SET_SELECTED_ENTITIES", entities);
213
+
214
+ dispatch("document/setAnnotationId", null, {
215
+ root: true,
160
216
  });
161
- },
162
217
 
163
- getTextFromEntities: ({ commit, dispatch }, selectedEntities) => {
164
- if (!selectedEntities) return;
218
+ let span;
165
219
 
166
- return dispatch("getTextFromBboxes", {
167
- box: selectedEntities,
168
- entities: true,
169
- });
220
+ if (entities) {
221
+ span = entities.flatMap((s) => {
222
+ return s.original;
223
+ });
224
+ } else {
225
+ span = [entities];
226
+ }
227
+ commit("SET_SPAN_SELECTION", span);
228
+ }
170
229
  },
171
230
 
172
231
  setSpanSelection: ({ commit }, span) => {
173
232
  commit("SET_SPAN_SELECTION", span);
174
233
  },
234
+ setPlaceholderSelection: ({ commit }, span) => {
235
+ commit("SET_PLACEHOLDER_SELECTION", span);
236
+ },
175
237
  };
176
238
 
177
239
  const mutations = {
178
- ELEMENT_SELECTED: (state, value) => {
179
- state.elementSelected = value;
180
- },
181
240
  START_SELECTION: (state, { pageNumber, start }) => {
182
241
  state.selection.end = null;
183
- state.isSelecting = true;
184
242
  state.selection.pageNumber = pageNumber;
185
- state.selection.custom = true;
186
243
  state.selection.start = start;
187
- state.selection.placeholderBox = null;
244
+ state.isSelecting = true;
188
245
  },
189
246
  MOVE_SELECTION: (state, points) => {
190
247
  const { start, end } = points;
@@ -200,20 +257,39 @@ const mutations = {
200
257
  state.isSelecting = false;
201
258
  },
202
259
  RESET_SELECTION: (state) => {
203
- state.isSelecting = false;
204
260
  state.selection.pageNumber = null;
205
261
  state.selection.start = null;
206
262
  state.selection.end = null;
207
- state.selection.placeholderBox = null;
208
263
  },
209
264
  SET_SPAN_SELECTION: (state, span) => {
210
- state.spanSelection = span;
265
+ if (!span) {
266
+ state.spanSelection = [];
267
+ } else {
268
+ state.spanSelection = span;
269
+ }
211
270
  },
212
- SET_SELECTION: (state, selection) => {
213
- state.selection = selection;
271
+ ADD_SPAN_SELECTION: (state, span) => {
272
+ state.spanSelection.push(span);
273
+ },
274
+ SET_PLACEHOLDER_SELECTION: (state, span) => {
275
+ if (!span) {
276
+ state.placeholderSelection = [];
277
+ } else {
278
+ state.placeholderSelection = span;
279
+ }
280
+ },
281
+ ADD_PLACEHOLDER_SELECTION: (state, span) => {
282
+ state.placeholderSelection.push(span);
214
283
  },
215
284
  SET_SELECTED_ENTITIES: (state, entities) => {
216
- state.selectedEntities = entities;
285
+ if (!entities) {
286
+ state.selectedEntities = [];
287
+ } else {
288
+ state.selectedEntities = entities;
289
+ }
290
+ },
291
+ SET_SPAN_LOADING: (state, loading) => {
292
+ state.spanLoading = loading;
217
293
  },
218
294
  };
219
295
 
@@ -1 +0,0 @@
1
- @import "./variables.scss";
@@ -1,372 +0,0 @@
1
- <!-- eslint-disable vue/no-v-html -->
2
- <template>
3
- <div
4
- v-if="annotation && !hide"
5
- class="annotation-popup small"
6
- :style="{ left: `${left}px`, top: `${top}px` }"
7
- >
8
- <b-dropdown
9
- v-model="selectedSet"
10
- aria-role="list"
11
- :class="[
12
- 'annotation-dropdown',
13
- 'no-padding-bottom',
14
- 'dropdown-full-width',
15
- setsList.length === 0 ? 'no-padding-top' : '',
16
- ]"
17
- scrollable
18
- >
19
- <template #trigger>
20
- <b-button
21
- :class="[
22
- 'popup-input',
23
- selectedSet ? '' : 'not-selected',
24
- 'has-right-icon',
25
- ]"
26
- type="is-text"
27
- >
28
- {{
29
- selectedSet
30
- ? `${selectedSet.label_set.name} ${
31
- selectedSet.id
32
- ? numberOfAnnotationSetGroup(selectedSet)
33
- : `${numberOfLabelSetGroup(selectedSet.label_set)} (${$t(
34
- "new"
35
- )})`
36
- }`
37
- : $t("select_annotation_set")
38
- }}
39
- <span class="caret-icon">
40
- <b-icon icon="angle-down" size="is-small" class="caret" />
41
- </span>
42
- </b-button>
43
- </template>
44
- <b-button
45
- type="is-ghost"
46
- :class="['add-ann-set', 'dropdown-item', 'no-icon-margin']"
47
- icon-left="plus"
48
- @click="openAnnotationSetCreation"
49
- >
50
- {{ $t("new_ann_set_title") }}
51
- </b-button>
52
- <b-dropdown-item
53
- v-for="(set, index) in setsList"
54
- :key="`${set.label_set.id}_${index}`"
55
- aria-role="listitem"
56
- :value="set"
57
- >
58
- <span>{{
59
- `${set.label_set.name} ${
60
- set.id
61
- ? numberOfAnnotationSetGroup(set)
62
- : `${numberOfLabelSetGroup(set.label_set)} (${$t("new")})`
63
- }`
64
- }}</span>
65
- </b-dropdown-item>
66
- </b-dropdown>
67
- <b-tooltip
68
- multilined
69
- :active="selectedSet && (!labelsFiltered || labelsFiltered.length === 0)"
70
- size="is-large"
71
- position="is-bottom"
72
- class="bottom-aligned"
73
- :close-delay="5000"
74
- >
75
- <template #content>
76
- <div
77
- v-html="
78
- `${$t('no_labels_available')} ${
79
- showBranding ? $t('no_labels_available_link') : ''
80
- }`
81
- "
82
- ></div>
83
- </template>
84
- <b-dropdown
85
- v-if="selectedLabel"
86
- v-model="selectedLabel"
87
- aria-role="list"
88
- :disabled="!labelsFiltered || labelsFiltered.length === 0"
89
- scrollable
90
- class="label-dropdown annotation-dropdown dropdown-full-width"
91
- >
92
- <template #trigger>
93
- <b-button
94
- class="popup-input has-right-icon"
95
- :disabled="!labelsFiltered"
96
- type="is-text"
97
- >
98
- {{ selectedLabel.name }}
99
- <span class="caret-icon">
100
- <b-icon icon="angle-down" size="is-small" class="caret" />
101
- </span>
102
- </b-button>
103
- </template>
104
- <b-dropdown-item
105
- v-for="label in labelsFiltered"
106
- :key="label.id"
107
- aria-role="listitem"
108
- :value="label"
109
- >
110
- <span>{{ label.name }}</span>
111
- </b-dropdown-item>
112
- </b-dropdown>
113
- </b-tooltip>
114
- <div class="annotation-buttons">
115
- <b-button
116
- type="is-text"
117
- class="cancel-button popup-button primary-button"
118
- :label="$t('hide')"
119
- :disabled="loading"
120
- @click.prevent="hide = true"
121
- />
122
- <b-button
123
- type="is-primary"
124
- class="popup-button primary-button"
125
- :label="$t('save')"
126
- :disabled="loading || !spanSelection || !selectedLabel || !wasChanged"
127
- @click.prevent="save"
128
- />
129
- </div>
130
- </div>
131
- </template>
132
- <script>
133
- /**
134
- * This component is used to show a popup
135
- * for editing an annotation.
136
- */
137
- const heightOfPopup = 142;
138
- const margin = 12;
139
- const widthOfPopup = 205;
140
-
141
- import { mapGetters, mapState } from "vuex";
142
-
143
- export default {
144
- props: {
145
- editAnnotation: {
146
- required: true,
147
- type: Object,
148
- },
149
- page: {
150
- required: true,
151
- type: Object,
152
- },
153
- containerWidth: {
154
- type: Number,
155
- required: true,
156
- },
157
- containerHeight: {
158
- type: Number,
159
- required: true,
160
- },
161
- },
162
- data() {
163
- return {
164
- annotation: null,
165
- selectedLabel: null,
166
- selectedSet: null,
167
- labelsFiltered: null,
168
- loading: false,
169
- isAnnSetModalShowing: false,
170
- setsList: [],
171
- hide: false,
172
- };
173
- },
174
- computed: {
175
- ...mapState("document", [
176
- "annotationSets",
177
- "annotations",
178
- "labels",
179
- "documentId",
180
- ]),
181
- ...mapGetters("document", [
182
- "numberOfAnnotationSetGroup",
183
- "numberOfLabelSetGroup",
184
- "labelsFilteredForAnnotationCreation",
185
- ]),
186
- ...mapState("display", ["showBranding"]),
187
- ...mapGetters("display", ["bboxToRect"]),
188
- ...mapState("selection", ["selection", "spanSelection"]),
189
- top() {
190
- if (this.selection && this.selection.start && this.selection.end) {
191
- const top = this.selection.start.y - heightOfPopup; // subtract the height of the popup plus some margin
192
-
193
- const height = this.selection.end.y - this.selection.start.y;
194
-
195
- //check if the popup will not go off the container on the top
196
- return this.selection.start.y > heightOfPopup
197
- ? top - margin
198
- : this.selection.start.y + height + margin;
199
- }
200
- return 0;
201
- },
202
- left() {
203
- if (this.selection && this.selection.start && this.selection.end) {
204
- const width = this.selection.end.x - this.selection.start.x;
205
-
206
- const left = this.selection.start.x + width / 2 - widthOfPopup / 2; // add the entity half width to be centered and then subtract half the width of the popup
207
-
208
- //check if the popup will not go off the container
209
- if (left + widthOfPopup > this.containerWidth) {
210
- // on the right side
211
- return this.containerWidth - widthOfPopup;
212
- } else {
213
- // on the left side
214
- return left > 0 ? left : 0;
215
- }
216
- }
217
- return 0;
218
- },
219
- wasChanged() {
220
- return (
221
- this.editAnnotation.annotationSet.id !== this.selectedSet.id ||
222
- this.editAnnotation.label.id !== this.selectedLabel.id
223
- );
224
- },
225
- },
226
- watch: {
227
- selectedSet(newValue) {
228
- this.labelsFiltered = this.labelsFilteredForAnnotationCreation(newValue);
229
- },
230
- editAnnotation() {
231
- this.hide = false;
232
- this.loadInfo();
233
- },
234
- },
235
- mounted() {
236
- this.loadInfo();
237
-
238
- setTimeout(() => {
239
- // prevent click propagation when opening the popup
240
- document.body.addEventListener("click", this.clickOutside);
241
- }, 200);
242
- },
243
- destroyed() {
244
- document.body.removeEventListener("click", this.clickOutside);
245
- },
246
- methods: {
247
- orderedSetList(setsList) {
248
- setsList.sort((a, b) => {
249
- const nameA = a.label_set.name;
250
- const nameB = b.label_set.name;
251
- if (nameA < nameB) {
252
- return -1;
253
- }
254
- if (nameA > nameB) {
255
- return 1;
256
- }
257
-
258
- // names must be equal
259
- return 0;
260
- });
261
- return setsList;
262
- },
263
- loadInfo() {
264
- this.setsList = this.orderedSetList([...this.annotationSets]);
265
-
266
- this.selectedSet = this.annotationSets.find(
267
- (annSet) => annSet.id === this.editAnnotation.annotationSet.id
268
- );
269
-
270
- this.labelsFiltered = this.labelsFilteredForAnnotationCreation(
271
- this.selectedSet
272
- );
273
-
274
- // if existing label is not able to be chosen we add it manually
275
- if (!this.labelsFiltered.includes(this.editAnnotation.label)) {
276
- this.labelsFiltered.push(this.editAnnotation.label);
277
- }
278
-
279
- this.selectedLabel = this.editAnnotation.label;
280
-
281
- this.annotation = this.annotations.find(
282
- (ann) => ann.id === this.editAnnotation.id
283
- );
284
- },
285
- close() {
286
- this.$store.dispatch("document/resetEditAnnotation");
287
- this.$store.dispatch("selection/disableSelection");
288
- this.$store.dispatch("selection/setSelectedEntities", null);
289
- this.$emit("close");
290
- },
291
- async save() {
292
- this.loading = true;
293
-
294
- if (this.wasChanged) {
295
- // first delete annotation, then create new one
296
- await this.$store
297
- .dispatch("document/deleteAnnotation", {
298
- annotationId: this.annotation.id,
299
- })
300
- .catch((error) => {
301
- this.$store.dispatch("document/createErrorMessage", {
302
- error,
303
- serverErrorMessage: this.$t("server_error"),
304
- defaultErrorMessage: this.$t("edit_error"),
305
- });
306
- });
307
-
308
- const spans = this.annotation.span;
309
- spans[this.editAnnotation.index] = this.spanSelection;
310
-
311
- const annotationToCreate = {
312
- document: this.documentId,
313
- span: spans,
314
- label: this.selectedLabel.id,
315
- is_correct: true,
316
- revised: false,
317
- };
318
-
319
- if (this.selectedSet.id) {
320
- annotationToCreate.annotation_set = this.selectedSet.id;
321
- } else {
322
- annotationToCreate.label_set = this.selectedSet.label_set.id;
323
- }
324
-
325
- this.$store
326
- .dispatch("document/createAnnotation", {
327
- annotation: annotationToCreate,
328
- })
329
- .catch((error) => {
330
- this.$store.dispatch("document/createErrorMessage", {
331
- error,
332
- serverErrorMessage: this.$t("server_error"),
333
- defaultErrorMessage: this.$t("error_creating_annotation"),
334
- });
335
- })
336
- .finally(() => {
337
- this.close();
338
- this.loading = false;
339
- });
340
- } else {
341
- this.close();
342
- }
343
- },
344
- chooseLabelSet(labelSet) {
345
- // check if there's already a new entry for that label set to be created
346
- const existsIndex = this.setsList.findIndex((set) => {
347
- return set.id === null && set.label_set.id === labelSet.id;
348
- });
349
-
350
- const newSet = {
351
- label_set: labelSet,
352
- labels: labelSet.labels,
353
- id: null,
354
- };
355
- if (existsIndex >= 0) {
356
- this.setsList[existsIndex] = newSet;
357
- } else {
358
- this.setsList.unshift(newSet);
359
- }
360
- this.selectedSet = newSet;
361
- },
362
- openAnnotationSetCreation() {
363
- this.$store.dispatch("display/showChooseLabelSetModal", {
364
- show: true,
365
- finish: this.chooseLabelSet,
366
- });
367
- },
368
- },
369
- };
370
- </script>
371
-
372
- <style scoped lang="scss" src="../../assets/scss/new_annotation.scss"></style>