Mercurial > gemma
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> |