@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
package/src/i18n.js CHANGED
@@ -1,7 +1,4 @@
1
- import Vue from "vue";
2
- import VueI18n from "vue-i18n";
3
-
4
- Vue.use(VueI18n);
1
+ import { createI18n } from "vue-i18n";
5
2
 
6
3
  function loadLocaleMessages() {
7
4
  const locales = require.context(
@@ -20,7 +17,7 @@ function loadLocaleMessages() {
20
17
  return messages;
21
18
  }
22
19
 
23
- export default new VueI18n({
20
+ export const i18n = createI18n({
24
21
  locale: process.env.VUE_APP_LOCALE || "en",
25
22
  fallbackLocale: "en",
26
23
  messages: loadLocaleMessages(),
@@ -166,5 +166,6 @@
166
166
  "checkbox_ann_details": "Für dieses Label wird ein Kästchen extrahiert.",
167
167
  "document_section": "Dokumentabschnitt",
168
168
  "label_size": "Spaltengröße:",
169
- "powered_by": "betrieben von Konfuzio"
169
+ "powered_by": "betrieben von Konfuzio",
170
+ "nav_label_anns": "Durch Annotationen navigieren"
170
171
  }
@@ -167,5 +167,6 @@
167
167
  "checkbox_ann_details": "A checkbox will be extracted for this label.",
168
168
  "document_section": "Document Section",
169
169
  "label_size": "Column size:",
170
- "powered_by": "powered by Konfuzio"
170
+ "powered_by": "powered by Konfuzio",
171
+ "nav_label_anns": "Navigate through annotations"
171
172
  }
@@ -166,5 +166,6 @@
166
166
  "checkbox_ann_details": "Se extraerá una casilla de verificación para esta etiqueta.",
167
167
  "document_section": "Sección del documento",
168
168
  "label_size": "Tamaño de columna:",
169
- "powered_by": "impulsado por Konfuzio"
169
+ "powered_by": "impulsado por Konfuzio",
170
+ "nav_label_anns": "Navegar por las anotaciones"
170
171
  }
package/src/main.js CHANGED
@@ -1,28 +1,26 @@
1
1
  import App from "./components/App";
2
- import Vue from "vue";
2
+ import { createApp } from "vue";
3
3
  import Buefy from "buefy";
4
4
  import VueKonva from "vue-konva";
5
- import i18n from "./i18n";
6
- import store from "./store";
7
- import VueObserveVisibility from "vue-observe-visibility";
5
+ import { i18n } from "./i18n";
6
+ import { store } from "./store";
7
+ import VueObserveVisibility from "vue3-observe-visibility";
8
8
  import Icons from "./icons";
9
- import VueSplit from "vue-split-panel";
10
9
 
11
- Vue.component("VueFontawesome", Icons);
12
- Vue.component("App", App);
13
- Vue.use(VueKonva);
14
- Vue.use(Buefy, {
10
+ const app = createApp();
11
+
12
+ app.component("App", App);
13
+ app.component("VueFontawesome", Icons);
14
+ app.use(VueKonva);
15
+ app.use(Buefy, {
15
16
  defaultIconPack: "fas",
16
17
  defaultIconComponent: "vue-fontawesome",
17
18
  });
18
- Vue.use(VueObserveVisibility);
19
- Vue.use(VueSplit);
19
+ app.use(VueObserveVisibility);
20
+ app.use(store);
21
+ app.use(i18n);
20
22
 
21
23
  /**
22
24
  * Main entrypoint for the App
23
25
  */
24
- new Vue({
25
- i18n,
26
- store,
27
- el: "#app",
28
- });
26
+ app.mount("#app");
@@ -113,32 +113,43 @@ const getters = {
113
113
  * image rendering.
114
114
  */
115
115
  imageScale: (state) => (page) => {
116
- return new BigNumber(page.size[0]).div(page.original_size[0]).toNumber();
116
+ if (
117
+ page.size &&
118
+ page.size.length > 0 &&
119
+ page.original_size &&
120
+ page.original_size.length > 0
121
+ ) {
122
+ return new BigNumber(page.size[0]).div(page.original_size[0]).toNumber();
123
+ }
124
+ return 0;
117
125
  },
118
126
  bboxToPoint:
119
127
  (state, getters) =>
120
128
  (page, point, hasOffset = false) => {
121
- const imageScale = getters.imageScale(page);
122
- const { x, y } = point;
123
- const pageHeight = new BigNumber(page.original_size[1]);
124
- const newPoint = {
125
- // left
126
- x: new BigNumber(x)
127
- .minus(hasOffset ? 1 : 0)
128
- .times(state.scale)
129
- .times(imageScale)
130
- .div(PIXEL_RATIO)
131
- .toNumber(),
132
- // top
133
- y: pageHeight
134
- .minus(new BigNumber(y))
135
- .minus(hasOffset ? 17.1 : 0)
136
- .times(state.scale)
137
- .times(imageScale)
138
- .div(PIXEL_RATIO)
139
- .toNumber(),
140
- };
141
- return newPoint;
129
+ if (page && page.original_size && page.original_size.length > 1) {
130
+ const imageScale = getters.imageScale(page);
131
+ const { x, y } = point;
132
+ const pageHeight = new BigNumber(page.original_size[1]);
133
+ const newPoint = {
134
+ // left
135
+ x: new BigNumber(x)
136
+ .minus(hasOffset ? 1 : 0)
137
+ .times(state.scale)
138
+ .times(imageScale)
139
+ .div(PIXEL_RATIO)
140
+ .toNumber(),
141
+ // top
142
+ y: pageHeight
143
+ .minus(new BigNumber(y))
144
+ .minus(hasOffset ? 17.1 : 0)
145
+ .times(state.scale)
146
+ .times(imageScale)
147
+ .div(PIXEL_RATIO)
148
+ .toNumber(),
149
+ };
150
+ return newPoint;
151
+ }
152
+ return { x: 0, y: 0 };
142
153
  },
143
154
  bboxToRect:
144
155
  (state, getters) =>
@@ -153,6 +153,31 @@ const getters = {
153
153
  return annotations.length > 0;
154
154
  },
155
155
 
156
+ /* Checks if the label has annotations to show */
157
+ isLabelMultiFalseAndGroupOfAnns: (state) => (label) => {
158
+ return (
159
+ label &&
160
+ label.annotations &&
161
+ label.annotations.length > 1 &&
162
+ !label.has_multiple_top_candidates &&
163
+ state.enableGroupingFeature
164
+ );
165
+ },
166
+
167
+ /* Returns the annotations ordered by highest confidence */
168
+ annotationsByConfidence: (state) => (annotations) => {
169
+ annotations.sort((a, b) => {
170
+ if (a.confidence < b.confidence) {
171
+ return -1;
172
+ } else if (a.confidence > b.confidence) {
173
+ return 1;
174
+ }
175
+ return 0;
176
+ });
177
+
178
+ return annotations;
179
+ },
180
+
156
181
  /* Checks if the document has an annotation set */
157
182
  annotationSetExists: (state) => (annotationSetId) => {
158
183
  return state.annotationSets.find((annSet) => annSet.id === annotationSetId);
@@ -256,11 +281,16 @@ const getters = {
256
281
  /* Get label for a given annotation */
257
282
  labelOfAnnotation: (state) => (annotationToFind) => {
258
283
  let foundLabel = null;
259
- state.annotationSets.forEach((annotationSet) => {
260
- annotationSet.labels.forEach((label) => {
261
- label.annotations.forEach((annotation) => {
262
- if (annotation.id === annotationToFind.id) {
263
- foundLabel = label;
284
+ if (state.annotationSets) {
285
+ state.annotationSets.forEach((annotationSet) => {
286
+ annotationSet.labels.forEach((label) => {
287
+ label.annotations.forEach((annotation) => {
288
+ if (annotation.id === annotationToFind.id) {
289
+ foundLabel = label;
290
+ return;
291
+ }
292
+ });
293
+ if (foundLabel) {
264
294
  return;
265
295
  }
266
296
  });
@@ -268,14 +298,12 @@ const getters = {
268
298
  return;
269
299
  }
270
300
  });
271
- if (foundLabel) {
272
- return;
273
- }
274
- });
301
+ }
302
+
275
303
  return foundLabel;
276
304
  },
277
305
 
278
- getAnnotationsFiltered: (state) => {
306
+ getAnnotationsFiltered: (state, getters) => {
279
307
  // group annotations for sidebar
280
308
  let annotations = [];
281
309
  let labels = [];
@@ -331,6 +359,18 @@ const getters = {
331
359
  return false;
332
360
  };
333
361
 
362
+ const sortByConfidenceOrByAnnotationSelected = (annotations) => {
363
+ annotations = getters.annotationsByConfidence(annotations);
364
+ if (state.annotationId) {
365
+ for (let i = 0; i < annotations.length; i++) {
366
+ if (state.annotationId == annotations[i].id) {
367
+ annotations.unshift(annotations.splice(i, 1)[0]);
368
+ }
369
+ }
370
+ }
371
+ return annotations;
372
+ };
373
+
334
374
  if (state.annotationSets) {
335
375
  state.annotationSets.forEach((annotationSet) => {
336
376
  labels = [];
@@ -350,6 +390,13 @@ const getters = {
350
390
  !state.annotationFilters.showFeedbackNeeded ||
351
391
  !state.annotationFilters.showAccepted
352
392
  ) {
393
+ if (!label.has_multiple_top_candidates) {
394
+ // if multi label = false, sort by confidence
395
+ label.annotations = sortByConfidenceOrByAnnotationSelected(
396
+ label.annotations
397
+ );
398
+ }
399
+
353
400
  label.annotations.forEach((annotation) => {
354
401
  if (
355
402
  state.annotationFilters.showFeedbackNeeded &&
@@ -379,6 +426,12 @@ const getters = {
379
426
  }
380
427
  });
381
428
  } else {
429
+ if (!label.has_multiple_top_candidates) {
430
+ // if multi label = false, sort by confidence
431
+ label.annotations = sortByConfidenceOrByAnnotationSelected(
432
+ label.annotations
433
+ );
434
+ }
382
435
  // add annotations to the document array
383
436
  label.annotations.forEach((annotation) => {
384
437
  const added = addAnnotation(
@@ -963,6 +1016,15 @@ const actions = {
963
1016
  commit("SET_DOC_ID", id);
964
1017
  },
965
1018
  setAnnotationId: ({ commit, dispatch, getters }, id) => {
1019
+ if (id) {
1020
+ // check if part of label with multi ann as false
1021
+ const annotation = getters.annotationById(id);
1022
+ const label = getters.labelOfAnnotation(annotation);
1023
+ if (getters.isLabelMultiFalseAndGroupOfAnns(label)) {
1024
+ dispatch("setAnnotationAsFirstInLabel", { label, annotation });
1025
+ }
1026
+ }
1027
+
966
1028
  commit("SET_ANNOTATION_ID", id);
967
1029
  setURLAnnotationHash(id);
968
1030
  },
@@ -1134,6 +1196,7 @@ const actions = {
1134
1196
  // Check if we first open the document dashboard or the edit mode
1135
1197
  if (
1136
1198
  !state.publicView &&
1199
+ state.selectedDocument &&
1137
1200
  (!state.selectedDocument.category ||
1138
1201
  (!state.selectedDocument.category_is_revised &&
1139
1202
  !getters.documentHasCorrectAnnotations &&
@@ -1541,6 +1604,57 @@ const actions = {
1541
1604
  showAcceptedAnnotations({ commit }, show) {
1542
1605
  commit("SET_SHOW_ACCEPTED_ANNOTATIONS", show);
1543
1606
  },
1607
+ setAnnotationAsFirstInLabel({ commit, state }, { label, annotation }) {
1608
+ state.annotationSets.forEach((annotationSet) => {
1609
+ annotationSet.labels.forEach((labelToFind) => {
1610
+ if (labelToFind.id === label.id) {
1611
+ if (labelToFind.annotations && labelToFind.annotations.length > 1) {
1612
+ for (let i = 0; i < labelToFind.annotations.length; i++) {
1613
+ if (labelToFind.annotations[i].id === annotation.id) {
1614
+ labelToFind.annotations.unshift(
1615
+ labelToFind.annotations.splice(i, 1)[0]
1616
+ );
1617
+ commit("SET_ANNOTATIONS_IN_LABEL", {
1618
+ label: labelToFind,
1619
+ annotations: labelToFind.annotations,
1620
+ });
1621
+ }
1622
+ }
1623
+ }
1624
+ }
1625
+ });
1626
+ });
1627
+ },
1628
+ putNextAnnotationInLabelFirst({ commit, state, dispatch }, label) {
1629
+ dispatch("setAnnotationId", null);
1630
+ let newFirstAnn = null;
1631
+ state.annotationSets.forEach((annotationSet) => {
1632
+ annotationSet.labels.forEach((labelToFind) => {
1633
+ if (labelToFind.id === label.id) {
1634
+ if (labelToFind.annotations && labelToFind.annotations.length > 1) {
1635
+ const firstElement = labelToFind.annotations.shift();
1636
+ labelToFind.annotations.push(firstElement);
1637
+ commit("SET_ANNOTATIONS_IN_LABEL", {
1638
+ label: labelToFind,
1639
+ annotations: labelToFind.annotations,
1640
+ });
1641
+ newFirstAnn = labelToFind.annotations[0];
1642
+ }
1643
+ }
1644
+ });
1645
+ });
1646
+
1647
+ if (newFirstAnn) {
1648
+ dispatch("setDocumentAnnotationSelected", {
1649
+ annotation: newFirstAnn,
1650
+ label: label,
1651
+ span: newFirstAnn.span[0],
1652
+ scrollTo: true,
1653
+ });
1654
+
1655
+ dispatch("scrollToDocumentAnnotationSelected");
1656
+ }
1657
+ },
1544
1658
  };
1545
1659
 
1546
1660
  const mutations = {
@@ -1686,6 +1800,13 @@ const mutations = {
1686
1800
  SET_LABELS: (state, labels) => {
1687
1801
  state.labels = labels;
1688
1802
  },
1803
+ SET_ANNOTATIONS_IN_LABEL: (state, { label, annotations }) => {
1804
+ state.labels.forEach((labelToFind) => {
1805
+ if (labelToFind.id === label.id) {
1806
+ labelToFind.annotations = annotations;
1807
+ }
1808
+ });
1809
+ },
1689
1810
  SET_EDIT_ANNOTATION: (state, editAnnotation) => {
1690
1811
  state.editAnnotation = editAnnotation;
1691
1812
  },
@@ -1,5 +1,4 @@
1
- import Vue from "vue";
2
- import Vuex from "vuex";
1
+ import { createStore } from "vuex";
3
2
 
4
3
  import display from "./display";
5
4
  import document from "./document";
@@ -8,15 +7,13 @@ import project from "./project";
8
7
  import selection from "./selection";
9
8
  import edit from "./edit";
10
9
 
11
- Vue.use(Vuex);
12
-
13
- export default new Vuex.Store({
10
+ export const store = createStore({
14
11
  modules: {
15
12
  display,
16
13
  document,
17
14
  category,
18
15
  project,
19
16
  selection,
20
- edit
21
- }
22
- });
17
+ edit,
18
+ },
19
+ });