Mercurial > gemma
changeset 1090:dbf0221b1cf1
bottleneck list uses different wfs endpoint now
to reduce own server-side-code the bottleneck list is now retreived as a feature
collection and includes more details.
author | Markus Kottlaender <markus@intevation.de> |
---|---|
date | Tue, 30 Oct 2018 11:35:36 +0100 |
parents | 8ae18a8d000e |
children | 4489e96fb2b4 |
files | client/src/bottlenecks/Bottlenecks.vue client/src/bottlenecks/store.js |
diffstat | 2 files changed, 142 insertions(+), 105 deletions(-) [+] |
line wrap: on
line diff
--- a/client/src/bottlenecks/Bottlenecks.vue Mon Oct 29 15:36:11 2018 +0100 +++ b/client/src/bottlenecks/Bottlenecks.vue Tue Oct 30 11:35:36 2018 +0100 @@ -7,38 +7,36 @@ <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 class="row p-2 border-top"> + <div class="col-5"> + <a href="#" @click="sortBy('name')" class="sort-link">Name</a> + <i :class="sortClass" v-if="sortColumn === 'name'"></i> + </div> + <div class="col-5"> + <a href="#" @click="sortBy('latestMeasurement')" class="sort-link">Latest Measurement</a> + <i :class="sortClass" v-if="sortColumn === 'latestMeasurement'"></i> </div> - <div class="d-flex flex-column bottleneck-list"> - <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> - </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 class="col-2"></div> + </div> + <div class="bottleneck-list"> + <div v-for="bottleneck in filteredAndSortedBottlenecks()" :key="bottleneck.properties.name" class="border-top row mx-0 py-2"> + <div class="col-5 text-left"> + <a href="#" class="d-block" @click="moveToBottleneck(bottleneck)"> + {{ bottleneck.properties.name }} + </a> + </div> + <div class="col-5"> + {{ displayCurrentSurvey(bottleneck) }} + </div> + <div class="col-2 text-right"> + <button type="button" class="btn btn-sm btn-outline-secondary" @click="toggleBottleneck(bottleneck)"> + <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)"> + {{ survey.date_info }} + </a> </div> </div> </div> @@ -49,14 +47,14 @@ /* * 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 + * + * Copyright (C) 2018 by via donau * – Österreichische Wasserstraßen-Gesellschaft mbH * Software engineering by Intevation GmbH - * + * * Author(s): * Markus Kottländer <markus.kottlaender@intevation.de> */ @@ -91,24 +89,6 @@ 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, @@ -119,52 +99,98 @@ } }, methods: { - selectSurvey(survey) { + filteredAndSortedBottlenecks() { + return this.bottlenecks.filter(bn => { + const foundInName = bn.properties.name + .toLowerCase() + .includes(this.search.toLowerCase()); + const latestMeasurement = (bn.properties.current || ''); + const foundInLatestMeasurement = latestMeasurement + .substr(0, latestMeasurement.length - 1) + .includes(this.search.toLowerCase()); + return foundInName || foundInLatestMeasurement; + }).sort((bnA, bnB) => { + switch (this.sortColumn) { + case "name": + if ( + bnA.properties.name.toLowerCase() < + bnB.properties.name.toLowerCase() + ) + return this.sortDirection === "ASC" ? -1 : 1; + if ( + bnA.properties.name.toLowerCase() > + bnB.properties.name.toLowerCase() + ) + return this.sortDirection === "ASC" ? 1 : -1; + return 0; + + case "latestMeasurement": + const currentA = bnA.properties.current || ''; + const currentB = bnB.properties.current || ''; + if (currentA < currentB) + return this.sortDirection === "ASC" ? -1 : 1; + if (currentA > currentB) + return this.sortDirection === "ASC" ? 1 : -1; + return 0; + + default: + return 0; + } + }); + }, + selectSurvey(survey, bottleneck) { this.$store.commit("fairwayprofile/setSelectedMorph", survey); - this.$store.commit("fairwayprofile/setAvailableSurveys", {surveys: this.surveys[this.selectedBottleneck.name] }); - this.moveToBottleneck(this.selectedBottleneck); + this.$store.commit("fairwayprofile/setAvailableSurveys", { + surveys: this.surveys[bottleneck.properties.name] + }); + this.moveToBottleneck(bottleneck); }, 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(); - const newZoom = Math.max(17, currentZoom); - view.animate( - { - zoom: newZoom, - center: fromLonLat( - bottleneck.geom.coordinates, - view.getProjection() - ) - }, - 700 - ); - } + let view = this.openLayersMap.getView(); + const currentZoom = view.getZoom(); + const newZoom = Math.max(17, currentZoom); + view.animate( + { + zoom: newZoom, + center: fromLonLat( + bottleneck.geometry.coordinates, + view.getProjection() + ) + }, + 700 + ); }, 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; + toggleBottleneck(bottleneck) { + if (bottleneck === this.selectedBottleneck) { + this.selectedBottleneck = null; + } else { + HTTP.get("/surveys/" + bottleneck.properties.name, { + headers: { + "X-Gemma-Auth": localStorage.getItem("token"), + "Content-type": "text/xml; charset=UTF-8" + } }) - .catch(error => { - const { status, data } = error.response; - displayError({ - title: "Backend Error", - message: `${status}: ${data.message || data}` + .then(response => { + this.surveys[bottleneck.properties.name] = response.data.surveys; + this.selectedBottleneck = bottleneck; + }) + .catch(error => { + const { status, data } = error.response; + displayError({ + title: "Backend Error", + message: `${status}: ${data.message || data}` + }); }); - }); + } + }, + displayCurrentSurvey(bottleneck) { + const current = bottleneck.properties.current; + return current ? current.substr(0, current.length - 1) : ""; } }, mounted() { @@ -182,7 +208,7 @@ padding-top: $offset; opacity: $slight-transparent; border-radius: $border-radius; - transition: left .3s ease; + transition: left 0.3s ease; overflow: hidden; background: #fff; } @@ -194,7 +220,7 @@ } .bottlenecksextended { - width: 500px; + width: 600px; } .close-bottlenecks {
--- a/client/src/bottlenecks/store.js Mon Oct 29 15:36:11 2018 +0100 +++ b/client/src/bottlenecks/store.js Tue Oct 30 11:35:36 2018 +0100 @@ -1,18 +1,19 @@ /* * 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 + * + * Copyright (C) 2018 by via donau * – Österreichische Wasserstraßen-Gesellschaft mbH * Software engineering by Intevation GmbH - * + * * Author(s): * Markus Kottländer <markuks.kottlaender@intevation.de> */ import { HTTP } from "../application/lib/http"; +import { WFS } from "ol/format.js"; const Bottlenecks = { namespaced: true, @@ -26,17 +27,27 @@ }, actions: { loadBottlenecks({ commit }) { - return new Promise((resolve, reject) => { - HTTP.get("/bottlenecks", { - headers: { "X-Gemma-Auth": localStorage.getItem("token") } - }) - .then(response => { - commit("setBottlenecks", response.data); - resolve(response); - }) - .catch(error => { - reject(error); - }); + var bottleneckFeatureCollectionRequest = new WFS().writeGetFeature({ + srsName: "EPSG:4326", + featureNS: "gemma", + featurePrefix: "gemma", + featureTypes: ["bottleneck_overview"], + outputFormat: "application/json" + }); + + HTTP.post( + "/internal/wfs", + new XMLSerializer().serializeToString( + bottleneckFeatureCollectionRequest + ), + { + headers: { + "X-Gemma-Auth": localStorage.getItem("token"), + "Content-type": "text/xml; charset=UTF-8" + } + } + ).then(response => { + commit("setBottlenecks", response.data.features); }); } }