changeset 1077:c58608084c11

finished bottleneck list (search, sort, sounding data)
author Markus Kottlaender <markus@intevation.de>
date Fri, 26 Oct 2018 14:04:37 +0200
parents 12312fb1cda2
children 2ed3b4eaaab4
files client/src/bottlenecks/Bottlenecks.vue
diffstat 1 files changed, 115 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/bottlenecks/Bottlenecks.vue	Fri Oct 26 10:05:20 2018 +0200
+++ b/client/src/bottlenecks/Bottlenecks.vue	Fri Oct 26 14:04:37 2018 +0200
@@ -1,23 +1,45 @@
 <template>
-    <div :class="bottlenecksStyle">
+    <div :class="bottlenecksStyle" style="overflow: hidden; background: #fff;">
         <div @click="$store.commit('application/toggleBottlenecks');" class="ui-element close-bottlenecks">
             <i class="fa fa-close"></i>
         </div>
 
-        <div v-if="!this.bottlenecksCollapsed">
-            <h4>Bottlenecks</h4>
-            <hr class="mb-0">
-            <div style="max-height: 500px; overflow-y: scroll">
-                <table class="table text-left mb-0" style="margin-top: -1px;">
-                    <tr v-for="(bottleneck) in bottlenecks"
-                        :key="bottleneck.name">
-                        <td>
+        <h4>Bottlenecks</h4>
+        <hr class="mb-0">
+        <input type="text" v-model="search" placeholder="Search Bottleneck..." class="border-0 w-100 p-2" />
+        <div class="bottleneck-table d-flex flex-column">
+            <div class="d-flex flex-row p-2 border-top">
+                <div>
+                    <a href="#" @click="sortBy('name')" class="sort-link">Name</a>
+                    <i :class="sortClass" v-if="sortColumn === 'name'"></i>
+                </div>
+                <!--<div>
+                    <a href="#" @click="sortBy('latestMeasurement')">Latest Measurement</a>
+                    <i :class="sortClass" v-if="sortColumn === 'latestMeasurement'"></i>
+                </div>-->
+                <div></div>
+            </div>
+            <div class="d-flex flex-column">
+                <div v-for="bottleneck in filteredAndSortedBottlenecks" :key="bottleneck.name" class="border-top">
+                    <div class="d-flex flex-row justify-content-between p-2">
+                        <div>
                             <a href="#" class="d-block" @click="moveToBottleneck(bottleneck)">
                                 {{ bottleneck.name }}
                             </a>
-                        </td>
-                    </tr>
-                </table>
+                        </div>
+                        <!--<td>2018-10-25</td>-->
+                        <div class="text-right">
+                            <button type="button" class="btn btn-sm btn-outline-secondary" @click="queryBottleneck(bottleneck)">
+                                <i class="fa fa-angle-down"></i>
+                            </button>
+                        </div>
+                    </div>
+                    <div :class="['surveys', {open: selectedBottleneck === bottleneck}]">
+                       <a href="#" class="d-block p-2 border-top" v-for="(survey, index) in surveys[bottleneck.name]" :key="index" @click="selectSurvey(survey)">
+                          {{ survey.date_info }}
+                        </a>
+                    </div>
+                </div>
             </div>
         </div>
     </div>
@@ -40,9 +62,20 @@
  */
 import { mapState } from "vuex";
 import { fromLonLat } from "ol/proj";
+import { HTTP } from "../application/lib/http";
+import { displayError } from "../application/lib/errors.js";
 
 export default {
   name: "bottlenecks",
+  data() {
+    return {
+      search: "",
+      sortColumn: "name",
+      sortDirection: "ASC",
+      selectedBottleneck: null,
+      surveys: {}
+    };
+  },
   computed: {
     ...mapState("application", ["bottlenecksCollapsed"]),
     ...mapState("bottlenecks", ["bottlenecks"]),
@@ -56,11 +89,41 @@
         bottlenecksextended: !this.bottlenecksCollapsed,
         shadow: true
       };
+    },
+    filteredAndSortedBottlenecks() {
+      return this.bottlenecks
+        .filter(bn => {
+          return bn.name.toLowerCase().includes(this.search.toLowerCase());
+        })
+        .sort((bnA, bnB) => {
+          switch (this.sortColumn) {
+            case "name":
+              if (bnA.name.toLowerCase() < bnB.name.toLowerCase())
+                return this.sortDirection === "ASC" ? -1 : 1;
+              if (bnA.name.toLowerCase() > bnB.name.toLowerCase())
+                return this.sortDirection === "ASC" ? 1 : -1;
+              return 0;
+            default:
+              return 0;
+          }
+        });
+    },
+    sortClass() {
+      return {
+        fa: true,
+        "fa-sort-amount-asc": this.sortDirection === "ASC",
+        "fa-sort-amount-desc": this.sortDirection === "DESC",
+        "ml-1": true
+      };
     }
   },
   methods: {
-    // TODO: make this central, duplicates code from application/Topbar.vue
+    selectSurvey(survey) {
+      this.$store.commit("fairwayprofile/setSelectedMorph", survey);
+      this.moveToBottleneck(this.selectedBottleneck);
+    },
     moveToBottleneck(bottleneck) {
+      // TODO: make this central, duplicates code from application/Topbar.vue
       if (bottleneck.geom.type == "Point") {
         let view = this.openLayersMap.getView();
         const currentZoom = view.getZoom();
@@ -77,6 +140,30 @@
         );
       }
       this.$store.commit("application/toggleBottlenecks");
+    },
+    sortBy(column) {
+      this.sortColumn = column;
+      this.sortDirection = this.sortDirection === "ASC" ? "DESC" : "ASC";
+    },
+    queryBottleneck(bottleneck) {
+      HTTP.get("/surveys/" + bottleneck.name, {
+        headers: {
+          "X-Gemma-Auth": localStorage.getItem("token"),
+          "Content-type": "text/xml; charset=UTF-8"
+        }
+      })
+        .then(response => {
+          this.surveys[bottleneck.name] = response.data.surveys;
+          this.selectedBottleneck =
+            this.selectedBottleneck === bottleneck ? null : bottleneck;
+        })
+        .catch(error => {
+          const { status, data } = error.response;
+          displayError({
+            title: "Backend Error",
+            message: `${status}: ${data.message || data}`
+          });
+        });
     }
   },
   mounted() {
@@ -104,7 +191,6 @@
 }
 
 .bottlenecksextended {
-  min-height: $sidebar-height;
   width: 500px;
 }
 
@@ -122,4 +208,19 @@
 .bottlenecksextended .close-bottlenecks {
   display: block;
 }
+
+.surveys {
+  max-height: 0;
+  overflow: hidden;
+  transition: max-height 0.3s ease;
+}
+
+.surveys.open {
+  max-height: 999px;
+}
+
+.sort-link {
+  color: #444;
+  font-weight: bold;
+}
 </style>