changeset 1545:494bb818d073

Translations: merging new translations
author Bernhard Reiter <bernhard@intevation.de>
date Mon, 10 Dec 2018 15:29:14 +0100
parents 5f80ec319a4f (diff) 9b0d3da61309 (current diff)
children b83928a8fadb
files client/src/locale/de_AT/LC_MESSAGES/app.po
diffstat 38 files changed, 1229 insertions(+), 486 deletions(-) [+]
line wrap: on
line diff
--- a/3rdpartylibs.sh	Thu Dec 06 16:04:37 2018 +0000
+++ b/3rdpartylibs.sh	Mon Dec 10 15:29:14 2018 +0100
@@ -32,6 +32,9 @@
 go get -u -v github.com/jonas-p/go-shp
 # MIT
 
+go get -u -v github.com/robfig/cron
+# MIT
+
 ## list of additional licenses that get fetched and installed as dependencies
 # github.com/fsnotify/fsnotify/ BSD-3-Clause
 # github.com/hashicorp/hcl/ MPL-2.0
--- a/client/package.json	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/package.json	Mon Dec 10 15:29:14 2018 +0100
@@ -34,12 +34,14 @@
     "locale2": "^2.2.0",
     "ol": "^5.3.0",
     "path": "^0.12.7",
+    "prettier": "^1.15.3",
     "purgecss-webpack-plugin": "^1.4.0",
     "v-tooltip": "^2.0.0-rc.33",
     "vue": "^2.5.16",
     "vue-clipboard2": "^0.2.1",
     "vue-color": "^2.6.0",
     "vue-highlightjs": "^1.3.3",
+    "vue-js-toggle-button": "^1.3.0",
     "vue-router": "^3.0.2",
     "vue-snotify": "^3.2.1",
     "vuex": "^3.0.1",
@@ -59,7 +61,7 @@
     "copy-webpack-plugin": "^4.6.0",
     "easygettext": "^2.7.0",
     "node-sass": "^4.10.0",
-    "pretty-quick": "^1.6.0",
+    "pretty-quick": "^1.8.0",
     "sass-loader": "^7.0.1",
     "vue-gettext": "^2.1.1",
     "vue-template-compiler": "^2.5.17",
--- a/client/src/components/Sidebar.vue	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/components/Sidebar.vue	Mon Dec 10 15:29:14 2018 +0100
@@ -4,11 +4,12 @@
       @click="$store.commit('application/showSidebar', !showSidebar)"
       class="menubutton ui-element d-print-none p-2 bg-white rounded position-absolute d-flex justify-content-center"
     >
-      <font-awesome-icon icon="bars"></font-awesome-icon>
+      <font-awesome-icon class="fa-fw" icon="bars"></font-awesome-icon>
     </div>
     <div class="menu text-nowrap text-left">
       <router-link to="/">
         <font-awesome-icon
+          class="fa-fw mr-2"
           fixed-width
           icon="map-marked-alt"
         ></font-awesome-icon>
@@ -19,7 +20,11 @@
         @click="toggleContextBox('bottlenecks')"
         href="#"
       >
-        <font-awesome-icon fixed-width icon="ship"></font-awesome-icon>
+        <font-awesome-icon
+          class="fa-fw  mr-2"
+          fixed-width
+          icon="ship"
+        ></font-awesome-icon>
         <span class="fix-trans-space" v-translate>Bottlenecks</span>
       </a>
       <div v-if="isWaterwayAdmin">
@@ -28,7 +33,11 @@
           @click="toggleContextBox('imports')"
           href="#"
         >
-          <font-awesome-icon fixed-width icon="upload"></font-awesome-icon>
+          <font-awesome-icon
+            class="fa-fw mr-2"
+            fixed-width
+            icon="upload"
+          ></font-awesome-icon>
           <span class="fix-trans-space" v-translate
             >Import soundingresults</span
           >
@@ -39,6 +48,7 @@
           href="#"
         >
           <font-awesome-icon
+            class="fa-fw mr-2"
             fixed-width
             icon="clipboard-check"
           ></font-awesome-icon>
@@ -49,31 +59,55 @@
         </small>
         <hr class="m-0" />
         <router-link to="usermanagement">
-          <font-awesome-icon fixed-width icon="users-cog"></font-awesome-icon>
+          <font-awesome-icon
+            class="fa-fw mr-2"
+            fixed-width
+            icon="users-cog"
+          ></font-awesome-icon>
           <span class="fix-trans-space" v-translate>Users</span>
         </router-link>
       </div>
       <div v-if="isSysAdmin">
         <router-link to="systemconfiguration">
-          <font-awesome-icon fixed-width icon="wrench"></font-awesome-icon>
+          <font-awesome-icon
+            class="fa-fw mr-2"
+            fixed-width
+            icon="wrench"
+          ></font-awesome-icon>
           <span class="fix-trans-space" v-translate>Configuration</span>
         </router-link>
         <router-link to="logs">
-          <font-awesome-icon fixed-width icon="book"></font-awesome-icon>
+          <font-awesome-icon
+            class="fa-fw mr-2"
+            fixed-width
+            icon="book"
+          ></font-awesome-icon>
           <span class="fix-trans-space" v-translate>Logs</span>
         </router-link>
         <router-link to="importqueue">
-          <font-awesome-icon fixed-width icon="tasks"></font-awesome-icon>
+          <font-awesome-icon
+            class="fa-fw mr-2"
+            fixed-width
+            icon="tasks"
+          ></font-awesome-icon>
           <span class="fix-trans-space" v-translate>Importqueue</span>
         </router-link>
         <router-link to="importschedule" v-if="this.$options.IMPORTSCHEDULE">
-          <font-awesome-icon fixed-width icon="clock"></font-awesome-icon>
+          <font-awesome-icon
+            class="fa-fw mr-2"
+            fixed-width
+            icon="clock"
+          ></font-awesome-icon>
           <translate class="fix-trans-space">Importschedule</translate>
         </router-link>
       </div>
       <hr class="m-0" />
       <a @click="logoff" href="#">
-        <font-awesome-icon fixed-width icon="power-off"></font-awesome-icon>
+        <font-awesome-icon
+          class="fa-fw mr-2"
+          fixed-width
+          icon="power-off"
+        ></font-awesome-icon>
         <span class="fix-trans-space" v-translate>Logout</span> {{ user }}
       </a>
     </div>
--- a/client/src/components/admin/Importqueue.vue	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/components/admin/Importqueue.vue	Mon Dec 10 15:29:14 2018 +0100
@@ -1,8 +1,8 @@
 <template>
   <div class="d-flex flex-row">
     <div :class="spacerStyle"></div>
-    <div class="mt-3">
-      <div class="card importqueuecard shadow-xs">
+    <div class="mt-3 importqueuecard flex-grow-1">
+      <div class="card shadow-xs">
         <h6
           class="mb-0 py-2 px-3 border-bottom d-flex text-info align-items-center"
         >
@@ -240,11 +240,13 @@
 }
 
 .spacer-expanded {
-  min-width: $sidebar-width + $offset;
+  min-width: $sidebar-width;
 }
 
 .importqueuecard {
-  width: 75vw;
+  width: 97%;
+  margin-left: $offset;
+  margin-right: $offset;
   min-height: 20rem;
 }
 
--- a/client/src/components/admin/Logs.vue	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/components/admin/Logs.vue	Mon Dec 10 15:29:14 2018 +0100
@@ -6,7 +6,7 @@
         <h6
           class="mb-0 py-2 px-3 border-bottom d-flex text-info align-items-center"
         >
-          <font-awesome-icon class="mr-2" icon="book"></font-awesome-icon>
+          <font-awesome-icon class="mr-2 fa-fw" icon="book"></font-awesome-icon>
           <translate class="headline">Logs</translate>
         </h6>
         <div class="logoutput text-left bg-white">
--- a/client/src/components/admin/Systemconfiguration.vue	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/components/admin/Systemconfiguration.vue	Mon Dec 10 15:29:14 2018 +0100
@@ -53,7 +53,8 @@
 }
 
 .sysconfig {
-  width: 30vw;
+  margin-right: $offset;
+  width: 100%;
   height: 100%;
 }
 
--- a/client/src/components/admin/importschedule/Importschedule.vue	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/components/admin/importschedule/Importschedule.vue	Mon Dec 10 15:29:14 2018 +0100
@@ -1,8 +1,8 @@
 <template>
   <div class="d-flex flex-row">
     <div :class="spacerStyle"></div>
-    <div class="mt-3">
-      <div class="card schedulecard shadow-xs">
+    <div class="mt-3 w-100">
+      <div class="card flex-grow-1 schedulecard shadow-xs">
         <h6
           class="mb-0 py-2 px-3 border-bottom d-flex text-info align-items-center"
         >
@@ -11,7 +11,7 @@
         </h6>
         <div class="card-body schedulecardbody">
           <div class="card-body schedulecardbody">
-            <div class="searchandfilter d-flex flex-row">
+            <div class="searchandfilter  w-50 d-flex flex-row">
               <div class="searchgroup input-group">
                 <div class="input-group-prepend">
                   <span class="input-group-text" id="search">
@@ -148,7 +148,7 @@
 }
 
 .schedulecard {
-  width: 40vw;
+  margin-right: $offset;
   min-height: 20rem;
 }
 
--- a/client/src/components/admin/importschedule/Importscheduledetail.vue	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/components/admin/importschedule/Importscheduledetail.vue	Mon Dec 10 15:29:14 2018 +0100
@@ -1,6 +1,9 @@
 <template>
-  <div class="importscheduledetails" v-if="importScheduleDetailVisible">
-    <div class="card shadow-xs">
+  <div
+    class="importscheduledetails  fadeIn animated"
+    v-if="importScheduleDetailVisible"
+  >
+    <div class="card h-100 shadow-xs">
       <h6
         class="mb-0 py-2 px-3 border-bottom d-flex text-info align-items-center"
       >
@@ -10,8 +13,79 @@
         </span>
       </h6>
       <div class="card-body">
-        <h1>lalala</h1>
-        <form @submit.prevent="save" class="ml-3"></form>
+        <form @submit.prevent="save" class="ml-3">
+          <div class="d-flex flex-row w-100">
+            <div class="flex-column w-100">
+              <div class="flex-row text-left">
+                <small class="text-muted">
+                  <translate>Imports</translate>
+                </small>
+              </div>
+              <select v-model="import_" class="custom-select" id="import_">
+                <option v-for="option in this.$options.imports" :key="option">{{
+                  option
+                }}</option>
+              </select>
+            </div>
+          </div>
+          <div class="d-flex flex-row mt-3 w-100 justify-content-between">
+            <div class="flex-column w-100 mr-2">
+              <div class="flex-row text-left">
+                <small class="text-muted">
+                  <translate>Importtype</translate>
+                </small>
+              </div>
+              <select v-model="import_" class="custom-select" id="importtype">
+                <option
+                  v-for="option in this.$options.importtype"
+                  :key="option"
+                  >{{ option }}</option
+                >
+              </select>
+            </div>
+            <div class="flex-column w-100 ml-2">
+              <div class="flex-row text-left">
+                <small class="text-muted">
+                  <translate>Schedule</translate>
+                </small>
+              </div>
+              <select v-model="schedule" class="custom-select" id="period">
+                <option v-for="option in this.$options.periods" :key="option">{{
+                  option
+                }}</option>
+              </select>
+            </div>
+          </div>
+          <div class="flex-column mt-3 w-100 mr-2">
+            <div class="flex-row text-left">
+              <small class="text-muted">
+                <translate>Email Notification</translate>
+              </small>
+            </div>
+            <div class="flex-flex-row text-left">
+              <toggle-button
+                v-model="eMailNotification"
+                class="mt-2"
+                :speed="100"
+                :labels="{
+                  checked: this.$options.on,
+                  unchecked: this.$options.off
+                }"
+                :width="50"
+                :height="20"
+              />
+            </div>
+          </div>
+          <div v-if="eMailNotification" class="flex-column w-100 mr-2">
+            <div class="flex-row text-left">
+              <small class="text-muted"> <translate>Email</translate> </small>
+            </div>
+            <input class="form-control" type="text" />
+          </div>
+          <button type="submit" class="shadow-sm btn btn-info submit-button">
+            <translate>Submit</translate>
+          </button>
+        </form>
       </div>
     </div>
   </div>
@@ -19,24 +93,54 @@
 
 <script>
 import { mapState } from "vuex";
+import { displayInfo } from "../../../lib/errors.js";
 
 export default {
   name: "importscheduledetail",
+  data() {
+    return {
+      schedule: null,
+      import_: null,
+      eMailNotification: false
+    };
+  },
   computed: {
     ...mapState("imports", ["importScheduleDetailVisible"])
   },
   methods: {
+    save() {
+      displayInfo({
+        title: "Import",
+        message: "under construction"
+      });
+    },
     closeDetailview() {
       this.$store.commit("imports/clearImportScheduleDetail");
       this.$store.commit("imports/setImportScheduleDetailInvisible");
     }
+  },
+  imports: [],
+  importtype: [],
+  on: "on",
+  off: "off",
+  periods: {
+    DAILY: "daily",
+    MONTHLY: "monthly"
   }
 };
 </script>
 
 <style lang="scss" scoped>
 .importscheduledetails {
+  height: 420px;
+  width: 45%;
   margin-top: $offset;
-  margin-left: $offset;
+  margin-right: $offset;
+}
+
+.submit-button {
+  position: absolute;
+  right: $offset;
+  bottom: $offset;
 }
 </style>
--- a/client/src/components/admin/usermanagement/Passwordfield.vue	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/components/admin/usermanagement/Passwordfield.vue	Mon Dec 10 15:29:14 2018 +0100
@@ -1,6 +1,8 @@
 <template>
-  <div>
-    <label for="password">{{ this.label }}</label>
+  <div class="w-100">
+    <div class="d-flex flex-row">
+      <label for="password">{{ this.label }}</label>
+    </div>
     <div class="d-flex d-row">
       <input
         :type="isPasswordVisible"
--- a/client/src/components/admin/usermanagement/Userdetail.vue	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/components/admin/usermanagement/Userdetail.vue	Mon Dec 10 15:29:14 2018 +0100
@@ -1,163 +1,172 @@
 <template>
-  <div class="userdetails h-100 mt-3 mr-auto shadow fadeIn animated">
-    <div class="card">
-      <h6
-        class="mb-0 py-2 px-3 border-bottom d-flex text-info align-items-center"
-      >
-        {{ this.cardHeader }}
-        <span @click="closeDetailview" class="closebutton">
-          <font-awesome-icon icon="times"></font-awesome-icon>
-        </span>
-      </h6>
-      <div class="card-body">
-        <form @submit.prevent="save" class="ml-3">
-          <div class="formfields">
-            <div v-if="currentUser.isNew" class="form-group row">
-              <label for="user"> <translate>Username</translate> </label>
-              <input
-                type="user"
-                :placeholder="userNamePlaceholder"
-                class="form-control form-control-sm"
-                id="user"
-                aria-describedby="userHelp"
-                v-model="currentUser.user"
-              />
-              <div v-show="errors.user" class="text-danger">
-                <small>
-                  <font-awesome-icon
-                    icon="exclamation-triangle"
-                  ></font-awesome-icon>
-                  {{ errors.user }}
-                </small>
-              </div>
-            </div>
-            <div class="form-group row">
-              <label for="country"> <translate>Country</translate> </label>
-              <select
-                class="form-control form-control-sm"
-                v-on:change="validateCountry"
-                v-model="currentUser.country"
-              >
-                <option disabled value>
-                  <translate>Please select one</translate>
-                </option>
-                <option
-                  v-for="country in countries"
-                  v-bind:value="country"
-                  v-bind:key="country"
-                  >{{ country }}</option
-                >
-              </select>
-              <div v-show="errors.country" class="text-danger">
-                <small>
-                  <font-awesome-icon
-                    icon="exclamation-triangle"
-                  ></font-awesome-icon>
-                  {{ errors.country }}
-                </small>
-              </div>
+  <div class="userdetails mt-3 shadow fadeIn animated card">
+    <h6
+      class="mb-0 py-2 px-3 border-bottom d-flex text-info align-items-center"
+    >
+      {{ this.cardHeader }}
+      <span @click="closeDetailview" class="closebutton">
+        <font-awesome-icon icon="times"></font-awesome-icon>
+      </span>
+    </h6>
+    <div class="card-body">
+      <form @submit.prevent="save" class="ml-3">
+        <div class="formfields">
+          <div v-if="currentUser.isNew" class="form-group row">
+            <label for="user"> <translate>Username</translate> </label>
+            <input
+              type="user"
+              :placeholder="userNamePlaceholder"
+              class="form-control form-control-sm"
+              id="user"
+              aria-describedby="userHelp"
+              v-model="currentUser.user"
+            />
+            <div v-show="errors.user" class="text-danger">
+              <small>
+                <font-awesome-icon
+                  icon="exclamation-triangle"
+                ></font-awesome-icon>
+                {{ errors.user }}
+              </small>
             </div>
-            <div class="form-group row">
-              <label for="email"> <translate>Email address</translate> </label>
-              <input
-                type="email"
-                v-on:change="validateEmailaddress"
-                class="form-control form-control-sm"
-                id="email"
-                aria-describedby="emailHelp"
-                v-model="currentUser.email"
-              />
-              <div v-show="errors.email" class="text-danger">
-                <small>
-                  <font-awesome-icon
-                    icon="exclamation-triangle"
-                  ></font-awesome-icon>
-                  {{ errors.email }}
-                </small>
-              </div>
-            </div>
-            <div class="form-group row">
-              <label for="role"> <translate>Role</translate> </label>
-              <select
-                class="form-control form-control-sm"
-                v-on:change="validateRole"
-                v-model="currentUser.role"
+          </div>
+          <div class="form-group row">
+            <label for="country"> <translate>Country</translate> </label>
+            <select
+              class="form-control form-control-sm"
+              v-on:change="validateCountry"
+              v-model="currentUser.country"
+            >
+              <option disabled value>
+                <translate>Please select one</translate>
+              </option>
+              <option
+                v-for="country in countries"
+                v-bind:value="country"
+                v-bind:key="country"
+                >{{ country }}</option
               >
-                <option disabled value>
-                  <translate>Please select one</translate>
-                </option>
-                <option value="sys_admin">
-                  <translate>Sysadmin</translate>
-                </option>
-                <option value="waterway_admin">
-                  <translate>Waterway Admin</translate>
-                </option>
-                <option value="waterway_user">
-                  <translate>Waterway User</translate>
-                </option>
-              </select>
-              <div v-show="errors.role" class="text-danger">
-                <small>
-                  <font-awesome-icon
-                    icon="exclamation-triangle"
-                  ></font-awesome-icon>
-                  {{ errors.role }}
-                </small>
-              </div>
-            </div>
-            <div class="form-group row">
-              <PasswordField
-                @fieldchange="passwordChanged"
-                :placeholder="passwordPlaceholder"
-                :label="passwordLabel"
-                :passworderrors="errors.password"
-              ></PasswordField>
-            </div>
-            <div class="form-group row">
-              <PasswordField
-                @fieldchange="passwordReChanged"
-                :placeholder="passwordRePlaceholder"
-                :label="passwordReLabel"
-                :passworderrors="errors.passwordre"
-              ></PasswordField>
+            </select>
+            <div v-show="errors.country" class="text-danger">
+              <small>
+                <font-awesome-icon
+                  icon="exclamation-triangle"
+                ></font-awesome-icon>
+                {{ errors.country }}
+              </small>
             </div>
           </div>
-          <div>
-            <button
-              type="submit"
-              :disabled="submitted"
-              class="shadow-sm btn btn-info pull-right"
-            >
-              <translate>Submit</translate>
-            </button>
+          <div class="form-group row">
+            <label for="email"> <translate>Email address</translate> </label>
+            <input
+              type="email"
+              v-on:change="validateEmailaddress"
+              class="form-control form-control-sm"
+              id="email"
+              aria-describedby="emailHelp"
+              v-model="currentUser.email"
+            />
+            <div v-show="errors.email" class="text-danger">
+              <small>
+                <font-awesome-icon
+                  icon="exclamation-triangle"
+                ></font-awesome-icon>
+                {{ errors.email }}
+              </small>
+            </div>
           </div>
-          <div
-            v-if="currentUser.role != 'waterway_user'"
-            class="form-group row d-flex flex-row justify-content-start mailbutton"
+          <div class="form-group row">
+            <label for="role"> <translate>Role</translate> </label>
+            <select
+              class="form-control form-control-sm"
+              v-on:change="validateRole"
+              v-model="currentUser.role"
+            >
+              <option disabled value>
+                <translate>Please select one</translate>
+              </option>
+              <option value="sys_admin">
+                <translate>Sysadmin</translate>
+              </option>
+              <option value="waterway_admin">
+                <translate>Waterway Admin</translate>
+              </option>
+              <option value="waterway_user">
+                <translate>Waterway User</translate>
+              </option>
+            </select>
+            <div v-show="errors.role" class="text-danger">
+              <small>
+                <font-awesome-icon
+                  icon="exclamation-triangle"
+                ></font-awesome-icon>
+                {{ errors.role }}
+              </small>
+            </div>
+          </div>
+          <div class="form-group row">
+            <PasswordField
+              @fieldchange="passwordChanged"
+              :placeholder="passwordPlaceholder"
+              :label="passwordLabel"
+              :passworderrors="errors.password"
+            ></PasswordField>
+          </div>
+          <div class="form-group row">
+            <PasswordField
+              @fieldchange="passwordReChanged"
+              :placeholder="passwordRePlaceholder"
+              :label="passwordReLabel"
+              :passworderrors="errors.passwordre"
+            ></PasswordField>
+          </div>
+        </div>
+        <div>
+          <button
+            type="submit"
+            :disabled="submitted"
+            class="shadow-sm btn btn-info submit-button"
           >
-            <a @click="sendTestMail" class="btn btn-light">
-              <font-awesome-icon icon="paper-plane"></font-awesome-icon>
-              <translate>Send testmail</translate>
-            </a>
-            <div v-if="mailsent"><translate>Mail was sent</translate></div>
-          </div>
-        </form>
-      </div>
+            <translate>Submit</translate>
+          </button>
+        </div>
+        <div
+          v-if="currentUser.role != 'waterway_user'"
+          class="form-group row d-flex flex-row justify-content-start mailbutton"
+        >
+          <a @click="sendTestMail" class="btn btn-light">
+            <font-awesome-icon icon="paper-plane"></font-awesome-icon>
+            <translate>Send testmail</translate>
+          </a>
+          <div v-if="mailsent"><translate>Mail was sent</translate></div>
+        </div>
+      </form>
     </div>
   </div>
 </template>
 
 <style lang="scss" scoped>
+.submit-button {
+  position: absolute;
+  right: $offset;
+  bottom: $offset;
+}
 .mailbutton {
   width: 12vw;
+  position: absolute;
+  left: $large-offset;
+  bottom: 0;
 }
 
 .formfields {
-  width: 10vw;
+  width: 60%;
 }
 
 .userdetails {
-  min-width: 40vw;
+  height: 600px;
+  margin-top: $offset;
+  margin-left: $offset;
+  margin-right: $offset;
 }
 
 form {
--- a/client/src/components/admin/usermanagement/Usermanagement.vue	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/components/admin/usermanagement/Usermanagement.vue	Mon Dec 10 15:29:14 2018 +0100
@@ -10,7 +10,7 @@
             >
               <font-awesome-icon
                 icon="users-cog"
-                class="mr-2"
+                class="mr-2 fa-fw"
               ></font-awesome-icon>
               <translate class="headline">Users</translate>
             </h6>
@@ -100,16 +100,16 @@
               </button>
             </div>
             <div class="mr-3 pb-3">
-              <button
-                @click="addUser"
-                class="btn btn-info pull-right shadow-sm"
-              >
+              <button @click="addUser" class="btn btn-info addbutton shadow-sm">
                 <translate>Add User</translate>
               </button>
             </div>
           </div>
         </div>
-        <Userdetail v-if="isUserDetailsVisible"></Userdetail>
+        <Userdetail
+          class="d-flex userdetails"
+          v-if="isUserDetailsVisible"
+        ></Userdetail>
       </div>
     </div>
   </div>
@@ -118,6 +118,19 @@
 <style scoped lang="scss">
 @import "../../../assets/tooltip.scss";
 
+.addbutton {
+  position: absolute;
+  bottom: $offset;
+  right: $offset;
+}
+
+.content {
+  width: 100%;
+}
+
+.userdetails {
+  width: 50%;
+}
 .spacer {
   height: 100vh;
   margin-left: $offset;
@@ -146,11 +159,11 @@
 }
 
 .userlistsmall {
-  width: 30vw;
+  width: 100%;
 }
 
 .userlistextended {
-  width: 70vw;
+  width: 100%;
 }
 
 .table {
--- a/client/src/components/map/Identify.vue	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/components/map/Identify.vue	Mon Dec 10 15:29:14 2018 +0100
@@ -27,15 +27,12 @@
         </div>
         <div v-for="(feature, i) of identifiedFeatures" :key="feature.getId()">
           <div v-if="feature.getId()" :class="{ 'mt-2': i }">
-            <b
-              >{{
-                feature
-                  .getId()
-                  .replace(
-                    /[.][^.]*$/,
-                    ""
-                  ) /* cut away everything from the last . to the end */
-              }}:</b>
+            <strong>
+              {{
+                feature.getId().replace(/[.][^.]*$/, "")
+                /* cut away everything from the last . to the end */
+              }}:
+            </strong>
             <small
               v-for="(value, key) in prepareProperties(feature)"
               :key="key"
@@ -66,10 +63,12 @@
           <a href="https://www.openstreetmap.org/copyright">%{ name }</a>
           contributors.
         </span>
-        <p v-translate="{geoLicense: 'CC-BY-4.0'}">
-           Uses
+        <p v-translate="{ geoLicense: 'CC-BY-4.0' }">
+          Uses
           <a href="https://download.geonames.org/export/dump/readme.txt"
-             >GeoNames</a> under %{ geoLicense }.
+            >GeoNames</a
+          >
+          under %{ geoLicense }.
         </p>
       </div>
     </div>
--- a/client/src/components/map/Maplayer.vue	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/components/map/Maplayer.vue	Mon Dec 10 15:29:14 2018 +0100
@@ -15,6 +15,14 @@
   height: 100vh;
 }
 
+// the following css part is for browser-printing based pdf generation
+@page {
+  size: A4 landscape !important;
+  margin: 4mm !important;
+  // according to https://www.w3.org/TR/css-page-3/#page-size-prop
+  // we shall now have 210 - 2*4 = 202 mm width and 297 - 2*4 = 289 mm height
+}
+
 @media print {
   .mapfull {
     width: 2000px;
--- a/client/src/components/map/contextbox/Bottlenecks.vue	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/components/map/contextbox/Bottlenecks.vue	Mon Dec 10 15:29:14 2018 +0100
@@ -54,13 +54,13 @@
           }}</a>
         </div>
         <div class="col-2 py-2">
-          {{ displayCurrentSurvey(bottleneck.properties.current) }}
+          {{ formatSurveyDate(bottleneck.properties.current) }}
         </div>
         <div class="col-3 py-2">
           {{
             displayCurrentChainage(
               bottleneck.properties.from,
-              bottleneck.properties.from
+              bottleneck.properties.to
             )
           }}
         </div>
@@ -108,7 +108,7 @@
             v-for="(survey, index) in openBottleneckSurveys"
             :key="index"
             @click="selectSurvey(survey, bottleneck)"
-            >{{ survey.date_info }}</a
+            >{{ formatSurveyDate(survey.date_info) }}</a
           >
         </div>
       </div>
@@ -136,6 +136,7 @@
 import { mapState } from "vuex";
 import { HTTP } from "../../../lib/http";
 import { displayError } from "../../../lib/errors.js";
+import { formatSurveyDate } from "../../../lib/date.js";
 
 export default {
   name: "bottlenecks",
@@ -162,6 +163,9 @@
     }
   },
   methods: {
+    formatSurveyDate(date) {
+      return formatSurveyDate(date);
+    },
     filteredAndSortedBottlenecks() {
       return this.bottlenecks
         .filter(bn => {
@@ -209,19 +213,38 @@
         });
     },
     selectSurvey(survey, bottleneck) {
-      this.selectBottleneck(bottleneck);
-      this.$store.commit("bottlenecks/selectedSurvey", survey);
+      this.$store
+        .dispatch(
+          "bottlenecks/setSelectedBottleneck",
+          bottleneck.properties.name
+        )
+        .then(() => {
+          this.$store.commit("bottlenecks/selectedSurvey", survey);
+        })
+        .then(() => {
+          this.$store.commit("map/moveMap", {
+            coordinates: bottleneck.geometry.coordinates,
+            zoom: 17,
+            preventZoomOut: true
+          });
+        });
     },
     selectBottleneck(bottleneck) {
-      this.$store.dispatch(
-        "bottlenecks/setSelectedBottleneck",
-        bottleneck.properties.name
-      );
-      this.$store.commit("map/moveMap", {
-        coordinates: bottleneck.geometry.coordinates,
-        zoom: 17,
-        preventZoomOut: true
-      });
+      this.$store
+        .dispatch(
+          "bottlenecks/setSelectedBottleneck",
+          bottleneck.properties.name
+        )
+        .then(() => {
+          this.$store.commit("bottlenecks/setFirstSurveySelected");
+        })
+        .then(() => {
+          this.$store.commit("map/moveMap", {
+            coordinates: bottleneck.geometry.coordinates,
+            zoom: 17,
+            preventZoomOut: true
+          });
+        });
     },
     sortBy(column) {
       this.sortColumn = column;
@@ -256,9 +279,6 @@
           .finally(() => (this.loading = null));
       }
     },
-    displayCurrentSurvey(current) {
-      return current ? current.substr(0, current.length - 1) : "";
-    },
     displayCurrentChainage(from, to) {
       return from / 10 + " - " + to / 10;
     }
--- a/client/src/components/map/contextbox/Staging.vue	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/components/map/contextbox/Staging.vue	Mon Dec 10 15:29:14 2018 +0100
@@ -188,8 +188,11 @@
         zoom: 17,
         preventZoomOut: true
       });
-      this.$store.dispatch("bottlenecks/setSelectedBottleneck", bottleneck);
-      this.$store.commit("bottlenecks/selectedSurvey", date);
+      this.$store
+        .dispatch("bottlenecks/setSelectedBottleneck", bottleneck)
+        .then(() => {
+          this.$store.commit("bottlenecks/setSelectedSurveyByDate", date);
+        });
     },
     toggleApproval(id, newStatus) {
       this.$store.commit("imports/toggleApproval", {
--- a/client/src/components/map/fairway/Profiles.vue	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/components/map/fairway/Profiles.vue	Mon Dec 10 15:29:14 2018 +0100
@@ -5,7 +5,7 @@
       { expanded: showProfiles }
     ]"
   >
-    <div style="width: 20rem">
+    <div>
       <h6 class="mb-0 py-2 px-3 border-bottom d-flex align-items-center">
         <font-awesome-icon icon="chart-area" class="mr-2"></font-awesome-icon>
         <translate>Profiles</translate>
@@ -53,7 +53,7 @@
                   v-for="survey in surveys"
                   :key="survey.date_info"
                   :value="survey"
-                  >{{ survey.date_info }}</option
+                  >{{ formatSurveyDate(survey.date_info) }}</option
                 >
               </select>
             </div>
@@ -73,7 +73,7 @@
                   v-for="survey in additionalSurveys"
                   :key="survey.date_info"
                   :value="survey"
-                  >{{ survey.date_info }}</option
+                  >{{ formatSurveyDate(survey.date_info) }}</option
                 >
               </select>
             </div>
@@ -250,6 +250,7 @@
 import Feature from "ol/Feature";
 import LineString from "ol/geom/LineString";
 import { displayError, displayInfo } from "../../../lib/errors.js";
+import { formatSurveyDate } from "../../../lib/date.js";
 
 export default {
   name: "profiles",
@@ -352,6 +353,9 @@
     }
   },
   methods: {
+    formatSurveyDate(date) {
+      return formatSurveyDate(date);
+    },
     loadProfile(survey) {
       if (survey) {
         this.$store.commit("fairwayprofile/profileLoading", true);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/lib/date.js	Mon Dec 10 15:29:14 2018 +0100
@@ -0,0 +1,27 @@
+/* This is Free Software under GNU Affero General Public License v >= 3.0
+ * without warranty, see README.md and license for details.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ * License-Filename: LICENSES/AGPL-3.0.txt
+ *
+ * Copyright (C) 2018 by via donau
+ *   – Österreichische Wasserstraßen-Gesellschaft mbH
+ * Software engineering by Intevation GmbH
+ *
+ * Author(s):
+ * Thomas Junk <thomas.junk@intevation.de>
+ */
+
+import locale2 from "locale2";
+
+const formatSurveyDate = current => {
+  return current
+    ? new Date(current).toLocaleDateString(locale2, {
+        day: "2-digit",
+        month: "2-digit",
+        year: "numeric"
+      })
+    : "";
+};
+
+export { formatSurveyDate };
--- a/client/src/locale/bg_BG/LC_MESSAGES/app.po	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/locale/bg_BG/LC_MESSAGES/app.po	Mon Dec 10 15:29:14 2018 +0100
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: gemmajs 1.99.0-dev\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-12-05 12:25+0100\n"
+"POT-Creation-Date: 2018-12-07 10:05+0100\n"
 "PO-Revision-Date: 2018-12-05 12:23+0100\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -37,7 +37,7 @@
 msgid "back to login"
 msgstr ""
 
-#: src/components/admin/Importqueue.vue:134
+#: src/components/admin/Importqueue.vue:136
 #: src/components/admin/Systemconfiguration.vue:133
 #: src/components/admin/Systemconfiguration.vue:148
 #: src/components/admin/Systemconfiguration.vue:167
@@ -48,7 +48,7 @@
 #: src/components/admin/usermanagement/Usermanagement.vue:308
 #: src/components/admin/usermanagement/Usermanagement.vue:334
 #: src/components/map/Search.vue:257
-#: src/components/map/contextbox/Bottlenecks.vue:252
+#: src/components/map/contextbox/Bottlenecks.vue:275
 #: src/components/map/contextbox/ImportSoundingresults.vue:205
 #: src/components/map/contextbox/ImportSoundingresults.vue:244
 #: src/components/map/contextbox/ImportSoundingresults.vue:275
@@ -67,7 +67,7 @@
 msgid "Bottleneck Areas stroke-color"
 msgstr ""
 
-#: src/components/Sidebar.vue:22
+#: src/components/Sidebar.vue:27
 #: src/components/map/contextbox/Bottlenecks.vue:4
 msgid "Bottlenecks"
 msgstr ""
@@ -93,7 +93,7 @@
 msgid "Compare with"
 msgstr ""
 
-#: src/components/Sidebar.vue:58
+#: src/components/Sidebar.vue:76
 msgid "Configuration"
 msgstr ""
 
@@ -102,7 +102,7 @@
 msgid "Confirm"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:374
+#: src/components/map/fairway/Profiles.vue:378
 msgid "Coordinates copied to clipboard!"
 msgstr ""
 
@@ -184,7 +184,7 @@
 msgid "Import"
 msgstr ""
 
-#: src/components/Sidebar.vue:31
+#: src/components/Sidebar.vue:40
 msgid "Import soundingresults"
 msgstr ""
 
@@ -196,11 +196,11 @@
 msgid "Imported"
 msgstr ""
 
-#: src/components/Sidebar.vue:66 src/components/admin/Importqueue.vue:9
+#: src/components/Sidebar.vue:92 src/components/admin/Importqueue.vue:9
 msgid "Importqueue"
 msgstr ""
 
-#: src/components/Sidebar.vue:70
+#: src/components/Sidebar.vue:100
 #: src/components/admin/importschedule/Importschedule.vue:9
 msgid "Importschedule"
 msgstr ""
@@ -209,7 +209,7 @@
 msgid "invalid email"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:408
+#: src/components/map/fairway/Profiles.vue:412
 msgid "Invalid input"
 msgstr ""
 
@@ -241,11 +241,11 @@
 msgid "Login failed"
 msgstr ""
 
-#: src/components/Sidebar.vue:76
+#: src/components/Sidebar.vue:110
 msgid "Logout"
 msgstr ""
 
-#: src/components/Sidebar.vue:62 src/components/admin/Logs.vue:9
+#: src/components/Sidebar.vue:84 src/components/admin/Logs.vue:9
 msgid "Logs"
 msgstr ""
 
@@ -253,7 +253,7 @@
 msgid "Mail was sent"
 msgstr ""
 
-#: src/components/Sidebar.vue:14
+#: src/components/Sidebar.vue:15
 msgid "Map"
 msgstr ""
 
@@ -340,8 +340,8 @@
 msgid "Please enter a reference"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:409
-#: src/components/map/fairway/Profiles.vue:410
+#: src/components/map/fairway/Profiles.vue:413
+#: src/components/map/fairway/Profiles.vue:414
 msgid "Please enter correct coordinates in the format: Lat,Lon,Lat,Lon"
 msgstr ""
 
@@ -358,11 +358,11 @@
 msgid "portrait"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:448
+#: src/components/map/fairway/Profiles.vue:452
 msgid "Profile deleted!"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:434
+#: src/components/map/fairway/Profiles.vue:438
 msgid "Profile saved!"
 msgstr ""
 
@@ -374,7 +374,7 @@
 msgid "Projection"
 msgstr ""
 
-#: src/components/admin/Importqueue.vue:70 src/components/admin/Logs.vue:48
+#: src/components/admin/Importqueue.vue:72 src/components/admin/Logs.vue:48
 msgid "Refresh"
 msgstr ""
 
@@ -414,6 +414,10 @@
 msgid "Send testmail"
 msgstr ""
 
+#: src/components/admin/Importqueue.vue:56
+msgid "Signer"
+msgstr ""
+
 #: src/components/map/Identify.vue:63
 msgid ""
 "Some data ©\n"
@@ -429,7 +433,7 @@
 msgid "source-code"
 msgstr ""
 
-#: src/components/Sidebar.vue:44
+#: src/components/Sidebar.vue:54
 msgid "Staging area"
 msgstr ""
 
@@ -445,7 +449,7 @@
 msgid "Starting import for "
 msgstr ""
 
-#: src/components/admin/Importqueue.vue:56
+#: src/components/admin/Importqueue.vue:57
 msgid "State"
 msgstr ""
 
@@ -453,7 +457,7 @@
 msgid "Submit"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:373
+#: src/components/map/fairway/Profiles.vue:377
 msgid "Success"
 msgstr ""
 
@@ -465,7 +469,7 @@
 msgid "Sysadmin"
 msgstr ""
 
-#: src/components/Sidebar.vue:47
+#: src/components/Sidebar.vue:57
 msgid "Systemadministration"
 msgstr ""
 
@@ -497,7 +501,7 @@
 msgid "Username"
 msgstr ""
 
-#: src/components/Sidebar.vue:52
+#: src/components/Sidebar.vue:66
 #: src/components/admin/usermanagement/Usermanagement.vue:14
 msgid "Users"
 msgstr ""
@@ -516,7 +520,15 @@
 msgid "Waterway User"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:435
-#: src/components/map/fairway/Profiles.vue:436
+#: src/components/map/fairway/Profiles.vue:439
+#: src/components/map/fairway/Profiles.vue:440
 msgid "You can now select these coordinates from the \"Saved cross profiles\" menu to restore this cross profile."
 msgstr ""
+
+#: src/store/map.js:415
+msgid "Length"
+msgstr ""
+
+#: src/store/map.js:436
+msgid "Area"
+msgstr ""
--- a/client/src/locale/en_GB/LC_MESSAGES/app.po	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/locale/en_GB/LC_MESSAGES/app.po	Mon Dec 10 15:29:14 2018 +0100
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: wamosjs 0.1.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-12-05 12:03+0100\n"
+"POT-Creation-Date: 2018-12-07 10:05+0100\n"
 "PO-Revision-Date: 2018-07-03 17:18+0200\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -37,7 +37,7 @@
 msgid "back to login"
 msgstr ""
 
-#: src/components/admin/Importqueue.vue:134
+#: src/components/admin/Importqueue.vue:136
 #: src/components/admin/Systemconfiguration.vue:133
 #: src/components/admin/Systemconfiguration.vue:148
 #: src/components/admin/Systemconfiguration.vue:167
@@ -48,7 +48,7 @@
 #: src/components/admin/usermanagement/Usermanagement.vue:308
 #: src/components/admin/usermanagement/Usermanagement.vue:334
 #: src/components/map/Search.vue:257
-#: src/components/map/contextbox/Bottlenecks.vue:252
+#: src/components/map/contextbox/Bottlenecks.vue:275
 #: src/components/map/contextbox/ImportSoundingresults.vue:205
 #: src/components/map/contextbox/ImportSoundingresults.vue:244
 #: src/components/map/contextbox/ImportSoundingresults.vue:275
@@ -67,7 +67,7 @@
 msgid "Bottleneck Areas stroke-color"
 msgstr ""
 
-#: src/components/Sidebar.vue:22
+#: src/components/Sidebar.vue:27
 #: src/components/map/contextbox/Bottlenecks.vue:4
 msgid "Bottlenecks"
 msgstr ""
@@ -93,7 +93,7 @@
 msgid "Compare with"
 msgstr ""
 
-#: src/components/Sidebar.vue:58
+#: src/components/Sidebar.vue:76
 msgid "Configuration"
 msgstr ""
 
@@ -102,7 +102,7 @@
 msgid "Confirm"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:374
+#: src/components/map/fairway/Profiles.vue:378
 msgid "Coordinates copied to clipboard!"
 msgstr ""
 
@@ -184,7 +184,7 @@
 msgid "Import"
 msgstr ""
 
-#: src/components/Sidebar.vue:31
+#: src/components/Sidebar.vue:40
 msgid "Import soundingresults"
 msgstr ""
 
@@ -196,11 +196,11 @@
 msgid "Imported"
 msgstr ""
 
-#: src/components/Sidebar.vue:66 src/components/admin/Importqueue.vue:9
+#: src/components/Sidebar.vue:92 src/components/admin/Importqueue.vue:9
 msgid "Importqueue"
 msgstr ""
 
-#: src/components/Sidebar.vue:70
+#: src/components/Sidebar.vue:100
 #: src/components/admin/importschedule/Importschedule.vue:9
 msgid "Importschedule"
 msgstr ""
@@ -209,7 +209,7 @@
 msgid "invalid email"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:408
+#: src/components/map/fairway/Profiles.vue:412
 msgid "Invalid input"
 msgstr ""
 
@@ -241,11 +241,11 @@
 msgid "Login failed"
 msgstr ""
 
-#: src/components/Sidebar.vue:76
+#: src/components/Sidebar.vue:110
 msgid "Logout"
 msgstr ""
 
-#: src/components/Sidebar.vue:62 src/components/admin/Logs.vue:9
+#: src/components/Sidebar.vue:84 src/components/admin/Logs.vue:9
 msgid "Logs"
 msgstr ""
 
@@ -253,7 +253,7 @@
 msgid "Mail was sent"
 msgstr ""
 
-#: src/components/Sidebar.vue:14
+#: src/components/Sidebar.vue:15
 msgid "Map"
 msgstr ""
 
@@ -340,8 +340,8 @@
 msgid "Please enter a reference"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:409
-#: src/components/map/fairway/Profiles.vue:410
+#: src/components/map/fairway/Profiles.vue:413
+#: src/components/map/fairway/Profiles.vue:414
 msgid "Please enter correct coordinates in the format: Lat,Lon,Lat,Lon"
 msgstr ""
 
@@ -358,11 +358,11 @@
 msgid "portrait"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:448
+#: src/components/map/fairway/Profiles.vue:452
 msgid "Profile deleted!"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:434
+#: src/components/map/fairway/Profiles.vue:438
 msgid "Profile saved!"
 msgstr ""
 
@@ -374,7 +374,7 @@
 msgid "Projection"
 msgstr ""
 
-#: src/components/admin/Importqueue.vue:70 src/components/admin/Logs.vue:48
+#: src/components/admin/Importqueue.vue:72 src/components/admin/Logs.vue:48
 msgid "Refresh"
 msgstr ""
 
@@ -414,6 +414,10 @@
 msgid "Send testmail"
 msgstr ""
 
+#: src/components/admin/Importqueue.vue:56
+msgid "Signer"
+msgstr ""
+
 #: src/components/map/Identify.vue:63
 msgid ""
 "Some data ©\n"
@@ -429,7 +433,7 @@
 msgid "source-code"
 msgstr ""
 
-#: src/components/Sidebar.vue:44
+#: src/components/Sidebar.vue:54
 msgid "Staging area"
 msgstr ""
 
@@ -445,7 +449,7 @@
 msgid "Starting import for "
 msgstr ""
 
-#: src/components/admin/Importqueue.vue:56
+#: src/components/admin/Importqueue.vue:57
 msgid "State"
 msgstr ""
 
@@ -453,7 +457,7 @@
 msgid "Submit"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:373
+#: src/components/map/fairway/Profiles.vue:377
 msgid "Success"
 msgstr ""
 
@@ -465,7 +469,7 @@
 msgid "Sysadmin"
 msgstr ""
 
-#: src/components/Sidebar.vue:47
+#: src/components/Sidebar.vue:57
 msgid "Systemadministration"
 msgstr ""
 
@@ -497,7 +501,7 @@
 msgid "Username"
 msgstr ""
 
-#: src/components/Sidebar.vue:52
+#: src/components/Sidebar.vue:66
 #: src/components/admin/usermanagement/Usermanagement.vue:14
 msgid "Users"
 msgstr ""
@@ -516,7 +520,15 @@
 msgid "Waterway User"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:435
-#: src/components/map/fairway/Profiles.vue:436
+#: src/components/map/fairway/Profiles.vue:439
+#: src/components/map/fairway/Profiles.vue:440
 msgid "You can now select these coordinates from the \"Saved cross profiles\" menu to restore this cross profile."
 msgstr ""
+
+#: src/store/map.js:415
+msgid "Length"
+msgstr ""
+
+#: src/store/map.js:436
+msgid "Area"
+msgstr ""
--- a/client/src/locale/hr_HR/LC_MESSAGES/app.po	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/locale/hr_HR/LC_MESSAGES/app.po	Mon Dec 10 15:29:14 2018 +0100
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: gemmajs 1.99.0-dev\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-12-05 12:25+0100\n"
+"POT-Creation-Date: 2018-12-07 10:05+0100\n"
 "PO-Revision-Date: 2018-12-05 12:23+0100\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -37,7 +37,7 @@
 msgid "back to login"
 msgstr ""
 
-#: src/components/admin/Importqueue.vue:134
+#: src/components/admin/Importqueue.vue:136
 #: src/components/admin/Systemconfiguration.vue:133
 #: src/components/admin/Systemconfiguration.vue:148
 #: src/components/admin/Systemconfiguration.vue:167
@@ -48,7 +48,7 @@
 #: src/components/admin/usermanagement/Usermanagement.vue:308
 #: src/components/admin/usermanagement/Usermanagement.vue:334
 #: src/components/map/Search.vue:257
-#: src/components/map/contextbox/Bottlenecks.vue:252
+#: src/components/map/contextbox/Bottlenecks.vue:275
 #: src/components/map/contextbox/ImportSoundingresults.vue:205
 #: src/components/map/contextbox/ImportSoundingresults.vue:244
 #: src/components/map/contextbox/ImportSoundingresults.vue:275
@@ -67,7 +67,7 @@
 msgid "Bottleneck Areas stroke-color"
 msgstr ""
 
-#: src/components/Sidebar.vue:22
+#: src/components/Sidebar.vue:27
 #: src/components/map/contextbox/Bottlenecks.vue:4
 msgid "Bottlenecks"
 msgstr ""
@@ -93,7 +93,7 @@
 msgid "Compare with"
 msgstr ""
 
-#: src/components/Sidebar.vue:58
+#: src/components/Sidebar.vue:76
 msgid "Configuration"
 msgstr ""
 
@@ -102,7 +102,7 @@
 msgid "Confirm"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:374
+#: src/components/map/fairway/Profiles.vue:378
 msgid "Coordinates copied to clipboard!"
 msgstr ""
 
@@ -184,7 +184,7 @@
 msgid "Import"
 msgstr ""
 
-#: src/components/Sidebar.vue:31
+#: src/components/Sidebar.vue:40
 msgid "Import soundingresults"
 msgstr ""
 
@@ -196,11 +196,11 @@
 msgid "Imported"
 msgstr ""
 
-#: src/components/Sidebar.vue:66 src/components/admin/Importqueue.vue:9
+#: src/components/Sidebar.vue:92 src/components/admin/Importqueue.vue:9
 msgid "Importqueue"
 msgstr ""
 
-#: src/components/Sidebar.vue:70
+#: src/components/Sidebar.vue:100
 #: src/components/admin/importschedule/Importschedule.vue:9
 msgid "Importschedule"
 msgstr ""
@@ -209,7 +209,7 @@
 msgid "invalid email"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:408
+#: src/components/map/fairway/Profiles.vue:412
 msgid "Invalid input"
 msgstr ""
 
@@ -241,11 +241,11 @@
 msgid "Login failed"
 msgstr ""
 
-#: src/components/Sidebar.vue:76
+#: src/components/Sidebar.vue:110
 msgid "Logout"
 msgstr ""
 
-#: src/components/Sidebar.vue:62 src/components/admin/Logs.vue:9
+#: src/components/Sidebar.vue:84 src/components/admin/Logs.vue:9
 msgid "Logs"
 msgstr ""
 
@@ -253,7 +253,7 @@
 msgid "Mail was sent"
 msgstr ""
 
-#: src/components/Sidebar.vue:14
+#: src/components/Sidebar.vue:15
 msgid "Map"
 msgstr ""
 
@@ -340,8 +340,8 @@
 msgid "Please enter a reference"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:409
-#: src/components/map/fairway/Profiles.vue:410
+#: src/components/map/fairway/Profiles.vue:413
+#: src/components/map/fairway/Profiles.vue:414
 msgid "Please enter correct coordinates in the format: Lat,Lon,Lat,Lon"
 msgstr ""
 
@@ -358,11 +358,11 @@
 msgid "portrait"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:448
+#: src/components/map/fairway/Profiles.vue:452
 msgid "Profile deleted!"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:434
+#: src/components/map/fairway/Profiles.vue:438
 msgid "Profile saved!"
 msgstr ""
 
@@ -374,7 +374,7 @@
 msgid "Projection"
 msgstr ""
 
-#: src/components/admin/Importqueue.vue:70 src/components/admin/Logs.vue:48
+#: src/components/admin/Importqueue.vue:72 src/components/admin/Logs.vue:48
 msgid "Refresh"
 msgstr ""
 
@@ -414,6 +414,10 @@
 msgid "Send testmail"
 msgstr ""
 
+#: src/components/admin/Importqueue.vue:56
+msgid "Signer"
+msgstr ""
+
 #: src/components/map/Identify.vue:63
 msgid ""
 "Some data ©\n"
@@ -429,7 +433,7 @@
 msgid "source-code"
 msgstr ""
 
-#: src/components/Sidebar.vue:44
+#: src/components/Sidebar.vue:54
 msgid "Staging area"
 msgstr ""
 
@@ -445,7 +449,7 @@
 msgid "Starting import for "
 msgstr ""
 
-#: src/components/admin/Importqueue.vue:56
+#: src/components/admin/Importqueue.vue:57
 msgid "State"
 msgstr ""
 
@@ -453,7 +457,7 @@
 msgid "Submit"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:373
+#: src/components/map/fairway/Profiles.vue:377
 msgid "Success"
 msgstr ""
 
@@ -465,7 +469,7 @@
 msgid "Sysadmin"
 msgstr ""
 
-#: src/components/Sidebar.vue:47
+#: src/components/Sidebar.vue:57
 msgid "Systemadministration"
 msgstr ""
 
@@ -497,7 +501,7 @@
 msgid "Username"
 msgstr ""
 
-#: src/components/Sidebar.vue:52
+#: src/components/Sidebar.vue:66
 #: src/components/admin/usermanagement/Usermanagement.vue:14
 msgid "Users"
 msgstr ""
@@ -516,7 +520,15 @@
 msgid "Waterway User"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:435
-#: src/components/map/fairway/Profiles.vue:436
+#: src/components/map/fairway/Profiles.vue:439
+#: src/components/map/fairway/Profiles.vue:440
 msgid "You can now select these coordinates from the \"Saved cross profiles\" menu to restore this cross profile."
 msgstr ""
+
+#: src/store/map.js:415
+msgid "Length"
+msgstr ""
+
+#: src/store/map.js:436
+msgid "Area"
+msgstr ""
--- a/client/src/locale/hu_HU/LC_MESSAGES/app.po	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/locale/hu_HU/LC_MESSAGES/app.po	Mon Dec 10 15:29:14 2018 +0100
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: gemmajs 1.99.0-dev\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-12-05 12:25+0100\n"
+"POT-Creation-Date: 2018-12-07 10:05+0100\n"
 "PO-Revision-Date: 2018-12-05 12:23+0100\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -37,7 +37,7 @@
 msgid "back to login"
 msgstr ""
 
-#: src/components/admin/Importqueue.vue:134
+#: src/components/admin/Importqueue.vue:136
 #: src/components/admin/Systemconfiguration.vue:133
 #: src/components/admin/Systemconfiguration.vue:148
 #: src/components/admin/Systemconfiguration.vue:167
@@ -48,7 +48,7 @@
 #: src/components/admin/usermanagement/Usermanagement.vue:308
 #: src/components/admin/usermanagement/Usermanagement.vue:334
 #: src/components/map/Search.vue:257
-#: src/components/map/contextbox/Bottlenecks.vue:252
+#: src/components/map/contextbox/Bottlenecks.vue:275
 #: src/components/map/contextbox/ImportSoundingresults.vue:205
 #: src/components/map/contextbox/ImportSoundingresults.vue:244
 #: src/components/map/contextbox/ImportSoundingresults.vue:275
@@ -67,7 +67,7 @@
 msgid "Bottleneck Areas stroke-color"
 msgstr ""
 
-#: src/components/Sidebar.vue:22
+#: src/components/Sidebar.vue:27
 #: src/components/map/contextbox/Bottlenecks.vue:4
 msgid "Bottlenecks"
 msgstr ""
@@ -93,7 +93,7 @@
 msgid "Compare with"
 msgstr ""
 
-#: src/components/Sidebar.vue:58
+#: src/components/Sidebar.vue:76
 msgid "Configuration"
 msgstr ""
 
@@ -102,7 +102,7 @@
 msgid "Confirm"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:374
+#: src/components/map/fairway/Profiles.vue:378
 msgid "Coordinates copied to clipboard!"
 msgstr ""
 
@@ -184,7 +184,7 @@
 msgid "Import"
 msgstr ""
 
-#: src/components/Sidebar.vue:31
+#: src/components/Sidebar.vue:40
 msgid "Import soundingresults"
 msgstr ""
 
@@ -196,11 +196,11 @@
 msgid "Imported"
 msgstr ""
 
-#: src/components/Sidebar.vue:66 src/components/admin/Importqueue.vue:9
+#: src/components/Sidebar.vue:92 src/components/admin/Importqueue.vue:9
 msgid "Importqueue"
 msgstr ""
 
-#: src/components/Sidebar.vue:70
+#: src/components/Sidebar.vue:100
 #: src/components/admin/importschedule/Importschedule.vue:9
 msgid "Importschedule"
 msgstr ""
@@ -209,7 +209,7 @@
 msgid "invalid email"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:408
+#: src/components/map/fairway/Profiles.vue:412
 msgid "Invalid input"
 msgstr ""
 
@@ -241,11 +241,11 @@
 msgid "Login failed"
 msgstr ""
 
-#: src/components/Sidebar.vue:76
+#: src/components/Sidebar.vue:110
 msgid "Logout"
 msgstr ""
 
-#: src/components/Sidebar.vue:62 src/components/admin/Logs.vue:9
+#: src/components/Sidebar.vue:84 src/components/admin/Logs.vue:9
 msgid "Logs"
 msgstr ""
 
@@ -253,7 +253,7 @@
 msgid "Mail was sent"
 msgstr ""
 
-#: src/components/Sidebar.vue:14
+#: src/components/Sidebar.vue:15
 msgid "Map"
 msgstr ""
 
@@ -340,8 +340,8 @@
 msgid "Please enter a reference"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:409
-#: src/components/map/fairway/Profiles.vue:410
+#: src/components/map/fairway/Profiles.vue:413
+#: src/components/map/fairway/Profiles.vue:414
 msgid "Please enter correct coordinates in the format: Lat,Lon,Lat,Lon"
 msgstr ""
 
@@ -358,11 +358,11 @@
 msgid "portrait"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:448
+#: src/components/map/fairway/Profiles.vue:452
 msgid "Profile deleted!"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:434
+#: src/components/map/fairway/Profiles.vue:438
 msgid "Profile saved!"
 msgstr ""
 
@@ -374,7 +374,7 @@
 msgid "Projection"
 msgstr ""
 
-#: src/components/admin/Importqueue.vue:70 src/components/admin/Logs.vue:48
+#: src/components/admin/Importqueue.vue:72 src/components/admin/Logs.vue:48
 msgid "Refresh"
 msgstr ""
 
@@ -414,6 +414,10 @@
 msgid "Send testmail"
 msgstr ""
 
+#: src/components/admin/Importqueue.vue:56
+msgid "Signer"
+msgstr ""
+
 #: src/components/map/Identify.vue:63
 msgid ""
 "Some data ©\n"
@@ -429,7 +433,7 @@
 msgid "source-code"
 msgstr ""
 
-#: src/components/Sidebar.vue:44
+#: src/components/Sidebar.vue:54
 msgid "Staging area"
 msgstr ""
 
@@ -445,7 +449,7 @@
 msgid "Starting import for "
 msgstr ""
 
-#: src/components/admin/Importqueue.vue:56
+#: src/components/admin/Importqueue.vue:57
 msgid "State"
 msgstr ""
 
@@ -453,7 +457,7 @@
 msgid "Submit"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:373
+#: src/components/map/fairway/Profiles.vue:377
 msgid "Success"
 msgstr ""
 
@@ -465,7 +469,7 @@
 msgid "Sysadmin"
 msgstr ""
 
-#: src/components/Sidebar.vue:47
+#: src/components/Sidebar.vue:57
 msgid "Systemadministration"
 msgstr ""
 
@@ -497,7 +501,7 @@
 msgid "Username"
 msgstr ""
 
-#: src/components/Sidebar.vue:52
+#: src/components/Sidebar.vue:66
 #: src/components/admin/usermanagement/Usermanagement.vue:14
 msgid "Users"
 msgstr ""
@@ -516,7 +520,15 @@
 msgid "Waterway User"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:435
-#: src/components/map/fairway/Profiles.vue:436
+#: src/components/map/fairway/Profiles.vue:439
+#: src/components/map/fairway/Profiles.vue:440
 msgid "You can now select these coordinates from the \"Saved cross profiles\" menu to restore this cross profile."
 msgstr ""
+
+#: src/store/map.js:415
+msgid "Length"
+msgstr ""
+
+#: src/store/map.js:436
+msgid "Area"
+msgstr ""
--- a/client/src/locale/ro_RO/LC_MESSAGES/app.po	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/locale/ro_RO/LC_MESSAGES/app.po	Mon Dec 10 15:29:14 2018 +0100
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: gemmajs 1.99.0-dev\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-12-05 12:25+0100\n"
+"POT-Creation-Date: 2018-12-07 10:05+0100\n"
 "PO-Revision-Date: 2018-12-05 12:23+0100\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -37,7 +37,7 @@
 msgid "back to login"
 msgstr ""
 
-#: src/components/admin/Importqueue.vue:134
+#: src/components/admin/Importqueue.vue:136
 #: src/components/admin/Systemconfiguration.vue:133
 #: src/components/admin/Systemconfiguration.vue:148
 #: src/components/admin/Systemconfiguration.vue:167
@@ -48,7 +48,7 @@
 #: src/components/admin/usermanagement/Usermanagement.vue:308
 #: src/components/admin/usermanagement/Usermanagement.vue:334
 #: src/components/map/Search.vue:257
-#: src/components/map/contextbox/Bottlenecks.vue:252
+#: src/components/map/contextbox/Bottlenecks.vue:275
 #: src/components/map/contextbox/ImportSoundingresults.vue:205
 #: src/components/map/contextbox/ImportSoundingresults.vue:244
 #: src/components/map/contextbox/ImportSoundingresults.vue:275
@@ -67,7 +67,7 @@
 msgid "Bottleneck Areas stroke-color"
 msgstr ""
 
-#: src/components/Sidebar.vue:22
+#: src/components/Sidebar.vue:27
 #: src/components/map/contextbox/Bottlenecks.vue:4
 msgid "Bottlenecks"
 msgstr ""
@@ -93,7 +93,7 @@
 msgid "Compare with"
 msgstr ""
 
-#: src/components/Sidebar.vue:58
+#: src/components/Sidebar.vue:76
 msgid "Configuration"
 msgstr ""
 
@@ -102,7 +102,7 @@
 msgid "Confirm"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:374
+#: src/components/map/fairway/Profiles.vue:378
 msgid "Coordinates copied to clipboard!"
 msgstr ""
 
@@ -184,7 +184,7 @@
 msgid "Import"
 msgstr ""
 
-#: src/components/Sidebar.vue:31
+#: src/components/Sidebar.vue:40
 msgid "Import soundingresults"
 msgstr ""
 
@@ -196,11 +196,11 @@
 msgid "Imported"
 msgstr ""
 
-#: src/components/Sidebar.vue:66 src/components/admin/Importqueue.vue:9
+#: src/components/Sidebar.vue:92 src/components/admin/Importqueue.vue:9
 msgid "Importqueue"
 msgstr ""
 
-#: src/components/Sidebar.vue:70
+#: src/components/Sidebar.vue:100
 #: src/components/admin/importschedule/Importschedule.vue:9
 msgid "Importschedule"
 msgstr ""
@@ -209,7 +209,7 @@
 msgid "invalid email"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:408
+#: src/components/map/fairway/Profiles.vue:412
 msgid "Invalid input"
 msgstr ""
 
@@ -241,11 +241,11 @@
 msgid "Login failed"
 msgstr ""
 
-#: src/components/Sidebar.vue:76
+#: src/components/Sidebar.vue:110
 msgid "Logout"
 msgstr ""
 
-#: src/components/Sidebar.vue:62 src/components/admin/Logs.vue:9
+#: src/components/Sidebar.vue:84 src/components/admin/Logs.vue:9
 msgid "Logs"
 msgstr ""
 
@@ -253,7 +253,7 @@
 msgid "Mail was sent"
 msgstr ""
 
-#: src/components/Sidebar.vue:14
+#: src/components/Sidebar.vue:15
 msgid "Map"
 msgstr ""
 
@@ -340,8 +340,8 @@
 msgid "Please enter a reference"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:409
-#: src/components/map/fairway/Profiles.vue:410
+#: src/components/map/fairway/Profiles.vue:413
+#: src/components/map/fairway/Profiles.vue:414
 msgid "Please enter correct coordinates in the format: Lat,Lon,Lat,Lon"
 msgstr ""
 
@@ -358,11 +358,11 @@
 msgid "portrait"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:448
+#: src/components/map/fairway/Profiles.vue:452
 msgid "Profile deleted!"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:434
+#: src/components/map/fairway/Profiles.vue:438
 msgid "Profile saved!"
 msgstr ""
 
@@ -374,7 +374,7 @@
 msgid "Projection"
 msgstr ""
 
-#: src/components/admin/Importqueue.vue:70 src/components/admin/Logs.vue:48
+#: src/components/admin/Importqueue.vue:72 src/components/admin/Logs.vue:48
 msgid "Refresh"
 msgstr ""
 
@@ -414,6 +414,10 @@
 msgid "Send testmail"
 msgstr ""
 
+#: src/components/admin/Importqueue.vue:56
+msgid "Signer"
+msgstr ""
+
 #: src/components/map/Identify.vue:63
 msgid ""
 "Some data ©\n"
@@ -429,7 +433,7 @@
 msgid "source-code"
 msgstr ""
 
-#: src/components/Sidebar.vue:44
+#: src/components/Sidebar.vue:54
 msgid "Staging area"
 msgstr ""
 
@@ -445,7 +449,7 @@
 msgid "Starting import for "
 msgstr ""
 
-#: src/components/admin/Importqueue.vue:56
+#: src/components/admin/Importqueue.vue:57
 msgid "State"
 msgstr ""
 
@@ -453,7 +457,7 @@
 msgid "Submit"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:373
+#: src/components/map/fairway/Profiles.vue:377
 msgid "Success"
 msgstr ""
 
@@ -465,7 +469,7 @@
 msgid "Sysadmin"
 msgstr ""
 
-#: src/components/Sidebar.vue:47
+#: src/components/Sidebar.vue:57
 msgid "Systemadministration"
 msgstr ""
 
@@ -497,7 +501,7 @@
 msgid "Username"
 msgstr ""
 
-#: src/components/Sidebar.vue:52
+#: src/components/Sidebar.vue:66
 #: src/components/admin/usermanagement/Usermanagement.vue:14
 msgid "Users"
 msgstr ""
@@ -516,7 +520,15 @@
 msgid "Waterway User"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:435
-#: src/components/map/fairway/Profiles.vue:436
+#: src/components/map/fairway/Profiles.vue:439
+#: src/components/map/fairway/Profiles.vue:440
 msgid "You can now select these coordinates from the \"Saved cross profiles\" menu to restore this cross profile."
 msgstr ""
+
+#: src/store/map.js:415
+msgid "Length"
+msgstr ""
+
+#: src/store/map.js:436
+msgid "Area"
+msgstr ""
--- a/client/src/locale/sk_SK/LC_MESSAGES/app.po	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/locale/sk_SK/LC_MESSAGES/app.po	Mon Dec 10 15:29:14 2018 +0100
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: wamosjs 0.1.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-12-05 12:03+0100\n"
+"POT-Creation-Date: 2018-12-07 10:05+0100\n"
 "PO-Revision-Date: 2018-07-03 17:18+0200\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"
@@ -37,7 +37,7 @@
 msgid "back to login"
 msgstr ""
 
-#: src/components/admin/Importqueue.vue:134
+#: src/components/admin/Importqueue.vue:136
 #: src/components/admin/Systemconfiguration.vue:133
 #: src/components/admin/Systemconfiguration.vue:148
 #: src/components/admin/Systemconfiguration.vue:167
@@ -48,7 +48,7 @@
 #: src/components/admin/usermanagement/Usermanagement.vue:308
 #: src/components/admin/usermanagement/Usermanagement.vue:334
 #: src/components/map/Search.vue:257
-#: src/components/map/contextbox/Bottlenecks.vue:252
+#: src/components/map/contextbox/Bottlenecks.vue:275
 #: src/components/map/contextbox/ImportSoundingresults.vue:205
 #: src/components/map/contextbox/ImportSoundingresults.vue:244
 #: src/components/map/contextbox/ImportSoundingresults.vue:275
@@ -67,7 +67,7 @@
 msgid "Bottleneck Areas stroke-color"
 msgstr ""
 
-#: src/components/Sidebar.vue:22
+#: src/components/Sidebar.vue:27
 #: src/components/map/contextbox/Bottlenecks.vue:4
 msgid "Bottlenecks"
 msgstr ""
@@ -93,7 +93,7 @@
 msgid "Compare with"
 msgstr ""
 
-#: src/components/Sidebar.vue:58
+#: src/components/Sidebar.vue:76
 msgid "Configuration"
 msgstr ""
 
@@ -102,7 +102,7 @@
 msgid "Confirm"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:374
+#: src/components/map/fairway/Profiles.vue:378
 msgid "Coordinates copied to clipboard!"
 msgstr ""
 
@@ -184,7 +184,7 @@
 msgid "Import"
 msgstr ""
 
-#: src/components/Sidebar.vue:31
+#: src/components/Sidebar.vue:40
 msgid "Import soundingresults"
 msgstr ""
 
@@ -196,11 +196,11 @@
 msgid "Imported"
 msgstr ""
 
-#: src/components/Sidebar.vue:66 src/components/admin/Importqueue.vue:9
+#: src/components/Sidebar.vue:92 src/components/admin/Importqueue.vue:9
 msgid "Importqueue"
 msgstr ""
 
-#: src/components/Sidebar.vue:70
+#: src/components/Sidebar.vue:100
 #: src/components/admin/importschedule/Importschedule.vue:9
 msgid "Importschedule"
 msgstr ""
@@ -209,7 +209,7 @@
 msgid "invalid email"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:408
+#: src/components/map/fairway/Profiles.vue:412
 msgid "Invalid input"
 msgstr ""
 
@@ -241,11 +241,11 @@
 msgid "Login failed"
 msgstr ""
 
-#: src/components/Sidebar.vue:76
+#: src/components/Sidebar.vue:110
 msgid "Logout"
 msgstr ""
 
-#: src/components/Sidebar.vue:62 src/components/admin/Logs.vue:9
+#: src/components/Sidebar.vue:84 src/components/admin/Logs.vue:9
 msgid "Logs"
 msgstr ""
 
@@ -253,7 +253,7 @@
 msgid "Mail was sent"
 msgstr ""
 
-#: src/components/Sidebar.vue:14
+#: src/components/Sidebar.vue:15
 msgid "Map"
 msgstr ""
 
@@ -340,8 +340,8 @@
 msgid "Please enter a reference"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:409
-#: src/components/map/fairway/Profiles.vue:410
+#: src/components/map/fairway/Profiles.vue:413
+#: src/components/map/fairway/Profiles.vue:414
 msgid "Please enter correct coordinates in the format: Lat,Lon,Lat,Lon"
 msgstr ""
 
@@ -358,11 +358,11 @@
 msgid "portrait"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:448
+#: src/components/map/fairway/Profiles.vue:452
 msgid "Profile deleted!"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:434
+#: src/components/map/fairway/Profiles.vue:438
 msgid "Profile saved!"
 msgstr ""
 
@@ -374,7 +374,7 @@
 msgid "Projection"
 msgstr ""
 
-#: src/components/admin/Importqueue.vue:70 src/components/admin/Logs.vue:48
+#: src/components/admin/Importqueue.vue:72 src/components/admin/Logs.vue:48
 msgid "Refresh"
 msgstr ""
 
@@ -414,6 +414,10 @@
 msgid "Send testmail"
 msgstr ""
 
+#: src/components/admin/Importqueue.vue:56
+msgid "Signer"
+msgstr ""
+
 #: src/components/map/Identify.vue:63
 msgid ""
 "Some data ©\n"
@@ -429,7 +433,7 @@
 msgid "source-code"
 msgstr ""
 
-#: src/components/Sidebar.vue:44
+#: src/components/Sidebar.vue:54
 msgid "Staging area"
 msgstr ""
 
@@ -445,7 +449,7 @@
 msgid "Starting import for "
 msgstr ""
 
-#: src/components/admin/Importqueue.vue:56
+#: src/components/admin/Importqueue.vue:57
 msgid "State"
 msgstr ""
 
@@ -453,7 +457,7 @@
 msgid "Submit"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:373
+#: src/components/map/fairway/Profiles.vue:377
 msgid "Success"
 msgstr ""
 
@@ -465,7 +469,7 @@
 msgid "Sysadmin"
 msgstr ""
 
-#: src/components/Sidebar.vue:47
+#: src/components/Sidebar.vue:57
 msgid "Systemadministration"
 msgstr ""
 
@@ -497,7 +501,7 @@
 msgid "Username"
 msgstr ""
 
-#: src/components/Sidebar.vue:52
+#: src/components/Sidebar.vue:66
 #: src/components/admin/usermanagement/Usermanagement.vue:14
 msgid "Users"
 msgstr ""
@@ -516,7 +520,15 @@
 msgid "Waterway User"
 msgstr ""
 
-#: src/components/map/fairway/Profiles.vue:435
-#: src/components/map/fairway/Profiles.vue:436
+#: src/components/map/fairway/Profiles.vue:439
+#: src/components/map/fairway/Profiles.vue:440
 msgid "You can now select these coordinates from the \"Saved cross profiles\" menu to restore this cross profile."
 msgstr ""
+
+#: src/store/map.js:415
+msgid "Length"
+msgstr ""
+
+#: src/store/map.js:436
+msgid "Area"
+msgstr ""
--- a/client/src/locale/translations.json	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/locale/translations.json	Mon Dec 10 15:29:14 2018 +0100
@@ -1,1 +1,1 @@
-{"bg_BG":{},"de_AT":{"Accepted":"Akzeptiert","Accesslog":"Zugriffs-Protokoll","Add User":"Benutzer hinzufügen","Author":"Autor","back to login":"zurück zur Anmeldung","Backend Error":"Server-Fehler","Bottleneck":"Engstelle","Bottleneck Areas fill-color":"Flächenfüllfarbe Engstelle","Bottleneck Areas stroke-color":"Flächenumrandungsfarbe Engstelle","Bottlenecks":"Engstellen","Cancel Upload":"Hochladen abbrechen","Chainage":"Verkettung","choose .zip- file":"Wählen Sie eine .zip Datei","Chose format:":"Format wählen:","Compare with":"Vergleiche mit","Configuration":"Konfiguration","Confirm":"Bestätigen","Coordinates copied to clipboard!":"Koordinaten auf die Zwischenablage kopiert!","Country":"Land","Date":"Datum","Depthreference":"Tiefenreferenz","Download":"Herunterladen","Download Meta.json":"Meta.json Herunterladen","Email":"E-Mail","Email address":"E-Mail Adresse","Enqueued":"Hinzugefügt","Enter coordinates manually":"Manuelle Koordinateneingabe","Enter label for cross profile":"Namen für Profilschnitt eingeben","Enter passphrase":"Passphrase eingeben","Errorlog":"Fehlerprotokoll","Failed":"Fehlgeschlagen","Forgot password":"Passwort vergessen","Generate PDF":"PDF generieren","Identified":"Identifiziert","Import":"Daten-Import","Import soundingresults":"Seichtstellenmessungen importieren","Import Soundingresults":"Seichtstellenmessungen importieren","Imported":"Importiert","Importqueue":"Import-Warteschlange","Importschedule":"Import-Zeitplan","Invalid input":"Ungültige Eingabe","Kind":"Art","landscape":"Querformat","Last refresh:":"Letzter Abgleich:","Latest":"Neustes","Layers":"Schichten","Login":"Login","Login failed":"Login fehlgeschlagen","Logout":"Abmelden","Logs":"Protokolle","Mail was sent":"E-Mail wurde gesendet","Map":"Karte","Measurement":"Messung","Name":"Name","New Import":"Neuer Import","No features identified.":"Keine Objekte identifiziert.","No results.":"Keine Ergebnisse.","No schedules":"Keine Pläne","Open in new window":"In neuem Fenster öffnen","Password reset requested!":"Passwort Zurücksetzung angefragt!","Pending":"Ausstehend","Please enter a date":"Bitte ein Datum eingeben","Please enter a projection":"Bitte eine Projektion eingeben","Please enter a reference":"Bitte ein Höhenreferenzsystem eingeben","Please enter correct coordinates in the format: Lat,Lon,Lat,Lon":"Bitte geben Sie die Koordinaten in folgendem Format an: Lat,Lon,Lat,Lon","Please select a bottleneck":"Bitte eine Seichtstelle wählen","Please select one":"Bitte auswählen","portrait":"Hochformat","Profile deleted!":"Profil gelöscht!","Profile saved!":"Profil gespeichert!","Profiles":"Profile","Projection":"Projektion","Refresh":"Aktualisieren","Rejected":"Abgelehnt","Request password reset!":"Passwort-Zurücksetzung anfragen!","Role":"Rolle","Saved cross profiles":"Gespeicherte Profile","Schedule":"Zeitplan","Select Bottleneck":"Wähle Engstelle","Send":"Absenden","Send testmail":"Test-E-Mail versenden","Sounding Result":"Seichtstellenvermessungsergebnisse","source-code":"Quelltext","Staging area":"Import-Überprüfung","Staging Area":"Import-Überprüfung","Start":"Start","Starting import for ":"Import gestartet ","State":"Zustand","Submit":"Abschicken","Success":"Erfolg","Successful":"Erfolgreich","Sysadmin":"Sys-Admin","Systemadministration":"System-Administration","Systemconfiguration":"System-Konfiguation","Type":"Typ","Upload":"Hochladen","User":"Benutzer","Users":"Benutzer","Waterway Admin":"Waterway-Admin","Waterway User":"Waterway-Benutzer","You can now select these coordinates from the \"Saved cross profiles\" menu to restore this cross profile.":"Sie können diese Koordinaten aus dem \"Gespeicherte Profile\"-Menü auswählen, um diesen Profilschnitt wieder herzustellen."},"en_GB":{},"hr_HR":{},"hu_HU":{},"ro_RO":{},"sk_SK":{}}
\ No newline at end of file
+{"bg_BG":{},"de_AT":{"Accepted":"Akzeptiert","Accesslog":"Zugriffs-Protokoll","Add User":"Benutzer hinzufügen","Author":"Autor","back to login":"zurück zur Anmeldung","Backend Error":"Server-Fehler","Bottleneck":"Seichtstelle","Bottleneck Areas fill-color":"Flächenfüllfarbe Seichtstelle","Bottleneck Areas stroke-color":"Flächenumrandungsfarbe Seichtstelle","Bottlenecks":"Seichtstellen","Cancel Upload":"Hochladen abbrechen","Chainage":"Verkettung","choose .zip- file":"Wählen Sie eine .zip Datei","Chose format:":"Format wählen:","Compare with":"Vergleiche mit","Configuration":"Konfiguration","Confirm":"Bestätigen","Coordinates copied to clipboard!":"Koordinaten auf die Zwischenablage kopiert!","Country":"Land","Date":"Datum","Depthreference":"Tiefenreferenz","Download":"Herunterladen","Download Meta.json":"Meta.json Herunterladen","Email":"E-Mail","Email address":"E-Mail Adresse","Enqueued":"Hinzugefügt","Enter coordinates manually":"Manuelle Koordinateneingabe","Enter label for cross profile":"Namen für Profilschnitt eingeben","Enter passphrase":"Passphrase eingeben","Enter username":"Benutzername eingeben","Error while saving user":"Während des Speicherns der Nutzerdaten trat ein Fehler auf","Errorlog":"Fehlerprotokoll","Failed":"Fehlgeschlagen","Forgot password":"Passwort vergessen","Generate PDF":"PDF generieren","Identified":"Identifiziert","Import":"Daten-Import","Import soundingresults":"Seichtstellenmessungen importieren","Import Soundingresults":"Seichtstellenmessungen importieren","Imported":"Importiert","Importqueue":"Import-Warteschlange","Importschedule":"Import-Zeitplan","invalid email":"Ungültige E-Mail","Invalid input":"Ungültige Eingabe","Kind":"Art","landscape":"Querformat","Last refresh:":"Letzter Abgleich:","Latest":"Neustes","Layers":"Ebenen","Login":"Login","Login failed":"Login fehlgeschlagen","Logout":"Abmelden","Logs":"Protokolle","Mail was sent":"E-Mail wurde gesendet","Map":"Karte","Measurement":"Messung","Name":"Name","New import":"Neuer Import","New Import":"Neuer Import","No features identified.":"Keine Objekte identifiziert.","No results.":"Keine Ergebnisse.","No schedules":"Keine Pläne","Open in new window":"In neuem Fenster öffnen","password":"Passwort","Password":"Passwort","password again":"Noch einmal das Passwort","Password reset requested!":"Passwort Zurücksetzung angefragt!","Password should at least be 8 char long including 1 digit and 1 special char like $":"Das Passwort sollte mindestens 8 Zeichen lang sein, eine Zahlenziffer und ein Sonderzeichen wie etwa $ enthalten","Passwords do not match!":"Die Passwörter stimmen nicht überein!","Pending":"Ausstehend","Please choose a country":"Bitte wählen Sie ein Land aus","Please choose a role":"Bitte wählen Sie eine Rolle aus","Please enter a date":"Bitte ein Datum eingeben","Please enter a projection":"Bitte eine Projektion eingeben","Please enter a reference":"Bitte ein Höhenreferenzsystem eingeben","Please enter correct coordinates in the format: Lat,Lon,Lat,Lon":"Bitte geben Sie die Koordinaten in folgendem Format an: Lat,Lon,Lat,Lon","Please select a bottleneck":"Bitte eine Seichtstelle wählen","Please select one":"Bitte auswählen","portrait":"Hochformat","Profile deleted!":"Profil gelöscht!","Profile saved!":"Profil gespeichert!","Profiles":"Profile","Projection":"Projektion","Refresh":"Aktualisieren","Rejected":"Abgelehnt","Repeat Password":"Passwort erneut eingeben","Request password reset!":"Passwort-Zurücksetzung anfragen!","Role":"Rolle","Saved cross profiles":"Gespeicherte Profile","Schedule":"Zeitplan","Select Bottleneck":"Wähle Engstelle","Send":"Absenden","Send testmail":"Test-E-Mail versenden","Sounding Result":"Seichtstellenvermessungsergebnisse","source-code":"Quelltext","Staging area":"Import-Überprüfung","Staging Area":"Import-Überprüfung","Start":"Start","Starting import for ":"Import gestartet ","State":"Zustand","Submit":"Abschicken","Success":"Erfolg","Successful":"Erfolgreich","Sysadmin":"Sys-Admin","Systemadministration":"System-Administration","Systemconfiguration":"System-Konfiguation","Type":"Typ","Upload":"Hochladen","User":"Benutzer","Username":"Benutzername","Users":"Benutzer","Waterway Admin":"Waterway-Admin","Waterway User":"Waterway-Benutzer","You can now select these coordinates from the \"Saved cross profiles\" menu to restore this cross profile.":"Sie können diese Koordinaten aus dem \"Gespeicherte Profile\"-Menü auswählen, um diesen Profilschnitt wieder herzustellen."},"en_GB":{},"hr_HR":{},"hu_HU":{},"ro_RO":{},"sk_SK":{}}
\ No newline at end of file
--- a/client/src/main.js	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/main.js	Mon Dec 10 15:29:14 2018 +0100
@@ -119,6 +119,9 @@
   faWater,
   faWrench
 );
+import ToggleButton from "vue-js-toggle-button";
+Vue.use(ToggleButton);
+
 Vue.component("font-awesome-icon", FontAwesomeIcon);
 
 Vue.use(VTooltip);
@@ -135,50 +138,29 @@
 
 let browserLanguage = locale2;
 
-// planned also SK, HU, HR, RS, BiH, BG, RO, UA
+// planned also RS, BiH, UA
 const supportedLanguages = {
   en_GB: "British English",
   de_AT: "Deutsch",
   sk_SK: "slovenčina",
-  hu_HU: "Magyat",
+  hu_HU: "Magyar",
   hr_HR: "Hrvatska",
   bg_BG: "български",
   ro_RO: "Română"
 };
 
-if (
-  browserLanguage === "de-DE" ||
-  browserLanguage === "de-LI" ||
-  browserLanguage === "de-LU" ||
-  browserLanguage === "de-CH" ||
-  browserLanguage === "de"
-) {
-  browserLanguage = "de-AT"; // map german,liechtenstein,luxenburg and switzerland to austrian variant for now
-}
+let isAvailableLanguage = Object.keys(supportedLanguages).filter(language => {
+  return browserLanguage.replace("-", "_") === language;
+});
 
-if (browserLanguage === "sk") {
-  browserLanguage = "sk_SK";
+if (isAvailableLanguage.length === 0) {
+  isAvailableLanguage = Object.keys(supportedLanguages).filter(language => {
+    return language.substr(0, 2) === browserLanguage.substr(0, 2);
+  });
 }
 
-if (browserLanguage === "hu") {
-  browserLanguage = "hu_HU";
-}
-
-if (browserLanguage === "hr") {
-  browserLanguage = "hr_HR";
-}
-
-if (browserLanguage === "bg") {
-  browserLanguage = "bg_BG";
-}
-
-if (browserLanguage === "ro") {
-  browserLanguage = "ro_RO";
-}
-
-const language = browserLanguage.replace("-", "_");
-const isLanguageAvailable = supportedLanguages[language];
-let defaultLanguage = isLanguageAvailable ? language : "en_GB";
+let defaultLanguage =
+  isAvailableLanguage.length > 0 ? isAvailableLanguage[0] : "en_GB";
 
 Vue.use(GetTextPlugin, {
   translations: translations,
--- a/client/src/store/bottlenecks.js	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/store/bottlenecks.js	Mon Dec 10 15:29:14 2018 +0100
@@ -41,6 +41,13 @@
     setSurveys(state, surveys) {
       state.surveys = surveys;
     },
+    setSelectedSurveyByDate(state, date) {
+      const survey = state.surveys.filter(x => x.date_info === date)[0];
+      state.selectedSurvey = survey;
+    },
+    setFirstSurveySelected(state) {
+      state.selectedSurvey = state.surveys[0];
+    },
     selectedSurvey(state, survey) {
       state.selectedSurvey = survey;
     },
@@ -49,76 +56,80 @@
     }
   },
   actions: {
-    setSelectedBottleneck(
-      { state, commit, dispatch, rootState, rootGetters },
-      name
-    ) {
-      if (name !== state.selectedBottleneck) {
-        commit("selectedSurvey", null);
-        commit("fairwayprofile/clearCurrentProfile", null, { root: true });
-        commit("application/showSplitscreen", false, { root: true });
-        rootState.map.cutTool.setActive(false);
-        rootGetters["map/getVSourceByName"]("Cut Tool").clear();
-      }
-      if (name) {
-        commit("application/showProfiles", true, { root: true });
-      }
-      commit("setSelectedBottleneck", name);
-      dispatch("querySurveys", name);
+    setSelectedBottleneck({ state, commit, rootState, rootGetters }, name) {
+      return new Promise((resolve, reject) => {
+        if (name !== state.selectedBottleneck) {
+          commit("selectedSurvey", null);
+          commit("fairwayprofile/clearCurrentProfile", null, { root: true });
+          commit("application/showSplitscreen", false, { root: true });
+          rootState.map.cutTool.setActive(false);
+          rootGetters["map/getVSourceByName"]("Cut Tool").clear();
+        }
+        if (name) {
+          commit("application/showProfiles", true, { root: true });
+        }
+        commit("setSelectedBottleneck", name);
+        if (name) {
+          commit("surveysLoading", true);
+          HTTP.get("/surveys/" + name, {
+            headers: {
+              "X-Gemma-Auth": localStorage.getItem("token"),
+              "Content-type": "text/xml; charset=UTF-8"
+            }
+          })
+            .then(response => {
+              const surveys = response.data.surveys.sort((a, b) =>
+                a.date_info < b.date_info ? 1 : -1
+              );
+              commit("setSurveys", surveys);
+              resolve(response);
+            })
+            .catch(error => {
+              commit("setSurveys", []);
+              commit("selectedSurvey", null);
+              const { status, data } = error.response;
+              displayError({
+                title: "Backend Error",
+                message: `${status}: ${data.message || data}`
+              });
+              reject(error);
+            })
+            .finally(() => commit("surveysLoading", false));
+        } else {
+          commit("setSurveys", []);
+          resolve();
+        }
+      });
     },
     loadBottlenecks({ commit }) {
-      var bottleneckFeatureCollectionRequest = new WFS().writeGetFeature({
-        srsName: "EPSG:4326",
-        featureNS: "gemma",
-        featurePrefix: "gemma",
-        featureTypes: ["bottleneck_overview"],
-        outputFormat: "application/json"
-      });
-
-      HTTP.post(
-        "/internal/wfs",
-        new XMLSerializer().serializeToString(
-          bottleneckFeatureCollectionRequest
-        ),
-        {
-          headers: {
-            "X-Gemma-Auth": localStorage.getItem("token"),
-            "Content-type": "text/xml; charset=UTF-8"
+      return new Promise((resolve, reject) => {
+        var bottleneckFeatureCollectionRequest = new WFS().writeGetFeature({
+          srsName: "EPSG:4326",
+          featureNS: "gemma",
+          featurePrefix: "gemma",
+          featureTypes: ["bottleneck_overview"],
+          outputFormat: "application/json"
+        });
+        HTTP.post(
+          "/internal/wfs",
+          new XMLSerializer().serializeToString(
+            bottleneckFeatureCollectionRequest
+          ),
+          {
+            headers: {
+              "X-Gemma-Auth": localStorage.getItem("token"),
+              "Content-type": "text/xml; charset=UTF-8"
+            }
           }
-        }
-      ).then(response => {
-        commit("setBottlenecks", response.data.features);
-      });
-    },
-    querySurveys({ commit }, name) {
-      if (name) {
-        commit("surveysLoading", true);
-        HTTP.get("/surveys/" + name, {
-          headers: {
-            "X-Gemma-Auth": localStorage.getItem("token"),
-            "Content-type": "text/xml; charset=UTF-8"
-          }
-        })
+        )
           .then(response => {
-            const surveys = response.data.surveys.sort((a, b) =>
-              a.date_info < b.date_info ? 1 : -1
-            );
-            commit("selectedSurvey", surveys[0]);
-            commit("setSurveys", surveys);
+            commit("setBottlenecks", response.data.features);
+            resolve(response);
           })
           .catch(error => {
-            commit("setSurveys", []);
-            commit("selectedSurvey", null);
-            const { status, data } = error.response;
-            displayError({
-              title: "Backend Error",
-              message: `${status}: ${data.message || data}`
-            });
-          })
-          .finally(() => commit("surveysLoading", false));
-      } else {
-        commit("setSurveys", []);
-      }
+            reject(error);
+          });
+      });
     }
   }
 };
--- a/client/src/store/map.js	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/src/store/map.js	Mon Dec 10 15:29:14 2018 +0100
@@ -28,6 +28,7 @@
 import { getLength, getArea } from "ol/sphere.js";
 import { unByKey } from "ol/Observable";
 import { getCenter } from "ol/extent";
+import app from "../main";
 
 // initial state
 const init = () => {
@@ -411,7 +412,7 @@
       });
       lineTool.on("drawend", event => {
         commit("setCurrentMeasurement", {
-          quantity: "Length",
+          quantity: app.$gettext("Length"),
           unitSymbol: "m",
           value: Math.round(getLength(event.feature.getGeometry()) * 10) / 10
         });
@@ -432,7 +433,7 @@
       polygonTool.on("drawend", event => {
         const areaSize = getArea(event.feature.getGeometry());
         commit("setCurrentMeasurement", {
-          quantity: "Area",
+          quantity: app.$gettext("Area"),
           unitSymbol: areaSize > 100000 ? "km²" : "m²",
           value:
             areaSize > 100000
--- a/client/yarn.lock	Thu Dec 06 16:04:37 2018 +0000
+++ b/client/yarn.lock	Mon Dec 10 15:29:14 2018 +0100
@@ -8555,7 +8555,7 @@
   resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.13.7.tgz#850f3b8af784a49a6ea2d2eaa7ed1428a34b7281"
   integrity sha512-KIU72UmYPGk4MujZGYMFwinB7lOf2LsDNGSOC8ufevsrPLISrZbNJlWstRi3m0AMuszbH+EFSQ/r6w56RSPK6w==
 
-prettier@^1.13.0, prettier@^1.15.2:
+prettier@^1.13.0, prettier@^1.15.2, prettier@^1.15.3:
   version "1.15.3"
   resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.15.3.tgz#1feaac5bdd181237b54dbe65d874e02a1472786a"
   integrity sha512-gAU9AGAPMaKb3NNSUUuhhFAS7SCO4ALTN4nRIn6PJ075Qd28Yn2Ig2ahEJWdJwJmlEBTUfC7mMUSFy8MwsOCfg==
@@ -8576,7 +8576,7 @@
     ansi-regex "^3.0.0"
     ansi-styles "^3.2.0"
 
-pretty-quick@^1.6.0:
+pretty-quick@^1.8.0:
   version "1.8.0"
   resolved "https://registry.yarnpkg.com/pretty-quick/-/pretty-quick-1.8.0.tgz#067ebe744ddb4e1ed4e1ee1af9648815121f78fc"
   integrity sha512-qV25sQF/ivJpdZ5efwemQYkQJa7sp3HqT/Vf/7z5vGYMcq1VrT2lDpFKAxJPf6219N1YAdR8mGkIhPAZ1odTmQ==
@@ -10768,6 +10768,11 @@
     tsconfig "^7.0.0"
     vue-template-es2015-compiler "^1.6.0"
 
+vue-js-toggle-button@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/vue-js-toggle-button/-/vue-js-toggle-button-1.3.0.tgz#59240f215fd502f54f0c210c5fac878960b0131c"
+  integrity sha512-lnRy+D7gHlvEyv1WKnvYWkxx42obCmeST5eAUwCnyIS+dC1l9Cu4AuWfw9XrRdNRpY7UZgu2TblZcOOF1H661A==
+
 vue-loader@^15.4.2:
   version "15.4.2"
   resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.4.2.tgz#812bb26e447dd3b84c485eb634190d914ce125e2"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/common/json.go	Mon Dec 10 15:29:14 2018 +0100
@@ -0,0 +1,34 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2018 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+package common
+
+import (
+	"encoding/json"
+	"strings"
+)
+
+// FromJSONString revives data from a JSON string.
+func FromJSONString(data string, dst interface{}) error {
+	return json.NewDecoder(strings.NewReader(data)).Decode(dst)
+}
+
+// ToJSONString serializes src into a string to
+// be revived by FromJSONString.
+func ToJSONString(src interface{}) (string, error) {
+	var b strings.Builder
+	if err := json.NewEncoder(&b).Encode(src); err != nil {
+		return "", err
+	}
+	return b.String(), nil
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/controllers/bnimports.go	Mon Dec 10 15:29:14 2018 +0100
@@ -0,0 +1,66 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2018 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+package controllers
+
+import (
+	"database/sql"
+	"log"
+	"net/http"
+
+	"gemma.intevation.de/gemma/pkg/auth"
+	"gemma.intevation.de/gemma/pkg/common"
+	"gemma.intevation.de/gemma/pkg/imports"
+	"gemma.intevation.de/gemma/pkg/models"
+)
+
+func importBottleneck(
+	input interface{},
+	req *http.Request,
+	conn *sql.Conn,
+) (jr JSONResult, err error) {
+
+	bi := input.(*models.BottleneckImport)
+
+	bn := &imports.Bottleneck{
+		URL:      bi.URL,
+		Insecure: bi.Insecure,
+	}
+
+	var serialized string
+	serialized, err = common.ToJSONString(bn)
+	if err != nil {
+		return
+	}
+
+	session, _ := auth.GetSession(req)
+
+	jobID, err := imports.AddJob(imports.BNJobKind, session.User, serialized)
+	if err != nil {
+		return
+	}
+
+	log.Printf("info: added import #%d to queue\n", jobID)
+
+	result := struct {
+		ID int64 `json:"id"`
+	}{
+		ID: jobID,
+	}
+
+	jr = JSONResult{
+		Code:   http.StatusCreated,
+		Result: &result,
+	}
+	return
+}
--- a/pkg/controllers/routes.go	Thu Dec 06 16:04:37 2018 +0000
+++ b/pkg/controllers/routes.go	Mon Dec 10 15:29:14 2018 +0100
@@ -170,6 +170,11 @@
 	api.Handle("/imports/soundingresult", waterwayAdmin(
 		http.HandlerFunc(importSoundingResult))).Methods(http.MethodPost)
 
+	api.Handle("/imports/bottleneck", waterwayAdmin(&JSONHandler{
+		Input:  func() interface{} { return new(models.BottleneckImport) },
+		Handle: importBottleneck,
+	})).Methods(http.MethodPost)
+
 	// Import queue
 	lsImports := waterwayAdmin(&JSONHandler{
 		Handle: listImports,
--- a/pkg/controllers/srimports.go	Thu Dec 06 16:04:37 2018 +0000
+++ b/pkg/controllers/srimports.go	Mon Dec 10 15:29:14 2018 +0100
@@ -152,7 +152,7 @@
 	}
 	sr.Dir = dir
 
-	serialized, err := sr.ToString()
+	serialized, err := common.ToJSONString(sr)
 	if err != nil {
 		log.Printf("error: %v\n", err)
 		http.Error(rw, "error: "+err.Error(), http.StatusInternalServerError)
@@ -217,12 +217,14 @@
 		Messages []string    `json:"messages,omitempty"`
 	}
 
-	var noXYZ bool
-	if noXYZ = common.FindInZIP(zr, ".xyz") == nil; noXYZ {
-		messages = append(messages, "no .xyz file found.")
+	find := func(ext string) *zip.File { return common.FindInZIP(zr, ext) }
+
+	noXYZ := find(".xyz") == nil && find(".txt") == nil
+	if noXYZ {
+		messages = append(messages, "no .xyz or .txt file found.")
 	}
 
-	if mj := common.FindInZIP(zr, "meta.json"); mj == nil {
+	if mj := find("meta.json"); mj == nil {
 		messages = append(messages, "no 'meta.json' file found.")
 	} else {
 		if meta, err := loadMeta(mj); err != nil {
--- a/pkg/controllers/user.go	Thu Dec 06 16:04:37 2018 +0000
+++ b/pkg/controllers/user.go	Mon Dec 10 15:29:14 2018 +0100
@@ -29,6 +29,7 @@
 	"gemma.intevation.de/gemma/pkg/auth"
 	"gemma.intevation.de/gemma/pkg/misc"
 	"gemma.intevation.de/gemma/pkg/models"
+	"gemma.intevation.de/gemma/pkg/scheduler"
 )
 
 const (
@@ -128,6 +129,7 @@
 
 	// Running in a go routine should not be necessary.
 	go func() { auth.Sessions.Logout(user) }()
+	go func() { scheduler.UnbindUser(user) }()
 
 	jr = JSONResult{Code: http.StatusNoContent}
 	return
@@ -205,6 +207,7 @@
 	if user != newUser.User {
 		// Running in a go routine should not be necessary.
 		go func() { auth.Sessions.Logout(string(user)) }()
+		go func() { scheduler.UnbindUser(string(user)) }()
 	}
 
 	jr = JSONResult{
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/imports/bn.go	Mon Dec 10 15:29:14 2018 +0100
@@ -0,0 +1,105 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2018 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+package imports
+
+import (
+	"context"
+	"database/sql"
+	"errors"
+
+	"gemma.intevation.de/gemma/pkg/common"
+	"gemma.intevation.de/gemma/pkg/soap/ifbn"
+)
+
+type Bottleneck struct {
+	URL      string `json:"url"`
+	Insecure bool   `json:"insecure"`
+}
+
+const BNJobKind JobKind = "bn"
+
+type bnJobCreator struct{}
+
+func init() {
+	RegisterJobCreator(BNJobKind, bnJobCreator{})
+}
+
+func (bnJobCreator) Create(_ JobKind, data string) (Job, error) {
+	bn := new(Bottleneck)
+	if err := common.FromJSONString(data, bn); err != nil {
+		return nil, err
+	}
+	return bn, nil
+}
+
+func (bnJobCreator) Depends() []string {
+	return []string{
+		"waterway.gauges",
+		"waterway.bottlenecks",
+	}
+}
+
+const (
+	// TODO: waterway.bottlenecks needs an integer id column.
+	bnStageDoneSQL = `
+UPDATE waterway.bottlenecks SET staging_done = true
+WHERE id IN (
+  SELECT key from waterway.track_imports
+  WHERE import_id = $1 AND
+        relation = 'waterway.bottlenecks'::regclass)`
+)
+
+// StageDone moves the imported bottleneck out of the staging area.
+func (bnJobCreator) StageDone(
+	ctx context.Context,
+	tx *sql.Tx,
+	id int64,
+) error {
+	_, err := tx.ExecContext(ctx, srStageDoneSQL, id)
+	return err
+}
+
+// CleanUp of a bottleneck import is a NOP.
+func (bn *Bottleneck) CleanUp() error { return nil }
+
+// Do executes the actual bottleneck import.
+func (bn *Bottleneck) Do(
+	ctx context.Context,
+	importID int64,
+	conn *sql.Conn,
+	feedback Feedback,
+) (interface{}, error) {
+	client := ifbn.NewIBottleneckService(bn.URL, bn.Insecure, nil)
+
+	req := &ifbn.Export_bn_by_isrs{}
+
+	resp, err := client.Export_bn_by_isrs(req)
+	if err != nil {
+		feedback.Error("%v", err)
+		return nil, err
+	}
+
+	if resp.Export_bn_by_isrsResult == nil {
+		err := errors.New("no Bottlenecks found")
+		feedback.Error("%v", err)
+		return nil, err
+	}
+
+	// TODO: Implement me!
+	bns := resp.Export_bn_by_isrsResult.BottleNeckType
+
+	_ = bns
+
+	return nil, nil
+}
--- a/pkg/imports/sr.go	Thu Dec 06 16:04:37 2018 +0000
+++ b/pkg/imports/sr.go	Mon Dec 10 15:29:14 2018 +0100
@@ -21,7 +21,6 @@
 	"crypto/sha1"
 	"database/sql"
 	"encoding/hex"
-	"encoding/json"
 	"errors"
 	"fmt"
 	"io"
@@ -76,7 +75,7 @@
 
 func (srJobCreator) Create(_ JobKind, data string) (Job, error) {
 	sr := new(SoundingResult)
-	if err := sr.FromString(data); err != nil {
+	if err := common.FromJSONString(data, sr); err != nil {
 		return nil, err
 	}
 	return sr, nil
@@ -169,21 +168,6 @@
 `
 )
 
-// FromString revives a SoundingResult import from a string.
-func (sr *SoundingResult) FromString(data string) error {
-	return json.NewDecoder(strings.NewReader(data)).Decode(sr)
-}
-
-// ToString serializes a SoundingResult import into a string to
-// be revived by FromString.
-func (sr *SoundingResult) ToString() (string, error) {
-	var b strings.Builder
-	if err := json.NewEncoder(&b).Encode(sr); err != nil {
-		return "", err
-	}
-	return b.String(), nil
-}
-
 // Do executes the actual sounding result import.
 func (sr *SoundingResult) Do(
 	ctx context.Context,
@@ -213,10 +197,15 @@
 		return nil, common.ToError(err)
 	}
 
-	feedback.Info("Looking for '*.xyz'")
-	xyzf := common.FindInZIP(z, ".xyz")
+	var xyzf *zip.File
+	for _, ext := range []string{".xyz", ".txt"} {
+		feedback.Info("Looking for '*%s'", ext)
+		if xyzf = common.FindInZIP(z, ext); xyzf != nil {
+			break
+		}
+	}
 	if xyzf == nil {
-		return nil, errors.New("Cannot find any *.xyz file")
+		return nil, errors.New("Cannot find any *.xyz or *.txt file")
 	}
 
 	xyz, err := loadXYZ(xyzf, feedback)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/models/bn.go	Mon Dec 10 15:29:14 2018 +0100
@@ -0,0 +1,19 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2018 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+package models
+
+type BottleneckImport struct {
+	URL      string `json:"url"`
+	Insecure bool   `json:"insecure"`
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/scheduler/scheduler.go	Mon Dec 10 15:29:14 2018 +0100
@@ -0,0 +1,218 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2018 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+package scheduler
+
+import (
+	"errors"
+	"sync"
+
+	"github.com/robfig/cron"
+)
+
+// ErrNoSuchAction if no fitting action was found.
+var ErrNoSuchAction = errors.New("No such action")
+
+// Action is called with a user and an optional configuration id.
+type Action func(user string, cfgID *int64)
+
+type userAction struct {
+	scheduler *scheduler
+	user      string
+	name      string
+	cfgID     *int64
+}
+
+type scheduler struct {
+	cr      *cron.Cron
+	actions map[string]Action
+	mu      sync.Mutex
+}
+
+// Run implements cron.Job.
+func (ua *userAction) Run() {
+	if a := ua.scheduler.action(ua.name); a != nil {
+		a(ua.user, ua.cfgID)
+	}
+}
+
+var global = scheduler{
+	cr:      cron.New(),
+	actions: make(map[string]Action),
+}
+
+// RegisterAction registers a named action to the global scheduler.
+func RegisterAction(name string, action Action) {
+	global.registerAction(name, action)
+}
+
+// UnregisterAction ungesiters a named action from the global scheduler.
+func UnregisterAction(name string) {
+	global.unregisterAction(name)
+}
+
+// BindAction binds a named action to a user, a cron spec and
+// an optional configuration id.
+func BindAction(name, spec, user string, cfgID *int64) error {
+	return global.bindAction(name, spec, user, cfgID)
+}
+
+// UnbindAction unbins a named action from a user and and
+// an optional configuration id.
+func UnbindAction(name, user string, cfgID *int64) error {
+	return global.unbindAction(name, user, cfgID)
+}
+
+func UnbindUser(user string) {
+	global.unbindUser(user)
+}
+
+func sameCfgID(a, b *int64) bool {
+	return (a == nil && b == nil) || (a != nil && b != nil && *a == *b)
+}
+
+func (s *scheduler) unbindUser(user string) {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	entries := s.cr.Entries()
+
+	if len(entries) == 0 {
+		return
+	}
+
+	var found bool
+	for _, entry := range entries {
+		ua := entry.Job.(*userAction)
+		if ua.user == user {
+			found = true
+			break
+		}
+	}
+	if !found {
+		return
+	}
+
+	s.cr.Stop()
+	s.cr = cron.New()
+	for _, entry := range entries {
+		ua := entry.Job.(*userAction)
+		if ua.user != user {
+			s.cr.Schedule(entry.Schedule, entry.Job)
+		}
+	}
+	s.cr.Start()
+}
+
+func (s *scheduler) unbindAction(name, user string, cfgID *int64) error {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	entries := s.cr.Entries()
+
+	var found *userAction
+	for _, entry := range entries {
+		ua := entry.Job.(*userAction)
+		if ua.name == name && ua.user == user && sameCfgID(cfgID, ua.cfgID) {
+			// Already have such a user/action/cfg tuple  -> re-schedule.
+			found = ua
+			break
+		}
+	}
+
+	if found == nil {
+		return ErrNoSuchAction
+	}
+
+	s.cr.Stop()
+	s.cr = cron.New()
+	for _, entry := range entries {
+		ua := entry.Job.(*userAction)
+		if ua != found {
+			s.cr.Schedule(entry.Schedule, entry.Job)
+		}
+	}
+	s.cr.Start()
+
+	return nil
+}
+
+func (s *scheduler) bindAction(name, spec, user string, cfgID *int64) error {
+
+	schedule, err := cron.Parse(spec)
+	if err != nil {
+		return err
+	}
+
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	action := s.actions[name]
+	if action == nil {
+		return ErrNoSuchAction
+	}
+
+	entries := s.cr.Entries()
+
+	var found *userAction
+	for _, entry := range entries {
+		ua := entry.Job.(*userAction)
+		if ua.name == name && ua.user == user && sameCfgID(cfgID, ua.cfgID) {
+			// Already have such a user/action/cfg tuple  -> re-schedule.
+			found = ua
+			break
+		}
+	}
+
+	if found == nil {
+		// Add to current plan.
+		job := &userAction{scheduler: s, user: user, name: name, cfgID: cfgID}
+		s.cr.Schedule(schedule, job)
+	} else {
+		// If found re-build all.
+		s.cr.Stop()
+		s.cr = cron.New()
+		for _, entry := range entries {
+			ua := entry.Job.(*userAction)
+			var sch cron.Schedule
+			if found == ua {
+				// replace with new schedule.
+				sch = schedule
+			} else {
+				sch = entry.Schedule
+			}
+			s.cr.Schedule(sch, entry.Job)
+		}
+	}
+	s.cr.Start()
+
+	return nil
+}
+
+func (s *scheduler) action(name string) Action {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	return s.actions[name]
+}
+
+func (s *scheduler) registerAction(name string, action Action) {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	s.actions[name] = action
+}
+
+func (s *scheduler) unregisterAction(name string) {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	delete(s.actions, name)
+}
--- a/schema/gemma.sql	Thu Dec 06 16:04:37 2018 +0000
+++ b/schema/gemma.sql	Mon Dec 10 15:29:14 2018 +0100
@@ -535,7 +535,7 @@
       ST_Centroid(area)::Geometry AS point,
       (lower(stretch)).hectometre AS from,
       (upper(stretch)).hectometre AS to,
-      sr.current
+      sr.current::text
     FROM waterway.bottlenecks bn LEFT JOIN (
       SELECT bottleneck_id, max(date_info) AS current FROM
       waterway.sounding_results