changeset 548:7feeb341bb4d

Merged
author Sascha Wilde <wilde@intevation.de>
date Thu, 30 Aug 2018 14:59:13 +0200
parents 9b67c4f5a7b2 (current diff) 505656a9947f (diff)
children b3f825c8445b
files
diffstat 11 files changed, 237 insertions(+), 230 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/App.vue	Wed Aug 29 16:45:22 2018 +0200
+++ b/client/src/App.vue	Thu Aug 30 14:59:13 2018 +0200
@@ -7,27 +7,22 @@
 <style lang="scss">
 html {
   height: 100%;
+  width: 100%;
+  margin: 0 auto;
 }
 body {
-  min-height: 100%;
+  height: 100%;
+  width: 100%;
   background-color: #efefef !important;
 }
 
 #app {
+  height: 100%;
+  width: 100%;
   font-family: "Avenir", Helvetica, Arial, sans-serif;
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
   text-align: center;
   color: #2c3e50;
 }
-#nav {
-  padding: 30px;
-  a {
-    font-weight: bold;
-    color: #2c3e50;
-    &.router-link-exact-active {
-      color: #42b983;
-    }
-  }
-}
 </style>
--- a/client/src/assets/application.scss	Wed Aug 29 16:45:22 2018 +0200
+++ b/client/src/assets/application.scss	Thu Aug 30 14:59:13 2018 +0200
@@ -10,6 +10,7 @@
 $transition: 0.5s;
 $transition-fast: 0.1s;
 $transition-slow: 3s;
+$topbarheight: 4vh;
 
 %fully-centered {
   position: absolute;
--- a/client/src/components/Layerselect.vue	Wed Aug 29 16:45:22 2018 +0200
+++ b/client/src/components/Layerselect.vue	Thu Aug 30 14:59:13 2018 +0200
@@ -1,11 +1,8 @@
 <template>
-    <div class="d-flex">
-        <label :for="layername">{{this.layername}}</label>
-        <input @change="visibilityToggled"
-               :id="layername"
-               type="checkbox"
-               :checked="isVisible">  
-    </div>
+  <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">
--- a/client/src/components/Maplayer.vue	Wed Aug 29 16:45:22 2018 +0200
+++ b/client/src/components/Maplayer.vue	Thu Aug 30 14:59:13 2018 +0200
@@ -1,36 +1,40 @@
 <template>
   <div class="mapdisplay">
     <div id="map"></div>
-    <div v-if="this.openLayersMap" class="layerselection">
-      <h4>Layers</h4>
-      <hr>
-      <Layerselect :layerindex="index"
-                   :layername="layer.name"
-                   v-for="(layer, index) in layers"
-                   :key="layer.name"
-                   :isVisible="layer.isVisible"
-                   @visibilityToggled="visibilityToggled"
-      ></Layerselect>
+    <div v-if="this.openLayersMap" class="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>
   </div>
 </template>
 
 <style lang="scss">
+@import "../assets/application.scss";
+
 .mapdisplay {
   height: 100%;
-  width: 100%;
 }
+
 #map {
-  height: 100%;
-  width: 100%;
+  height: 96vh;
 }
+
 .layerselection {
   position: absolute;
-  top: 0;
-  right: 0;
+  top: $topbarheight;
+  margin-top: $small-offset;
+  right: $small-offset;
   min-height: 20%;
   min-width: 10%;
   background-color: white;
+  z-index: 10;
 }
 </style>
 
--- a/client/src/components/Sidebar.vue	Wed Aug 29 16:45:22 2018 +0200
+++ b/client/src/components/Sidebar.vue	Thu Aug 30 14:59:13 2018 +0200
@@ -1,6 +1,5 @@
 <template>
   <div :class="sidebarStyle">
-    <div :class="collapseStyle"><i @click="collapse" :class="collapseicon"></i></div>
     <nav :class="menuStyle">
       <router-link to="/" class="d-flex nav-link">Riverbed Morphology</router-link>
       <a class="d-flex nav-link" href="#">Link</a>
@@ -13,10 +12,13 @@
     </nav>
     <div :class="userinfoStyle">
       <div class="menupadding userinfo">
-        <img class="userpic" src="../assets/user.png"><span class="username">{{ userinfo }}</span>
+        <img class="userpic" src="../assets/user.png">
+        <span class="username">{{ userinfo }}</span>
       </div>
       <div>
-        <span class="logout" @click="logoff"><i class="fa fa-power-off"></i></span>
+        <span class="logout" @click="logoff">
+          <i class="fa fa-power-off"></i>
+        </span>
       </div>
     </div>
   </div>
@@ -27,62 +29,48 @@
 
 export default {
   name: "sidebar",
-  props: ["isOverlay"],
   computed: {
     ...mapGetters("user", ["userinfo", "isSysAdmin"]),
-    collapseicon() {
-      return {
-        fa: true,
-        "fa-angle-double-left": !this.isCollapsed,
-        "fa-angle-double-right": this.isCollapsed
-      };
-    },
+    ...mapGetters("application", ["sidebarCollapsed"]),
     menuStyle() {
       return {
         menu: true,
         nav: true,
         "flex-column": true,
-        "visibility-extended": !this.isCollapsed,
-        "visibility-collapsed": this.isCollapsed
+        "visibility-extended": !this.sidebarCollapsed,
+        "visibility-collapsed": this.sidebarCollapsed
       };
     },
     userinfoStyle() {
       return {
         user: true,
         "d-flex": true,
-        "visibility-extended": !this.isCollapsed,
-        "visibility-collapsed": this.isCollapsed
+        "visibility-extended": !this.sidebarCollapsed,
+        "visibility-collapsed": this.sidebarCollapsed
       };
     },
     collapseStyle() {
       return {
         collapser: true,
-        collapserextended: !this.isCollapsed,
-        collapsercollapsed: this.isCollapsed
+        collapserextended: !this.sidebarCollapsed,
+        collapsercollapsed: this.sidebarCollapsed
       };
     },
     sidebarStyle() {
       return {
         sidebar: true,
-        overlay: this.isOverlay,
-        sidebarcollapsed: this.isCollapsed,
-        sidebarextended: !this.isCollapsed
+        overlay: true,
+        sidebarcollapsed: this.sidebarCollapsed,
+        sidebarextended: !this.sidebarCollapsed,
+        shadow: true
       };
     }
   },
   methods: {
-    collapse() {
-      this.isCollapsed = !this.isCollapsed;
-    },
     logoff() {
       this.$store.commit("user/clear_auth");
       this.$router.push("/login");
     }
-  },
-  data() {
-    return {
-      isCollapsed: false
-    };
   }
 };
 </script>
@@ -137,9 +125,10 @@
   margin-top: auto;
 }
 .sidebar {
+  margin-top: $topbarheight;
   background-color: #ffffff;
   padding-top: $large-offset;
-  height: 100vh;
+  height: 96vh;
 }
 
 .overlay {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/components/Topbar.vue	Thu Aug 30 14:59:13 2018 +0200
@@ -0,0 +1,24 @@
+<template>
+    <div class="topbar shadow-sm d-flex flex-row justify-content-between">
+        <div class="align-self-center">
+            <i @click="toggleSidebar" class="menubutton fa fa-bars"></i>
+        </div>
+        <div class="">
+            <h2>Topbar</h2>
+        </div>
+        <div>
+
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+  name: "topbar",
+  methods: {
+    toggleSidebar() {
+      this.$store.commit("application/toggleSidebar");
+    }
+  }
+};
+</script>
--- a/client/src/stores/application.js	Wed Aug 29 16:45:22 2018 +0200
+++ b/client/src/stores/application.js	Thu Aug 30 14:59:13 2018 +0200
@@ -4,7 +4,7 @@
     appTitle: process.env.VUE_APP_TITLE,
     secondaryLogo: process.env.VUE_APP_SECONDARY_LOGO_URL,
     sidebar: {
-      iscollapsed: false
+      iscollapsed: true
     },
     countries: ["AT", "SK", "HU", "HR", "RS", "BiH", "BG", "RO", "UA"]
   },
@@ -23,8 +23,8 @@
     }
   },
   mutations: {
-    toggleSidebar: () => {
-      this.sidebar.iscollapsed = !this.sidebar.iscollapsed;
+    toggleSidebar: state => {
+      state.sidebar.iscollapsed = !state.sidebar.iscollapsed;
     }
   },
   actions: {}
--- a/client/src/views/Login.vue	Wed Aug 29 16:45:22 2018 +0200
+++ b/client/src/views/Login.vue	Thu Aug 30 14:59:13 2018 +0200
@@ -1,138 +1,90 @@
 (<template>
-  <div :class="loginStyle">
-    <div>
-      <div class="logogroup d-flex flex-row justify-content-center">
+  <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 class="title">
+          <h1>{{ appTitle }}</h1>
+        </div>
       </div>
-    </div>
-    <div class="login-wrapper d-flex flex-row justify-content-center">
-      <form class="loginform form-signin" @submit.prevent="login">
-           <div id="alert" v-if="loginFailed" class="loginerrormessage alert alert-danger" role="alert">
-             <span class="loginerror"><translate>Login failed</translate></span>
-           </div>
-           <div id="alert" v-if="passwordJustResetted"
-                class="loginerrormessage alert alert-danger" role="alert">
-             <span class="loginerror"
-               ><translate>Password reset requested!</translate></span>
-           </div>
-        <div class="input-group mb-3 usernamegroup">
-          <input type="text" v-model="user" id="inputUsername" class="form-control" :placeholder="usernameLabel" required autofocus>
+      <!-- end logo section -->
+      <div id="alert" :style="errorMessageStyle" :class="errorMessageClass" role="alert">
+        <span>{{ errorMessage }}</span>
+      </div>
+      <form class="loginform" @submit.prevent="login">
+        <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 passwordgroup">
-          <input :type="isPasswordVisible" v-model="password"
-            id="inputPassword" class="form-control"
-            :placeholder='passwordLabel'
-            :required='!showPasswordReset' :disabled='showPasswordReset'>
+        <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>
+            <span class="input-group-text disabled" id="basic-addon2" @click="showPassword">
+              <i :class="eyeIcon"></i>
+            </span>
           </div>
         </div>
-        <button class="submitbutton btn btn-primary btn-block"
-          :disabled="submitted || showPasswordReset" type="submit"
-          ><translate>Login</translate></button>
-      </form>
-    </div>
-
-    <!-- password forgotten part -->
-    <div class="d-flex flex-row justify-content-center">
-      <form class="loginform form-signin">
+        <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">
-          <!--
-          TODO text and action for password reset
-          <div class="input-group mb-3 usernamegroup">
-            <input type="text" v-model="usernameToReset" class="form-control" :placeholder="usernameLabel" required>
+          <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>
-          -->
-          <button class="btn btn-warning btn-block" type="button"
-            @click="resetPassword"
-            ><translate>Request password reset!</translate></button>
-            <div class="forgottenlink small">
-            <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>
-        <div v-else class="forgottenlink small">
-            <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>
-
-    <!-- bottom logo section -->
-    <div class="secondary-logo d-flex flex-row justify-content-center"
-        ><img :src="secondaryLogo"></div>
   </div>
 </template>)
 
 <style lang="scss">
 @import "../assets/application.scss";
-$logincollapsed: 470px;
-$loginextended: 550px;
 
-.usernamegroup {
-  box-shadow: $basic-shadow-light !important;
-}
-.forgottenlink {
-  text-align: right;
-  margin-top: $small-offset;
-  margin-bottom: $small-offset;
-}
-#inputPassword {
-  border-right: none;
-}
-.input-group-text {
-  background-color: white !important;
+.login {
+  background-color: white;
+  min-width: 375px;
+  min-height: 500px;
+  @extend %fully-centered;
 }
 
-.login {
-  width: 375px;
-  @extend %fully-centered;
-  padding-top: $offset;
-  padding-bottom: $offset;
-  box-shadow: $basic-shadow;
-}
-.logincollapsed {
-  height: $logincollapsed;
+.loginform {
+  max-width: 375px;
+  margin-left: auto;
+  margin-right: auto;
 }
 
-.loginextended {
-  height: $loginextended;
-}
-.loginerror {
-  white-space: pre;
+.loginmask {
+  margin-left: $large-offset;
+  margin-right: $large-offset;
+  margin-top: $large-offset;
 }
-.loginerrormessage {
-  box-shadow: $basic-shadow-light !important;
-}
-.loginform {
-  width: 300px;
-}
-.logogroup {
-  margin-top: $offset;
-  margin-bottom: $offset;
+
+.logo {
+  margin-right: $offset;
 }
-.passwordreset {
-  margin-top: $offset;
-  margin-bottom: $offset;
-}
-.mail-icon {
-  width: $iconwidth;
-}
-.passwordgroup {
-  box-shadow: $basic-shadow-light !important;
+
+.alert {
+  padding: 0.5rem;
 }
-.password-icon {
-  position: relative;
-  top: 10px;
-  font-size: $iconsize;
-  line-height: $iconLineHeight;
-  width: $iconwidth;
-}
-.submitbutton {
-  box-shadow: $basic-shadow-light !important;
-}
-.title {
-  margin-left: $offset;
+
+.secondary-logo {
+  max-width: 375px;
+  margin-left: auto;
+  margin-right: auto;
+  margin-bottom: auto;
 }
 </style>
 
@@ -155,6 +107,12 @@
     };
   },
   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");
     },
@@ -171,14 +129,25 @@
         "fa-eye-slash": this.readablePassword
       };
     },
-    loginStyle() {
-      return {
-        login: true,
-        logincollapsed: !this.loginFailed,
-        loginextended: this.loginFailed,
-        "bg-white": true,
-        rounded: true
+    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"])
   },
@@ -207,6 +176,7 @@
     togglePasswordReset() {
       this.passwordJustResetted = false;
       this.showPasswordReset = !this.showPasswordReset;
+      this.loginFailed = false;
     },
     resetPassword() {
       if (this.user) {
--- a/client/src/views/Main.vue	Wed Aug 29 16:45:22 2018 +0200
+++ b/client/src/views/Main.vue	Thu Aug 30 14:59:13 2018 +0200
@@ -1,32 +1,34 @@
 <template>
-  <div class="main d-flex">
-    <Sidebar v-bind:isOverlay="true"></Sidebar>
-    <Maplayer :lat="6155376"
-      :long="1819178"
-      :zoom="11"
-    ></Maplayer>
+  <div class="main d-flex flex-column">
+    <Topbar></Topbar>
+    <Sidebar></Sidebar>
+    <Maplayer :lat="6155376" :long="1819178" :zoom="11"></Maplayer>
   </div>
 </template>
 
 <style lang="scss">
-.main {
-  height: 100vh;
+@import "../assets/application.scss";
+.topbar {
+  background-color: white;
+  height: $topbarheight;
+  z-index: 10;
 }
 
-#map {
-  background-color: #ffffff;
-  width: 100%;
+.menubutton {
+  margin-left: $small-offset;
 }
 </style>
 
 <script>
 import Maplayer from "../components/Maplayer";
 import Sidebar from "../components/Sidebar";
+import Topbar from "../components/Topbar";
 export default {
   name: "mainview",
   components: {
     Maplayer,
-    Sidebar
+    Sidebar,
+    Topbar
   }
 };
 </script>
--- a/client/src/views/Users.vue	Wed Aug 29 16:45:22 2018 +0200
+++ b/client/src/views/Users.vue	Thu Aug 30 14:59:13 2018 +0200
@@ -1,42 +1,64 @@
 <template>
-  <div class="main d-flex">
-    <Sidebar v-bind:isOverlay="false"></Sidebar>
+  <div class="main d-flex flex-column">
+    <Topbar></Topbar>
+    <Sidebar></Sidebar>
     <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>{{ user.role }}</td>
-                      <td><i @click="deleteUser(user.user)" class="fa fa-trash-o"></i></td>
-                      </tr>
-                    </tbody>
-                </table>
-              </div>
-              <div><i @click="prevPage" v-if="this.currentPage!=1" class="pages fa fa-caret-left"></i> {{this.currentPage}} / {{this.pages}} <i @click="nextPage" class="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 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>{{ user.role }}</td>
+                    <td>
+                      <i @click="deleteUser(user.user)" class="fa fa-trash-o"></i>
+                    </td>
+                  </tr>
+                </tbody>
+              </table>
+            </div>
+            <div>
+              <i @click="prevPage" v-if="this.currentPage!=1" class="pages fa fa-caret-left"></i> {{this.currentPage}} / {{this.pages}}
+              <i @click="nextPage" class="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>
-          <Userdetail v-if="isUserDetailsVisible"></Userdetail>
+        </div>
+        <Userdetail v-if="isUserDetailsVisible"></Userdetail>
       </div>
     </div>
   </div>
@@ -103,6 +125,7 @@
 
 <script>
 import Sidebar from "../components/Sidebar";
+import Topbar from "../components/Topbar";
 import Userdetail from "../components/Userdetail";
 import store from "../store";
 import { mapGetters } from "vuex";
@@ -119,7 +142,8 @@
   },
   components: {
     Sidebar,
-    Userdetail
+    Userdetail,
+    Topbar
   },
   computed: {
     ...mapGetters("usermanagement", ["isUserDetailsVisible"]),
--- a/pkg/controllers/proxy.go	Wed Aug 29 16:45:22 2018 +0200
+++ b/pkg/controllers/proxy.go	Thu Aug 30 14:59:13 2018 +0200
@@ -33,6 +33,7 @@
 	"http://www.opengis.net/gml/3.2":            struct{}{},
 	"http://www.opengis.net/fes/2.0":            struct{}{},
 	"http://schemas.opengis.net/gml":            struct{}{},
+	"http://www.opengis.net/wfs":                struct{}{},
 }
 
 func proxyDirector(lookup func(string) (string, bool)) func(*http.Request) {