changeset 1119:6d4cc4389c8f store-refactoring

merged default into store-refactoring
author Markus Kottlaender <markus@intevation.de>
date Tue, 06 Nov 2018 09:12:05 +0100
parents 7e788814cbde (diff) ef7c102497b8 (current diff)
children 035dc35e1dfc
files client/src/application/Topbar.vue
diffstat 19 files changed, 201 insertions(+), 261 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/application/Main.vue	Tue Nov 06 07:30:49 2018 +0100
+++ b/client/src/application/Main.vue	Tue Nov 06 09:12:05 2018 +0100
@@ -70,14 +70,14 @@
       "totalLength",
       "waterLevels",
       "fairwayCoordinates",
-      "selectedWaterLevel",
-      "availableSurveys",
-      "selectedMorph"
+      "selectedWaterLevel"
     ]),
+    ...mapState("bottlenecks", ["surveys", "selectedSurvey"]),
     additionalSurveys() {
-      if (!this.availableSurveys) return [];
-      return this.availableSurveys.surveys.filter(x => {
-        return x.date_info !== this.selectedMorph.date_info;
+      if (!this.surveys) return [];
+      if (!this.selectedSurvey) return this.surveys;
+      return this.surveys.filter(survey => {
+        return survey.date_info !== this.selectedSurvey.date_info;
       });
     },
     xAxis() {
--- a/client/src/application/Topbar.vue	Tue Nov 06 07:30:49 2018 +0100
+++ b/client/src/application/Topbar.vue	Tue Nov 06 09:12:05 2018 +0100
@@ -140,7 +140,7 @@
     };
   },
   computed: {
-    ...mapState("mapstore", ["openLayersMap"]),
+    ...mapState("map", ["openLayersMap"]),
     ...mapState("fairwayprofile", ["currentProfile"]),
     searchIndicator: function() {
       if (this.isSearching) {
--- a/client/src/bottlenecks/Bottlenecks.vue	Tue Nov 06 07:30:49 2018 +0100
+++ b/client/src/bottlenecks/Bottlenecks.vue	Tue Nov 06 09:12:05 2018 +0100
@@ -30,18 +30,18 @@
                     </a>
                 </div>
                 <div class="col-2">
-                    {{ displayCurrentSurvey(bottleneck) }}
+                    {{ displayCurrentSurvey(bottleneck.properties.current) }}
                 </div>
                 <div class="col-3">
-                    {{ displayCurrentChainage(bottleneck) }}
+                    {{ displayCurrentChainage(bottleneck.properties.from, bottleneck.properties.from) }}
                 </div>
                 <div class="col-2 text-right">
-                    <button type="button" class="btn btn-sm btn-outline-secondary" @click="toggleBottleneck(bottleneck)">
+                    <button type="button" class="btn btn-sm btn-outline-secondary" @click="toggleBottleneck(bottleneck.properties.name)">
                         <i class="fa fa-angle-down"></i>
                     </button>
                 </div>
-                <div :class="['col-12', 'surveys', {open: selectedBottleneck === bottleneck}]">
-                   <a href="#" class="d-block p-2" v-for="(survey, index) in surveys[bottleneck.properties.name]" :key="index" @click="selectSurvey(survey, bottleneck)">
+                <div :class="['col-12', 'surveys', {open: openBottleneck === bottleneck.properties.name}]">
+                   <a href="#" class="d-block p-2" v-for="(survey, index) in openBottleneckSurveys" :key="index" @click="selectSurvey(survey, bottleneck)">
                       {{ survey.date_info }}
                     </a>
                 </div>
@@ -77,14 +77,14 @@
       search: "",
       sortColumn: "name",
       sortDirection: "ASC",
-      selectedBottleneck: null,
-      surveys: {}
+      openBottleneck: null,
+      openBottleneckSurveys: null
     };
   },
   computed: {
     ...mapState("application", ["bottlenecksCollapsed"]),
     ...mapState("bottlenecks", ["bottlenecks"]),
-    ...mapState("mapstore", ["openLayersMap"]),
+    ...mapState("map", ["openLayersMap"]),
     ...mapGetters("application", ["sidebarCollapsed"]),
     bottlenecksStyle() {
       return {
@@ -153,10 +153,8 @@
         });
     },
     selectSurvey(survey, bottleneck) {
-      this.$store.commit("fairwayprofile/setSelectedMorph", survey);
-      this.$store.commit("fairwayprofile/setAvailableSurveys", {
-        surveys: this.surveys[bottleneck.properties.name]
-      });
+      this.$store.dispatch("bottlenecks/setSelectedBottleneck", bottleneck.properties.name);
+      this.$store.commit("bottlenecks/setSelectedSurvey", survey);
       this.moveToBottleneck(bottleneck);
     },
     moveToBottleneck(bottleneck) {
@@ -179,19 +177,21 @@
       this.sortColumn = column;
       this.sortDirection = this.sortDirection === "ASC" ? "DESC" : "ASC";
     },
-    toggleBottleneck(bottleneck) {
-      if (bottleneck === this.selectedBottleneck) {
-        this.selectedBottleneck = null;
+    toggleBottleneck(name) {
+      this.openBottleneckSurveys = null;
+      if (name === this.openBottleneck) {
+        this.openBottleneck = null;
       } else {
-        HTTP.get("/surveys/" + bottleneck.properties.name, {
+        this.openBottleneck = name;
+        
+        HTTP.get("/surveys/" + name, {
           headers: {
             "X-Gemma-Auth": localStorage.getItem("token"),
             "Content-type": "text/xml; charset=UTF-8"
           }
         })
           .then(response => {
-            this.surveys[bottleneck.properties.name] = response.data.surveys;
-            this.selectedBottleneck = bottleneck;
+            this.openBottleneckSurveys = response.data.surveys;
           })
           .catch(error => {
             const { status, data } = error.response;
@@ -202,13 +202,12 @@
           });
       }
     },
-    displayCurrentSurvey(bottleneck) {
-      const current = bottleneck.properties.current;
+    displayCurrentSurvey(current) {
       return current ? current.substr(0, current.length - 1) : "";
     },
-    displayCurrentChainage(bottleneck) {
+    displayCurrentChainage(from, to) {
       return (
-        bottleneck.properties.from / 10 + " - " + bottleneck.properties.to / 10
+        from / 10 + " - " + to / 10
       );
     }
   },
--- a/client/src/fairway/Fairwayprofile.vue	Tue Nov 06 07:30:49 2018 +0100
+++ b/client/src/fairway/Fairwayprofile.vue	Tue Nov 06 09:12:05 2018 +0100
@@ -8,6 +8,7 @@
                 <option
                     v-for="survey in additionalSurveys"
                     :key="survey.date_info"
+                    :value="survey"
                 >{{survey.date_info}}</option>
             </select>
             <small class="mt-2">
@@ -99,7 +100,6 @@
       "startPoint",
       "endPoint",
       "currentProfile",
-      "selectedMorph",
       "minAlt",
       "maxAlt",
       "totalLength",
@@ -107,6 +107,7 @@
       "waterLevels",
       "selectedWaterLevel"
     ]),
+    ...mapState("bottlenecks", ["selectedSurvey"]),
     additionalSurvey: {
       get() {
         return this.$store.getters["fairwayprofile/additionalSurvey"];
@@ -117,11 +118,18 @@
       }
     },
     currentData() {
-      const currentSurveyDate = this.selectedMorph.date_info;
-      return this.currentProfile[currentSurveyDate];
+      if (
+        !this.selectedSurvey ||
+        !this.currentProfile.hasOwnProperty(this.selectedSurvey.date_info)
+      ) return [];
+      return this.currentProfile[this.selectedSurvey.date_info];
     },
     additionalData() {
-      return this.currentProfile[this.additionalSurvey];
+      if (
+        !this.additionalSurvey ||
+        !this.currentProfile.hasOwnProperty(this.additionalSurvey.date_info)
+      ) return [];
+      return this.currentProfile[this.additionalSurvey.date_info];
     },
     waterColor() {
       const result = this.waterLevels.find(
@@ -160,7 +168,7 @@
       if (
         !this.additionalSurvey ||
         this.wait ||
-        this.currentProfile[this.additionalSurvey]
+        this.currentProfile[this.additionalSurvey.date_info]
       ) {
         this.drawDiagram();
         return;
--- a/client/src/identify/Identify.vue	Tue Nov 06 07:30:49 2018 +0100
+++ b/client/src/identify/Identify.vue	Tue Nov 06 09:12:05 2018 +0100
@@ -109,7 +109,7 @@
   },
   computed: {
     ...mapGetters("application", ["versionStr"]),
-    ...mapState("identifystore", ["identifiedFeatures", "currentMeasurement"]),
+    ...mapState("map", ["identifiedFeatures", "currentMeasurement"]),
     identifyStyle() {
       return {
         "ui-element": true,
--- a/client/src/layers/Layers.vue	Tue Nov 06 07:30:49 2018 +0100
+++ b/client/src/layers/Layers.vue	Tue Nov 06 09:12:05 2018 +0100
@@ -80,7 +80,7 @@
     Layerselect
   },
   computed: {
-    ...mapGetters("mapstore", ["layers"]),
+    ...mapGetters("map", ["layers"]),
     layerSelectStyle() {
       return {
         "ui-element": true,
@@ -97,7 +97,7 @@
       this.collapsed = !this.collapsed;
     },
     visibilityToggled(layer) {
-      this.$store.commit("mapstore/toggleVisibility", layer);
+      this.$store.commit("map/toggleVisibility", layer);
     }
   }
 };
--- a/client/src/layers/LegendElement.vue	Tue Nov 06 07:30:49 2018 +0100
+++ b/client/src/layers/LegendElement.vue	Tue Nov 06 09:12:05 2018 +0100
@@ -37,7 +37,7 @@
     };
   },
   computed: {
-    ...mapGetters("mapstore", ["getLayerByName"]),
+    ...mapGetters("map", ["getLayerByName"]),
     id() {
       return "legendelement" + this.layerindex;
     },
--- a/client/src/linetool/Linetool.vue	Tue Nov 06 07:30:49 2018 +0100
+++ b/client/src/linetool/Linetool.vue	Tue Nov 06 09:12:05 2018 +0100
@@ -1,5 +1,5 @@
 <template>
-    <div @click="drawLine" class="ui-element d-flex shadow drawtool">
+    <div @click="cycleDrawMode" class="ui-element d-flex shadow drawtool">
         <i :class="icon"></i>
     </div>
 </template>
@@ -44,24 +44,23 @@
 export default {
   name: "linetool",
   methods: {
-    drawLine() {
-      if (!this.selectedMorph && this.drawMode === "LineString") {
-        this.$store.commit("application/activateDrawModePolygon");
+    cycleDrawMode() {
+      if (!this.selectedSurvey && this.drawMode === "LineString") {
+        this.$store.commit("map/activateDrawModePolygon");
       } else {
-        this.$store.commit("application/toggleDrawModeLine");
+        this.$store.commit("map/toggleDrawModeLine");
       }
     }
   },
   computed: {
-    ...mapState("application", ["drawMode"]),
-    ...mapState("identifystore", ["identifiedFeatures"]),
-    ...mapState("fairwayprofile", ["selectedMorph"]),
+    ...mapState("map", ["identifiedFeatures", "drawMode"]),
+    ...mapState("bottlenecks", ["selectedSurvey"]),
     icon() {
       return {
         fa: true,
-        "fa-area-chart": this.selectedMorph,
-        "fa-edit": !this.selectedMorph && this.drawMode === "Polygon",
-        "fa-pencil": !this.selectedMorph && this.drawMode !== "Polygon",
+        "fa-area-chart": this.selectedSurvey,
+        "fa-edit": !this.selectedSurvey && this.drawMode === "Polygon",
+        "fa-pencil": !this.selectedSurvey && this.drawMode !== "Polygon",
         inverted: this.drawMode
       };
     }
--- a/client/src/map/Maplayer.vue	Tue Nov 06 07:30:49 2018 +0100
+++ b/client/src/map/Maplayer.vue	Tue Nov 06 09:12:05 2018 +0100
@@ -71,10 +71,9 @@
     };
   },
   computed: {
-    ...mapGetters("mapstore", ["layers", "getLayerByName"]),
-    ...mapState("application", ["drawMode"]),
-    ...mapState("mapstore", ["openLayersMap"]),
-    ...mapState("fairwayprofile", ["selectedMorph"]),
+    ...mapGetters("map", ["layers", "getLayerByName"]),
+    ...mapState("map", ["openLayersMap", "drawMode"]),
+    ...mapState("bottlenecks", ["selectedSurvey"]),
     mapStyle() {
       return {
         mapfull: !this.split,
@@ -124,7 +123,7 @@
       return styles;
     },
     removeCurrentInteraction() {
-      this.$store.commit("identifystore/setCurrentMeasurement", null);
+      this.$store.commit("map/setCurrentMeasurement", null);
       this.vectorSource.clear();
       this.openLayersMap.removeInteraction(this.interaction);
       this.interaction = null;
@@ -138,7 +137,7 @@
       });
       draw.on("drawstart", () => {
         this.vectorSource.clear();
-        this.$store.commit("identifystore/setCurrentMeasurement", null);
+        this.$store.commit("map/setCurrentMeasurement", null);
         // we are not setting an id here, to avoid the regular identify to
         // pick it up
         // event.feature.setId("drawn.1"); // unique id for new feature
@@ -152,14 +151,14 @@
         // also place the a rounded areaSize in a property,
         // so identify will show it
         if (areaSize > 100000) {
-          this.$store.commit("identifystore/setCurrentMeasurement", {
+          this.$store.commit("map/setCurrentMeasurement", {
             quantity: "Area",
             unitSymbol: "km²",
             // convert into 1 km² == 1000*1000 m² and round to 1000 m²
             value: Math.round(areaSize / 1000) / 1000
           });
         } else {
-          this.$store.commit("identifystore/setCurrentMeasurement", {
+          this.$store.commit("map/setCurrentMeasurement", {
             quantity: "Area",
             unitSymbol: "m²",
             value: Math.round(areaSize)
@@ -168,7 +167,7 @@
       }
       if (this.drawMode === "LineString") {
         const length = getLength(event.feature.getGeometry());
-        this.$store.commit("identifystore/setCurrentMeasurement", {
+        this.$store.commit("map/setCurrentMeasurement", {
           quantity: "Length",
           unitSymbol: "m",
           value: Math.round(length * 10) / 10
@@ -178,9 +177,9 @@
       // if a survey has been selected, request a profile
       // TODO an improvement could be to check if the line intersects
       // with the bottleneck area's polygon before trying the server request
-      if (this.selectedMorph) {
+      if (this.selectedSurvey) {
         this.$store.commit("fairwayprofile/clearCurrentProfile");
-        console.log("requesting profile for", this.selectedMorph);
+        console.log("requesting profile for", this.selectedSurvey);
         const inputLineString = event.feature.getGeometry().clone();
         inputLineString.transform("EPSG:3857", "EPSG:4326");
         const [start, end] = inputLineString
@@ -190,7 +189,7 @@
         this.$store.commit("fairwayprofile/setEndPoint", end);
         const profileLine = new LineString([start, end]);
         this.$store
-          .dispatch("fairwayprofile/loadProfile", this.selectedMorph.date_info)
+          .dispatch("fairwayprofile/loadProfile", this.selectedSurvey)
           .then(() => {
             var vectorSource = this.getLayerByName(
               "Fairway Dimensions"
@@ -242,10 +241,21 @@
       this.openLayersMap.addInteraction(interaction);
     },
     identify(coordinate, pixel) {
-      this.$store.commit("identifystore/setIdentifiedFeatures", []);
+      this.$store.commit("map/setIdentifiedFeatures", []);
       // checking our WFS layers
       var features = this.openLayersMap.getFeaturesAtPixel(pixel);
-      this.$store.commit("identifystore/setIdentifiedFeatures", features);
+      if (features) {
+        this.$store.commit("map/setIdentifiedFeatures", features);
+        
+        // get selected bottleneck from identified features
+        for (let feature of features) {
+          let id = feature.getId();
+          // RegExp.prototype.test() works with number, str and undefined
+          if (/^bottlenecks\./.test(id)) {
+            this.$store.dispatch("bottlenecks/setSelectedBottleneck", feature.get("objnam"));
+          }
+        }
+      }
 
       // DEBUG output and example how to remove the GeometryName
       /*
@@ -384,11 +394,11 @@
         map.updateSize();
       });
     },
-    selectedMorph(newSelectedMorph) {
-      if (newSelectedMorph) {
+    selectedSurvey(newSelectedSurvey) {
+      if (newSelectedSurvey) {
         this.updateBottleneckFilter(
-          newSelectedMorph.bottleneck_id,
-          newSelectedMorph.date_info
+          newSelectedSurvey.bottleneck_id,
+          newSelectedSurvey.date_info
         );
       } else {
         this.updateBottleneckFilter("does_not_exist", "1999-10-01");
@@ -411,7 +421,7 @@
         projection: this.projection
       })
     });
-    this.$store.commit("mapstore/setOpenLayersMap", map);
+    this.$store.commit("map/setOpenLayersMap", map);
 
     // TODO make display of layers more dynamic, e.g. from a list
 
--- a/client/src/morphtool/Morphtool.vue	Tue Nov 06 07:30:49 2018 +0100
+++ b/client/src/morphtool/Morphtool.vue	Tue Nov 06 09:12:05 2018 +0100
@@ -1,36 +1,34 @@
 <template>
     <div class="morphcontainer">
-        <div v-if="selectedBottleneck">
-            <div v-if="surveyList && !drawMode" class="ui-element card card-body shadow">
-                <div class="headline">
-                    <h4>{{bottleneckName}}</h4>
-                    <hr>
-                    <div
-                        @click="clearSelection"
-                        class="float-left ui-element d-flex morphtoolminus"
-                    >
-                        <i class="fa fa-close morphtoolsminus"></i>
-                    </div>
+        <div v-if="selectedBottleneck && surveys && !selectedSurvey" class="ui-element card card-body shadow">
+            <div class="headline">
+                <h4>{{ selectedBottleneck }}</h4>
+                <hr>
+                <div
+                    @click="clearSelection"
+                    class="float-left ui-element d-flex morphtoolminus"
+                >
+                    <i class="fa fa-close morphtoolsminus"></i>
                 </div>
-                <ul class="list-group surveylist">
-                    <li
-                        v-for="survey of surveyList.surveys"
-                        :key="survey.data_info"
-                        class="list-group-item"
-                        @click.prevent="selectSurvey(survey)"
-                    >
-                        <a href="#" @click.prevent>{{survey.date_info}}</a>
-                    </li>
-                </ul>
             </div>
+            <ul class="list-group surveylist">
+                <li
+                    v-for="survey of surveys"
+                    :key="survey.data_info"
+                    class="list-group-item"
+                    @click.prevent="$store.commit('bottlenecks/setSelectedSurvey', survey)"
+                >
+                    <a href="#" @click.prevent>{{ survey.date_info }}</a>
+                </li>
+            </ul>
         </div>
-        <div v-if="selectedMorph" @click="clearSelection" class="ui-element shadow morphtool">
+        <div v-if="selectedSurvey" @click="clearSelection" class="ui-element shadow morphtool">
             <div class="d-flex flex-row justify-content-between">
                 <i class="fa fa-close text-danger"></i>
                 <small>Bottleneck:&nbsp;</small>
                 <h6>
-                    {{bottleneckName}}
-                    <small>( {{selectedMorph.date_info}} )</small>
+                    {{ selectedBottleneck }}
+                    <small>( {{ selectedSurvey.date_info }} )</small>
                 </h6>
             </div>
         </div>
@@ -108,83 +106,22 @@
  */
 import { mapState } from "vuex";
 
-import { displayError } from "../application/lib/errors.js";
-import { HTTP } from "../application/lib/http";
-
 export default {
   name: "morphtool",
-  data() {
-    return {
-      surveyList: null,
-      bottleneckName: ""
-    };
-  },
   computed: {
-    ...mapState("application", ["drawMode"]),
-    ...mapState("identifystore", ["identifiedFeatures"]),
-    ...mapState("fairwayprofile", ["selectedMorph"]),
-    selectedBottleneck: function() {
-      if (this.identifiedFeatures && !this.drawMode) {
-        for (let feature of this.identifiedFeatures) {
-          let id = feature.getId();
-          // RegExp.prototype.test() works with number, str and undefined
-          if (/^bottlenecks\./.test(id)) {
-            this.$store.commit("fairwayprofile/setSelectedMorph", null);
-            return feature;
-          }
-        }
-      }
-      return null;
-    }
-  },
-  watch: {
-    selectedBottleneck: function(bottleneckFeature) {
-      if (bottleneckFeature) {
-        let bottleneckName = bottleneckFeature.get("objnam");
-        if (bottleneckName) {
-          this.bottleneckName = bottleneckName;
-          this.queryBottleneck(bottleneckName);
-        }
-      }
-    }
+    ...mapState("map", ["drawMode"]),
+    ...mapState("bottlenecks", [
+      "selectedBottleneck",
+      "surveys",
+      "selectedSurvey"
+    ])
   },
   methods: {
-    queryBottleneck(name) {
-      // DEBUG console.log("starting to query bottleneck", name);
-      HTTP.get("/surveys/" + name, {
-        headers: {
-          "X-Gemma-Auth": localStorage.getItem("token"),
-          "Content-type": "text/xml; charset=UTF-8"
-        }
-      })
-        .then(response => {
-          this.surveyList = response.data;
-          this.$store.commit(
-            "fairwayprofile/setAvailableSurveys",
-            response.data
-          );
-        })
-        .catch(error => {
-          this.surveyList = null;
-          const { status, data } = error.response;
-          displayError({
-            title: "Backend Error",
-            message: `${status}: ${data.message || data}`
-          });
-        });
-    },
-    selectSurvey(survey) {
-      this.$store.commit("fairwayprofile/setSelectedMorph", survey);
-      this.surveyList = null;
-    },
     clearSelection() {
-      this.$store.commit("identifystore/setIdentifiedFeatures", []);
-      this.$store.commit("fairwayprofile/setSelectedMorph", null);
-      this.$store.commit("fairwayprofile/clearCurrentProfile");
+      this.$store.dispatch("bottlenecks/setSelectedBottleneck", null);
       this.$store.commit("application/closeSplitScreen");
-      this.surveyList = null;
       if (this.drawMode) {
-        this.$store.commit("application/toggleDrawModeLine");
+        this.$store.commit("map/toggleDrawModeLine");
       }
     }
   }
--- a/client/src/store.js	Tue Nov 06 07:30:49 2018 +0100
+++ b/client/src/store.js	Tue Nov 06 09:12:05 2018 +0100
@@ -16,24 +16,22 @@
 
 import Vue from "vue";
 import Vuex from "vuex";
-import Application from "./store/application";
+import application from "./store/application";
 import user from "./store/user";
 import usermanagement from "./store/usermanagement";
-import mapstore from "./store/map";
-import FairwayProfile from "./store/fairway";
-import IdentifyStore from "./store/identify";
-import Bottlenecks from "./store/bottlenecks";
+import map from "./store/map";
+import fairwayprofile from "./store/fairway";
+import bottlenecks from "./store/bottlenecks";
 
 Vue.use(Vuex);
 
 export default new Vuex.Store({
   modules: {
-    application: Application,
-    fairwayprofile: FairwayProfile,
-    identifystore: IdentifyStore,
-    bottlenecks: Bottlenecks,
-    mapstore: mapstore,
-    user: user,
-    usermanagement: usermanagement
+    application,
+    fairwayprofile,
+    bottlenecks,
+    map,
+    user,
+    usermanagement
   }
 });
--- a/client/src/store/application.js	Tue Nov 06 07:30:49 2018 +0100
+++ b/client/src/store/application.js	Tue Nov 06 09:12:05 2018 +0100
@@ -25,7 +25,7 @@
   };
 };
 
-const Application = {
+export default {
   namespaced: true,
   state: {
     appTitle: process.env.VUE_APP_TITLE,
@@ -39,8 +39,6 @@
       iscollapsed: defaultCollapseState
     },
     countries: ["AT", "SK", "HU", "HR", "RS", "BiH", "BG", "RO", "UA"],
-    // there are three states of drawMode: null, "LineString", "Polygon"
-    drawMode: null,
     version
   },
   getters: {
@@ -114,19 +112,7 @@
     },
     resetSplitScreen: state => {
       state.splitsceen = initializeSplitScreen();
-    },
-    toggleDrawModeLine: state => {
-      if (state.drawMode) {
-        state.drawMode = null;
-      } else {
-        state.drawMode = "LineString";
-      }
-    },
-    activateDrawModePolygon: state => {
-      state.drawMode = "Polygon";
     }
   },
   actions: {}
 };
-
-export default Application;
--- a/client/src/store/bottlenecks.js	Tue Nov 06 07:30:49 2018 +0100
+++ b/client/src/store/bottlenecks.js	Tue Nov 06 09:12:05 2018 +0100
@@ -14,18 +14,39 @@
  */
 import { HTTP } from "../application/lib/http";
 import { WFS } from "ol/format.js";
+import { displayError } from "../application/lib/errors.js";
 
-const Bottlenecks = {
+export default {
   namespaced: true,
   state: {
-    bottlenecks: []
+    bottlenecks: [],
+    selectedBottleneck: null,
+    surveys: [],
+    selectedSurvey: null
   },
   mutations: {
     setBottlenecks: (state, bottlenecks) => {
       state.bottlenecks = bottlenecks;
+    },
+    setSelectedBottleneck: (state, name) => {
+      state.selectedBottleneck = name;
+    },
+    setSurveys(state, surveys) {
+      state.surveys = surveys;
+    },
+    setSelectedSurvey(state, survey) {
+      state.selectedSurvey = survey;
     }
   },
   actions: {
+    setSelectedBottleneck({ state, commit, dispatch }, name) {
+      if (name !== state.selectedBottleneck) {
+        commit("setSelectedSurvey", null);
+        commit("fairwayprofile/clearCurrentProfile", null, { root: true });
+      }
+      commit("setSelectedBottleneck", name);
+      dispatch("querySurveys", name);
+    },
     loadBottlenecks({ commit }) {
       var bottleneckFeatureCollectionRequest = new WFS().writeGetFeature({
         srsName: "EPSG:4326",
@@ -49,8 +70,29 @@
       ).then(response => {
         commit("setBottlenecks", response.data.features);
       });
+    },
+    querySurveys({ commit }, name) {
+      if (name) {
+        HTTP.get("/surveys/" + name, {
+          headers: {
+            "X-Gemma-Auth": localStorage.getItem("token"),
+            "Content-type": "text/xml; charset=UTF-8"
+          }
+        })
+          .then(response => {
+            commit("setSurveys", response.data.surveys);
+          })
+          .catch(error => {
+            commit("setSurveys", []);
+            const { status, data } = error.response;
+            displayError({
+              title: "Backend Error",
+              message: `${status}: ${data.message || data}`
+            });
+          });
+      } else {
+        commit("setSurveys", []);
+      }
     }
   }
 };
-
-export default Bottlenecks;
--- a/client/src/store/fairway.js	Tue Nov 06 07:30:49 2018 +0100
+++ b/client/src/store/fairway.js	Tue Nov 06 09:12:05 2018 +0100
@@ -21,11 +21,10 @@
 
 const DEMOLEVEL = 149.345;
 
-const FairwayProfile = {
+export default {
   namespaced: true,
   state: {
     additionalSurvey: "",
-    availableSurveys: null,
     totalLength: 0,
     minAlt: 0,
     maxAlt: 0,
@@ -34,8 +33,7 @@
     selectedWaterLevel: DEMOLEVEL,
     fairwayCoordinates: [],
     startPoint: null,
-    endPoint: null,
-    selectedMorph: null
+    endPoint: null
   },
   getters: {
     length: state => {
@@ -49,12 +47,6 @@
     setAdditionalSurvey: (state, additionalSurvey) => {
       state.additionalSurvey = additionalSurvey;
     },
-    setSelectedMorph: (state, selectedMorph) => {
-      state.selectedMorph = selectedMorph;
-    },
-    setAvailableSurveys: (state, surveys) => {
-      state.availableSurveys = surveys;
-    },
     setSelectedWaterLevel: (state, level) => {
       state.selectedWaterLevel = level;
     },
@@ -101,13 +93,13 @@
     }
   },
   actions: {
-    loadProfile({ commit, state }, date_info) {
+    loadProfile({ commit, state }, survey) {
       return new Promise((resolve, reject) => {
         const profileLine = new LineString([state.startPoint, state.endPoint]);
         const geoJSON = generateFeatureRequest(
           profileLine,
-          state.selectedMorph.bottleneck_id,
-          date_info
+          survey.bottleneck_id,
+          survey.date_info
         );
         HTTP.post("/cross", geoJSON, {
           headers: { "X-Gemma-Auth": localStorage.getItem("token") }
@@ -115,7 +107,7 @@
           .then(response => {
             commit("profileLoaded", {
               response: response,
-              surveyDate: date_info
+              surveyDate: survey.date_info
             });
             resolve(response);
           })
@@ -126,5 +118,3 @@
     }
   }
 };
-
-export default FairwayProfile;
--- a/client/src/store/identify.js	Tue Nov 06 07:30:49 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * 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>
- */
-
-// note that some identified features may not have an id
-// especially related to drawing in our own vector layer
-
-const IndentifyStore = {
-  namespaced: true,
-  state: {
-    identifiedFeatures: [],
-    currentMeasurement: null
-  },
-  getters: {
-    identifiedFeatures: state => {
-      return state.identifiedFeatures;
-    },
-    currentMeasurement: state => {
-      return state.currentMeasurement;
-    }
-  },
-  mutations: {
-    setIdentifiedFeatures: (state, identifiedFeatures) => {
-      state.identifiedFeatures = identifiedFeatures;
-    },
-    setCurrentMeasurement: (state, measurement) => {
-      state.currentMeasurement = measurement;
-    }
-  }
-};
-
-export default IndentifyStore;
--- a/client/src/store/map.js	Tue Nov 06 07:30:49 2018 +0100
+++ b/client/src/store/map.js	Tue Nov 06 09:12:05 2018 +0100
@@ -23,10 +23,14 @@
 import { bbox as bboxStrategy } from "ol/loadingstrategy";
 import { HTTP } from "../application/lib/http";
 
-const MapStore = {
+export default {
   namespaced: true,
   state: {
     openLayersMap: null,
+    identifiedFeatures: [],
+    currentMeasurement: null,
+    // there are three states of drawMode: null, "LineString", "Polygon"
+    drawMode: null,
     layers: [
       {
         name: "Open Streetmap",
@@ -228,8 +232,22 @@
     },
     setOpenLayersMap: (state, map) => {
       state.openLayersMap = map;
+    },
+    setIdentifiedFeatures: (state, identifiedFeatures) => {
+      state.identifiedFeatures = identifiedFeatures;
+    },
+    setCurrentMeasurement: (state, measurement) => {
+      state.currentMeasurement = measurement;
+    },
+    toggleDrawModeLine: state => {
+      if (state.drawMode) {
+        state.drawMode = null;
+      } else {
+        state.drawMode = "LineString";
+      }
+    },
+    activateDrawModePolygon: state => {
+      state.drawMode = "Polygon";
     }
   }
 };
-
-export default MapStore;
--- a/client/src/store/user.js	Tue Nov 06 07:30:49 2018 +0100
+++ b/client/src/store/user.js	Tue Nov 06 09:12:05 2018 +0100
@@ -15,7 +15,7 @@
 
 import { HTTP } from "../application/lib/http";
 
-const User = {
+export default {
   namespaced: true,
   state: {
     authenticated: false,
@@ -92,5 +92,3 @@
     }
   }
 };
-
-export default User;
--- a/client/src/store/usermanagement.js	Tue Nov 06 07:30:49 2018 +0100
+++ b/client/src/store/usermanagement.js	Tue Nov 06 09:12:05 2018 +0100
@@ -27,7 +27,7 @@
   };
 };
 
-const UserManagement = {
+export default {
   namespaced: true,
   state: {
     users: null,
@@ -145,5 +145,3 @@
     }
   }
 };
-
-export default UserManagement;
--- a/client/src/zoom/zoom.vue	Tue Nov 06 07:30:49 2018 +0100
+++ b/client/src/zoom/zoom.vue	Tue Nov 06 09:12:05 2018 +0100
@@ -30,7 +30,7 @@
 export default {
   name: "zoom",
   computed: {
-    ...mapState("mapstore", ["openLayersMap"]),
+    ...mapState("map", ["openLayersMap"]),
     zoomLevel: {
       get() {
         return this.openLayersMap.getView().getZoom();