changeset 1625:de4e4dcb8f87

staging area: implemented details and zoom to bbox
author Thomas Junk <thomas.junk@intevation.de>
date Wed, 19 Dec 2018 12:52:33 +0100
parents 943823d03d50
children 92da44ba610c
files client/src/components/Contextbox.vue client/src/components/staging/Staging.vue client/src/components/staging/StagingDetail.vue client/src/store/bottlenecks.js
diffstat 4 files changed, 134 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/components/Contextbox.vue	Tue Dec 18 18:36:02 2018 +0100
+++ b/client/src/components/Contextbox.vue	Wed Dec 19 12:52:33 2018 +0100
@@ -79,7 +79,7 @@
 }
 
 .contextboxextended {
-  max-width: 600px;
+  max-width: 700px;
   max-height: 640px;
 }
 
--- a/client/src/components/staging/Staging.vue	Tue Dec 18 18:36:02 2018 +0100
+++ b/client/src/components/staging/Staging.vue	Wed Dec 19 12:52:33 2018 +0100
@@ -7,8 +7,8 @@
       ></font-awesome-icon>
       <translate>Staging Area</translate>
     </h6>
-    <div>
-      <div class="mt-3 ml-3 mr-3 text-left flex-row d-flex border-bottom">
+    <div class="mt-3 pl-3 pr-3">
+      <div class="mt-3 text-left flex-row d-flex border-bottom">
         <div class="header text-left name"><translate>Name</translate></div>
         <div class="header text-left type"><translate>Type</translate></div>
         <div class="header text-left date"><translate>Date</translate></div>
@@ -20,7 +20,7 @@
         </div>
         <div class="ml-3 controls"></div>
       </div>
-      <div class="ml-3 mr-3 mt-3" v-if="filteredData.length">
+      <div class="mt-3" v-if="filteredData.length">
         <StagingDetail
           class="mb-3 border-bottom"
           :key="data.id"
@@ -142,7 +142,7 @@
 
 <style lang="scss" scoped>
 .name {
-  width: 120px;
+  width: 180px;
 }
 
 .date {
--- a/client/src/components/staging/StagingDetail.vue	Tue Dec 18 18:36:02 2018 +0100
+++ b/client/src/components/staging/StagingDetail.vue	Wed Dec 19 12:52:33 2018 +0100
@@ -8,7 +8,11 @@
           href="#"
           >{{ data.summary.bottleneck }}</a
         >
-        <span v-else class="mr-auto ml-auto">*</span>
+        <span v-else class="text-left"
+          ><translate>Bottlenecks</translate> ({{
+            data.summary.bottlenecks.length
+          }})</span
+        >
       </div>
       <div class="mt-auto mb-auto small text-left type">
         {{ data.kind.toUpperCase() }}
@@ -77,14 +81,52 @@
         <div v-else class="empty"></div>
       </div>
     </div>
-    <div class="d-flex flex-row" v-if="show">
-      <a
-        class="small"
-        v-for="(bottleneck, index) in data.summary.bottlenecks"
-        :key="index"
-        href="#"
-        >{{ bottleneck }}</a
-      >
+    <div
+      v-for="(bottleneck, index) in bottlenecks"
+      :key="index"
+      class="d-flex flex-row"
+      v-if="show"
+    >
+      <div class="d-flex flex-column">
+        <div class="d-flex flex-row">
+          <a
+            @click="moveToBottleneck(bottleneck.properties.bbox)"
+            class="small"
+            href="#"
+            >{{ bottleneck.properties.objnam }}</a
+          >
+          <div
+            @click="showFull = !showFull"
+            class="small mt-auto mb-auto text-info text-left"
+          >
+            <font-awesome-icon
+              v-if="showFull"
+              icon="angle-up"
+              fixed-width
+            ></font-awesome-icon>
+            <font-awesome-icon
+              v-if="!showFull"
+              icon="angle-down"
+              fixed-width
+            ></font-awesome-icon>
+          </div>
+        </div>
+
+        <div class="d-flex flex-row" v-if="showFull">
+          <table>
+            <tr
+              v-for="(info, index) in Object.keys(bottleneck.properties)"
+              :key="index"
+              class="mr-1 small text-muted"
+            >
+              <td class="condensed text-left">{{ info }}</td>
+              <td class="condensed pl-3 text-left">
+                {{ bottleneck.properties[info] }}
+              </td>
+            </tr>
+          </table>
+        </div>
+      </div>
     </div>
   </div>
 </template>
@@ -106,23 +148,78 @@
 
 import { formatSurveyDate } from "@/lib/date.js";
 import { STATES } from "@/store/imports.js";
+import { HTTP } from "@/lib/http";
+import { WFS } from "ol/format.js";
+import { or as orFilter, equalTo as equalToFilter } from "ol/format/filter.js";
+import { displayError } from "@/lib/errors.js";
 
 export default {
   name: "stagingdetail",
   props: ["data"],
   data() {
     return {
+      showFull: false,
       show: false,
-      loading: false
+      loading: false,
+      bottlenecks: []
     };
   },
+  mounted() {
+    this.bottlenecks = [];
+  },
   methods: {
     showDetails() {
       if (this.show) {
         this.show = false;
         return;
       }
-      this.show = true;
+      if (this.bottlenecks.length > 0) {
+        this.show = true;
+        return;
+      }
+      this.loading = true;
+      const generateFilter = () => {
+        const { bottlenecks } = this.data.summary;
+        if (bottlenecks.length === 1)
+          return equalToFilter("bottleneck_id", bottlenecks[0]);
+        const orExpressions = bottlenecks.map(x => {
+          equalToFilter("bottleneck_id", x);
+        });
+        return orFilter(...orExpressions);
+      };
+      const filterExpression = generateFilter();
+      const bottleneckFeatureCollectionRequest = new WFS().writeGetFeature({
+        srsName: "EPSG:4326",
+        featureNS: "gemma",
+        featurePrefix: "gemma",
+        featureTypes: ["bottlenecks"],
+        outputFormat: "application/json",
+        filter: filterExpression
+      });
+      HTTP.post(
+        "/internal/wfs",
+        new XMLSerializer().serializeToString(
+          bottleneckFeatureCollectionRequest
+        ),
+        {
+          headers: {
+            "X-Gemma-Auth": localStorage.getItem("token"),
+            "Content-type": "text/xml; charset=UTF-8"
+          }
+        }
+      )
+        .then(response => {
+          this.bottlenecks = response.data.features;
+          this.show = true;
+          this.loading = false;
+        })
+        .catch(error => {
+          const { status, data } = error.response;
+          displayError({
+            title: this.$gettext("Backend Error"),
+            message: `${status}: ${data.message || data}`
+          });
+        });
     },
     isBottleneck(kind) {
       return kind === "BN";
@@ -139,15 +236,25 @@
     isApproved(item) {
       return item.status === STATES.APPROVED;
     },
-    zoomTo() {
-      const { lat, lon, bottleneck, date } = this.data.summary;
-      const coordinates = [lat, lon];
-
+    moveToBottleneck(bbox) {
+      const [lat1, long1, lat2, long2] = bbox;
+      const coordinates = [
+        lat1 + (lat2 - lat1) / 2,
+        long1 + (long2 - long1) / 2
+      ];
+      this.moveMap(coordinates);
+    },
+    moveMap(coordinates) {
       this.$store.commit("map/moveMap", {
         coordinates: coordinates,
         zoom: 17,
         preventZoomOut: true
       });
+    },
+    zoomTo() {
+      const { lat, lon, bottleneck, date } = this.data.summary;
+      const coordinates = [lat, lon];
+      this.moveMap(coordinates);
       this.$store
         .dispatch("bottlenecks/setSelectedBottleneck", bottleneck)
         .then(() => {
@@ -166,12 +273,16 @@
 </script>
 
 <style lang="scss" scoped>
+.condensed {
+  font-stretch: condensed;
+}
+
 .empty {
   margin-right: 20px;
 }
 
 .name {
-  width: 120px;
+  width: 180px;
 }
 
 .date {
--- a/client/src/store/bottlenecks.js	Tue Dec 18 18:36:02 2018 +0100
+++ b/client/src/store/bottlenecks.js	Wed Dec 19 12:52:33 2018 +0100
@@ -12,9 +12,9 @@
  * Markus Kottländer <markuks.kottlaender@intevation.de>
  * Thomas Junk <thomas.junk@intevation.de>
  */
-import { HTTP } from "../lib/http";
+import { HTTP } from "@/lib/http";
 import { WFS } from "ol/format.js";
-import { displayError } from "../lib/errors.js";
+import { displayError } from "@/lib/errors.js";
 
 // initial state
 const init = () => {