@konfuzio/document-validation-ui 0.1.33 → 0.1.34-patch.1

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.33",
3
+ "version": "0.1.34-patch.1",
4
4
  "repository": "git://github.com:konfuzio-ai/document-validation-ui.git",
5
5
  "main": "dist/app.js",
6
6
  "scripts": {
@@ -517,15 +517,14 @@
517
517
  }
518
518
 
519
519
  .accept-decline-container {
520
- padding-right: 14px;
521
520
  display: flex;
522
521
  flex-direction: row;
522
+ gap: 6px;
523
523
  justify-content: center;
524
524
  button {
525
- padding: 6px;
525
+ padding: 0px;
526
526
 
527
527
  .decline-icon {
528
- padding: 6px;
529
528
  color: $red;
530
529
  vertical-align: middle;
531
530
  }
@@ -6,6 +6,7 @@
6
6
  justify-content: center;
7
7
  gap: 12px;
8
8
  line-height: 20px;
9
+ width: 400px;
9
10
 
10
11
  .document-icon {
11
12
  display: flex;
@@ -17,6 +18,9 @@
17
18
  .document-name {
18
19
  display: inline-block;
19
20
  vertical-align: middle;
21
+ white-space: nowrap;
22
+ overflow: hidden;
23
+ text-overflow: ellipsis;
20
24
 
21
25
  &.is-editable {
22
26
  display: inline-block;
@@ -25,7 +29,6 @@
25
29
  border-radius: 8px;
26
30
  padding: 6px 14px 6px 14px;
27
31
  outline: 1px solid $grey-outline;
28
- max-width: 420px;
29
32
  }
30
33
  }
31
34
 
@@ -35,7 +35,6 @@
35
35
  .center-bar-components {
36
36
  display: flex;
37
37
  align-items: center;
38
- gap: 38px;
39
38
 
40
39
  &.single-component {
41
40
  flex: 1;
@@ -52,7 +52,7 @@
52
52
  type="is-ghost"
53
53
  @click.stop="decline"
54
54
  >
55
- <b-icon icon="xmark" size="is-24" class="decline-icon" />
55
+ <b-icon icon="xmark" size="is-20" class="decline-icon" />
56
56
  </b-button>
57
57
  <b-button
58
58
  v-if="acceptBtn"
@@ -106,7 +106,6 @@
106
106
  import { mapGetters, mapState } from "vuex";
107
107
  import AcceptedCheckMark from "../../assets/images/AcceptedCheckMark";
108
108
  import { TEXT_BREAKPOINT_WIDTH } from "../../constants";
109
- import { setURLAnnotationHash } from "../../utils/utils";
110
109
  export default {
111
110
  name: "AnnotationActionButtons",
112
111
  components: {
@@ -150,7 +149,9 @@ export default {
150
149
  },
151
150
  data() {
152
151
  return {
153
- showText: window.innerWidth > TEXT_BREAKPOINT_WIDTH,
152
+ showText:
153
+ window.innerWidth >
154
+ TEXT_BREAKPOINT_WIDTH(this.$i18n ? this.$i18n.locale : "en"),
154
155
  };
155
156
  },
156
157
  computed: {
@@ -186,7 +187,8 @@ export default {
186
187
  }
187
188
  },
188
189
  resize() {
189
- this.showText = window.innerWidth > TEXT_BREAKPOINT_WIDTH;
190
+ this.showText =
191
+ window.innerWidth > TEXT_BREAKPOINT_WIDTH(this.$i18n.locale);
190
192
  },
191
193
  save() {
192
194
  this.$emit("save");
@@ -52,18 +52,45 @@ export default {
52
52
  anchorSize: 6,
53
53
  };
54
54
  },
55
- ...mapState("selection", ["selection", "isSelecting"]),
55
+ ...mapState("selection", [
56
+ "selection",
57
+ "isSelecting",
58
+ "elementSelected",
59
+ "spanSelection",
60
+ ]),
56
61
  ...mapGetters("display", ["clientToBbox"]),
57
- ...mapGetters("selection", ["isSelectionValid"]),
62
+ ...mapGetters("selection", ["isSelectionValid", "entitiesOnSelection"]),
63
+ },
64
+ watch: {
65
+ isSelecting(isSelecting) {
66
+ if (!isSelecting) {
67
+ this.updateTransformer();
68
+ this.handleSelection();
69
+ }
70
+ },
58
71
  },
59
72
  mounted() {
60
- this.updateTransformer();
61
-
62
- if (this.selection.custom) {
63
- this.getBoxSelectionContent();
73
+ if (!this.selection.custom) {
74
+ // if annotation was selected, then add transformer
75
+ this.updateTransformer();
64
76
  }
65
77
  },
66
78
  methods: {
79
+ handleSelection() {
80
+ if (!this.elementSelected) {
81
+ const box = this.clientToBbox(
82
+ this.page,
83
+ this.selection.start,
84
+ this.selection.end
85
+ );
86
+ this.$emit(
87
+ "createAnnotations",
88
+ this.entitiesOnSelection(box, this.page)
89
+ );
90
+ } else {
91
+ this.getBoxSelectionContent();
92
+ }
93
+ },
67
94
  updateTransformer() {
68
95
  // here we need to manually attach or detach Transformer node
69
96
  const transformer = this.$refs.boxTransformer;
@@ -97,15 +124,17 @@ export default {
97
124
  },
98
125
 
99
126
  getBoxSelectionContent() {
100
- const box = this.clientToBbox(
101
- this.page,
102
- this.selection.start,
103
- this.selection.end
104
- );
105
- this.$store.dispatch("selection/getTextFromBboxes", {
106
- box,
107
- entities: false,
108
- });
127
+ if (!this.isSelecting) {
128
+ const box = this.clientToBbox(
129
+ this.page,
130
+ this.selection.start,
131
+ this.selection.end
132
+ );
133
+ this.$store.dispatch("selection/getTextFromBboxes", {
134
+ box,
135
+ entities: false,
136
+ });
137
+ }
109
138
  },
110
139
 
111
140
  /**
@@ -144,7 +173,7 @@ export default {
144
173
  node.scaleX(1);
145
174
  node.scaleY(1);
146
175
 
147
- this.getBoxSelectionContent();
176
+ this.handleSelection();
148
177
  },
149
178
  ...mapActions("selection", ["moveSelection"]),
150
179
  },
@@ -62,7 +62,7 @@
62
62
  </template>
63
63
  <v-group v-if="!publicView || !isDocumentReviewed" ref="entities">
64
64
  <v-rect
65
- v-for="(entity, index) in scaledEntities"
65
+ v-for="(entity, index) in scaledEntities(page.entities, page)"
66
66
  :key="index"
67
67
  :config="entityRect(entity)"
68
68
  @click="handleClickedEntity(entity)"
@@ -148,10 +148,13 @@
148
148
  />
149
149
  </v-label>
150
150
  </v-layer>
151
- <v-layer v-if="isBoxSelection">
152
- <box-selection :page="page" />
151
+ <v-layer v-if="page.number === selectionPage">
152
+ <box-selection
153
+ :page="page"
154
+ @createAnnotations="handleCreateAnnotationsFromSelection"
155
+ />
153
156
  </v-layer>
154
- <v-layer v-else-if="isMultiSelection">
157
+ <v-layer v-if="isMultiSelection">
155
158
  <multi-ann-selection
156
159
  :page="page"
157
160
  @buttonEnter="onElementEnter"
@@ -224,19 +227,31 @@ export default {
224
227
  "annotationId",
225
228
  ]),
226
229
  ...mapState("edit", ["editMode"]),
227
- ...mapGetters("display", ["visiblePageRange", "bboxToRect"]),
230
+ ...mapGetters("display", [
231
+ "visiblePageRange",
232
+ "bboxToRect",
233
+ "scaledEntities",
234
+ ]),
228
235
  ...mapGetters("selection", ["isSelectionValid", "isElementSelected"]),
229
236
  ...mapGetters("document", [
230
237
  "getAnnotationsFiltered",
231
238
  "isAnnotationInEditMode",
232
239
  "isDocumentReadyToBeReviewed",
233
- "entitiesOnSelection",
234
240
  "isDocumentReviewed",
235
241
  "labelOfAnnotation",
236
242
  "isNegative",
237
243
  ]),
238
-
244
+ selectionPage() {
245
+ return this.selection && this.selection.pageNumber;
246
+ },
239
247
  isBoxSelection() {
248
+ if (!MULTI_ANN_TABLE_FEATURE) {
249
+ return (
250
+ true &&
251
+ this.selection &&
252
+ this.selection.pageNumber === this.currentPage
253
+ );
254
+ }
240
255
  return this.selection && !this.isSelecting && this.isElementSelected;
241
256
  },
242
257
  isMultiSelection() {
@@ -274,31 +289,6 @@ export default {
274
289
  return this.visiblePageRange.includes(this.page.number);
275
290
  },
276
291
 
277
- /**
278
- * We take the entities from the backend and resize them according
279
- * to the `scale` (zoom), the `imageScale` (proportion between the original
280
- * document and the served image) and `PIXEL_RATIO` (in case of retina displays).
281
- * We also change the original bbox format to something that can be used with CSS.
282
- * The original is stored inside the `original` property, since it can be reused
283
- * when we're sending the entity to the backend for selection or saving.
284
- */
285
- scaledEntities() {
286
- // entities are either not loaded yet or empty
287
- if (!this.page.hasOwnProperty("entities") || !this.page.entities) {
288
- return [];
289
- }
290
-
291
- return this.page.entities.map((entity) => {
292
- const box = this.bboxToRect(this.page, entity);
293
- return {
294
- original: entity,
295
- scaled: {
296
- ...box,
297
- },
298
- };
299
- });
300
- },
301
-
302
292
  /**
303
293
  * A filtered version of `annotations` for the chosen page.
304
294
  * Include annotations that have *at least* one bbox in the page.
@@ -348,12 +338,12 @@ export default {
348
338
  }
349
339
  },
350
340
  scale() {
351
- this.closePopups(true);
341
+ this.closePopups();
352
342
  },
353
343
  async selectedEntities(newValue) {
354
344
  if (!newValue) {
355
345
  this.$store.dispatch("selection/setSpanSelection", null);
356
- this.closePopups(true);
346
+ this.closePopups();
357
347
  }
358
348
 
359
349
  await this.$store.dispatch("selection/getTextFromEntities", newValue);
@@ -365,7 +355,7 @@ export default {
365
355
  },
366
356
  searchEnabled(isEnabled) {
367
357
  if (isEnabled) {
368
- this.closePopups(true);
358
+ this.closePopups();
369
359
  }
370
360
  },
371
361
  },
@@ -400,7 +390,15 @@ export default {
400
390
  )
401
391
  return;
402
392
 
403
- this.closePopups();
393
+ if (
394
+ event.target.getParent() &&
395
+ event.target.getParent().className === "Transformer"
396
+ ) {
397
+ // if we are editing a box then close popups
398
+ this.closePopups();
399
+
400
+ return;
401
+ }
404
402
 
405
403
  // check if element and delegate to it
406
404
  if (
@@ -410,9 +408,7 @@ export default {
410
408
  event.target.name() === "multiAnnBoxTransformer" ||
411
409
  event.target.name() === "multiAnnButton" ||
412
410
  event.target.name() === "boxSelection" ||
413
- event.target.name() === "boxTransformer" ||
414
- (event.target.getParent() &&
415
- event.target.getParent().className === "Transformer")
411
+ event.target.name() === "boxTransformer"
416
412
  ) {
417
413
  return;
418
414
  }
@@ -458,7 +454,32 @@ export default {
458
454
 
459
455
  handleFocusedAnnotation(annotation) {
460
456
  this.$store.dispatch("document/setAnnotationId", annotation.id);
461
- this.closePopups(true);
457
+ this.closePopups();
458
+ },
459
+
460
+ handleCreateAnnotationsFromSelection(entities) {
461
+ if (
462
+ this.categorizeModalIsActive ||
463
+ this.publicView ||
464
+ this.isDocumentReviewed
465
+ )
466
+ return;
467
+ this.newAnnotation = [];
468
+ // this.endSelection();
469
+
470
+ const normalizedEntities = this.scaledEntities(entities, this.page);
471
+ if (normalizedEntities) {
472
+ this.newAnnotation.push(...normalizedEntities);
473
+ }
474
+
475
+ if (this.newAnnotation.length > 0) {
476
+ this.$store.dispatch(
477
+ "selection/setSelectedEntities",
478
+ this.newAnnotation
479
+ );
480
+ } else {
481
+ this.$store.dispatch("selection/setSelectedEntities", null);
482
+ }
462
483
  },
463
484
 
464
485
  handleClickedEntity(entity) {
@@ -650,10 +671,8 @@ export default {
650
671
  y: rect.y,
651
672
  };
652
673
  },
653
- closePopups(closeNewAnnotaton) {
654
- if (closeNewAnnotaton) {
655
- this.newAnnotation = [];
656
- }
674
+ closePopups() {
675
+ this.newAnnotation = [];
657
676
  },
658
677
  },
659
678
  };
@@ -167,30 +167,47 @@ export default {
167
167
  "labelsFilteredForAnnotationCreation",
168
168
  "isNegative",
169
169
  ]),
170
- ...mapState("selection", ["spanSelection"]),
170
+ ...mapState("selection", ["spanSelection", "selection"]),
171
171
  top() {
172
- const top = this.newAnnotation[0].scaled.y - heightOfPopup; // subtract the height of the popup plus some margin
172
+ if (this.selection && this.selection.end) {
173
+ const top = this.selection.end.y + margin;
174
+ //check if the popup will not go off the container on the top
175
+ return top + heightOfPopup < this.containerHeight
176
+ ? top
177
+ : this.selection.end.y - heightOfPopup;
178
+ } else {
179
+ const top = this.newAnnotation[0].scaled.y - heightOfPopup; // subtract the height of the popup plus some margin
173
180
 
174
- //check if the popup will not go off the container on the top
175
- return this.newAnnotation[0].scaled.y > heightOfPopup
176
- ? top
177
- : this.newAnnotation[0].scaled.y +
178
- this.newAnnotation[0].scaled.height +
179
- margin;
181
+ //check if the popup will not go off the container on the top
182
+ return this.newAnnotation[0].scaled.y > heightOfPopup
183
+ ? top
184
+ : this.newAnnotation[0].scaled.y +
185
+ this.newAnnotation[0].scaled.height +
186
+ margin;
187
+ }
180
188
  },
181
189
  left() {
182
- const left =
183
- this.newAnnotation[0].scaled.x +
184
- this.newAnnotation[0].scaled.width / 2 -
185
- widthOfPopup / 2; // add the entity half width to be centered and then subtract half the width of the popup
186
-
187
- //check if the popup will not go off the container
188
- if (left + widthOfPopup > this.containerWidth) {
189
- // on the right side
190
- return this.containerWidth - widthOfPopup;
190
+ if (this.selection && this.selection.start && this.selection.end) {
191
+ const left = this.selection.start.x;
192
+ //check if the popup will not go off the container on the right
193
+ return left + widthOfPopup < this.containerWidth
194
+ ? left
195
+ : this.containerWidth - widthOfPopup;
196
+ return this.selection.start.x;
191
197
  } else {
192
- // on the left side
193
- return left > 0 ? left : 0;
198
+ const left =
199
+ this.newAnnotation[0].scaled.x +
200
+ this.newAnnotation[0].scaled.width / 2 -
201
+ widthOfPopup / 2; // add the entity half width to be centered and then subtract half the width of the popup
202
+
203
+ //check if the popup will not go off the container
204
+ if (left + widthOfPopup > this.containerWidth) {
205
+ // on the right side
206
+ return this.containerWidth - widthOfPopup;
207
+ } else {
208
+ // on the left side
209
+ return left > 0 ? left : 0;
210
+ }
194
211
  }
195
212
  },
196
213
  textFromEntities() {
@@ -227,6 +244,7 @@ export default {
227
244
  methods: {
228
245
  close() {
229
246
  this.$store.dispatch("selection/setSelectedEntities", null);
247
+ this.$store.dispatch("selection/endSelection");
230
248
  this.$emit("close");
231
249
  },
232
250
  save() {
@@ -10,17 +10,26 @@
10
10
  <b-skeleton width="15px" height="22px" :rounded="false" />
11
11
  </ServerImage>
12
12
  </div>
13
- <span class="file-name-section">
14
- <span
15
- :class="['document-name', isEditable && 'is-editable']"
16
- :contenteditable="isEditable"
17
- @input="handleInput"
18
- @paste="handlePaste"
19
- @keydown.enter="handleSave"
20
- @blur="handleSave"
21
- >{{ textContent }}</span
22
- >
23
- </span>
13
+ <b-tooltip
14
+ :label="fullText"
15
+ multilined
16
+ :active="isFileNameBiggerThanMaxSize && !isEditable"
17
+ size="is-large"
18
+ position="is-bottom"
19
+ >
20
+ <span class="file-name-section">
21
+ <span
22
+ :class="['document-name', isEditable && 'is-editable']"
23
+ :contenteditable="isEditable"
24
+ @input="handleInput"
25
+ @paste="handlePaste"
26
+ @keydown.enter="handleSave"
27
+ @blur="handleSave"
28
+ >{{ textContent }}</span
29
+ >
30
+ </span>
31
+ </b-tooltip>
32
+
24
33
  <div
25
34
  v-if="
26
35
  !publicView &&
@@ -84,6 +93,7 @@ export default {
84
93
  },
85
94
  data() {
86
95
  return {
96
+ maxFilenameChars: 26,
87
97
  isEditable: false,
88
98
  showEditBtn: true,
89
99
  showSaveBtn: false,
@@ -117,6 +127,20 @@ export default {
117
127
  return this.shortFilenameIfNeeded(this.dataFileName);
118
128
  }
119
129
  },
130
+ fullText() {
131
+ if (this.fileName) {
132
+ return this.fileName;
133
+ } else {
134
+ return this.dataFileName;
135
+ }
136
+ },
137
+ isFileNameBiggerThanMaxSize() {
138
+ if (this.fileName) {
139
+ return this.fileName.length >= this.maxFilenameChars;
140
+ } else {
141
+ return this.dataFileName.length >= this.maxFilenameChars;
142
+ }
143
+ },
120
144
  },
121
145
  updated() {
122
146
  const contentEditable = document.querySelector(".document-name");
@@ -137,15 +161,14 @@ export default {
137
161
  },
138
162
  methods: {
139
163
  shortFilenameIfNeeded(filename) {
140
- if (
141
- filename &&
142
- (filename.length >= 70 ||
143
- (filename.length >= 25 && !this.optimalResolution))
144
- ) {
164
+ if (filename && filename.length >= this.maxFilenameChars) {
145
165
  return (
146
- filename.substr(0, 20) +
166
+ filename.substr(0, this.maxFilenameChars / 2) +
147
167
  "..." +
148
- filename.substr(filename.length - 10, filename.length)
168
+ filename.substr(
169
+ filename.length - this.maxFilenameChars / 2,
170
+ filename.length
171
+ )
149
172
  );
150
173
  }
151
174
  return filename;