Mercurial > gemma
comparison client/src/components/stretches/Stretches.vue @ 3263:d23532a4d0c3
client: define stretches: renamed component file and moved to subdirectory
as preparation for splitting list and edit view into separate components and then duplicating for sections
author | Markus Kottlaender <markus@intevation.de> |
---|---|
date | Wed, 15 May 2019 12:04:14 +0200 |
parents | |
children | f92f7c9df392 |
comparison
equal
deleted
inserted
replaced
3262:a2e9671f4ad6 | 3263:d23532a4d0c3 |
---|---|
1 <template> | |
2 <div class="d-flex flex-column mb-3"> | |
3 <UIBoxHeader | |
4 icon="road" | |
5 :title="defineStretchesLabel" | |
6 :closeCallback="$parent.close" | |
7 /> | |
8 <div class="position-relative"> | |
9 <UISpinnerOverlay v-if="loading" /> | |
10 <div v-if="!edit" class="mb-3"> | |
11 <UITableHeader | |
12 :columns="[ | |
13 { id: 'properties.name', title: `${nameLabel}`, class: 'col-4' }, | |
14 { | |
15 id: 'properties.date_info', | |
16 title: `${dateLabel}`, | |
17 class: 'col-2' | |
18 }, | |
19 { | |
20 id: 'properties.source_organization', | |
21 title: `${sourceorganizationLabel}`, | |
22 class: 'col-3' | |
23 } | |
24 ]" | |
25 /> | |
26 <UITableBody | |
27 :data="filteredStretches() | sortTable(sortColumn, sortDirection)" | |
28 > | |
29 <template v-slot:row="{ item: stretch }"> | |
30 <div class="py-1 col-4 "> | |
31 <a | |
32 class="pointer text-info" | |
33 v-if="isInStaging(stretch.properties.name)" | |
34 @click="gotoStaging(getStagingLink(stretch.properties.name))" | |
35 > | |
36 {{ stretch.properties.name | |
37 }}<font-awesome-icon | |
38 class="ml-1 text-danger" | |
39 icon="exclamation-triangle" | |
40 fixed-width | |
41 ></font-awesome-icon | |
42 ><small class="ml-1">review</small> | |
43 </a> | |
44 <a v-else @click="moveMapToStretch(stretch)" href="#">{{ | |
45 stretch.properties.name | |
46 }}</a> | |
47 </div> | |
48 <div class="py-1 col-2"> | |
49 {{ stretch.properties.date_info | surveyDate }} | |
50 </div> | |
51 <div class="py-1 col-3"> | |
52 {{ stretch.properties.source_organization }} | |
53 </div> | |
54 <div class="py-1 col text-right"> | |
55 <button | |
56 class="btn btn-xs btn-dark mr-1" | |
57 @click="editStretch(stretch)" | |
58 > | |
59 <font-awesome-icon icon="pencil-alt" fixed-width /> | |
60 </button> | |
61 <button | |
62 class="btn btn-xs btn-dark" | |
63 @click="deleteStretch(stretch)" | |
64 > | |
65 <font-awesome-icon icon="trash" fixed-width /> | |
66 </button> | |
67 </div> | |
68 </template> | |
69 </UITableBody> | |
70 </div> | |
71 <div v-if="edit"> | |
72 <div class="ml-3 mr-3"> | |
73 <div class="d-flex flex-row justify-content-between"> | |
74 <div class="mt-2 w-50 mr-2 text-left"> | |
75 <small class="text-muted"> <translate>ID</translate> </small> | |
76 <input | |
77 id="id" | |
78 type="text" | |
79 class="form-control" | |
80 placeholder="AT_Section_12" | |
81 aria-label="id" | |
82 v-model="id" | |
83 :disabled="editExistingStretch" | |
84 /> | |
85 <span class="text-left text-danger"> | |
86 <small v-if="idError && !id"> | |
87 <translate>Please enter an id</translate> | |
88 </small> | |
89 </span> | |
90 </div> | |
91 <div class="mt-2 w-50 ml-2 text-left"> | |
92 <div> | |
93 <small class="text-muted"> | |
94 <translate>Countrycode</translate> | |
95 </small> | |
96 <input | |
97 id="countryCode" | |
98 type="text" | |
99 class="form-control" | |
100 placeholder="AT" | |
101 aria-label="id" | |
102 v-model="countryCode" | |
103 /> | |
104 <span class="text-left text-danger"> | |
105 <small v-if="countryCodeError && !countryCode"> | |
106 <translate>Please enter a countrycode </translate> | |
107 </small> | |
108 </span> | |
109 </div> | |
110 <div class="w-50 ml-2"></div> | |
111 </div> | |
112 </div> | |
113 <div class="d-flex flex-column justify-content-between"> | |
114 <div class="mt-2 text-left"> | |
115 <small class="text-muted"> | |
116 <translate>Start rhm</translate> | |
117 </small> | |
118 <div class="d-flex flex-row"> | |
119 <input | |
120 id="startrhm" | |
121 type="text" | |
122 class="form-control" | |
123 placeholder="e.g. ATXXX000010000019900" | |
124 aria-label="startrhm" | |
125 v-model="startrhm" | |
126 /> | |
127 <span class="input-group-text" @click="togglePipette('start')"> | |
128 <font-awesome-icon | |
129 :class="{ 'text-info': pipetteStart }" | |
130 icon="crosshairs" | |
131 /> | |
132 </span> | |
133 </div> | |
134 <span class="text-left text-danger"> | |
135 <small v-if="startrhmError && !startrhm"> | |
136 <translate>Please enter a start point</translate> | |
137 </small> | |
138 </span> | |
139 </div> | |
140 <div class="mt-2 text-left"> | |
141 <small class="text-muted"> <translate>End rhm</translate> </small> | |
142 <div class="d-flex flex-row"> | |
143 <input | |
144 id="endrhm" | |
145 type="text" | |
146 class="form-control" | |
147 placeholder="e.g. ATXXX000010000019900" | |
148 aria-label="endrhm" | |
149 v-model="endrhm" | |
150 /> | |
151 <span class="input-group-text" @click="togglePipette('end')"> | |
152 <font-awesome-icon | |
153 :class="{ 'text-info': pipetteEnd }" | |
154 icon="crosshairs" | |
155 /> | |
156 </span> | |
157 </div> | |
158 <span class="text-left text-danger"> | |
159 <small v-if="endrhmError && !endrhm"> | |
160 <translate>Please enter an end point</translate> | |
161 </small> | |
162 </span> | |
163 </div> | |
164 </div> | |
165 <div | |
166 v-if="!editExistingStretch" | |
167 class="d-flex flex-row justify-content-between" | |
168 > | |
169 <div class="mt-2 mr-2 w-50 text-left"> | |
170 <small class="text-muted"> | |
171 <translate | |
172 >Tolerance for snapping of waterway axis [m]</translate | |
173 > | |
174 </small> | |
175 <input | |
176 class="form-control" | |
177 v-model.number="tolerance" | |
178 placeholder="" | |
179 type="number" | |
180 min="0" | |
181 step="any" | |
182 aria-label="tolerance" | |
183 id="tolerance" | |
184 /> | |
185 <span class="text-left text-danger"> | |
186 <small v-if="toleranceError && !tolerance"> | |
187 <translate>Please enter a tolerance value</translate> | |
188 </small> | |
189 </span> | |
190 </div> | |
191 </div> | |
192 <div class="d-flex flex-row justify-content-between"> | |
193 <div class="mt-2 mr-2 w-50 text-left"> | |
194 <small class="text-muted"> | |
195 <translate>Object name</translate> | |
196 </small> | |
197 <input | |
198 id="objbn" | |
199 type="text" | |
200 class="form-control" | |
201 placeholder="" | |
202 aria-label="objbn" | |
203 v-model="objbn" | |
204 /> | |
205 <span class="text-left text-danger"> | |
206 <small v-if="objbnError && !objbn"> | |
207 <translate>Please enter an objectname</translate> | |
208 </small> | |
209 </span> | |
210 </div> | |
211 <div class="mt-2 ml-2 w-50 text-left"> | |
212 <small class="text-muted"> | |
213 <translate>National Object name</translate> | |
214 </small> | |
215 <input | |
216 id="nobjbn" | |
217 type="text" | |
218 class="form-control" | |
219 placeholder="" | |
220 aria-label="nobjbn" | |
221 v-model="nobjbn" | |
222 /> | |
223 </div> | |
224 </div> | |
225 <div class="d-flex flex-row justify-content-between"> | |
226 <div class="mt-2 mr-2 w-50 text-left"> | |
227 <small class="text-muted"> | |
228 <translate>Date info</translate> | |
229 </small> | |
230 <input | |
231 id="date_info" | |
232 type="date" | |
233 class="form-control" | |
234 placeholder="date_info" | |
235 aria-label="date_info" | |
236 v-model="date_info" | |
237 /> | |
238 <span class="text-left text-danger"> | |
239 <small v-if="date_infoError && !date_info"> | |
240 <translate>Please enter a date</translate> | |
241 </small> | |
242 </span> | |
243 </div> | |
244 <div class="mt-2 ml-2 w-50 text-left"> | |
245 <small class="text-muted"> <translate>Source</translate> </small> | |
246 <input | |
247 id="source" | |
248 type="text" | |
249 class="form-control" | |
250 placeholder="source" | |
251 aria-label="source" | |
252 v-model="source" | |
253 /> | |
254 <span class="text-left text-danger"> | |
255 <small v-if="sourceError && !source"> | |
256 <translate>Please enter a source</translate> | |
257 </small> | |
258 </span> | |
259 </div> | |
260 </div> | |
261 </div> | |
262 <div class="text-right mt-2 mr-3 mb-3"> | |
263 <button @click="edit = false" class="btn btn-warning mr-2"> | |
264 Back | |
265 </button> | |
266 <button | |
267 @click="save" | |
268 type="submit" | |
269 class="shadow-sm btn btn-info submit-button" | |
270 > | |
271 <translate>Submit</translate> | |
272 </button> | |
273 </div> | |
274 </div> | |
275 <div class="text-right mr-3"> | |
276 <button v-if="!edit" @click="startEdit()" class="btn btn-info"> | |
277 <translate>New stretch</translate> | |
278 </button> | |
279 </div> | |
280 </div> | |
281 </div> | |
282 </template> | |
283 | |
284 <script> | |
285 /* This is Free Software under GNU Affero General Public License v >= 3.0 | |
286 * without warranty, see README.md and license for details. | |
287 * | |
288 * SPDX-License-Identifier: AGPL-3.0-or-later | |
289 * License-Filename: LICENSES/AGPL-3.0.txt | |
290 * | |
291 * Copyright (C) 2018, 2019 by via donau | |
292 * – Österreichische Wasserstraßen-Gesellschaft mbH | |
293 * Software engineering by Intevation GmbH | |
294 * | |
295 * Author(s): | |
296 * Thomas Junk <thomas.junk@intevation.de> | |
297 * Tom Gottfried <tom.gottfried@intevation.de> | |
298 */ | |
299 import { mapState, mapGetters } from "vuex"; | |
300 import { displayError, displayInfo } from "@/lib/errors"; | |
301 import { HTTP } from "@/lib/http"; | |
302 import { sortTable } from "@/lib/mixins"; | |
303 | |
304 export default { | |
305 name: "importstretches", | |
306 mixins: [sortTable], | |
307 data() { | |
308 return { | |
309 staging: [], | |
310 edit: false, | |
311 editExistingStretch: false, | |
312 id: "", | |
313 funktion: "", | |
314 startrhm: "", | |
315 endrhm: "", | |
316 tolerance: 5, | |
317 objbn: "", | |
318 nobjbn: "", | |
319 countryCode: "", | |
320 date_info: new Date().toISOString().split("T")[0], | |
321 source: "", | |
322 pipetteStart: false, | |
323 pipetteEnd: false, | |
324 idError: false, | |
325 funktionError: false, | |
326 startrhmError: false, | |
327 endrhmError: false, | |
328 toleranceError: false, | |
329 objbnError: false, | |
330 nobjbnError: false, | |
331 date_infoError: false, | |
332 sourceError: false, | |
333 countryCodeError: false, | |
334 loading: false | |
335 }; | |
336 }, | |
337 computed: { | |
338 ...mapState("application", ["searchQuery"]), | |
339 ...mapState("map", ["identifiedFeatures", "currentMeasurement"]), | |
340 ...mapGetters("map", ["openLayersMap"]), | |
341 ...mapGetters("user", ["isSysAdmin"]), | |
342 ...mapState("imports", ["stretches"]), | |
343 defineStretchesLabel() { | |
344 return this.$gettext("Define Stretches"); | |
345 }, | |
346 nameLabel() { | |
347 return this.$gettext("Name"); | |
348 }, | |
349 dateLabel() { | |
350 return this.$gettext("Date"); | |
351 }, | |
352 sourceorganizationLabel() { | |
353 return this.$gettext("Source organization"); | |
354 }, | |
355 stretchesInStaging() { | |
356 const result = []; | |
357 for (let stretch of this.stretches) { | |
358 for (let s of this.staging) { | |
359 if (s.kind == "st" && s.summary.stretch == stretch.properties.name) { | |
360 result.push({ name: s.summary.stretch, id: s.id }); | |
361 } | |
362 } | |
363 } | |
364 return result; | |
365 } | |
366 }, | |
367 watch: { | |
368 identifiedFeatures() { | |
369 const distanceMark = this.identifiedFeatures.find(x => | |
370 /^distance_marks_geoserver/.test(x["id_"]) | |
371 ); | |
372 if (distanceMark) { | |
373 const location = distanceMark.get("location"); | |
374 this.startrhm = this.pipetteStart ? location : this.startrhm; | |
375 this.endrhm = this.pipetteEnd ? location : this.endrhm; | |
376 this.pipetteStart = false; | |
377 this.pipetteEnd = false; | |
378 this.$store.commit("map/mapPopupEnabled", true); | |
379 } | |
380 } | |
381 }, | |
382 methods: { | |
383 filteredStretches() { | |
384 return this.stretches.filter(s => { | |
385 return (s.properties.name + s.properties.source_organization) | |
386 .toLowerCase() | |
387 .includes(this.searchQuery.toLowerCase()); | |
388 }); | |
389 }, | |
390 gotoStaging(id) { | |
391 this.$router.push("/review/" + id); | |
392 }, | |
393 isInStaging(stretchname) { | |
394 for (let s of this.stretchesInStaging) { | |
395 if (s.name == stretchname) return true; | |
396 } | |
397 return false; | |
398 }, | |
399 getStagingLink(stretchname) { | |
400 for (let s of this.stretchesInStaging) { | |
401 if (s.name == stretchname) return s.id; | |
402 } | |
403 }, | |
404 loadStagingData() { | |
405 return new Promise((resolve, reject) => { | |
406 HTTP.get("/imports?states=pending", { | |
407 headers: { "X-Gemma-Auth": localStorage.getItem("token") } | |
408 }) | |
409 .then(response => { | |
410 const { imports } = response.data; | |
411 this.staging = imports; | |
412 resolve(response); | |
413 }) | |
414 .catch(error => { | |
415 reject(error); | |
416 }); | |
417 }); | |
418 }, | |
419 editStretch(stretch) { | |
420 const properties = stretch.properties; | |
421 this.date_info = properties.date_info.split("T")[0]; | |
422 this.id = properties.name; | |
423 this.nobjbn = properties.nobjnam; | |
424 this.objbn = properties.objnam; | |
425 this.countryCode = properties.countries; | |
426 this.source = properties["source_organization"]; | |
427 this.edit = true; | |
428 this.startrhm = properties.lower; | |
429 this.endrhm = properties.upper; | |
430 this.editExistingStretch = true; | |
431 }, | |
432 deleteStretch(stretch) { | |
433 this.$store.commit("application/popup", { | |
434 icon: "trash", | |
435 title: this.$gettext("Delete Stretch"), | |
436 content: | |
437 this.$gettext("Do you really want to delete this stretch:") + | |
438 `<br> | |
439 <b>${stretch.properties.name}, ${ | |
440 stretch.properties.source_organization | |
441 } (${stretch.properties.countries})</b>`, | |
442 confirm: { | |
443 label: this.$gettext("Delete"), | |
444 icon: "trash", | |
445 callback: () => { | |
446 displayInfo({ | |
447 title: this.$gettext("Not implemented"), | |
448 message: this.$gettext("Deleting ") + stretch.id | |
449 }); | |
450 } | |
451 }, | |
452 cancel: { | |
453 label: this.$gettext("Cancel"), | |
454 icon: "times" | |
455 } | |
456 }); | |
457 }, | |
458 moveMapToStretch(stretch) { | |
459 this.$store.commit("imports/selectedStretchId", stretch.id); | |
460 this.openLayersMap() | |
461 .getLayer("STRETCHES") | |
462 .setVisible(true); | |
463 this.$store.dispatch("map/moveToFeauture", { | |
464 feature: stretch, | |
465 zoom: 17, | |
466 preventZoomOut: true | |
467 }); | |
468 }, | |
469 clean() { | |
470 this.id = ""; | |
471 this.edit = false; | |
472 this.editExistingStretch = false; | |
473 this.funktion = ""; | |
474 this.startrhm = ""; | |
475 this.tolerance = 5; | |
476 this.endrhm = ""; | |
477 this.objbn = ""; | |
478 this.nobjbn = ""; | |
479 this.countryCode = ""; | |
480 this.date_info = new Date().toISOString().split("T")[0]; | |
481 this.source = ""; | |
482 this.pipetteStart = false; | |
483 this.pipetteEnd = false; | |
484 this.idError = false; | |
485 this.funktionError = false; | |
486 this.startrhmError = false; | |
487 this.endrhmError = false; | |
488 this.toleranceError = false; | |
489 this.objbnError = false; | |
490 this.nobjbnError = false; | |
491 this.date_infoError = false; | |
492 this.sourceError = false; | |
493 this.countryCodeError = false; | |
494 }, | |
495 startEdit() { | |
496 this.clean(); | |
497 this.edit = true; | |
498 }, | |
499 togglePipette(t) { | |
500 this.openLayersMap() | |
501 .getLayer("DISTANCEMARKSAXIS") | |
502 .setVisible(true); | |
503 if (t === "start") { | |
504 this.$store.commit("map/mapPopupEnabled", this.pipetteStart); | |
505 this.pipetteStart = !this.pipetteStart; | |
506 this.pipetteEnd = false; | |
507 } else { | |
508 this.$store.commit("map/mapPopupEnabled", this.pipetteEnd); | |
509 this.pipetteEnd = !this.pipetteEnd; | |
510 this.pipetteStart = false; | |
511 } | |
512 }, | |
513 validate() { | |
514 const fields = [ | |
515 "id", | |
516 "funktion", | |
517 "startrhm", | |
518 "tolerance", | |
519 "endrhm", | |
520 "objbn", | |
521 "nobjbn", | |
522 "countryCode", | |
523 "date_info", | |
524 "source" | |
525 ]; | |
526 fields.forEach(field => { | |
527 if (!this[field]) { | |
528 this[field + "Error"] = true; | |
529 } else { | |
530 this[field + "Error"] = false; | |
531 } | |
532 }); | |
533 }, | |
534 save() { | |
535 this.validate(); | |
536 if ( | |
537 !this.id || | |
538 !this.startrhm || | |
539 !this.endrhm || | |
540 (!this.tolerance && this.editExistingStretch) || | |
541 !this.source || | |
542 !this.date_info || | |
543 !this.objbn || | |
544 !this.countryCode | |
545 ) | |
546 return; | |
547 const data = { | |
548 name: this.id, | |
549 from: this.startrhm, | |
550 to: this.endrhm, | |
551 "source-organization": this.source, | |
552 "date-info": this.date_info, | |
553 objnam: this.objbn, | |
554 nobjnam: this.nobjbn, | |
555 countries: this.countryCode.split(",").map(x => { | |
556 return x.trim(); | |
557 }) | |
558 }; | |
559 if (!this.editExistingStretch) { | |
560 data["tolerance"] = this.tolerance; | |
561 } | |
562 this.$store | |
563 .dispatch("imports/saveStretch", data) | |
564 .then(() => { | |
565 displayInfo({ | |
566 title: this.$gettext("Import"), | |
567 message: this.$gettext("Starting import of stretch") | |
568 }); | |
569 this.clean(); | |
570 this.$store.dispatch("imports/loadStretches").then(() => { | |
571 this.edit = false; | |
572 }); | |
573 }) | |
574 .catch(error => { | |
575 const { status, data } = error.response; | |
576 displayError({ | |
577 title: this.$gettext("Backend Error"), | |
578 message: `${status}: ${data.message || data}` | |
579 }); | |
580 }); | |
581 } | |
582 }, | |
583 mounted() { | |
584 this.edit = false; | |
585 this.loading = true; | |
586 this.$store | |
587 .dispatch("imports/loadStretches") | |
588 .catch(error => { | |
589 const { status, data } = error.response; | |
590 displayError({ | |
591 title: this.$gettext("Backend Error"), | |
592 message: `${status}: ${data.message || data}` | |
593 }); | |
594 }) | |
595 .finally(() => (this.loading = false)); | |
596 this.loadStagingData().catch(error => { | |
597 const { status, data } = error.response; | |
598 displayError({ | |
599 title: this.$gettext("Backend Error"), | |
600 message: `${status}: ${data.message || data}` | |
601 }); | |
602 }); | |
603 } | |
604 }; | |
605 </script> |