@konfuzio/document-validation-ui 0.1.32 → 0.1.34
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/dist/css/app.css +1 -1
- package/dist/index.html +1 -1
- package/dist/js/app.js +1 -1
- package/dist/js/app.js.map +1 -1
- package/package.json +1 -1
- package/src/assets/scss/document_annotations.scss +2 -3
- package/src/assets/scss/document_name.scss +4 -1
- package/src/assets/scss/document_top_bar.scss +0 -1
- package/src/components/DocumentAnnotations/AnnotationActionButtons.vue +6 -4
- package/src/components/DocumentPage/BoxSelection.vue +45 -16
- package/src/components/DocumentPage/DocumentPage.vue +63 -44
- package/src/components/DocumentPage/NewAnnotation.vue +37 -19
- package/src/components/DocumentTopBar/DocumentName.vue +41 -18
- package/src/components/DocumentTopBar/DocumentNameEditModal.vue +186 -0
- package/src/components/DocumentTopBar/DocumentTopBar.vue +4 -10
- package/src/constants.js +7 -1
- package/src/store/display.js +25 -0
- package/src/store/document.js +1 -13
- package/src/store/project.js +1 -1
- package/src/store/selection.js +13 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<section class="document-name-edit-modal">
|
|
3
|
+
<b-modal
|
|
4
|
+
ref="modal"
|
|
5
|
+
v-model="show"
|
|
6
|
+
:can-cancel="['x', 'outside']"
|
|
7
|
+
class="modal-absolute modal-400 modal-no-footer model-overflow-visible"
|
|
8
|
+
:on-cancel="close"
|
|
9
|
+
>
|
|
10
|
+
<section class="modal-card-body">
|
|
11
|
+
<div class="content">
|
|
12
|
+
<h3>
|
|
13
|
+
{{
|
|
14
|
+
isMultipleAnnotations
|
|
15
|
+
? $t("new_multi_ann_title")
|
|
16
|
+
: $t("new_ann_set_title")
|
|
17
|
+
}}
|
|
18
|
+
</h3>
|
|
19
|
+
<p>
|
|
20
|
+
{{
|
|
21
|
+
isMultipleAnnotations
|
|
22
|
+
? $t("new_multi_ann_description")
|
|
23
|
+
: $t("new_ann_set_description")
|
|
24
|
+
}}
|
|
25
|
+
</p>
|
|
26
|
+
<b-tooltip
|
|
27
|
+
multilined
|
|
28
|
+
:active="labelSets.length === 0"
|
|
29
|
+
size="is-large"
|
|
30
|
+
position="is-bottom"
|
|
31
|
+
class="bottom-aligned"
|
|
32
|
+
:close-delay="5000"
|
|
33
|
+
>
|
|
34
|
+
<template #content>
|
|
35
|
+
<div ref="tooltipContent"></div>
|
|
36
|
+
</template>
|
|
37
|
+
<b-dropdown
|
|
38
|
+
v-model="selectedLabelSet"
|
|
39
|
+
aria-role="list"
|
|
40
|
+
:disabled="labelSets.length === 0"
|
|
41
|
+
:class="[
|
|
42
|
+
'label-set-dropdown',
|
|
43
|
+
labelSets.length === 0 && 'dropdown-disabled',
|
|
44
|
+
]"
|
|
45
|
+
scrollable
|
|
46
|
+
>
|
|
47
|
+
<template #trigger>
|
|
48
|
+
<div>
|
|
49
|
+
<div>
|
|
50
|
+
<span v-if="selectedLabelSet">{{
|
|
51
|
+
selectedLabelSet.name
|
|
52
|
+
}}</span>
|
|
53
|
+
<span v-else>{{ $t("select_label_set") }}</span>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</template>
|
|
57
|
+
<b-dropdown-item
|
|
58
|
+
v-for="labelSetItem in labelSets"
|
|
59
|
+
:key="labelSetItem.id"
|
|
60
|
+
aria-role="listitem"
|
|
61
|
+
:value="labelSetItem"
|
|
62
|
+
@click="setSelectedLabelSet(labelSetItem)"
|
|
63
|
+
>
|
|
64
|
+
<span>{{ labelSetItem.name }}</span>
|
|
65
|
+
</b-dropdown-item>
|
|
66
|
+
</b-dropdown>
|
|
67
|
+
</b-tooltip>
|
|
68
|
+
<div v-if="selectedLabelSet" class="labels-list">
|
|
69
|
+
<div v-if="isMultipleAnnotations" class="labels-select">
|
|
70
|
+
<div v-for="label in labels" :key="label.id">
|
|
71
|
+
<b-checkbox v-model="label.selected">{{
|
|
72
|
+
label.name
|
|
73
|
+
}}</b-checkbox>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
<span v-for="(label, index) in labels" v-else :key="label.id">{{
|
|
77
|
+
`${label.name}${index + 1 !== labels.length ? ", " : ""}`
|
|
78
|
+
}}</span>
|
|
79
|
+
</div>
|
|
80
|
+
<b-button
|
|
81
|
+
class="submit-ann-set primary-button"
|
|
82
|
+
type="is-primary"
|
|
83
|
+
:disabled="!selectedLabelSet"
|
|
84
|
+
@click="submit"
|
|
85
|
+
>
|
|
86
|
+
{{ $t("continue") }}
|
|
87
|
+
</b-button>
|
|
88
|
+
<p
|
|
89
|
+
v-if="!isMultipleAnnotations && selectedLabelSet"
|
|
90
|
+
class="next-step-description"
|
|
91
|
+
>
|
|
92
|
+
{{ $t("new_ann_set_hint") }}
|
|
93
|
+
</p>
|
|
94
|
+
</div>
|
|
95
|
+
</section>
|
|
96
|
+
</b-modal>
|
|
97
|
+
</section>
|
|
98
|
+
</template>
|
|
99
|
+
|
|
100
|
+
<script>
|
|
101
|
+
/**
|
|
102
|
+
* This component shows a modal to choose a label set from the project
|
|
103
|
+
*/
|
|
104
|
+
|
|
105
|
+
import { mapGetters, mapState } from "vuex";
|
|
106
|
+
|
|
107
|
+
export default {
|
|
108
|
+
name: "CreateAnnotationSetModal",
|
|
109
|
+
props: {
|
|
110
|
+
isMultipleAnnotations: {
|
|
111
|
+
type: Boolean,
|
|
112
|
+
default: false,
|
|
113
|
+
required: false,
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
data() {
|
|
117
|
+
return {
|
|
118
|
+
selectedLabelSet: null,
|
|
119
|
+
labelSets: [],
|
|
120
|
+
show: true,
|
|
121
|
+
labels: [],
|
|
122
|
+
};
|
|
123
|
+
},
|
|
124
|
+
computed: {
|
|
125
|
+
...mapState("document", ["annotationSets"]),
|
|
126
|
+
...mapGetters("project", ["labelSetsFilteredForAnnotationSetCreation"]),
|
|
127
|
+
},
|
|
128
|
+
watch: {
|
|
129
|
+
labelSets(newValue) {
|
|
130
|
+
if (newValue.length === 0) {
|
|
131
|
+
this.setTooltipText();
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
mounted() {
|
|
136
|
+
this.$store.dispatch("project/fetchLabelSets").then((data) => {
|
|
137
|
+
this.labelSets = this.labelSetsFilteredForAnnotationSetCreation(
|
|
138
|
+
data,
|
|
139
|
+
this.annotationSets
|
|
140
|
+
);
|
|
141
|
+
});
|
|
142
|
+
},
|
|
143
|
+
methods: {
|
|
144
|
+
submit() {
|
|
145
|
+
// filter labels that were selected (by default all are selected so no issue if the feature is disabled)
|
|
146
|
+
const labelsFiltered = this.labels.filter((label) => label.selected);
|
|
147
|
+
this.selectedLabelSet.labels = this.selectedLabelSet.labels.filter(
|
|
148
|
+
(label) => {
|
|
149
|
+
return labelsFiltered.find((filtered) => filtered.id === label.id);
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
this.$emit("finish", this.selectedLabelSet);
|
|
154
|
+
this.close();
|
|
155
|
+
},
|
|
156
|
+
setSelectedLabelSet(labelSet) {
|
|
157
|
+
this.createLabelsList(labelSet.labels);
|
|
158
|
+
this.selectedLabelSet = labelSet;
|
|
159
|
+
},
|
|
160
|
+
close() {
|
|
161
|
+
this.$store.dispatch("display/showChooseLabelSetModal", null);
|
|
162
|
+
this.$emit("close");
|
|
163
|
+
},
|
|
164
|
+
createLabelsList(labels) {
|
|
165
|
+
this.labels = labels.map((label) => {
|
|
166
|
+
return {
|
|
167
|
+
...label,
|
|
168
|
+
selected: true,
|
|
169
|
+
};
|
|
170
|
+
});
|
|
171
|
+
},
|
|
172
|
+
setTooltipText() {
|
|
173
|
+
// Text set from innerHTML vs 'label' due to html tag in locales file string
|
|
174
|
+
this.$refs.tooltipContent.innerHTML = this.$t(
|
|
175
|
+
"no_multi_ann_labelset_model"
|
|
176
|
+
);
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
</script>
|
|
181
|
+
|
|
182
|
+
<style
|
|
183
|
+
scoped
|
|
184
|
+
lang="scss"
|
|
185
|
+
src="../../assets/scss/choose_label_set_modal.scss"
|
|
186
|
+
></style>
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
]"
|
|
18
18
|
>
|
|
19
19
|
<div
|
|
20
|
-
|
|
20
|
+
:style="`visibility: ${previousDocument ? 'visible' : 'hidden'}`"
|
|
21
21
|
class="left-arrow navigation-arrow"
|
|
22
22
|
type="button"
|
|
23
23
|
@click="navigateToDocument(previousDocument)"
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
<DocumentName :data-file-name="selectedDocument.data_file_name" />
|
|
29
29
|
|
|
30
30
|
<div
|
|
31
|
-
v-if="nextDocument"
|
|
32
31
|
class="right-arrow navigation-arrow"
|
|
32
|
+
:style="`visibility: ${nextDocument ? 'visible' : 'hidden'}`"
|
|
33
33
|
type="button"
|
|
34
34
|
@click="navigateToDocument(nextDocument)"
|
|
35
35
|
>
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
</div>
|
|
85
85
|
</div>
|
|
86
86
|
<div v-else class="loading-top-bar">
|
|
87
|
-
<b-skeleton position="is-centered" width="
|
|
87
|
+
<b-skeleton position="is-centered" width="20%" height="60%" />
|
|
88
88
|
</div>
|
|
89
89
|
</div>
|
|
90
90
|
</template>
|
|
@@ -160,13 +160,7 @@ export default {
|
|
|
160
160
|
this.setComponentWidth(this.$refs.documentTopBar.offsetWidth);
|
|
161
161
|
},
|
|
162
162
|
getPreviousAndNextDocuments() {
|
|
163
|
-
|
|
164
|
-
const filteredDocuments =
|
|
165
|
-
this.documentsInProject; /*this.documentsInProject.filter(
|
|
166
|
-
(document) =>
|
|
167
|
-
(this.isDocumentReadyToBeReviewed(document)) ||
|
|
168
|
-
this.waitingForSplittingConfirmation(document)
|
|
169
|
-
);*/
|
|
163
|
+
const filteredDocuments = this.documentsInProject;
|
|
170
164
|
|
|
171
165
|
if (!filteredDocuments) return;
|
|
172
166
|
|
package/src/constants.js
CHANGED
|
@@ -2,5 +2,11 @@ export const PIXEL_RATIO = window.devicePixelRatio || 1;
|
|
|
2
2
|
export const VIEWPORT_RATIO = 0.98;
|
|
3
3
|
export const MINIMUM_APP_WIDTH = 600;
|
|
4
4
|
export const MINIMUM_OPTIMIZED_APP_WIDTH = 950;
|
|
5
|
-
export const TEXT_BREAKPOINT_WIDTH =
|
|
5
|
+
export const TEXT_BREAKPOINT_WIDTH = (locale) => {
|
|
6
|
+
if (locale === "en") {
|
|
7
|
+
return 1350;
|
|
8
|
+
} else {
|
|
9
|
+
return 1800;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
6
12
|
export const MULTI_ANN_TABLE_FEATURE = false;
|
package/src/store/display.js
CHANGED
|
@@ -87,6 +87,31 @@ const getters = {
|
|
|
87
87
|
return currentResult;
|
|
88
88
|
},
|
|
89
89
|
|
|
90
|
+
/**
|
|
91
|
+
* We take the entities from the backend and resize them according
|
|
92
|
+
* to the `scale` (zoom), the `imageScale` (proportion between the original
|
|
93
|
+
* document and the served image) and `PIXEL_RATIO` (in case of retina displays).
|
|
94
|
+
* We also change the original bbox format to something that can be used with CSS.
|
|
95
|
+
* The original is stored inside the `original` property, since it can be reused
|
|
96
|
+
* when we're sending the entity to the backend for selection or saving.
|
|
97
|
+
*/
|
|
98
|
+
scaledEntities: (state, getters) => (entities, page) => {
|
|
99
|
+
// entities are either not loaded yet or empty
|
|
100
|
+
if (!entities || entities.length === 0) {
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return entities.map((entity) => {
|
|
105
|
+
const box = getters.bboxToRect(page, entity);
|
|
106
|
+
return {
|
|
107
|
+
original: entity,
|
|
108
|
+
scaled: {
|
|
109
|
+
...box,
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
|
|
90
115
|
/**
|
|
91
116
|
* The proportion between the original size of the page and the
|
|
92
117
|
* image rendering.
|
package/src/store/document.js
CHANGED
|
@@ -55,19 +55,6 @@ const state = {
|
|
|
55
55
|
},
|
|
56
56
|
};
|
|
57
57
|
const getters = {
|
|
58
|
-
/**
|
|
59
|
-
* Get entities inside a box
|
|
60
|
-
*/
|
|
61
|
-
entitiesOnSelection: (state) => (box, page) => {
|
|
62
|
-
return page.entities.filter(
|
|
63
|
-
(entity) =>
|
|
64
|
-
box.x0 <= entity.x0 &&
|
|
65
|
-
box.x1 >= entity.x1 &&
|
|
66
|
-
box.y0 <= entity.y0 &&
|
|
67
|
-
box.y1 >= entity.y1
|
|
68
|
-
);
|
|
69
|
-
},
|
|
70
|
-
|
|
71
58
|
/**
|
|
72
59
|
* Number of pages. If the pages array doesn't exist yet, return 0.
|
|
73
60
|
*/
|
|
@@ -1345,6 +1332,7 @@ const actions = {
|
|
|
1345
1332
|
if (state.splittingSuggestions) {
|
|
1346
1333
|
commit("SET_SPLITTING_SUGGESTIONS", null);
|
|
1347
1334
|
}
|
|
1335
|
+
commit("SET_RECALCULATING_ANNOTATIONS", false);
|
|
1348
1336
|
|
|
1349
1337
|
if (getURLQueryParam("document") || getURLPath("d")) {
|
|
1350
1338
|
navigateToNewDocumentURL(state.selectedDocument.id, newDocumentId);
|
package/src/store/project.js
CHANGED
|
@@ -93,7 +93,7 @@ const actions = {
|
|
|
93
93
|
|
|
94
94
|
fetchDocumentList: ({ commit, state }, parameters) => {
|
|
95
95
|
return HTTP.get(
|
|
96
|
-
`documents/?project=${state.projectId}&
|
|
96
|
+
`documents/?project=${state.projectId}&limit=100&${parameters}`
|
|
97
97
|
)
|
|
98
98
|
.then((response) => {
|
|
99
99
|
if (response.data.results) {
|
package/src/store/selection.js
CHANGED
|
@@ -38,6 +38,19 @@ const getters = {
|
|
|
38
38
|
}
|
|
39
39
|
return null;
|
|
40
40
|
},
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get entities inside a box
|
|
44
|
+
*/
|
|
45
|
+
entitiesOnSelection: (state) => (box, page) => {
|
|
46
|
+
return page.entities.filter(
|
|
47
|
+
(entity) =>
|
|
48
|
+
box.x0 <= entity.x0 &&
|
|
49
|
+
box.x1 >= entity.x1 &&
|
|
50
|
+
box.y0 <= entity.y0 &&
|
|
51
|
+
box.y1 >= entity.y1
|
|
52
|
+
);
|
|
53
|
+
},
|
|
41
54
|
};
|
|
42
55
|
|
|
43
56
|
const actions = {
|