@konfuzio/document-validation-ui 0.1.24-dev.0 → 0.1.24-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 (31) hide show
  1. package/dist/css/app.css +1 -1
  2. package/dist/index.html +1 -1
  3. package/dist/js/app.js +1 -1
  4. package/dist/js/app.js.map +1 -1
  5. package/dist/js/chunk-vendors.js +1 -1
  6. package/dist/js/chunk-vendors.js.map +1 -1
  7. package/package.json +1 -1
  8. package/src/assets/scss/document_annotations.scss +5 -1
  9. package/src/assets/scss/document_search_bar.scss +71 -0
  10. package/src/assets/scss/document_toolbar.scss +2 -1
  11. package/src/assets/scss/theme.scss +2 -1
  12. package/src/assets/scss/variables.scss +1 -0
  13. package/src/components/App.vue +16 -0
  14. package/src/components/DocumentAnnotations/AnnotationActionButtons.vue +10 -0
  15. package/src/components/DocumentAnnotations/AnnotationRow.vue +11 -6
  16. package/src/components/DocumentAnnotations/DocumentAnnotations.vue +4 -5
  17. package/src/components/DocumentPage/DocumentPage.cy.js +82 -1
  18. package/src/components/DocumentPage/DocumentPage.vue +41 -1
  19. package/src/components/DocumentPage/DocumentToolbar.cy.js +12 -0
  20. package/src/components/DocumentPage/DocumentToolbar.vue +9 -1
  21. package/src/components/DocumentPage/NewAnnotation.vue +6 -2
  22. package/src/components/DocumentPage/ScrollingDocument.vue +6 -0
  23. package/src/components/DocumentPage/ScrollingPage.vue +26 -4
  24. package/src/components/DocumentPage/SearchBar.vue +130 -0
  25. package/src/components/DocumentTopBar/DocumentName.vue +10 -2
  26. package/src/icons.js +3 -1
  27. package/src/locales/de.json +7 -1
  28. package/src/locales/en.json +8 -1
  29. package/src/locales/es.json +7 -1
  30. package/src/store/display.js +114 -0
  31. package/src/store/document.js +1 -2
@@ -0,0 +1,130 @@
1
+ <template>
2
+ <div id="document-search">
3
+ <div class="search-container">
4
+ <input
5
+ ref="searchInput"
6
+ v-model="search"
7
+ :placeholder="$t('search')"
8
+ class="search-input"
9
+ @keyup.13="focusSearchResult(1)"
10
+ />
11
+ <div v-if="searchLoading" class="search-loading">
12
+ <b-icon icon="spinner" class="fa-spin loading-icon-size spinner" />
13
+ </div>
14
+
15
+ <div
16
+ v-else-if="
17
+ searchResults.length === 0 && search.length >= minSearchLength
18
+ "
19
+ class="search-no-results"
20
+ >
21
+ {{ $t("no_results") }}
22
+ </div>
23
+ <div v-else class="search-navigation">
24
+ <span v-if="searchBelowMinimum" class="search-counters">
25
+ {{ $t("search_below_minimum") }}
26
+ </span>
27
+ <span v-else class="search-counters"
28
+ >{{ currentCounter }}/{{ searchResults.length }}</span
29
+ >
30
+ <b-button
31
+ v-if="!searchBelowMinimum"
32
+ class="is-ghost is-small next-search"
33
+ :disabled="!searchResults.length || searchResults.length <= 1"
34
+ @click="focusSearchResult(1)"
35
+ ><b-icon icon="angle-down" class="is-small"
36
+ /></b-button>
37
+
38
+ <b-button
39
+ v-if="!searchBelowMinimum"
40
+ class="is-ghost is-small previous-search"
41
+ :disabled="!searchResults.length || searchResults.length <= 1"
42
+ @click="focusSearchResult(-1)"
43
+ ><b-icon icon="angle-up" class="is-small"
44
+ /></b-button>
45
+ </div>
46
+ <div class="search-close">
47
+ <b-button class="is-ghost is-small" @click="closeSearch">
48
+ <b-icon icon="xmark" class="is-small" />
49
+ </b-button>
50
+ </div>
51
+ </div>
52
+ </div>
53
+ </template>
54
+
55
+ <script>
56
+ import { mapState } from "vuex";
57
+
58
+ export default {
59
+ name: "SearchBar",
60
+ data() {
61
+ return {
62
+ search: "",
63
+ minSearchLength: 3,
64
+ };
65
+ },
66
+ computed: {
67
+ ...mapState("display", [
68
+ "currentSearchResult",
69
+ "currentSearch",
70
+ "searchEnabled",
71
+ "searchResults",
72
+ "searchLoading",
73
+ ]),
74
+ searchBelowMinimum() {
75
+ return (
76
+ this.search &&
77
+ this.search.length > 0 &&
78
+ this.search.length < this.minSearchLength
79
+ );
80
+ },
81
+ currentCounter() {
82
+ return this.currentSearchResult != null && this.searchResults.length > 0
83
+ ? this.currentSearchResult + 1
84
+ : 0;
85
+ },
86
+ },
87
+ watch: {
88
+ search(search) {
89
+ console.log("search", search);
90
+ this.$store.dispatch("display/setCurrentSearch", search);
91
+ if (search.length >= this.minSearchLength) {
92
+ this.$store.dispatch("display/startSearchLoading");
93
+ }
94
+ this.$store.dispatch("display/debounceSearch", search);
95
+ },
96
+ currentSearch(search) {
97
+ if (this.search !== search) {
98
+ this.search = search;
99
+ }
100
+ },
101
+ searchEnabled(enabled) {
102
+ if (enabled) {
103
+ this.$nextTick(() => {
104
+ this.$refs.searchInput.focus();
105
+ });
106
+ }
107
+ },
108
+ },
109
+ mounted() {
110
+ if (this.currentSearch !== this.search) {
111
+ this.search = this.currentSearch;
112
+ }
113
+ },
114
+ methods: {
115
+ focusSearchResult(n) {
116
+ this.$store.dispatch("display/setCurrentSearchResult", n);
117
+ },
118
+ closeSearch() {
119
+ this.$store.dispatch("display/resetSearch");
120
+ this.$store.dispatch("display/toggleSearch");
121
+ },
122
+ },
123
+ };
124
+ </script>
125
+
126
+ <style
127
+ scoped
128
+ lang="scss"
129
+ src="../../assets/scss/document_search_bar.scss"
130
+ ></style>
@@ -32,7 +32,7 @@
32
32
  class="edit-btn btn"
33
33
  @click="handleEdit"
34
34
  >
35
- {{ $t("edit") }}
35
+ {{ $t("rename") }}
36
36
  </div>
37
37
  <div
38
38
  v-if="showSaveBtn && !editMode"
@@ -56,6 +56,10 @@
56
56
  <span v-else class="cloud-icon"><FileNameNotSaved /></span>
57
57
  <span>{{ saved ? $t("saved") : $t("not_saved") }}</span>
58
58
  </div>
59
+
60
+ <div v-if="detailsUrl" class="details-btn btn" @click="openDocumentDetails">
61
+ {{ $t("document_details") }}
62
+ </div>
59
63
  </div>
60
64
  </template>
61
65
 
@@ -97,8 +101,9 @@ export default {
97
101
  "selectedDocument",
98
102
  "publicView",
99
103
  "recalculatingAnnotations",
104
+ "documentId",
100
105
  ]),
101
- ...mapState("display", ["optimalResolution"]),
106
+ ...mapState("display", ["optimalResolution", "detailsUrl"]),
102
107
  ...mapState("edit", ["editMode"]),
103
108
  ...mapGetters("document", ["isDocumentReviewed"]),
104
109
  textContent() {
@@ -229,6 +234,9 @@ export default {
229
234
  contentNotEditable.blur();
230
235
  }
231
236
  },
237
+ openDocumentDetails() {
238
+ window.location.href = this.detailsUrl;
239
+ },
232
240
  },
233
241
  };
234
242
  </script>
package/src/icons.js CHANGED
@@ -18,6 +18,7 @@ import {
18
18
  faArrowLeft,
19
19
  faArrowRight,
20
20
  faDownload,
21
+ faSearch,
21
22
  } from "@fortawesome/free-solid-svg-icons";
22
23
  import { FontAwesomeIcon as Icons } from "@fortawesome/vue-fontawesome";
23
24
 
@@ -39,7 +40,8 @@ library.add(
39
40
  faRepeat,
40
41
  faArrowLeft,
41
42
  faArrowRight,
42
- faDownload
43
+ faDownload,
44
+ faSearch
43
45
  );
44
46
 
45
47
  export default Icons;
@@ -16,6 +16,7 @@
16
16
  "set_status": "Setzen Sie bitte einen Status",
17
17
  "status_error": "Wir konnten den Status nicht ändern. Bitte versuchen Sie es später erneut.",
18
18
  "edit": "Bearbeiten",
19
+ "rename": "Umbenennen",
19
20
  "save": "Speichern",
20
21
  "autosaving": "Automatisches Speichern...",
21
22
  "saved": "Gespeichert",
@@ -146,5 +147,10 @@
146
147
  "translated_string_title": "Übersetzter Text",
147
148
  "no_translated_string": "Es existiert noch keine Übersetzung.",
148
149
  "add_translation": "Klicken Sie zum hinzufügen",
149
- "edit_translation": "Zum Bearbeiten anklicken"
150
+ "edit_translation": "Zum Bearbeiten anklicken",
151
+ "search": "Suchen",
152
+ "no_results": "Keine Ergebnisse",
153
+ "search_below_minimum": "Mindestens 3 Zeichen",
154
+ "search_in_document": "Suche im Dokument",
155
+ "document_details": "Einzelheiten"
150
156
  }
@@ -16,7 +16,9 @@
16
16
  "set_status": "Set a status",
17
17
  "status_error": "We couldn’t change the status. Please try again later.",
18
18
  "edit": "Edit",
19
+ "rename": "Rename",
19
20
  "save": "Save",
21
+ "details": "Details",
20
22
  "autosaving": "Auto saving...",
21
23
  "saved": "Saved",
22
24
  "not_saved": "Could not save. Try again",
@@ -146,5 +148,10 @@
146
148
  "translated_string_title": "Translated text",
147
149
  "no_translated_string": "No translation exists yet.",
148
150
  "add_translation": "Click to add one",
149
- "edit_translation": "Click to edit"
151
+ "edit_translation": "Click to edit",
152
+ "search": "Search",
153
+ "no_results": "No results",
154
+ "search_below_minimum": "Minimum 3 characters",
155
+ "search_in_document": "Search document",
156
+ "document_details": "Details"
150
157
  }
@@ -16,6 +16,7 @@
16
16
  "set_status": "Establecer estado",
17
17
  "status_error": "No ha sido posible cambiar el estado del documento. Por favor, inténtelo de nuevo más tarde.",
18
18
  "edit": "Editar",
19
+ "rename": "Rebautizar",
19
20
  "save": "Guardar",
20
21
  "autosaving": "Auto guardando...",
21
22
  "saved": "Guardado",
@@ -146,5 +147,10 @@
146
147
  "translated_string_title": "Texto traducido",
147
148
  "no_translated_string": "Aún no existe traducción.",
148
149
  "add_translation": "Clic para agregar",
149
- "edit_translation": "Clic para editar"
150
+ "edit_translation": "Clic para editar",
151
+ "search": "Buscar",
152
+ "no_results": "Sin resultados",
153
+ "search_below_minimum": "Mínimo 3 caracteres",
154
+ "search_in_document": "Buscar en documento",
155
+ "document_details": "Detalles"
150
156
  }
@@ -1,10 +1,14 @@
1
1
  import BigNumber from "bignumber.js";
2
+ import myImports from "../api";
2
3
  import {
3
4
  PIXEL_RATIO,
4
5
  VIEWPORT_RATIO,
5
6
  MINIMUM_APP_WIDTH,
6
7
  MINIMUM_OPTIMIZED_APP_WIDTH,
7
8
  } from "../constants";
9
+
10
+ const HTTP = myImports.HTTP;
11
+
8
12
  const debounce = (cb, duration) => {
9
13
  let timer;
10
14
  return (...args) => {
@@ -31,6 +35,12 @@ const state = {
31
35
  pageChangedFromThumbnail: false,
32
36
  showAnnSetTable: null,
33
37
  showChooseLabelSetModal: null,
38
+ currentSearch: "",
39
+ searchEnabled: false,
40
+ searchResults: [],
41
+ searchLoading: false,
42
+ currentSearchResult: null,
43
+ detailsUrl: null,
34
44
  };
35
45
 
36
46
  const getters = {
@@ -54,6 +64,28 @@ const getters = {
54
64
  return [previousPage, state.currentPage, nextPage];
55
65
  },
56
66
 
67
+ searchResultsForPage: (state, getters) => (pageNumber) => {
68
+ if (!state.searchEnabled || state.searchResults.length < 1) {
69
+ return [];
70
+ }
71
+
72
+ return state.searchResults.filter((r) => r.page_index + 1 === pageNumber);
73
+ },
74
+
75
+ currentSearchResultForPage: (state) => (pageNumber) => {
76
+ if (!state.searchEnabled || state.searchResults.length < 1) {
77
+ return false;
78
+ }
79
+
80
+ const currentResult = state.searchResults[state.currentSearchResult];
81
+
82
+ if (!currentResult || currentResult.page_index !== pageNumber - 1) {
83
+ return false;
84
+ }
85
+
86
+ return currentResult;
87
+ },
88
+
57
89
  /**
58
90
  * The proportion between the original size of the page and the
59
91
  * image rendering.
@@ -259,6 +291,66 @@ const actions = {
259
291
  setPageChangedFromThumbnail: ({ commit }, value) => {
260
292
  commit("SET_PAGE_CHANGED_FROM_THUMBNAIL", value);
261
293
  },
294
+
295
+ setDetailsUrl: ({ commit }, value) => {
296
+ commit("SET_DETAILS_URL", value);
297
+ },
298
+
299
+ debounceSearch: debounce(({ commit, dispatch }, query) => {
300
+ dispatch("search", query);
301
+ }, 300),
302
+
303
+ startSearchLoading({ commit }) {
304
+ commit("SET_SEARCH_LOADING", true);
305
+ },
306
+
307
+ search({ commit, rootState }, query) {
308
+ // only allow queries that are at least 3 characters long
309
+ if (query.length >= 3) {
310
+ return HTTP.post(`documents/${rootState.document.documentId}/search/`, {
311
+ q: query,
312
+ }).then((response) => {
313
+ commit("SET_SEARCH_RESULTS", response.data.span);
314
+ commit("SET_SEARCH_LOADING", false);
315
+ });
316
+ } else {
317
+ commit("SET_SEARCH_RESULTS", []);
318
+ commit("SET_SEARCH_LOADING", false);
319
+ }
320
+ },
321
+
322
+ resetSearch({ commit }) {
323
+ commit("SET_CURRENT_SEARCH", "");
324
+ commit("SET_SEARCH_RESULTS", []);
325
+ commit("SET_SEARCH_LOADING", false);
326
+ },
327
+
328
+ toggleSearch({ commit }) {
329
+ commit("TOGGLE_SEARCH");
330
+ },
331
+
332
+ enableSearch({ commit }, toEnable) {
333
+ commit("ENABLE_SEARCH", toEnable);
334
+ },
335
+
336
+ setCurrentSearch({ commit }, currentSearch) {
337
+ commit("SET_CURRENT_SEARCH", currentSearch);
338
+ },
339
+
340
+ setCurrentSearchResult({ commit, state }, n) {
341
+ let newSearchResult = state.currentSearchResult + n;
342
+ const searchResultsMaxIndex = state.searchResults.length - 1;
343
+
344
+ if (newSearchResult > searchResultsMaxIndex) {
345
+ // once we're at the end of the results, start again
346
+ newSearchResult = 0;
347
+ } else if (newSearchResult < 0) {
348
+ // once we're at the beginning of the results, go to the end
349
+ newSearchResult = searchResultsMaxIndex;
350
+ }
351
+
352
+ commit("SET_CURRENT_SEARCH_RESULT", newSearchResult);
353
+ },
262
354
  };
263
355
 
264
356
  const mutations = {
@@ -303,6 +395,28 @@ const mutations = {
303
395
  SET_SHOW_CHOOSE_LABEL_SET_MODAL: (state, options) => {
304
396
  state.showChooseLabelSetModal = options;
305
397
  },
398
+ SET_SEARCH_RESULTS: (state, searchResults) => {
399
+ state.currentSearchResult = 0;
400
+ state.searchResults = searchResults;
401
+ },
402
+ SET_SEARCH_LOADING: (state, loading) => {
403
+ state.searchLoading = loading;
404
+ },
405
+ TOGGLE_SEARCH: (state) => {
406
+ state.searchEnabled = !state.searchEnabled;
407
+ },
408
+ ENABLE_SEARCH: (state, toEnable) => {
409
+ state.searchEnabled = toEnable;
410
+ },
411
+ SET_CURRENT_SEARCH: (state, currentSearch) => {
412
+ state.currentSearch = currentSearch;
413
+ },
414
+ SET_CURRENT_SEARCH_RESULT: (state, n) => {
415
+ state.currentSearchResult = n;
416
+ },
417
+ SET_DETAILS_URL: (state, value) => {
418
+ state.detailsUrl = value;
419
+ },
306
420
  };
307
421
 
308
422
  export default {
@@ -663,8 +663,6 @@ const getters = {
663
663
  return label.annotations;
664
664
  });
665
665
 
666
- console.log(annotations);
667
-
668
666
  return annotations.length === 0 ? true : false;
669
667
  },
670
668
  };
@@ -672,6 +670,7 @@ const getters = {
672
670
  const actions = {
673
671
  startLoading: ({ commit }) => {
674
672
  commit("SET_LOADING", true);
673
+ commit("display/ENABLE_SEARCH", false, { root: true });
675
674
  },
676
675
  endLoading: ({ commit }) => {
677
676
  commit("SET_LOADING", false);