comparison client/src/bottlenecks/Bottlenecks.vue @ 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 c9badb264d16
children 5979b63cce9d
comparison
equal deleted inserted replaced
1070:12312fb1cda2 1077:c58608084c11
1 <template> 1 <template>
2 <div :class="bottlenecksStyle"> 2 <div :class="bottlenecksStyle" style="overflow: hidden; background: #fff;">
3 <div @click="$store.commit('application/toggleBottlenecks');" class="ui-element close-bottlenecks"> 3 <div @click="$store.commit('application/toggleBottlenecks');" class="ui-element close-bottlenecks">
4 <i class="fa fa-close"></i> 4 <i class="fa fa-close"></i>
5 </div> 5 </div>
6 6
7 <div v-if="!this.bottlenecksCollapsed"> 7 <h4>Bottlenecks</h4>
8 <h4>Bottlenecks</h4> 8 <hr class="mb-0">
9 <hr class="mb-0"> 9 <input type="text" v-model="search" placeholder="Search Bottleneck..." class="border-0 w-100 p-2" />
10 <div style="max-height: 500px; overflow-y: scroll"> 10 <div class="bottleneck-table d-flex flex-column">
11 <table class="table text-left mb-0" style="margin-top: -1px;"> 11 <div class="d-flex flex-row p-2 border-top">
12 <tr v-for="(bottleneck) in bottlenecks" 12 <div>
13 :key="bottleneck.name"> 13 <a href="#" @click="sortBy('name')" class="sort-link">Name</a>
14 <td> 14 <i :class="sortClass" v-if="sortColumn === 'name'"></i>
15 </div>
16 <!--<div>
17 <a href="#" @click="sortBy('latestMeasurement')">Latest Measurement</a>
18 <i :class="sortClass" v-if="sortColumn === 'latestMeasurement'"></i>
19 </div>-->
20 <div></div>
21 </div>
22 <div class="d-flex flex-column">
23 <div v-for="bottleneck in filteredAndSortedBottlenecks" :key="bottleneck.name" class="border-top">
24 <div class="d-flex flex-row justify-content-between p-2">
25 <div>
15 <a href="#" class="d-block" @click="moveToBottleneck(bottleneck)"> 26 <a href="#" class="d-block" @click="moveToBottleneck(bottleneck)">
16 {{ bottleneck.name }} 27 {{ bottleneck.name }}
17 </a> 28 </a>
18 </td> 29 </div>
19 </tr> 30 <!--<td>2018-10-25</td>-->
20 </table> 31 <div class="text-right">
32 <button type="button" class="btn btn-sm btn-outline-secondary" @click="queryBottleneck(bottleneck)">
33 <i class="fa fa-angle-down"></i>
34 </button>
35 </div>
36 </div>
37 <div :class="['surveys', {open: selectedBottleneck === bottleneck}]">
38 <a href="#" class="d-block p-2 border-top" v-for="(survey, index) in surveys[bottleneck.name]" :key="index" @click="selectSurvey(survey)">
39 {{ survey.date_info }}
40 </a>
41 </div>
42 </div>
21 </div> 43 </div>
22 </div> 44 </div>
23 </div> 45 </div>
24 </template> 46 </template>
25 47
38 * Author(s): 60 * Author(s):
39 * Markus Kottländer <markus.kottlaender@intevation.de> 61 * Markus Kottländer <markus.kottlaender@intevation.de>
40 */ 62 */
41 import { mapState } from "vuex"; 63 import { mapState } from "vuex";
42 import { fromLonLat } from "ol/proj"; 64 import { fromLonLat } from "ol/proj";
65 import { HTTP } from "../application/lib/http";
66 import { displayError } from "../application/lib/errors.js";
43 67
44 export default { 68 export default {
45 name: "bottlenecks", 69 name: "bottlenecks",
70 data() {
71 return {
72 search: "",
73 sortColumn: "name",
74 sortDirection: "ASC",
75 selectedBottleneck: null,
76 surveys: {}
77 };
78 },
46 computed: { 79 computed: {
47 ...mapState("application", ["bottlenecksCollapsed"]), 80 ...mapState("application", ["bottlenecksCollapsed"]),
48 ...mapState("bottlenecks", ["bottlenecks"]), 81 ...mapState("bottlenecks", ["bottlenecks"]),
49 ...mapState("mapstore", ["openLayersMap"]), 82 ...mapState("mapstore", ["openLayersMap"]),
50 bottlenecksStyle() { 83 bottlenecksStyle() {
54 overlay: true, 87 overlay: true,
55 bottleneckscollapsed: this.bottlenecksCollapsed, 88 bottleneckscollapsed: this.bottlenecksCollapsed,
56 bottlenecksextended: !this.bottlenecksCollapsed, 89 bottlenecksextended: !this.bottlenecksCollapsed,
57 shadow: true 90 shadow: true
58 }; 91 };
92 },
93 filteredAndSortedBottlenecks() {
94 return this.bottlenecks
95 .filter(bn => {
96 return bn.name.toLowerCase().includes(this.search.toLowerCase());
97 })
98 .sort((bnA, bnB) => {
99 switch (this.sortColumn) {
100 case "name":
101 if (bnA.name.toLowerCase() < bnB.name.toLowerCase())
102 return this.sortDirection === "ASC" ? -1 : 1;
103 if (bnA.name.toLowerCase() > bnB.name.toLowerCase())
104 return this.sortDirection === "ASC" ? 1 : -1;
105 return 0;
106 default:
107 return 0;
108 }
109 });
110 },
111 sortClass() {
112 return {
113 fa: true,
114 "fa-sort-amount-asc": this.sortDirection === "ASC",
115 "fa-sort-amount-desc": this.sortDirection === "DESC",
116 "ml-1": true
117 };
59 } 118 }
60 }, 119 },
61 methods: { 120 methods: {
62 // TODO: make this central, duplicates code from application/Topbar.vue 121 selectSurvey(survey) {
122 this.$store.commit("fairwayprofile/setSelectedMorph", survey);
123 this.moveToBottleneck(this.selectedBottleneck);
124 },
63 moveToBottleneck(bottleneck) { 125 moveToBottleneck(bottleneck) {
126 // TODO: make this central, duplicates code from application/Topbar.vue
64 if (bottleneck.geom.type == "Point") { 127 if (bottleneck.geom.type == "Point") {
65 let view = this.openLayersMap.getView(); 128 let view = this.openLayersMap.getView();
66 const currentZoom = view.getZoom(); 129 const currentZoom = view.getZoom();
67 const newZoom = Math.max(17, currentZoom); 130 const newZoom = Math.max(17, currentZoom);
68 view.animate( 131 view.animate(
75 }, 138 },
76 700 139 700
77 ); 140 );
78 } 141 }
79 this.$store.commit("application/toggleBottlenecks"); 142 this.$store.commit("application/toggleBottlenecks");
143 },
144 sortBy(column) {
145 this.sortColumn = column;
146 this.sortDirection = this.sortDirection === "ASC" ? "DESC" : "ASC";
147 },
148 queryBottleneck(bottleneck) {
149 HTTP.get("/surveys/" + bottleneck.name, {
150 headers: {
151 "X-Gemma-Auth": localStorage.getItem("token"),
152 "Content-type": "text/xml; charset=UTF-8"
153 }
154 })
155 .then(response => {
156 this.surveys[bottleneck.name] = response.data.surveys;
157 this.selectedBottleneck =
158 this.selectedBottleneck === bottleneck ? null : bottleneck;
159 })
160 .catch(error => {
161 const { status, data } = error.response;
162 displayError({
163 title: "Backend Error",
164 message: `${status}: ${data.message || data}`
165 });
166 });
80 } 167 }
81 }, 168 },
82 mounted() { 169 mounted() {
83 this.$store.dispatch("bottlenecks/loadBottlenecks"); 170 this.$store.dispatch("bottlenecks/loadBottlenecks");
84 } 171 }
102 height: 0; 189 height: 0;
103 transition: $transition-fast; 190 transition: $transition-fast;
104 } 191 }
105 192
106 .bottlenecksextended { 193 .bottlenecksextended {
107 min-height: $sidebar-height;
108 width: 500px; 194 width: 500px;
109 } 195 }
110 196
111 .close-bottlenecks { 197 .close-bottlenecks {
112 position: absolute; 198 position: absolute;
120 } 206 }
121 207
122 .bottlenecksextended .close-bottlenecks { 208 .bottlenecksextended .close-bottlenecks {
123 display: block; 209 display: block;
124 } 210 }
211
212 .surveys {
213 max-height: 0;
214 overflow: hidden;
215 transition: max-height 0.3s ease;
216 }
217
218 .surveys.open {
219 max-height: 999px;
220 }
221
222 .sort-link {
223 color: #444;
224 font-weight: bold;
225 }
125 </style> 226 </style>