@konfuzio/document-validation-ui 0.1.13-dev.2 → 0.1.13-dev.4
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/dist/js/chunk-vendors.js +1 -1
- package/dist/js/chunk-vendors.js.map +1 -1
- package/package.json +1 -1
- package/src/api.js +13 -9
- package/src/assets/images/ServerImage.vue +1 -1
- package/src/assets/scss/annotation_details.scss +5 -2
- package/src/assets/scss/document_thumbnails.scss +1 -1
- package/src/assets/scss/document_toolbar.scss +21 -7
- package/src/assets/scss/theme.scss +9 -0
- package/src/components/App.cy.js +1 -1
- package/src/components/App.vue +1 -1
- package/src/components/DocumentAnnotations/AnnotationDetails.vue +5 -3
- package/src/components/DocumentPage/DocumentPage.vue +1 -1
- package/src/components/DocumentPage/DocumentToolbar.vue +56 -0
- package/src/components/DocumentThumbnails/DocumentThumbnails.cy.js +64 -0
- package/src/components/DocumentThumbnails/DocumentThumbnails.vue +2 -2
- package/src/icons.js +3 -1
- package/src/locales/de.json +4 -1
- package/src/locales/en.json +4 -1
- package/src/locales/es.json +4 -1
- package/src/store/document.js +4 -2
- package/src/store/project.js +1 -1
package/package.json
CHANGED
package/src/api.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
2
|
import { cacheAdapterEnhancer } from "axios-extensions";
|
|
3
3
|
|
|
4
|
-
let HTTP,
|
|
4
|
+
let HTTP, FILE_REQUEST, authToken, appLocale;
|
|
5
5
|
const DEFAULT_URL = "https://app.konfuzio.com";
|
|
6
6
|
|
|
7
7
|
axios.defaults.xsrfCookieName = "csrftoken";
|
|
@@ -11,7 +11,7 @@ HTTP = axios.create({
|
|
|
11
11
|
baseURL: process.env.VUE_APP_API_URL || `${DEFAULT_URL}/api/v3/`,
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
FILE_REQUEST = axios.create({
|
|
15
15
|
baseURL: process.env.VUE_APP_DOCUMENT_IMAGES_URL || `${DEFAULT_URL}`,
|
|
16
16
|
responseType: "blob",
|
|
17
17
|
adapter: cacheAdapterEnhancer(axios.defaults.adapter),
|
|
@@ -25,8 +25,8 @@ const setApiUrl = (url) => {
|
|
|
25
25
|
HTTP.defaults.baseURL = url;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
const
|
|
29
|
-
|
|
28
|
+
const setFileUrl = (url) => {
|
|
29
|
+
FILE_REQUEST.defaults.baseURL = url;
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
const setLocale = (locale) => {
|
|
@@ -45,22 +45,25 @@ HTTP.interceptors.request.use(getInterceptorConfig, (error) => {
|
|
|
45
45
|
return Promise.reject(error);
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
FILE_REQUEST.interceptors.request.use(getInterceptorConfig, (error) => {
|
|
49
49
|
return Promise.reject(error);
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
-
const
|
|
52
|
+
const makeFileRequest = (fileUrl) => {
|
|
53
53
|
return new Promise((resolve, reject) => {
|
|
54
54
|
if (process.env.NODE_ENV === "test") {
|
|
55
55
|
reject("Running unit tests!");
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
|
-
|
|
58
|
+
FILE_REQUEST.get(fileUrl)
|
|
59
59
|
.then((response) => {
|
|
60
60
|
return response.data;
|
|
61
61
|
})
|
|
62
62
|
.then((myBlob) => {
|
|
63
63
|
resolve(myBlob);
|
|
64
|
+
})
|
|
65
|
+
.catch((error) => {
|
|
66
|
+
reject(error);
|
|
64
67
|
});
|
|
65
68
|
});
|
|
66
69
|
};
|
|
@@ -68,8 +71,9 @@ const makeImageRequest = (imageURL) => {
|
|
|
68
71
|
export default {
|
|
69
72
|
HTTP,
|
|
70
73
|
setApiUrl,
|
|
71
|
-
|
|
72
|
-
|
|
74
|
+
setFileUrl,
|
|
75
|
+
makeFileRequest,
|
|
73
76
|
setAuthToken,
|
|
74
77
|
setLocale,
|
|
78
|
+
FILE_REQUEST,
|
|
75
79
|
};
|
|
@@ -66,8 +66,11 @@
|
|
|
66
66
|
display: flex;
|
|
67
67
|
flex-direction: row;
|
|
68
68
|
justify-content: space-between;
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
|
|
70
|
+
&:not(.tooltip-in-public-view) {
|
|
71
|
+
border-bottom: 1px solid $low-opacity-white;
|
|
72
|
+
padding-bottom: 8px;
|
|
73
|
+
}
|
|
71
74
|
|
|
72
75
|
.value {
|
|
73
76
|
color: $green;
|
|
@@ -24,6 +24,16 @@
|
|
|
24
24
|
display: none;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
.edit-mode-disabled,
|
|
28
|
+
.zoom-disabled {
|
|
29
|
+
opacity: 30%;
|
|
30
|
+
|
|
31
|
+
&:hover {
|
|
32
|
+
cursor: not-allowed !important;
|
|
33
|
+
background: inherit;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
27
37
|
.toolbar-divider {
|
|
28
38
|
width: 1px;
|
|
29
39
|
background-color: $grey-detail;
|
|
@@ -72,7 +82,6 @@
|
|
|
72
82
|
padding: 7px;
|
|
73
83
|
margin-right: 20px;
|
|
74
84
|
}
|
|
75
|
-
|
|
76
85
|
.icon {
|
|
77
86
|
width: 32px;
|
|
78
87
|
height: 32px;
|
|
@@ -83,13 +92,18 @@
|
|
|
83
92
|
background: $low-opacity-white;
|
|
84
93
|
border-radius: 4px;
|
|
85
94
|
}
|
|
86
|
-
|
|
87
|
-
|
|
95
|
+
}
|
|
96
|
+
}
|
|
88
97
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
98
|
+
.download-file {
|
|
99
|
+
color: $toolbar-elements;
|
|
100
|
+
|
|
101
|
+
.is-active {
|
|
102
|
+
background: $low-opacity-white;
|
|
103
|
+
border-radius: 4px;
|
|
104
|
+
|
|
105
|
+
.icon:hover {
|
|
106
|
+
background: none;
|
|
93
107
|
}
|
|
94
108
|
}
|
|
95
109
|
}
|
package/src/components/App.cy.js
CHANGED
package/src/components/App.vue
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
:animated="false"
|
|
4
4
|
:position="fromTable ? 'is-top' : 'is-bottom'"
|
|
5
5
|
:class="[!fromTable && 'left-aligned', 'annotation-details']"
|
|
6
|
-
:active="!publicView"
|
|
7
6
|
>
|
|
8
7
|
<div :class="['label-icon', fromTable && 'is-small']">
|
|
9
8
|
<div v-if="(created(annotation) || edited(annotation)) && !publicView">
|
|
@@ -68,7 +67,10 @@
|
|
|
68
67
|
<div v-if="description" class="label-description">
|
|
69
68
|
<span>{{ description }}</span>
|
|
70
69
|
</div>
|
|
71
|
-
<div
|
|
70
|
+
<div
|
|
71
|
+
v-if="confidence(annotation)"
|
|
72
|
+
:class="['confidence', publicView && 'tooltip-in-public-view']"
|
|
73
|
+
>
|
|
72
74
|
<span>{{ $t("confidence") }}</span
|
|
73
75
|
><span
|
|
74
76
|
:class="[
|
|
@@ -82,7 +84,7 @@
|
|
|
82
84
|
>{{ Math.floor(confidence(annotation) * 100) / 100 }}</span
|
|
83
85
|
>
|
|
84
86
|
</div>
|
|
85
|
-
<div class="revision">
|
|
87
|
+
<div v-if="!publicView" class="revision">
|
|
86
88
|
<div class="detail-icons">
|
|
87
89
|
<div v-if="created(annotation) || edited(annotation)">
|
|
88
90
|
<div
|
|
@@ -26,6 +26,26 @@
|
|
|
26
26
|
v-if="!editMode && !publicView && !isDocumentReviewed"
|
|
27
27
|
class="toolbar-divider"
|
|
28
28
|
/>
|
|
29
|
+
|
|
30
|
+
<div v-if="!publicView" class="download-file icons">
|
|
31
|
+
<b-dropdown aria-role="list" position="is-top-right">
|
|
32
|
+
<template #trigger>
|
|
33
|
+
<b-icon icon="download" size="small" class="download-file" />
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<b-dropdown-item aria-role="listitem" @click="handleDownloadFile()">{{
|
|
37
|
+
$t("original_file")
|
|
38
|
+
}}</b-dropdown-item>
|
|
39
|
+
<b-dropdown-item
|
|
40
|
+
aria-role="listitem"
|
|
41
|
+
@click="handleDownloadFile('ocr')"
|
|
42
|
+
>{{ $t("pdf_file") }}</b-dropdown-item
|
|
43
|
+
>
|
|
44
|
+
</b-dropdown>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<div v-if="!publicView" class="toolbar-divider" />
|
|
48
|
+
|
|
29
49
|
<div class="icons icons-right">
|
|
30
50
|
<div
|
|
31
51
|
:class="[
|
|
@@ -63,6 +83,7 @@ import FitZoomIcon from "../../assets/images/FitZoomIcon";
|
|
|
63
83
|
import PlusIcon from "../../assets/images/PlusIcon";
|
|
64
84
|
import MinusIcon from "../../assets/images/MinusIcon";
|
|
65
85
|
import EditDocIcon from "../../assets/images/EditDocIcon";
|
|
86
|
+
import api from "../../api";
|
|
66
87
|
|
|
67
88
|
export default {
|
|
68
89
|
name: "DocumentToolbar",
|
|
@@ -158,6 +179,41 @@ export default {
|
|
|
158
179
|
this.$store.dispatch("display/updateScale", { scale });
|
|
159
180
|
});
|
|
160
181
|
},
|
|
182
|
+
handleDownloadFile(fileType) {
|
|
183
|
+
let fileUrl;
|
|
184
|
+
// get the file name without the extension
|
|
185
|
+
let fileName = this.getFileName(this.selectedDocument.data_file_name);
|
|
186
|
+
|
|
187
|
+
if (fileType === "ocr") {
|
|
188
|
+
fileUrl = this.selectedDocument.file_url;
|
|
189
|
+
fileName = `${fileName}_${fileType}`;
|
|
190
|
+
} else {
|
|
191
|
+
fileUrl = `/doc/show-original/${this.selectedDocument.id}/`;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Automatically download original or ocr files
|
|
195
|
+
return api
|
|
196
|
+
.makeFileRequest(fileUrl)
|
|
197
|
+
.then((myBlob) => {
|
|
198
|
+
const url = URL.createObjectURL(myBlob);
|
|
199
|
+
const link = document.createElement("a");
|
|
200
|
+
link.href = url;
|
|
201
|
+
link.setAttribute("download", fileName);
|
|
202
|
+
link.click();
|
|
203
|
+
URL.revokeObjectURL(link.href);
|
|
204
|
+
})
|
|
205
|
+
.catch((error) => {
|
|
206
|
+
this.$store.dispatch("document/createErrorMessage", {
|
|
207
|
+
error,
|
|
208
|
+
serverErrorMessage: this.$t("server_error"),
|
|
209
|
+
defaultErrorMessage: this.$t("error_downloading_file"),
|
|
210
|
+
});
|
|
211
|
+
console.log(error);
|
|
212
|
+
});
|
|
213
|
+
},
|
|
214
|
+
getFileName(fileName) {
|
|
215
|
+
return fileName.split(".").slice(0, -1).join(".");
|
|
216
|
+
},
|
|
161
217
|
cancelAnnotationEditMode() {
|
|
162
218
|
this.$store.dispatch("document/resetEditAnnotation");
|
|
163
219
|
this.$store.dispatch("selection/disableSelection");
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import DocumentThumbnails from "./DocumentThumbnails.vue";
|
|
2
|
+
|
|
3
|
+
describe("Document Thumbnails", () => {
|
|
4
|
+
beforeEach(() => {
|
|
5
|
+
cy.fetchDocument();
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it("shows thumbnails for all document pages", () => {
|
|
9
|
+
cy.mount(DocumentThumbnails);
|
|
10
|
+
cy.get("#document-pages")
|
|
11
|
+
.find(".document-thumbnail")
|
|
12
|
+
.then((elements) => {
|
|
13
|
+
cy.storeState("document", "selectedDocument")
|
|
14
|
+
.its("pages")
|
|
15
|
+
.its("length")
|
|
16
|
+
.should("equal", elements.length);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("loads thumbnail pictures that are shown on screen", () => {
|
|
21
|
+
cy.intercept("GET", "**/page/show-thumbnail/**").as("getThumbnail");
|
|
22
|
+
cy.mount(DocumentThumbnails);
|
|
23
|
+
|
|
24
|
+
cy.get("#document-pages")
|
|
25
|
+
.find(".document-thumbnail")
|
|
26
|
+
.then((elements) => {
|
|
27
|
+
cy.get("@getThumbnail.all")
|
|
28
|
+
.its("length")
|
|
29
|
+
.should("equal", elements.length);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("displays page number correctly", () => {
|
|
34
|
+
cy.mount(DocumentThumbnails);
|
|
35
|
+
cy.get("#document-pages")
|
|
36
|
+
.find(".document-thumbnail")
|
|
37
|
+
.each(($row, index) => {
|
|
38
|
+
cy.wrap($row)
|
|
39
|
+
.find(".number-thumbnail")
|
|
40
|
+
.contains(index + 1);
|
|
41
|
+
cy.wait(1000);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("navigates to every document thumbnail", () => {
|
|
46
|
+
cy.mount(DocumentThumbnails);
|
|
47
|
+
cy.get("#document-pages")
|
|
48
|
+
.find(".document-thumbnail")
|
|
49
|
+
.each(($row, index) => {
|
|
50
|
+
cy.wrap($row).click();
|
|
51
|
+
cy.storeState("display", "currentPage").should("equal", index + 1);
|
|
52
|
+
cy.wait(1000);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("show loading when a document is not set", () => {
|
|
57
|
+
cy.mount(DocumentThumbnails);
|
|
58
|
+
cy.dispatchAction("document", "setSelectedDocument", null);
|
|
59
|
+
cy.get("#document-pages")
|
|
60
|
+
.find(".document-thumbnail-loading")
|
|
61
|
+
.its("length")
|
|
62
|
+
.should("equal", 1);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div id="document-pages" ref="documentThumbnails">
|
|
3
3
|
<div v-if="selectedDocument">
|
|
4
4
|
<div
|
|
5
5
|
v-for="page in selectedDocument.pages"
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
</div>
|
|
33
33
|
</div>
|
|
34
34
|
</div>
|
|
35
|
-
<div v-else>
|
|
35
|
+
<div v-else class="document-thumbnail-loading">
|
|
36
36
|
<div class="document-thumbnail">
|
|
37
37
|
<div class="image-section">
|
|
38
38
|
<div class="image-container">
|
package/src/icons.js
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
faRepeat,
|
|
18
18
|
faArrowLeft,
|
|
19
19
|
faArrowRight,
|
|
20
|
+
faDownload,
|
|
20
21
|
} from "@fortawesome/free-solid-svg-icons";
|
|
21
22
|
import { FontAwesomeIcon as Icons } from "@fortawesome/vue-fontawesome";
|
|
22
23
|
|
|
@@ -37,7 +38,8 @@ library.add(
|
|
|
37
38
|
faScissors,
|
|
38
39
|
faRepeat,
|
|
39
40
|
faArrowLeft,
|
|
40
|
-
faArrowRight
|
|
41
|
+
faArrowRight,
|
|
42
|
+
faDownload
|
|
41
43
|
);
|
|
42
44
|
|
|
43
45
|
export default Icons;
|
package/src/locales/de.json
CHANGED
|
@@ -132,5 +132,8 @@
|
|
|
132
132
|
"delete_label": "Label löschen",
|
|
133
133
|
"table": "Tabelle",
|
|
134
134
|
"prepare_document": "Dokument vorbereiten",
|
|
135
|
-
"delete_table": "Tabelle löschen"
|
|
135
|
+
"delete_table": "Tabelle löschen",
|
|
136
|
+
"error_downloading_file": "Die Datei konnte nicht heruntergeladen werden.",
|
|
137
|
+
"original_file": "Originaldatei",
|
|
138
|
+
"pdf_file": "PDF Datei"
|
|
136
139
|
}
|
package/src/locales/en.json
CHANGED
|
@@ -132,5 +132,8 @@
|
|
|
132
132
|
"edit_label": "Edit label",
|
|
133
133
|
"delete_label": "Delete label",
|
|
134
134
|
"table": "Table",
|
|
135
|
-
"delete_table": "Delete table"
|
|
135
|
+
"delete_table": "Delete table",
|
|
136
|
+
"error_downloading_file": "The file could not be downloaded.",
|
|
137
|
+
"original_file": "Original file",
|
|
138
|
+
"pdf_file": "PDF file"
|
|
136
139
|
}
|
package/src/locales/es.json
CHANGED
|
@@ -132,5 +132,8 @@
|
|
|
132
132
|
"new_multi_ann_description": "Seleccione un modelo de datos de los existentes, luego deseleccione las etiquetas que no existen en este documento.",
|
|
133
133
|
"new_multi_ann_title": "Crear múltiples anotaciones",
|
|
134
134
|
"prepare_document": "Prepare el documento",
|
|
135
|
-
"delete_table": "Eliminar tabla"
|
|
135
|
+
"delete_table": "Eliminar tabla",
|
|
136
|
+
"error_downloading_file": "El documento no pudo ser descargado.",
|
|
137
|
+
"original_file": "Documento original",
|
|
138
|
+
"pdf_file": "Documento PDF"
|
|
136
139
|
}
|
package/src/store/document.js
CHANGED
|
@@ -17,7 +17,7 @@ const state = {
|
|
|
17
17
|
annotationSets: null,
|
|
18
18
|
annotations: null,
|
|
19
19
|
labels: [],
|
|
20
|
-
documentId:
|
|
20
|
+
documentId: process.env.VUE_APP_DOCUMENT_ID,
|
|
21
21
|
sidebarAnnotationSelected: null,
|
|
22
22
|
documentAnnotationSelected: null,
|
|
23
23
|
selectedDocument: null,
|
|
@@ -1256,7 +1256,9 @@ const mutations = {
|
|
|
1256
1256
|
state.selectedDocument = document;
|
|
1257
1257
|
|
|
1258
1258
|
// this is to handle cache when a document is edited or changed
|
|
1259
|
-
state.selectedDocument
|
|
1259
|
+
if (state.selectedDocument) {
|
|
1260
|
+
state.selectedDocument.downloaded_at = Date.now();
|
|
1261
|
+
}
|
|
1260
1262
|
},
|
|
1261
1263
|
SET_RECALCULATING_ANNOTATIONS: (state, recalculatingAnnotations) => {
|
|
1262
1264
|
state.recalculatingAnnotations = recalculatingAnnotations;
|