changeset 586:2821e087a973

remove files
author Thomas Junk <thomas.junk@intevation.de>
date Fri, 07 Sep 2018 11:36:48 +0200
parents ef307bd6b5d8
children 53b7a46c53a7
files client/src/assets/application.scss client/src/assets/logo.png client/src/assets/tooltip.scss client/src/assets/user.png client/src/components/Fairwayprofile.vue client/src/components/Layers.vue client/src/components/Layerselect.vue client/src/components/Maplayer.vue client/src/components/Passwordfield.vue client/src/components/Sidebar.vue client/src/components/Topbar.vue client/src/components/User.vue client/src/components/Userdetail.vue client/src/lib/errors.js client/src/lib/http.js client/src/lib/session.js client/src/stores/application.js client/src/stores/mapstore.js client/src/stores/user.js client/src/stores/usermanagement.js client/src/views/Login.vue client/src/views/Main.vue client/src/views/Usermanagement.vue client/src/views/Users.vue
diffstat 24 files changed, 0 insertions(+), 2118 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/assets/application.scss	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-$offset: 20px;
-$small-offset: 10px;
-$large-offset: 30px;
-$x-large-offset: 50px;
-$iconsize: 3em;
-$iconLineHeight: 0.25em;
-$iconwidth: 20px;
-$basic-shadow: 1px 3px 8px 2px rgba(220, 220, 220, 0.75);
-$basic-shadow-light: 1px 1px 12px 1px rgba(235, 235, 235, 0.75);
-$transition: 0.5s;
-$transition-fast: 0.1s;
-$transition-slow: 3s;
-$topbarheight: 5vh;
-
-%fully-centered {
-  position: absolute;
-  top: 50%;
-  left: 50%;
-  transform: translate(-50%, -50%);
-}
-
-.ui-element {
-  pointer-events: auto;
-}
Binary file client/src/assets/logo.png has changed
--- a/client/src/assets/tooltip.scss	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,109 +0,0 @@
-.tooltip {
-  display: block !important;
-  z-index: 10000;
-
-  .tooltip-inner {
-    background: black;
-    color: white;
-    border-radius: 16px;
-    padding: 5px 10px 4px;
-  }
-
-  .tooltip-arrow {
-    width: 0;
-    height: 0;
-    border-style: solid;
-    position: absolute;
-    margin: 5px;
-    border-color: black;
-    z-index: 1;
-  }
-
-  &[x-placement^="top"] {
-    margin-bottom: 5px;
-
-    .tooltip-arrow {
-      border-width: 5px 5px 0 5px;
-      border-left-color: transparent !important;
-      border-right-color: transparent !important;
-      border-bottom-color: transparent !important;
-      bottom: -5px;
-      left: calc(50% - 5px);
-      margin-top: 0;
-      margin-bottom: 0;
-    }
-  }
-
-  &[x-placement^="bottom"] {
-    margin-top: 5px;
-
-    .tooltip-arrow {
-      border-width: 0 5px 5px 5px;
-      border-left-color: transparent !important;
-      border-right-color: transparent !important;
-      border-top-color: transparent !important;
-      top: -5px;
-      left: calc(50% - 5px);
-      margin-top: 0;
-      margin-bottom: 0;
-    }
-  }
-
-  &[x-placement^="right"] {
-    margin-left: 5px;
-
-    .tooltip-arrow {
-      border-width: 5px 5px 5px 0;
-      border-left-color: transparent !important;
-      border-top-color: transparent !important;
-      border-bottom-color: transparent !important;
-      left: -5px;
-      top: calc(50% - 5px);
-      margin-left: 0;
-      margin-right: 0;
-    }
-  }
-
-  &[x-placement^="left"] {
-    margin-right: 5px;
-
-    .tooltip-arrow {
-      border-width: 5px 0 5px 5px;
-      border-top-color: transparent !important;
-      border-right-color: transparent !important;
-      border-bottom-color: transparent !important;
-      right: -5px;
-      top: calc(50% - 5px);
-      margin-left: 0;
-      margin-right: 0;
-    }
-  }
-
-  &.popover {
-    $color: #f9f9f9;
-
-    .popover-inner {
-      background: $color;
-      color: black;
-      padding: 24px;
-      border-radius: 5px;
-      box-shadow: 0 5px 30px rgba(black, 0.1);
-    }
-
-    .popover-arrow {
-      border-color: $color;
-    }
-  }
-
-  &[aria-hidden="true"] {
-    visibility: hidden;
-    opacity: 0;
-    transition: opacity 0.15s, visibility 0.15s;
-  }
-
-  &[aria-hidden="false"] {
-    visibility: visible;
-    opacity: 1;
-    transition: opacity 0.15s;
-  }
-}
Binary file client/src/assets/user.png has changed
--- a/client/src/components/Fairwayprofile.vue	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,163 +0,0 @@
-<template>
-  <div class="fairwayprofile">
-    <svg :width="width +'px'" :height="height +'px'">
-    </svg>
-  </div>
-</template>
-
-<style lang="scss">
-.fairwayprofile {
-  background-color: white;
-  margin-left: auto;
-  margin-right: auto;
-  margin-top: auto;
-  margin-bottom: auto;
-}
-</style>
-
-<script>
-import * as d3 from "d3";
-
-const WATER_COLOR = "#005DFF";
-const GROUND_COLOR = "#4A2F06";
-
-const sampleData = [
-  { x: 0, y: -3.0 },
-  { x: 25, y: -2.0 },
-  { x: 50, y: -4.5 },
-  { x: 75, y: -4.0 },
-  { x: 100, y: -3.0 },
-  { x: 125, y: -4.0 },
-  { x: 150, y: -5.0 },
-  { x: 175, y: -4.0 },
-  { x: 200, y: -3.0 },
-  { x: 225, y: -3.5 },
-  { x: 250, y: -3.0 },
-  { x: 300, y: -2.5 }
-];
-
-export default {
-  name: "fairwayprofile",
-  props: ["width", "height", "xScale", "yScaleLeft", "yScaleRight", "margin"],
-  data() {
-    return {};
-  },
-  methods: {
-    generateCoordinates(svg, height, width) {
-      let xScale = d3
-        .scaleLinear()
-        .domain(this.xScale)
-        .rangeRound([0, width]);
-
-      xScale.ticks(5);
-      let yScaleLeft = d3
-        .scaleLinear()
-        .domain(this.yScaleLeft)
-        .rangeRound([height, 0]);
-
-      let yScaleRight = d3
-        .scaleLinear()
-        .domain(this.yScaleRight)
-        .rangeRound([height, 0]);
-
-      let xAxis = d3.axisBottom(xScale);
-      let yAxis = d3.axisLeft(yScaleLeft);
-      let yAxis2 = d3.axisRight(yScaleRight);
-      let graph = svg
-        .append("g")
-        .attr(
-          "transform",
-          "translate(" + this.margin.left + "," + this.margin.top + ")"
-        );
-      graph
-        .append("g")
-        .attr("transform", "translate(0," + height + ")")
-        .call(xAxis.ticks(5));
-      graph.append("g").call(yAxis);
-      graph
-        .append("g")
-        .attr("transform", "translate(" + width + ",0)")
-        .call(yAxis2);
-      return { xScale, yScaleLeft, yScaleRight, graph };
-    },
-    drawWaterlevel({ graph, xScale, yScaleRight, height }) {
-      let waterArea = d3
-        .area()
-        .x(function(d) {
-          return xScale(d.x);
-        })
-        .y0(height)
-        .y1(function(d) {
-          return yScaleRight(d.y);
-        });
-      graph
-        .append("path")
-        .datum([{ x: 0, y: 0 }, { x: 300, y: 0 }])
-        .attr("fill", WATER_COLOR)
-        .attr("stroke", WATER_COLOR)
-        .attr("d", waterArea);
-    },
-    drawProfile({ graph, xScale, yScaleRight, sampleData, height }) {
-      let profileLine = d3
-        .line()
-        .x(d => {
-          return xScale(d.x);
-        })
-        .y(d => {
-          return yScaleRight(d.y);
-        });
-      let profileArea = d3
-        .area()
-        .x(function(d) {
-          return xScale(d.x);
-        })
-        .y0(height)
-        .y1(function(d) {
-          return yScaleRight(d.y);
-        });
-      graph
-        .append("path")
-        .datum(sampleData)
-        .attr("fill", GROUND_COLOR)
-        .attr("stroke", GROUND_COLOR)
-        .attr("stroke-width", 3)
-        .attr("d", profileArea);
-      graph
-        .append("path")
-        .datum(sampleData)
-        .attr("fill", "none")
-        .attr("stroke", "black")
-        .attr("stroke-linejoin", "round")
-        .attr("stroke-linecap", "round")
-        .attr("stroke-width", 3)
-        .attr("d", profileLine);
-    }
-  },
-  mounted() {
-    let svg = d3.select("svg");
-    const width = this.width - this.margin.right - this.margin.left;
-    const height = this.height - this.margin.top - this.margin.bottom;
-
-    const { xScale, yScaleRight, graph } = this.generateCoordinates(
-      svg,
-      height,
-      width
-    );
-    this.drawWaterlevel({
-      graph,
-      xScale,
-      yScaleRight,
-      height,
-      width
-    });
-    this.drawProfile({
-      graph,
-      xScale,
-      yScaleRight,
-      sampleData,
-      height,
-      width
-    });
-  }
-};
-</script>
--- a/client/src/components/Layers.vue	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-<template>
-  <div class="ui-element card layerselection shadow">
-    <div class="card-body">
-      <div class="headline">
-        <h4 class="card-title">Layers</h4>
-      </div>
-      <hr>
-      <div class="d-flex flex-column">
-        <Layerselect :layerindex="index" :layername="layer.name" v-for="(layer, index) in layers" :key="layer.name" :isVisible="layer.isVisible" @visibilityToggled="visibilityToggled"></Layerselect>
-      </div>
-    </div>
-  </div>
-</template>
-
-<style lang="scss">
-@import "../assets/application.scss";
-
-.layerselection {
-  background-color: white;
-  margin-left: 0.5rem;
-}
-</style>
-
-<script>
-import Layerselect from "./Layerselect";
-import { mapGetters } from "vuex";
-export default {
-  name: "layers",
-  components: {
-    Layerselect
-  },
-  computed: {
-    ...mapGetters("mapstore", ["layers"])
-  },
-  methods: {
-    visibilityToggled(layer) {
-      this.$store.commit("mapstore/toggleVisibility", layer);
-    }
-  }
-};
-</script>
--- a/client/src/components/Layerselect.vue	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-<template>
-  <div class="form-check d-flex flex-row">
-    <input class="form-check-input" @change="visibilityToggled" :id="layername" type="checkbox" :checked="isVisible">
-    <label class="form-check-label" :for="layername">{{this.layername}}</label>
-  </div>
-</template>
-
-<style lang="sass">
-
-</style>
-
-
-<script>
-export default {
-  props: ["layername", "layerindex", "isVisible"],
-  name: "layerselect",
-  methods: {
-    visibilityToggled() {
-      this.$emit("visibilityToggled", this.layerindex);
-    }
-  }
-};
-</script>
--- a/client/src/components/Maplayer.vue	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-<template>
-  <div class="mapdisplay">
-    <div id="map"></div>
-    <!-- <div class="profile d-flex flex-row">
-      <Fairwayprofile height="300" width="1024" :xScale="[0, 300]" :yScaleLeft="[191, 199]" :yScaleRight="[-6, 1]" :margin="{ top: 20, right: 40, bottom: 20, left: 40 }"></Fairwayprofile>
-    </div> -->
-  </div>
-</template>
-
-<style lang="scss">
-@import "../assets/application.scss";
-
-.profile {
-  background-color: white;
-  height: 50vh-$topbarheight;
-}
-
-.mapdisplay {
-  height: 100vh;
-}
-
-#map {
-  height: 100vh;
-}
-
-.ol-zoom {
-  display: flex;
-  left: 15vw;
-  margin-top: 2vh;
-  z-index: 5;
-  background-color: white;
-}
-</style>
-
-<script>
-import { HTTP } from "../lib/http";
-import "ol/ol.css";
-import { Map, View } from "ol";
-// needed for vector filter example
-// import { greaterThan as greaterThanFilter } from "ol/format/filter.js";
-import { WFS, GeoJSON } from "ol/format.js";
-import { mapGetters } from "vuex";
-import Fairwayprofile from "./Fairwayprofile";
-
-export default {
-  name: "maplayer",
-  props: ["lat", "long", "zoom"],
-  components: {
-    Fairwayprofile
-  },
-  data() {
-    return {
-      projection: "EPSG:3857",
-      openLayersMap: null
-    };
-  },
-  computed: {
-    ...mapGetters("mapstore", ["layers"]),
-    layerData() {
-      return this.layers.map(x => {
-        return x.data;
-      });
-    }
-  },
-  methods: {},
-  mounted() {
-    var that = this;
-    this.openLayersMap = new Map({
-      layers: this.layerData,
-      target: "map",
-      view: new View({
-        center: [this.long, this.lat],
-        zoom: this.zoom,
-        projection: this.projection
-      })
-    });
-
-    var featureRequest = new WFS().writeGetFeature({
-      // srsName: "urn:ogc:def:crs:EPSG::4326",
-      srsName: "EPSG:3857",
-      featureNS: "gemma",
-      featurePrefix: "gemma",
-      featureTypes: ["fairway_dimensions"],
-      outputFormat: "application/json"
-      // example for a filter
-      //filter: greaterThanFilter("level_of_service", 0)
-    });
-
-    HTTP.post(
-      "/internal/wfs",
-      new XMLSerializer().serializeToString(featureRequest),
-      {
-        headers: {
-          "X-Gemma-Auth": localStorage.getItem("token"),
-          "Content-type": "text/xml; charset=UTF-8"
-        }
-      }
-    ).then(function(response) {
-      var features = new GeoJSON().readFeatures(JSON.stringify(response.data));
-      var vectorSrc = that.layers[2].data.getSource();
-      vectorSrc.addFeatures(features);
-      // would scale to the extend of all resulting features
-      // that.openLayersMap.getView().fit(vectorSrc.getExtent());
-    });
-  }
-};
-</script>
--- a/client/src/components/Passwordfield.vue	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-<template>
-  <div>
-    <label for="password">{{this.label}}</label>
-    <div class="d-flex d-row">
-      <input :type="isPasswordVisible" @change="fieldChanged" class="form-control" :placeholder='placeholder' :required="required">
-      <span class="input-group-text" @click="showPassword"><i :class="eyeIcon"></i></span>
-    </div>
-    <div v-show="passworderrors" class="text-danger"><small><i class="fa fa-warning"></i> {{ this.passworderrors}}</small></div>
-  </div>
-</template>
-
-<script>
-export default {
-  name: "passwordfield",
-  props: ["model", "placeholder", "label", "passworderrors", "required"],
-  data() {
-    return {
-      password: "",
-      readablePassword: false
-    };
-  },
-  methods: {
-    showPassword() {
-      this.readablePassword = !this.readablePassword;
-    },
-    fieldChanged(e) {
-      this.$emit("fieldchange", e.target.value);
-    }
-  },
-  computed: {
-    isPasswordVisible() {
-      return this.readablePassword ? "text" : "password";
-    },
-    eyeIcon() {
-      return {
-        fa: true,
-        "fa-eye": !this.readablePassword,
-        "fa-eye-slash": this.readablePassword
-      };
-    }
-  }
-};
-</script>
--- a/client/src/components/Sidebar.vue	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-<template>
-  <div :class="sidebarStyle">
-    <div :class="menuStyle">
-      <router-link to="/" class="text-body d-flex flex-row nav-link">
-        <i class="fa fa-map-o align-self-center navicon"></i>Riverbed Morphology</router-link>
-      <div v-if="isSysAdmin">
-        <hr/>
-        <div class="nav-link d-flex menupadding text-muted">Administration</div>
-        <router-link class="text-body d-flex flex-row nav-link" to="usermanagement">
-          <i class="fa fa-address-card-o align-self-center navicon"></i>Users
-        </router-link>
-      </div>
-    </div>
-    <User></User>
-  </div>
-</template>
-
-<script>
-import { mapGetters } from "vuex";
-import User from "../components/User";
-
-export default {
-  name: "sidebar",
-  components: {
-    User: User
-  },
-  computed: {
-    ...mapGetters("user", ["isSysAdmin"]),
-    ...mapGetters("application", ["sidebarCollapsed"]),
-    menuStyle() {
-      return {
-        menu: true,
-        nav: true,
-        "flex-column": true
-      };
-    },
-    sidebarStyle() {
-      return {
-        "ui-element": true,
-        sidebar: true,
-        overlay: true,
-        sidebarcollapsed: this.sidebarCollapsed,
-        sidebarextended: !this.sidebarCollapsed,
-        shadow: true
-      };
-    }
-  }
-};
-</script>
-
-<style lang="scss">
-@import "../assets/application.scss";
-
-.router-link-exact-active {
-  background-color: #f2f2f2;
-}
-
-.navicon {
-  margin-right: $small-offset;
-}
-
-.menu {
-  padding-top: 5vh;
-  height: 90%;
-}
-
-.sidebar {
-  top: 0;
-  background-color: #ffffff;
-  padding-top: $large-offset;
-  height: 100vh;
-  opacity: 0.96;
-}
-
-.overlay {
-  position: absolute;
-  z-index: -1;
-}
-
-.sidebarcollapsed {
-  transition: $transition;
-  left: -250px;
-}
-
-.sidebarextended {
-  transition: $transition;
-  left: 0;
-}
-</style>
--- a/client/src/components/Topbar.vue	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-<template>
-  <div class="topbar d-flex flex-row justify-content-between">
-    <div>
-      <i @click="toggleSidebar" class="ui-element menubutton fa fa-bars"></i>
-    </div>
-    <div v-if="routeName != 'usermanagement'" class="input-group searchcontainer">
-      <div class="input-group-prepend">
-        <span class="input-group-text searchlabel" for="search">
-          <i class="fa fa-search"></i>
-        </span>
-      </div>
-      <input id="search" type="text" class="form-control ui-element search searchbar">
-    </div>
-    <Layers v-if="routeName != 'usermanagement'"></Layers>
-  </div>
-</template>
-
-<style lang="scss">
-@import "../assets/application.scss";
-
-.menubutton {
-  background-color: white;
-  padding: 0.5rem;
-}
-
-.searchcontainer {
-  margin-left: 20vw;
-  margin-right: auto;
-  width: 50vw !important;
-  height: 39px;
-  border-radius: 0.25rem;
-}
-
-.searchbar {
-  margin-left: auto;
-  margin-right: auto;
-  height: 50px;
-}
-
-.topbar {
-  padding-top: 2vh;
-  margin-right: 1vw;
-  margin-left: 0;
-}
-
-.logout {
-  font-size: x-large;
-}
-</style>
-
-
-<script>
-import Layers from "./Layers";
-export default {
-  name: "topbar",
-  components: {
-    Layers: Layers
-  },
-  methods: {
-    toggleSidebar() {
-      this.$store.commit("application/toggleSidebar");
-    }
-  },
-  computed: {
-    routeName() {
-      const routeName = this.$route.name;
-      console.log(routeName);
-      return routeName;
-    }
-  }
-};
-</script>
--- a/client/src/components/User.vue	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-<template>
-  <div class="ui-element d-flex justify-content-around usermanagement">
-    <img class="userpic" src="../assets/user.png">
-    <span class="username align-self-center">{{ userinfo }}</span>
-    <span class="logout align-self-center" @click="logoff">
-      <i class="fa fa-power-off"></i>
-    </span>
-  </div>
-</template>
-
-<style lang="scss">
-.usermanagement {
-  background: white;
-  width: 150px;
-  padding: 0.25rem;
-  border-radius: 0.25rem;
-}
-</style>
-
-<script>
-import { mapGetters } from "vuex";
-export default {
-  name: "user",
-  data() {
-    return {};
-  },
-  methods: {
-    logoff() {
-      this.$store.commit("user/clear_auth");
-      this.$store.commit("application/resetSidebar");
-      this.$router.push("/login");
-    }
-  },
-  computed: {
-    ...mapGetters("user", ["userinfo"])
-  }
-};
-</script>
--- a/client/src/components/Userdetail.vue	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,262 +0,0 @@
-<template>
-  <div class="userdetails shadow fadeIn animated">
-    <div class="card">
-      <div class="card-header shadow-sm text-white bg-info mb-3">
-        {{ this.cardHeader }}
-        <span @click="closeDetailview" class="pull-right">
-          <i class="fa fa-close"></i>
-        </span>
-      </div>
-      <div class="card-body">
-        <form @submit.prevent="save">
-          <div class="formfields">
-            <div v-if="currentUser.isNew" class="form-group row">
-              <label for="user">Username</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>
-                  <i class="fa fa-warning"></i> {{ errors.user }}</small>
-              </div>
-            </div>
-            <div class="form-group row">
-              <label for="country">Country</label>
-              <select class="form-control form-control-sm" v-on:change="validateCountry" v-model="currentUser.country">
-                <option disabled value="">Please select one</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>
-                  <i class="fa fa-warning"></i> {{ errors.country }}</small>
-              </div>
-            </div>
-            <div class="form-group row">
-              <label for="email">Email address</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>
-                  <i class="fa fa-warning"></i> {{ errors.email }}</small>
-              </div>
-            </div>
-            <div class="form-group row">
-              <label for="role">Role</label>
-              <select class="form-control form-control-sm" v-on:change="validateRole" v-model="currentUser.role">
-                <option disabled value="">Please select one</option>
-                <option value="sys_admin">Sysadmin</option>
-                <option value="waterway_admin">Waterway Admin</option>
-                <option value="waterway_user">Waterway User</option>
-              </select>
-              <div v-show="errors.role" class="text-danger">
-                <small>
-                  <i class="fa fa-warning"></i> {{ 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 pull-right">Submit</button>
-          </div>
-        </form>
-      </div>
-    </div>
-  </div>
-</template>
-
-<style lang="scss">
-@import "../assets/application.scss";
-
-.formfields {
-  width: 10vw;
-}
-
-.userdetails {
-  margin-top: $topbarheight;
-  min-width: 40vw;
-  margin-right: auto;
-  height: 100%;
-}
-
-form {
-  margin-left: $offset;
-  font-size: 0.9rem;
-}
-</style>
-<script>
-import { displayError } from "../lib/errors.js";
-import { mapGetters } from "vuex";
-import PasswordField from "../components/Passwordfield";
-
-const emptyErrormessages = () => {
-  return {
-    email: "",
-    country: "",
-    role: "",
-    password: "",
-    passwordre: ""
-  };
-};
-
-const isEmailValid = email => {
-  /**
-   *
-   * For convenience purposes the same regex used as in the go code
-   * cf. types.go
-   *
-   */
-  // eslint-disable-next-line
-  return /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/.test(
-    email
-  );
-};
-
-const violatedPasswordRules = password => {
-  return (
-    // rules according to issue 70
-    password.length < 7 ||
-    /\W/.test(password) == false ||
-    /\d/.test(password) == false
-  );
-};
-
-export default {
-  name: "userdetail",
-  components: {
-    PasswordField
-  },
-  data() {
-    return {
-      passwordLabel: "Password",
-      passwordReLabel: "Repeat Password",
-      passwordPlaceholder: "password",
-      passwordRePlaceholder: "password again",
-      password: "",
-      passwordre: "",
-      currentUser: {},
-      path: null,
-      submitted: false,
-      errors: {
-        email: "",
-        country: "",
-        role: "",
-        password: "",
-        passwordre: ""
-      }
-    };
-  },
-  mounted() {
-    this.currentUser = { ...this.user };
-    this.path = this.user.name;
-  },
-  watch: {
-    user() {
-      this.currentUser = { ...this.user };
-      this.path = this.user.name;
-      this.clearPassword();
-      this.clearErrors();
-    }
-  },
-  computed: {
-    cardHeader() {
-      if (this.currentUser.isNew) return "N.N";
-      return this.currentUser.user;
-    },
-    userNamePlaceholder() {
-      if (this.currentUser.isNew) return "N.N";
-      return "";
-    },
-    ...mapGetters("application", ["countries"]),
-    user() {
-      return this.$store.getters["usermanagement/currentUser"];
-    },
-    isFormValid() {
-      return (
-        isEmailValid(this.currentUser.email) &&
-        this.currentUser.country &&
-        this.password === this.passwordre &&
-        (this.password === "" || !violatedPasswordRules(this.password))
-      );
-    }
-  },
-  methods: {
-    passwordChanged(value) {
-      this.password = value;
-      this.validatePassword();
-    },
-    passwordReChanged(value) {
-      this.passwordre = value;
-      this.validatePassword();
-    },
-    clearErrors() {
-      this.errors = emptyErrormessages();
-    },
-    clearPassword() {
-      this.password = "";
-      this.passwordre = "";
-    },
-    closeDetailview() {
-      this.$store.commit("usermanagement/clearCurrentUser");
-      this.$store.commit("usermanagement/setUserDetailsInvisible");
-    },
-    validateCountry() {
-      this.errors.country = this.currentUser.country
-        ? ""
-        : "Please choose a country";
-    },
-    validateRole() {
-      this.errors.role = this.currentUser.role ? "" : "Please choose a role";
-    },
-    validatePassword() {
-      this.errors.passwordre =
-        this.password === this.passwordre ? "" : "Passwords do not match!";
-      this.errors.password =
-        this.password === "" || !violatedPasswordRules(this.password)
-          ? ""
-          : "Password should at least be 8 char long including 1 digit and 1 special char like $";
-    },
-    validateEmailaddress() {
-      this.errors.email = isEmailValid(this.currentUser.email)
-        ? ""
-        : "invalid email";
-    },
-    validate() {
-      this.validateCountry();
-      this.validateRole();
-      this.validatePassword();
-      this.validateEmailaddress();
-    },
-    save() {
-      this.validate();
-      if (!this.isFormValid) return;
-      if (this.password) this.currentUser.password = this.password;
-      this.submitted = true;
-      this.$store
-        .dispatch("usermanagement/saveCurrentUser", {
-          path: this.user.user,
-          user: this.currentUser
-        })
-        .then(() => {
-          this.submitted = false;
-          this.$store.dispatch("usermanagement/loadUsers").catch(error => {
-            const { status, data } = error.response;
-            displayError({
-              title: "Backend Error",
-              message: `${status}: ${data.message || data}`
-            });
-          });
-        })
-        .catch(error => {
-          this.submitted = false;
-          const { status, data } = error.response;
-          displayError({
-            title: "Error while saving user",
-            message: `${status}: ${data.message || data}`
-          });
-        });
-    }
-  }
-};
-</script>
--- a/client/src/lib/errors.js	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-/** facade to wrap calls to vue2-toastr */
-import app from "../main";
-
-const displayError = ({ title, message }) => {
-  app.$toast.error({
-    title: title,
-    message: message
-  });
-};
-
-export { displayError };
--- a/client/src/lib/http.js	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-import axios from "axios";
-
-export const HTTP = axios.create({
-  baseURL: process.env.VUE_APP_API_URL || "/api"
-  /* headers: {
-    Authorization: 'Bearer {token}'
-  }*/
-});
--- a/client/src/lib/session.js	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-/**
- * Compares whether session is current
- * based on the expiry information and the
- * current date
- *
- * @param  {number} expiresFromPastSession
- */
-function sessionStillActive(expiresFromPastSession) {
-  if (!expiresFromPastSession) return false;
-  const now = Date.now();
-  const stillActive = now < expiresFromPastSession;
-  return stillActive;
-}
-/**
- * Converts a given unix time to Milliseconds
- *
- * @param  {string} timestring
- */
-function toMillisFromString(timestring) {
-  return timestring * 1000;
-}
-
-export { sessionStillActive, toMillisFromString };
--- a/client/src/stores/application.js	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-const defaultCollapseState = true;
-
-const Application = {
-  namespaced: true,
-  state: {
-    appTitle: process.env.VUE_APP_TITLE,
-    secondaryLogo: process.env.VUE_APP_SECONDARY_LOGO_URL,
-    sidebar: {
-      iscollapsed: defaultCollapseState
-    },
-    countries: ["AT", "SK", "HU", "HR", "RS", "BiH", "BG", "RO", "UA"]
-  },
-  getters: {
-    countries: state => {
-      return state.countries;
-    },
-    sidebarCollapsed: state => {
-      return state.sidebar.iscollapsed;
-    },
-    appTitle: state => {
-      return state.appTitle;
-    },
-    secondaryLogo: state => {
-      return state.secondaryLogo;
-    }
-  },
-  mutations: {
-    toggleSidebar: state => {
-      state.sidebar.iscollapsed = !state.sidebar.iscollapsed;
-    },
-    resetSidebar: state => {
-      state.sidebar.iscollapsed = defaultCollapseState;
-    },
-    collapseSidebar: state => {
-      state.sidebar.iscollapsed = true;
-    }
-  },
-  actions: {}
-};
-
-export default Application;
--- a/client/src/stores/mapstore.js	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-//import { HTTP } from "../lib/http";
-
-import TileWMS from "ol/source/TileWMS.js";
-import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer.js";
-import OSM from "ol/source/OSM";
-import { Stroke, Style } from "ol/style.js";
-import VectorSource from "ol/source/Vector.js";
-
-const MapStore = {
-  namespaced: true,
-  state: {
-    layers: [
-      {
-        name: "Open Streetmap",
-        data: new TileLayer({
-          source: new OSM()
-        }),
-        isVisible: true
-      },
-      {
-        name: "D4D",
-        data: new TileLayer({
-          source: new TileWMS({
-            url: "https://demo.d4d-portal.info/wms",
-            params: { LAYERS: "d4d", VERSION: "1.1.1", TILED: true }
-          })
-        }),
-        isVisible: true
-      },
-      {
-        name: "Fairways Dimensions",
-        data: new VectorLayer({
-          source: new VectorSource(),
-          style: new Style({
-            stroke: new Stroke({
-              color: "rgba(0, 0, 255, 1.0)",
-              width: 2
-            })
-          })
-        }),
-        isVisible: true
-      }
-    ]
-  },
-  getters: {
-    layers: state => {
-      return state.layers;
-    }
-  },
-  mutations: {
-    toggleVisibility: (state, layer) => {
-      state.layers[layer].isVisible = !state.layers[layer].isVisible;
-      state.layers[layer].data.setVisible(state.layers[layer].isVisible);
-    }
-  }
-};
-
-export default MapStore;
--- a/client/src/stores/user.js	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-import { HTTP } from "../lib/http";
-
-const User = {
-  namespaced: true,
-  state: {
-    authenticated: false,
-    expires: null,
-    roles: [],
-    user: ""
-  },
-  getters: {
-    isAuthenticated: state => {
-      return state.authenticated;
-    },
-    userinfo: state => {
-      return state.user;
-    },
-    roles: state => {
-      return state.roles;
-    },
-    expires: state => {
-      return state.expires;
-    },
-    isWaterwayAdmin: state => {
-      return state.roles.includes("waterway_admin");
-    },
-    isSysAdmin: state => {
-      return state.roles.includes("sys_admin");
-    }
-  },
-  mutations: {
-    auth_success: (state, data) => {
-      const { token, user, expires, roles } = data;
-      localStorage.setItem("expires", expires);
-      localStorage.setItem("roles", roles);
-      localStorage.setItem("token", token);
-      localStorage.setItem("user", user);
-      state.expires = expires;
-      state.roles = roles;
-      state.user = user;
-      state.authenticated = true;
-    },
-    clear_auth: state => {
-      state.authenticated = false;
-      state.expires = null;
-      state.roles = [];
-      state.user = "";
-      localStorage.clear();
-    },
-    set_user: (state, name) => {
-      state.user = name;
-    },
-    set_roles: (state, roles) => {
-      state.roles = roles;
-    },
-    set_expires: (state, expires) => {
-      state.expires = expires;
-    },
-    set_authenticate: state => {
-      state.authenticated = true;
-    }
-  },
-  actions: {
-    login({ commit }, user) {
-      // using POST is a bit more secure than GET
-      return new Promise((resolve, reject) => {
-        HTTP.post("/login", user)
-          .then(response => {
-            commit("auth_success", response.data);
-            resolve(response);
-          })
-          .catch(error => {
-            commit("clear_auth");
-            reject(error);
-          });
-      });
-    }
-  }
-};
-
-export default User;
--- a/client/src/stores/usermanagement.js	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,134 +0,0 @@
-import { HTTP } from "../lib/http";
-
-const newUser = () => {
-  return {
-    user: "",
-    email: "",
-    country: null,
-    role: null,
-    isNew: true,
-    password: "",
-    roleLabel: ""
-  };
-};
-
-const UserManagement = {
-  namespaced: true,
-  state: {
-    users: null,
-    currentUser: null,
-    userDetailsVisible: false
-  },
-  getters: {
-    isUserDetailsVisible: state => {
-      return state.userDetailsVisible;
-    },
-    currentUser: state => {
-      return state.currentUser;
-    },
-    users: state => {
-      return state.users;
-    },
-    getUserByName: state => name => {
-      return state.users.find(user => {
-        return user.user === name;
-      });
-    }
-  },
-  mutations: {
-    setUserDetailsInvisible: state => {
-      state.userDetailsVisible = false;
-    },
-    setUserDetailsVisible: state => {
-      state.userDetailsVisible = true;
-    },
-    usersLoaded: (state, data) => {
-      const resolveLabel = x => {
-        const labels = {
-          waterway_user: "Waterway User",
-          waterway_admin: "Waterway Administrator",
-          sys_admin: "System Admininistrator"
-        };
-        return labels[x];
-      };
-      let users = data.users.map(u => {
-        u["roleLabel"] = resolveLabel(u["role"]);
-        return u;
-      });
-      state.users = users;
-    },
-    setCurrentUser: (state, data) => {
-      state.currentUser = data;
-      state.userDetailsVisible = true;
-    },
-    clearCurrentUser: state => {
-      state.currentUser = newUser();
-    }
-  },
-  actions: {
-    deleteUser({ commit }, data) {
-      const { name } = data;
-      return new Promise((resolve, reject) => {
-        HTTP.delete("/users/" + name, {
-          headers: { "X-Gemma-Auth": localStorage.getItem("token") }
-        })
-          .then(response => {
-            commit("clearCurrentUser");
-            commit("setUserDetailsInvisible");
-            resolve(response);
-          })
-          .catch(error => {
-            reject(error);
-          });
-      });
-    },
-    saveCurrentUser({ commit }, data) {
-      const { path, user } = data;
-      if (user.isNew) {
-        return new Promise((resolve, reject) => {
-          HTTP.post("/users", user, {
-            headers: { "X-Gemma-Auth": localStorage.getItem("token") }
-          })
-            .then(response => {
-              commit("setUserDetailsInvisible");
-              commit("clearCurrentUser");
-              resolve(response);
-            })
-            .catch(error => {
-              reject(error);
-            });
-        });
-      } else {
-        return new Promise((resolve, reject) => {
-          HTTP.put("/users/" + path, user, {
-            headers: { "X-Gemma-Auth": localStorage.getItem("token") }
-          })
-            .then(response => {
-              commit("setUserDetailsInvisible");
-              commit("clearCurrentUser");
-              resolve(response);
-            })
-            .catch(error => {
-              reject(error);
-            });
-        });
-      }
-    },
-    loadUsers({ commit }) {
-      return new Promise((resolve, reject) => {
-        HTTP.get("/users", {
-          headers: { "X-Gemma-Auth": localStorage.getItem("token") }
-        })
-          .then(response => {
-            commit("usersLoaded", response.data);
-            resolve(response);
-          })
-          .catch(error => {
-            reject(error);
-          });
-      });
-    }
-  }
-};
-
-export default UserManagement;
--- a/client/src/views/Login.vue	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,201 +0,0 @@
-(<template>
-  <div class="d-flex flex-column login shadow-lg">
-    <div class="loginmask">
-      <!-- logo section -->
-      <div class="d-flex flex-row justify-content-center mb-3">
-        <div class="logo"><img src="../assets/logo.png"></div>
-        <div class="title">
-          <h1>{{ appTitle }}</h1>
-        </div>
-      </div>
-      <!-- end logo section -->
-      <form class="loginform" @submit.prevent="login">
-        <div id="alert" :style="errorMessageStyle" :class="errorMessageClass" role="alert">
-          <span>{{ errorMessage }}</span>
-        </div>
-        <div class="input-group mb-3">
-          <input type="text" v-model="user" id="inputUsername" class="form-control shadow-sm" :placeholder="usernameLabel" required autofocus>
-        </div>
-        <div class="input-group mb-3">
-          <input :type="isPasswordVisible" v-model="password" id="inputPassword" class="form-control shadow-sm" :placeholder='passwordLabel' :required='!showPasswordReset' :disabled='showPasswordReset'>
-          <div class="input-group-append">
-            <span class="input-group-text disabled" id="basic-addon2" @click="showPassword">
-              <i :class="eyeIcon"></i>
-            </span>
-          </div>
-        </div>
-        <button v-if="showPasswordReset==false" class="btn btn-primary btn-block shadow-sm" :disabled="submitted || showPasswordReset" type="submit">
-          <translate>Login</translate>
-        </button>
-        <div v-if="showPasswordReset" class="passwordreset">
-          <button class="btn btn-block btn-info" type="button" @click="resetPassword">
-            <translate>Request password reset!</translate>
-          </button>
-          <div class="pull-right">
-            <a href="#" @click.prevent="togglePasswordReset">
-              <translate>back to login</translate>
-            </a>
-          </div>
-        </div>
-        <div v-else class="pull-right">
-          <a href="#" @click.prevent="togglePasswordReset">
-            <translate>Forgot password</translate>
-          </a>
-        </div>
-      </form>
-
-      <!-- bottom logo section -->
-      <div class="mb-3 secondary-logo"><img :src="secondaryLogo"></div>
-    </div>
-  </div>
-</template>)
-
-<style lang="scss">
-@import "../assets/application.scss";
-
-.login {
-  background-color: white;
-  min-width: 375px;
-  min-height: 500px;
-  @extend %fully-centered;
-}
-
-.loginform {
-  max-width: 375px;
-  margin-left: auto;
-  margin-right: auto;
-}
-
-.loginmask {
-  margin-left: $large-offset;
-  margin-right: $large-offset;
-  margin-top: $large-offset;
-}
-
-.logo {
-  margin-right: $offset;
-}
-
-.alert {
-  padding: 0.5rem;
-}
-
-.secondary-logo {
-  max-width: 375px;
-  margin-left: auto;
-  margin-right: auto;
-  margin-bottom: auto;
-}
-</style>
-
-<script>
-import { mapGetters } from "vuex";
-import { HTTP } from "../lib/http";
-import { displayError } from "../lib/errors.js";
-
-export default {
-  name: "login",
-  data() {
-    return {
-      user: "",
-      password: "",
-      submitted: false,
-      loginFailed: false,
-      passwordJustResetted: false,
-      readablePassword: false,
-      showPasswordReset: false,
-      usernameToReset: ""
-    };
-  },
-  computed: {
-    errorMessage() {
-      if (this.loginFailed) return this.$gettext("Login failed");
-      if (this.passwordJustResetted)
-        return this.$gettext("Password reset requested!");
-      return "&npsp;";
-    },
-    passwordLabel() {
-      return this.$gettext("Enter passphrase");
-    },
-    usernameLabel() {
-      return this.$gettext("Enter username");
-    },
-    isPasswordVisible() {
-      return this.readablePassword ? "text" : "password";
-    },
-    eyeIcon() {
-      return {
-        fa: true,
-        "fa-eye": !this.readablePassword,
-        "fa-eye-slash": this.readablePassword
-      };
-    },
-    errorMessageStyle() {
-      if (this.loginFailed || this.passwordJustResetted) {
-        return "visibility:visible";
-      }
-      return "visibility:hidden";
-    },
-    errorMessageClass() {
-      let result = {
-        "mb-3": true,
-        errormessage: true,
-        alert: true
-      };
-      if (this.loginFailed) {
-        result["alert-danger"] = true;
-      }
-      if (this.passwordJustResetted) {
-        result["alert-info"] = true;
-      }
-      return result;
-    },
-    ...mapGetters("application", ["appTitle", "secondaryLogo"])
-  },
-  methods: {
-    login() {
-      this.submitted = true;
-      this.passwordJustResetted = false;
-      const { user, password } = this;
-      this.$store
-        .dispatch("user/login", { user, password })
-        .then(() => {
-          this.loginFailed = false;
-          this.$router.push("/");
-        })
-        .catch(error => {
-          this.loginFailed = true;
-          this.submitted = false;
-          const { status, data } = error.response;
-          displayError({
-            title: "Backend Error",
-            message: `${status}: ${data.message || data}`
-          });
-        });
-    },
-    showPassword() {
-      // disallowing toggle when in reset mode
-      if (this.showPasswordReset) return;
-      this.readablePassword = !this.readablePassword;
-    },
-    togglePasswordReset() {
-      this.passwordJustResetted = false;
-      this.showPasswordReset = !this.showPasswordReset;
-      this.loginFailed = false;
-    },
-    resetPassword() {
-      if (this.user) {
-        HTTP.post("/users/passwordreset", { user: this.user }).catch(error => {
-          const { status, data } = error.response;
-          displayError({
-            title: "Backend Error",
-            message: `${status}: ${data.message || data}`
-          });
-        });
-        this.togglePasswordReset();
-        this.passwordJustResetted = true;
-      }
-    }
-  }
-};
-</script>
--- a/client/src/views/Main.vue	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-<template>
-    <div class="main d-flex flex-column">
-        <Maplayer :lat="6155376" :long="1819178" :zoom="11"></Maplayer>
-    </div>
-</template>
-
-<style lang="scss">
-@import "../assets/application.scss";
-
-.menubutton {
-  margin-left: $small-offset;
-}
-</style>
-
-<script>
-import Maplayer from "../components/Maplayer";
-
-export default {
-  name: "mainview",
-  components: {
-    Maplayer
-  }
-};
-</script>
--- a/client/src/views/Usermanagement.vue	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,283 +0,0 @@
-<template>
-  <div class="main d-flex flex-column">
-    <div class="d-flex content flex-column">
-      <div class="d-flex flex-row">
-        <div :class="userlistStyle">
-          <div class="card">
-            <div class="card-header shadow-sm text-white bg-info mb-3">
-              Users
-            </div>
-            <div class="card-body">
-              <table id="datatable" :class="tableStyle">
-                <thead>
-                  <tr>
-                    <th scope="col" @click="sortBy('user')">
-                      <span>Username&nbsp;
-                        <i v-if="sortCriterion=='user'" class="fa fa-angle-down"></i>
-                      </span>
-                    </th>
-                    <th scope="col" @click="sortBy('country')">
-                      <span>Country&nbsp;
-                        <i v-if="sortCriterion=='country'" class="fa fa-angle-down"></i>
-                      </span>
-                    </th>
-                    <th scope="col" @click="sortBy('email')">
-                      <span>Email&nbsp;
-                        <i v-if="sortCriterion=='email'" class="fa fa-angle-down"></i>
-                      </span>
-                    </th>
-                    <th scope="col" @click="sortBy('role')">
-                      <span>Role&nbsp;
-                        <i v-if="sortCriterion=='role'" class="fa fa-angle-down"></i>
-                      </span>
-                    </th>
-                    <th scope="col"></th>
-                  </tr>
-                </thead>
-                <tbody>
-                  <tr v-for="user in users" :key="user.user" @click="selectUser(user.user)">
-                    <td>{{ user.user }}</td>
-                    <td>{{ user.country }}</td>
-                    <td>{{ user.email}}</td>
-                    <td>
-                      <i v-tooltip="user.roleLabel" :class="{
-                        fa:true,
-                        icon:true, 
-                        'fa-user':user.role==='waterway_user',
-                        'fa-star':user.role=='sys_admin',
-                        'fa-adn':user.role==='waterway_admin'}"></i>
-                    </td>
-                    <td>
-                      <i @click="deleteUser(user.user)" class="icon fa fa-trash-o"></i>
-                    </td>
-                  </tr>
-                </tbody>
-              </table>
-            </div>
-            <div class="d-flex flex-row pagination">
-              <i @click=" prevPage " v-if="this.currentPage!=1 " class="backwards btn btn-sm btn-light align-self-center pages fa fa-caret-left "></i> {{this.currentPage}} / {{this.pages}}
-              <i @click="nextPage " class="forwards btn btn-sm btn-light align-self-center pages fa fa-caret-right "></i>
-            </div>
-            <div class="adduser ">
-              <button @click="addUser " class="btn btn-info pull-right shadow-sm ">Add User</button>
-            </div>
-          </div>
-        </div>
-        <Userdetail v-if="isUserDetailsVisible "></Userdetail>
-      </div>
-    </div>
-  </div>
-</template>
-
-<style lang="scss">
-@import "../assets/application.scss";
-@import "../assets/tooltip.scss";
-.main {
-  height: 100vh;
-}
-
-.backwards {
-  margin-right: 0.5rem;
-}
-
-.forwards {
-  margin-left: 0.5rem;
-}
-
-.content {
-  margin-top: $large-offset;
-  margin-left: auto;
-  margin-right: auto;
-}
-
-.adduser {
-  margin-right: $offset;
-  padding-bottom: $offset;
-}
-
-.icon {
-  font-size: large;
-}
-
-.userlist {
-  margin-top: $topbarheight;
-  margin-right: $offset;
-  min-width: 520px;
-  height: 100%;
-}
-
-.pagination {
-  margin-left: auto;
-  margin-right: auto;
-}
-.userlistsmall {
-  width: 30vw;
-}
-
-.userlistextended {
-  width: 70vw;
-}
-
-.table {
-  width: 90% !important;
-  margin: auto;
-}
-
-.table th,
-.pages {
-  cursor: pointer;
-}
-
-.table th,
-td {
-  font-size: 0.9rem;
-  border-top: 0px !important;
-  text-align: left;
-  padding: 0.5rem !important;
-}
-
-.table td {
-  font-size: 0.9rem;
-  cursor: pointer;
-}
-
-tr span {
-  display: flex;
-}
-</style>
-
-<script>
-import Userdetail from "../components/Userdetail";
-import store from "../store";
-import { mapGetters } from "vuex";
-import { displayError } from "../lib/errors.js";
-
-export default {
-  name: "userview",
-  data() {
-    return {
-      sortCriterion: "user",
-      pageSize: 10,
-      currentPage: 1
-    };
-  },
-  components: {
-    Userdetail
-  },
-  computed: {
-    ...mapGetters("usermanagement", ["isUserDetailsVisible"]),
-    ...mapGetters("application", ["sidebarCollapsed"]),
-    users() {
-      let users = [...this.$store.getters["usermanagement/users"]];
-      users.sort((a, b) => {
-        if (
-          a[this.sortCriterion].toLowerCase() <
-          b[this.sortCriterion].toLowerCase()
-        )
-          return -1;
-        if (
-          a[this.sortCriterion].toLowerCase() >
-          b[this.sortCriterion].toLowerCase()
-        )
-          return 1;
-        return 0;
-      });
-      const start = (this.currentPage - 1) * this.pageSize;
-      return users.slice(start, start + this.pageSize);
-    },
-    pages() {
-      let users = [...this.$store.getters["usermanagement/users"]];
-      return Math.ceil(users.length / this.pageSize);
-    },
-    tableStyle() {
-      return {
-        table: true,
-        "table-hover": true,
-        "table-sm": this.isUserDetailsVisible,
-        fadeIn: true,
-        animated: true
-      };
-    },
-    userlistStyle() {
-      return {
-        userlist: true,
-        shadow: true,
-        userlistsmall: this.isUserDetailsVisible,
-        userlistextended: !this.isUserDetailsVisible
-      };
-    }
-  },
-  methods: {
-    tween() {},
-    nextPage() {
-      if (this.currentPage < this.pages) {
-        document.querySelector("#datatable").classList.add("fadeOut");
-        setTimeout(() => {
-          document.querySelector("#datatable").classList.remove("fadeOut");
-          this.currentPage += 1;
-        }, 10);
-      }
-      return;
-    },
-    prevPage() {
-      if (this.currentPage > 0) {
-        document.querySelector("#datatable").classList.add("fadeOut");
-        setTimeout(() => {
-          document.querySelector("#datatable").classList.remove("fadeOut");
-          this.currentPage -= 1;
-        }, 10);
-      }
-      return;
-    },
-    sortBy(criterion) {
-      this.sortCriterion = criterion;
-    },
-    deleteUser(name) {
-      this.$store
-        .dispatch("usermanagement/deleteUser", { name: name })
-        .then(() => {
-          this.submitted = false;
-          this.$store.dispatch("usermanagement/loadUsers").catch(error => {
-            const { status, data } = error.response;
-            displayError({
-              title: "Backend Error",
-              message: `${status}: ${data.message || data}`
-            });
-          });
-        })
-        .catch(error => {
-          const { status, data } = error.response;
-          displayError({
-            title: "Backend Error",
-            message: `${status}: ${data.message || data}`
-          });
-        });
-    },
-    addUser() {
-      this.$store.commit("usermanagement/clearCurrentUser");
-      this.$store.commit("usermanagement/setUserDetailsVisible");
-    },
-    selectUser(name) {
-      const user = this.$store.getters["usermanagement/getUserByName"](name);
-      this.$store.commit("usermanagement/setCurrentUser", user);
-    }
-  },
-  beforeRouteEnter(to, from, next) {
-    store
-      .dispatch("usermanagement/loadUsers")
-      .then(next)
-      .catch(error => {
-        const { status, data } = error.response;
-        displayError({
-          title: "Backend Error",
-          message: `${status}: ${data}`
-        });
-      });
-  },
-  beforeRouteLeave(to, from, next) {
-    store.commit("usermanagement/clearCurrentUser");
-    store.commit("usermanagement/setUserDetailsInvisible");
-    next();
-  }
-};
-</script>
--- a/client/src/views/Users.vue	Fri Sep 07 11:13:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,283 +0,0 @@
-<template>
-  <div class="main d-flex flex-column">
-    <div class="d-flex content flex-column">
-      <div class="d-flex flex-row">
-        <div :class="userlistStyle">
-          <div class="card">
-            <div class="card-header shadow-sm text-white bg-info mb-3">
-              Users
-            </div>
-            <div class="card-body">
-              <table id="datatable" :class="tableStyle">
-                <thead>
-                  <tr>
-                    <th scope="col" @click="sortBy('user')">
-                      <span>Username&nbsp;
-                        <i v-if="sortCriterion=='user'" class="fa fa-angle-down"></i>
-                      </span>
-                    </th>
-                    <th scope="col" @click="sortBy('country')">
-                      <span>Country&nbsp;
-                        <i v-if="sortCriterion=='country'" class="fa fa-angle-down"></i>
-                      </span>
-                    </th>
-                    <th scope="col" @click="sortBy('email')">
-                      <span>Email&nbsp;
-                        <i v-if="sortCriterion=='email'" class="fa fa-angle-down"></i>
-                      </span>
-                    </th>
-                    <th scope="col" @click="sortBy('role')">
-                      <span>Role&nbsp;
-                        <i v-if="sortCriterion=='role'" class="fa fa-angle-down"></i>
-                      </span>
-                    </th>
-                    <th scope="col"></th>
-                  </tr>
-                </thead>
-                <tbody>
-                  <tr v-for="user in users" :key="user.user" @click="selectUser(user.user)">
-                    <td>{{ user.user }}</td>
-                    <td>{{ user.country }}</td>
-                    <td>{{ user.email}}</td>
-                    <td>
-                      <i v-tooltip="user.roleLabel" :class="{
-                        fa:true,
-                        icon:true, 
-                        'fa-user':user.role==='waterway_user',
-                        'fa-star':user.role=='sys_admin',
-                        'fa-adn':user.role==='waterway_admin'}"></i>
-                    </td>
-                    <td>
-                      <i @click="deleteUser(user.user)" class="icon fa fa-trash-o"></i>
-                    </td>
-                  </tr>
-                </tbody>
-              </table>
-            </div>
-            <div class="d-flex flex-row pagination">
-              <i @click=" prevPage " v-if="this.currentPage!=1 " class="backwards btn btn-sm btn-light align-self-center pages fa fa-caret-left "></i> {{this.currentPage}} / {{this.pages}}
-              <i @click="nextPage " class="forwards btn btn-sm btn-light align-self-center pages fa fa-caret-right "></i>
-            </div>
-            <div class="adduser ">
-              <button @click="addUser " class="btn btn-info pull-right shadow-sm ">Add User</button>
-            </div>
-          </div>
-        </div>
-        <Userdetail v-if="isUserDetailsVisible "></Userdetail>
-      </div>
-    </div>
-  </div>
-</template>
-
-<style lang="scss">
-@import "../assets/application.scss";
-@import "../assets/tooltip.scss";
-.main {
-  height: 100vh;
-}
-
-.backwards {
-  margin-right: 0.5rem;
-}
-
-.forwards {
-  margin-left: 0.5rem;
-}
-
-.content {
-  margin-top: $large-offset;
-  margin-left: auto;
-  margin-right: auto;
-}
-
-.adduser {
-  margin-right: $offset;
-  padding-bottom: $offset;
-}
-
-.icon {
-  font-size: large;
-}
-
-.userlist {
-  margin-top: $topbarheight;
-  margin-right: $offset;
-  min-width: 520px;
-  height: 100%;
-}
-
-.pagination {
-  margin-left: auto;
-  margin-right: auto;
-}
-.userlistsmall {
-  width: 30vw;
-}
-
-.userlistextended {
-  width: 70vw;
-}
-
-.table {
-  width: 90% !important;
-  margin: auto;
-}
-
-.table th,
-.pages {
-  cursor: pointer;
-}
-
-.table th,
-td {
-  font-size: 0.9rem;
-  border-top: 0px !important;
-  text-align: left;
-  padding: 0.5rem !important;
-}
-
-.table td {
-  font-size: 0.9rem;
-  cursor: pointer;
-}
-
-tr span {
-  display: flex;
-}
-</style>
-
-<script>
-import Userdetail from "../components/Userdetail";
-import store from "../store";
-import { mapGetters } from "vuex";
-import { displayError } from "../lib/errors.js";
-
-export default {
-  name: "userview",
-  data() {
-    return {
-      sortCriterion: "user",
-      pageSize: 10,
-      currentPage: 1
-    };
-  },
-  components: {
-    Userdetail
-  },
-  computed: {
-    ...mapGetters("usermanagement", ["isUserDetailsVisible"]),
-    ...mapGetters("application", ["sidebarCollapsed"]),
-    users() {
-      let users = [...this.$store.getters["usermanagement/users"]];
-      users.sort((a, b) => {
-        if (
-          a[this.sortCriterion].toLowerCase() <
-          b[this.sortCriterion].toLowerCase()
-        )
-          return -1;
-        if (
-          a[this.sortCriterion].toLowerCase() >
-          b[this.sortCriterion].toLowerCase()
-        )
-          return 1;
-        return 0;
-      });
-      const start = (this.currentPage - 1) * this.pageSize;
-      return users.slice(start, start + this.pageSize);
-    },
-    pages() {
-      let users = [...this.$store.getters["usermanagement/users"]];
-      return Math.ceil(users.length / this.pageSize);
-    },
-    tableStyle() {
-      return {
-        table: true,
-        "table-hover": true,
-        "table-sm": this.isUserDetailsVisible,
-        fadeIn: true,
-        animated: true
-      };
-    },
-    userlistStyle() {
-      return {
-        userlist: true,
-        shadow: true,
-        userlistsmall: this.isUserDetailsVisible,
-        userlistextended: !this.isUserDetailsVisible
-      };
-    }
-  },
-  methods: {
-    tween() {},
-    nextPage() {
-      if (this.currentPage < this.pages) {
-        document.querySelector("#datatable").classList.add("fadeOut");
-        setTimeout(() => {
-          document.querySelector("#datatable").classList.remove("fadeOut");
-          this.currentPage += 1;
-        }, 10);
-      }
-      return;
-    },
-    prevPage() {
-      if (this.currentPage > 0) {
-        document.querySelector("#datatable").classList.add("fadeOut");
-        setTimeout(() => {
-          document.querySelector("#datatable").classList.remove("fadeOut");
-          this.currentPage -= 1;
-        }, 10);
-      }
-      return;
-    },
-    sortBy(criterion) {
-      this.sortCriterion = criterion;
-    },
-    deleteUser(name) {
-      this.$store
-        .dispatch("usermanagement/deleteUser", { name: name })
-        .then(() => {
-          this.submitted = false;
-          this.$store.dispatch("usermanagement/loadUsers").catch(error => {
-            const { status, data } = error.response;
-            displayError({
-              title: "Backend Error",
-              message: `${status}: ${data.message || data}`
-            });
-          });
-        })
-        .catch(error => {
-          const { status, data } = error.response;
-          displayError({
-            title: "Backend Error",
-            message: `${status}: ${data.message || data}`
-          });
-        });
-    },
-    addUser() {
-      this.$store.commit("usermanagement/clearCurrentUser");
-      this.$store.commit("usermanagement/setUserDetailsVisible");
-    },
-    selectUser(name) {
-      const user = this.$store.getters["usermanagement/getUserByName"](name);
-      this.$store.commit("usermanagement/setCurrentUser", user);
-    }
-  },
-  beforeRouteEnter(to, from, next) {
-    store
-      .dispatch("usermanagement/loadUsers")
-      .then(next)
-      .catch(error => {
-        const { status, data } = error.response;
-        displayError({
-          title: "Backend Error",
-          message: `${status}: ${data}`
-        });
-      });
-  },
-  beforeRouteLeave(to, from, next) {
-    store.commit("usermanagement/clearCurrentUser");
-    store.commit("usermanagement/setUserDetailsInvisible");
-    next();
-  }
-};
-</script>