@konfuzio/document-validation-ui 0.1.10-dev.14 → 0.1.10-dev.16

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@konfuzio/document-validation-ui",
3
- "version": "0.1.10-dev.14",
3
+ "version": "0.1.10-dev.16",
4
4
  "repository": "git://github.com:konfuzio-ai/document-validation-ui.git",
5
5
  "main": "dist/app.js",
6
6
  "scripts": {
@@ -46,6 +46,8 @@
46
46
  display: flex;
47
47
  flex-direction: row;
48
48
  justify-content: space-between;
49
+ height: 100%;
50
+ align-items: center;
49
51
  }
50
52
  .bottom-section {
51
53
  text-align: center;
@@ -1,11 +1,9 @@
1
1
  @import "./imports.scss";
2
2
 
3
3
  .document-name-component {
4
- flex: 1;
5
4
  display: flex;
6
5
  align-items: center;
7
6
  justify-content: center;
8
- width: 100%;
9
7
  gap: 12px;
10
8
  line-height: 20px;
11
9
 
@@ -32,6 +32,29 @@
32
32
  flex: 1;
33
33
  }
34
34
 
35
+ .center-bar-components {
36
+ display: flex;
37
+ align-items: center;
38
+ gap: 38px;
39
+
40
+ &.single-component {
41
+ flex: 1;
42
+ align-items: center;
43
+ justify-content: center;
44
+ }
45
+
46
+ .navigation-arrow {
47
+ &:hover {
48
+ cursor: pointer;
49
+ }
50
+
51
+ &.navigation-disabled {
52
+ cursor: not-allowed;
53
+ filter: opacity(0.5);
54
+ }
55
+ }
56
+ }
57
+
35
58
  .right-bar-components {
36
59
  align-items: center;
37
60
  justify-content: flex-end;
@@ -291,7 +291,7 @@
291
291
  }
292
292
 
293
293
  .b-checkbox.checkbox {
294
- .check {
294
+ input[type="checkbox"] + .check {
295
295
  background-color: $white;
296
296
  }
297
297
  &:hover input[type="checkbox"]:not(:disabled) + .check {
@@ -66,10 +66,10 @@ export default {
66
66
  required: false,
67
67
  default: "",
68
68
  },
69
+ // eslint-disable-next-line vue/require-default-prop
69
70
  locale: {
70
71
  type: String,
71
72
  required: false,
72
- default: "en",
73
73
  },
74
74
  // eslint-disable-next-line vue/prop-name-casing
75
75
  documents_list_path: {
@@ -111,11 +111,7 @@ export default {
111
111
  }
112
112
  },
113
113
  isPublicView() {
114
- if (
115
- process.env.VUE_APP_GUEST_USER_TOKEN ||
116
- this.user_token ||
117
- (this.full_mode && this.full_mode === "true")
118
- ) {
114
+ if (this.userToken || (this.full_mode && this.full_mode === "true")) {
119
115
  return false;
120
116
  } else {
121
117
  return true;
@@ -53,10 +53,6 @@ export default {
53
53
  type: Object,
54
54
  required: true,
55
55
  },
56
- saveChanges: {
57
- type: Boolean,
58
- required: false,
59
- },
60
56
  },
61
57
  data() {
62
58
  return {
@@ -70,7 +66,6 @@ export default {
70
66
  "isDocumentReviewed",
71
67
  ]),
72
68
  ...mapGetters("display", ["bboxToRect"]),
73
- ...mapState("selection", ["spanSelection"]),
74
69
  ...mapState("document", [
75
70
  "editAnnotation",
76
71
  "publicView",
@@ -107,12 +102,6 @@ export default {
107
102
  this.handleCancel(true);
108
103
  }
109
104
  },
110
-
111
- saveChanges(newValue) {
112
- if (newValue) {
113
- this.saveAnnotationChanges();
114
- }
115
- },
116
105
  },
117
106
  methods: {
118
107
  setText(text) {
@@ -205,14 +194,40 @@ export default {
205
194
  index = this.spanIndex;
206
195
  }
207
196
 
197
+ let spans = [];
198
+
199
+ // Validate if we are deleting an Annotation that it's not multi-lined
200
+ let isToDelete =
201
+ this.annotationText.length === 0 &&
202
+ (!isElementArray(this.annotation.span) ||
203
+ this.annotation.span.length === 1);
204
+
205
+ if (!isToDelete) {
206
+ const span = this.createSpan();
207
+
208
+ spans = [...annotation.span];
209
+
210
+ spans[index] = span;
211
+
212
+ if (this.annotationText.length === 0) {
213
+ spans.splice(index, 1);
214
+ }
215
+ }
208
216
  // API call handled in parent component - AnnotationRow
209
- this.$emit(
210
- "save-annotation-changes",
211
- this.annotation,
212
- index,
213
- this.span,
214
- this.annotationText
215
- );
217
+ this.$emit("save-annotation-changes", spans, isToDelete);
218
+ },
219
+
220
+ createSpan() {
221
+ return {
222
+ offset_string: this.annotationText,
223
+ page_index: this.span.page_index,
224
+ x0: this.span.x0,
225
+ x1: this.span.x1,
226
+ y0: this.span.y0,
227
+ y1: this.span.y1,
228
+ start_offset: this.span.start_offset,
229
+ end_offset: this.span.end_offset,
230
+ };
216
231
  },
217
232
  },
218
233
  };
@@ -49,14 +49,14 @@
49
49
  @mouseleave="onAnnotationHoverLeave"
50
50
  >
51
51
  <AnnotationContent
52
+ :ref="`span_${annotation.id}_${index}`"
52
53
  :annotation="annotation"
53
54
  :span="span"
54
55
  :span-index="index"
55
56
  :label="label"
56
57
  :annotation-set="annotationSet"
57
58
  :is-hovered="hoveredAnnotation"
58
- :save-changes="saveChanges"
59
- @save-annotation-changes="handleSaveAnnotationChanges"
59
+ @save-annotation-changes="saveAnnotationChanges"
60
60
  />
61
61
  </div>
62
62
  </div>
@@ -70,7 +70,6 @@
70
70
  :label="label"
71
71
  :annotation-set="annotationSet"
72
72
  :is-hovered="hoveredAnnotation"
73
- :save-changes="saveChanges"
74
73
  :is-missing-annotation="
75
74
  annotationIsNotFound(annotationSet, label)
76
75
  "
@@ -82,7 +81,6 @@
82
81
  :label="label"
83
82
  :annotation-set="annotationSet"
84
83
  :is-hovered="hoveredAnnotation"
85
- :save-changes="saveChanges"
86
84
  :is-missing-annotation="annotationIsNotFound(annotationSet, label)"
87
85
  @save-empty-annotation-changes="saveEmptyAnnotationChanges"
88
86
  />
@@ -156,8 +154,6 @@ export default {
156
154
  isSelected: false,
157
155
  annotationAnimationTimeout: null,
158
156
  hoveredAnnotation: null,
159
- saveChanges: false,
160
- toDecline: false,
161
157
  };
162
158
  },
163
159
  computed: {
@@ -261,7 +257,6 @@ export default {
261
257
  },
262
258
  editAnnotation(newValue) {
263
259
  if (!newValue) {
264
- this.saveChanges = false;
265
260
  this.isLoading = false;
266
261
  }
267
262
  },
@@ -451,20 +446,24 @@ export default {
451
446
  if (this.publicView || this.isDocumentReviewed) return;
452
447
 
453
448
  if (
454
- this.showAcceptButton() ||
455
- this.showDeclineButton() ||
456
- this.isAnnotationInEditMode(
457
- this.annotationId(),
458
- this.editAnnotation.index
459
- )
449
+ this.annotation &&
450
+ (this.showAcceptButton() ||
451
+ this.showDeclineButton() ||
452
+ this.isAnnotationInEditMode(
453
+ this.annotationId(),
454
+ this.editAnnotation.index
455
+ ))
460
456
  ) {
461
- this.saveChanges = true;
462
- if (decline) {
463
- this.toDecline = true;
464
- }
465
- }
466
-
467
- if (
457
+ // retrieve all edited spans from every AnnotationContent component
458
+ let spans = [];
459
+ Object.keys(this.$refs).forEach((ref) => {
460
+ if (ref.includes(`span_${this.annotation.id}`)) {
461
+ // call child component createSpan method
462
+ spans.push(this.$refs[ref][0].createSpan());
463
+ }
464
+ });
465
+ this.saveAnnotationChanges(spans, decline);
466
+ } else if (
468
467
  !this.annotation &&
469
468
  this.isAnnotationInEditMode(this.annotationId())
470
469
  ) {
@@ -495,12 +494,7 @@ export default {
495
494
  this.closedTag = null;
496
495
  });
497
496
  },
498
- handleSaveAnnotationChanges(
499
- annotation,
500
- index,
501
- annotationSpan,
502
- annotationContent
503
- ) {
497
+ saveAnnotationChanges(spans, isToDeleteOrDecline) {
504
498
  // This function deals with declining Annotations
505
499
  // or editing an Annotation or a part of it (if multi line)
506
500
  this.isLoading = true;
@@ -508,29 +502,14 @@ export default {
508
502
  let updatedString; // what will be sent to the API
509
503
  let storeAction; // if it will be 'delete' or 'patch'
510
504
 
511
- // Validate if we are deleting an Annotation that it's not multi-lined
512
- let isToDelete =
513
- annotationContent.length === 0 &&
514
- (!isElementArray(annotation.span) || annotation.span.length === 1);
515
-
516
505
  // Verify if we delete the entire Annotation or a part of the text
517
- if (isToDelete || this.toDecline) {
506
+ if (isToDeleteOrDecline) {
518
507
  storeAction = "document/deleteAnnotation";
519
508
  } else {
520
509
  // Editing the Annotation
521
510
  // Deleting part of multi-line Annotation
522
511
  storeAction = "document/updateAnnotation";
523
512
 
524
- let spans = [...annotation.span];
525
-
526
- const span = this.createSpan(annotationSpan, annotationContent);
527
-
528
- spans[index] = span;
529
-
530
- if (annotationContent.length === 0) {
531
- spans.splice(index, 1);
532
- }
533
-
534
513
  updatedString = {
535
514
  is_correct: true,
536
515
  revised: true,
@@ -555,21 +534,8 @@ export default {
555
534
  this.$store.dispatch("document/resetEditAnnotation");
556
535
  this.$store.dispatch("selection/disableSelection");
557
536
  this.$store.dispatch("selection/setSelectedEntities", null);
558
- this.toDecline = false;
559
537
  });
560
538
  },
561
- createSpan(span, annotationContent) {
562
- return {
563
- offset_string: annotationContent,
564
- page_index: span.page_index,
565
- x0: span.x0,
566
- x1: span.x1,
567
- y0: span.y0,
568
- y1: span.y1,
569
- start_offset: span.start_offset,
570
- end_offset: span.end_offset,
571
- };
572
- },
573
539
  saveEmptyAnnotationChanges() {
574
540
  let annotationToCreate;
575
541
 
@@ -624,12 +590,10 @@ export default {
624
590
 
625
591
  if (found) {
626
592
  this.isLoading = true;
627
- this.saveChanges = false;
628
593
  return;
629
594
  }
630
595
 
631
596
  this.isLoading = false;
632
- this.saveChanges = false;
633
597
  return;
634
598
  }
635
599
 
@@ -637,7 +601,6 @@ export default {
637
601
  // while waiting for it to be removed from the row
638
602
  if (!this.annotationsMarkedAsMissing) {
639
603
  this.isLoading = false;
640
- this.saveChanges = false;
641
604
  return;
642
605
  }
643
606
 
@@ -652,7 +615,6 @@ export default {
652
615
  // Check if we wanna add loading to all empty annotations
653
616
  if (this.hoveredAnnotationSet) {
654
617
  this.isLoading = true;
655
- this.saveChanges = false;
656
618
  return;
657
619
  }
658
620
 
@@ -662,7 +624,6 @@ export default {
662
624
  annotation.label === this.label.id
663
625
  ) {
664
626
  this.isLoading = true;
665
- this.saveChanges = false;
666
627
  return;
667
628
  }
668
629
  }
@@ -67,10 +67,6 @@ export default {
67
67
  required: false,
68
68
  default: 0,
69
69
  },
70
- saveChanges: {
71
- type: Boolean,
72
- required: false,
73
- },
74
70
  isMissingAnnotation: {
75
71
  type: Boolean,
76
72
  required: true,
@@ -85,8 +85,9 @@ export default {
85
85
  "selectedPages",
86
86
  "submitEditChanges",
87
87
  ]),
88
- ...mapState("project", ["projectId", "documentsListPath"]),
88
+ ...mapState("project", ["projectId", "documentsListPath", "currentUser"]),
89
89
  ...mapGetters("edit", ["documentShouldBePostprocessed"]),
90
+ ...mapGetters("document", ["waitingForSplittingConfirmation"]),
90
91
  },
91
92
  watch: {
92
93
  renameAndCategorize(newValue) {
@@ -375,7 +376,10 @@ export default {
375
376
  // Send update request to the backend
376
377
  saveEditChanges() {
377
378
  // Verify if there was splitting, rotating and/or reordering
378
- if (this.documentShouldBePostprocessed) {
379
+ if (
380
+ this.documentShouldBePostprocessed ||
381
+ this.waitingForSplittingConfirmation(this.selectedDocument)
382
+ ) {
379
383
  this.$store
380
384
  .dispatch("edit/editDocument", this.updatedDocument)
381
385
  .catch((error) => {
@@ -386,9 +390,13 @@ export default {
386
390
  });
387
391
  });
388
392
 
389
- navigateToDocumentsList(this.documentsListPath, this.projectId);
393
+ navigateToDocumentsList(
394
+ this.documentsListPath,
395
+ this.projectId,
396
+ this.currentUser.id
397
+ );
390
398
  } else {
391
- // Check if only the category changes:
399
+ // Check if only the category and/or name changes:
392
400
  const newCategory = this.updatedDocument[0].category;
393
401
  const newName = this.updatedDocument[0].name;
394
402
  let category = {};
@@ -11,9 +11,7 @@
11
11
  isVisible && 'visible',
12
12
  checkboxValue && 'selected',
13
13
  ]"
14
- :style="{
15
- transform: `rotate(${rotation}deg)`,
16
- }"
14
+ :style="`rotate:${rotation}deg`"
17
15
  @click="selectPage()"
18
16
  >
19
17
  <ServerImage :image-url="`${page.thumbnail_url}?${page.updated_at}`">
@@ -96,7 +96,7 @@ export default {
96
96
  };
97
97
  },
98
98
  computed: {
99
- ...mapState("edit", ["selectedPages"]),
99
+ ...mapState("edit", ["selectedPages", "updatedDocument"]),
100
100
  ...mapState("document", ["splittingSuggestions", "selectedDocument"]),
101
101
  ...mapGetters("document", ["documentHasProposedSplit"]),
102
102
  },
@@ -117,6 +117,11 @@ export default {
117
117
  this.switchStatus = false;
118
118
  }
119
119
  },
120
+ updatedDocument(newValue) {
121
+ if (newValue && newValue.length === 1) {
122
+ this.switchStatus = false;
123
+ }
124
+ },
120
125
  },
121
126
  mounted() {
122
127
  this.$nextTick(() => {
@@ -119,6 +119,7 @@ export default {
119
119
  methods: {
120
120
  handleEdit() {
121
121
  if (this.editModeDisabled) return;
122
+ this.$store.dispatch("selection/disableSelection");
122
123
  this.$store.dispatch("edit/enableEditMode");
123
124
  },
124
125
  zoomIn() {
@@ -1,5 +1,7 @@
1
1
  <template>
2
- <div class="document-name-component">
2
+ <div
3
+ :class="['document-name-component', editMode && 'document-name-edit-mode']"
4
+ >
3
5
  <div class="document-icon">
4
6
  <ServerImage
5
7
  :height="'22px'"
@@ -10,7 +10,36 @@
10
10
  />
11
11
  </div>
12
12
 
13
- <DocumentName :data-file-name="selectedDocument.data_file_name" />
13
+ <div
14
+ :class="[
15
+ 'center-bar-components',
16
+ recalculatingAnnotations && 'single-component',
17
+ ]"
18
+ >
19
+ <div
20
+ :class="[
21
+ 'left-arrow navigation-arrow',
22
+ !previousDocument && 'navigation-disabled',
23
+ ]"
24
+ type="button"
25
+ @click="navigateToDocument(previousDocument)"
26
+ >
27
+ <b-icon icon="angle-left" size="is-small" />
28
+ </div>
29
+
30
+ <DocumentName :data-file-name="selectedDocument.data_file_name" />
31
+
32
+ <div
33
+ :class="[
34
+ 'right-arrow navigation-arrow',
35
+ !nextDocument && 'navigation-disabled',
36
+ ]"
37
+ type="button"
38
+ @click="navigateToDocument(nextDocument)"
39
+ >
40
+ <b-icon icon="angle-right" size="is-small" />
41
+ </div>
42
+ </div>
14
43
 
15
44
  <div v-if="!recalculatingAnnotations" class="right-bar-components">
16
45
  <div
@@ -87,6 +116,8 @@ export default {
87
116
  data() {
88
117
  return {
89
118
  categoryError: false,
119
+ previousDocument: null,
120
+ nextDocument: null,
90
121
  };
91
122
  },
92
123
  computed: {
@@ -98,7 +129,19 @@ export default {
98
129
  ]),
99
130
  ...mapState("category", ["categories"]),
100
131
  ...mapState("edit", ["editMode"]),
101
- ...mapGetters("document", ["isDocumentReviewed"]),
132
+ ...mapState("project", ["documentsInProject"]),
133
+ ...mapGetters("document", [
134
+ "isDocumentReviewed",
135
+ "isDocumentReadyToBeReviewed",
136
+ "waitingForSplittingConfirmation",
137
+ ]),
138
+ },
139
+ watch: {
140
+ documentsInProject(newValue) {
141
+ if (newValue && this.selectedDocument) {
142
+ this.getPreviousAndNextDocuments();
143
+ }
144
+ },
102
145
  },
103
146
  created() {
104
147
  window.addEventListener("resize", this.handleResize);
@@ -120,6 +163,42 @@ export default {
120
163
  handleResize() {
121
164
  this.setComponentWidth(this.$refs.documentTopBar.offsetWidth);
122
165
  },
166
+ getPreviousAndNextDocuments() {
167
+ // Only consider documents who have a status of "ready"
168
+ const filteredDocuments = this.documentsInProject.filter(
169
+ (document) =>
170
+ this.isDocumentReadyToBeReviewed(document) ||
171
+ this.waitingForSplittingConfirmation(document)
172
+ );
173
+
174
+ if (!filteredDocuments) return;
175
+
176
+ const found = filteredDocuments.find(
177
+ (document) => document.id === this.selectedDocument.id
178
+ );
179
+
180
+ const indexOfCurrentDocument = filteredDocuments.indexOf(found);
181
+
182
+ if (!(indexOfCurrentDocument < 0)) {
183
+ this.previousDocument = filteredDocuments[indexOfCurrentDocument - 1];
184
+ this.nextDocument = filteredDocuments[indexOfCurrentDocument + 1];
185
+ } else {
186
+ this.previousDocument = filteredDocuments[0];
187
+ this.nextDocument = filteredDocuments[1];
188
+ }
189
+ },
190
+ navigateToDocument(document) {
191
+ if (!document) return;
192
+
193
+ this.$store.dispatch("document/changeCurrentDocument", document.id);
194
+
195
+ if (this.editMode) {
196
+ // Reset edit mode when changing the document,
197
+ // in case the change was made from the arrows in the Edit Mode
198
+ // so that the user does not get stuck in this interface
199
+ this.$store.dispatch("edit/disableEditMode");
200
+ }
201
+ },
123
202
  },
124
203
  };
125
204
  </script>
@@ -110,12 +110,7 @@ export default {
110
110
  },
111
111
  methods: {
112
112
  changeDocument(documentId) {
113
- if (getURLQueryParam("document") || getURLPath("docs")) {
114
- navigateToNewDocumentURL(this.selectedDocument.id, documentId);
115
- } else {
116
- this.$store.dispatch("document/setDocId", documentId);
117
- this.$store.dispatch("document/fetchDocument");
118
- }
113
+ this.$store.dispatch("document/changeCurrentDocument", documentId);
119
114
  },
120
115
  requestTrialAccess() {
121
116
  window.open("https://konfuzio.com", "_blank");