Mercurial > gemma
view client/src/components/ImportStretches.vue @ 2455:54c9fe587fe6
Subdivide SQL function to prepare for improved error handling
The context of an error (e.g. the function in which it occured)
can be inferred by the database client. Not doing all in one
statement will render the context more meaningful.
author | Tom Gottfried <tom@intevation.de> |
---|---|
date | Fri, 01 Mar 2019 18:38:02 +0100 |
parents | 8fc546b03822 |
children | 9ae2a2f758bb |
line wrap: on
line source
<template> <div class="d-flex flex-column mb-3"> <UIBoxHeader icon="road" title="Define Stretches" :closeCallback="$parent.close" /> <div v-if="!edit" class="mb-3 mr-3 ml-3 text-left"> <table v-if="stretches.length > 0" class="table"> <thead> <tr> <th class="header"><translate>Name</translate></th> <th class="header"><translate>Datum</translate></th> <th class="header"><translate>Source organization</translate></th> <th></th> </tr> </thead> <tbody> <tr class="small" v-for="(stretch, index) in stretches" :key="index"> <td class=""> <a class="linkto text-info" v-if="isInStaging(stretch.properties.name)" @click="gotoStaging(getStagingLink(stretch.properties.name))" > {{ stretch.properties.name }}<font-awesome-icon class="ml-1 text-danger" icon="exclamation-triangle" fixed-width ></font-awesome-icon ><small class="ml-1">review</small> </a> <a v-else @click="moveMapToStretch(index)" href="#">{{ stretch.properties.name }}</a> </td> <td class=""> {{ formatSurveyDate(stretch.properties["date_info"]) }} </td> <td>{{ stretch.properties["source_organization"] }}</td> <td class="text-right"> <button class="btn btn-sm btn-dark mr-1" @click="editStretch(index)" > <font-awesome-icon icon="pencil-alt" fixed-width /> </button> <button class="btn btn-sm btn-dark" @click="deleteStretch(stretch)" > <font-awesome-icon icon="trash" fixed-width /> </button> </td> </tr> </tbody> </table> <div class="mt-3" v-if="stretches.length == 0"> <translate>No results.</translate> </div> </div> <div v-if="edit"> <div class="ml-3 mr-3"> <div class="d-flex flex-row justify-content-between"> <div class="mt-2 w-50 mr-2 text-left"> <small class="text-muted"> <translate>ID</translate> </small> <input id="id" type="text" class="form-control" placeholder="AT_Section_12" aria-label="id" v-model="id" :disabled="!idEditable" /> <span class="text-left text-danger"> <small v-if="idError && !id"> <translate>Please enter an id</translate> </small> </span> </div> <div class="mt-2 w-50 ml-2 text-left"> <div> <small class="text-muted"> <translate>Countrycode</translate> </small> <input id="countryCode" type="text" class="form-control" placeholder="AT" aria-label="id" v-model="countryCode" /> <span class="text-left text-danger"> <small v-if="countryCodeError && !countryCode"> <translate>Please enter a countrycode </translate> </small> </span> </div> <div class="w-50 ml-2"></div> </div> </div> <div class="d-flex flex-column justify-content-between"> <div class="mt-2 text-left"> <small class="text-muted"> <translate>Start rhm</translate> </small> <div class="d-flex flex-row"> <input id="startrhm" type="text" class="form-control" placeholder="e.g. ATXXX000010000019900" aria-label="startrhm" v-model="startrhm" /> <span class="input-group-text"> <font-awesome-icon @click="togglePipette('start')" :class="{ 'text-info': pipetteStart }" icon="bullseye" ></font-awesome-icon> </span> </div> <span class="text-left text-danger"> <small v-if="startrhmError && !startrhm"> <translate>Please enter a start point</translate> </small> </span> </div> <div class="mt-2 text-left"> <small class="text-muted"> <translate>End rhm</translate> </small> <div class="d-flex flex-row"> <input id="endrhm" type="text" class="form-control" placeholder="e.g. ATXXX000010000019900" aria-label="endrhm" v-model="endrhm" /> <span class="input-group-text"> <font-awesome-icon @click="togglePipette('end')" :class="{ 'text-info': pipetteEnd }" icon="bullseye" ></font-awesome-icon> </span> </div> <span class="text-left text-danger"> <small v-if="endrhmError && !endrhm"> <translate>Please enter an end point</translate> </small> </span> </div> <span class="text-left text-danger"> <small v-if="!pointsValid"> <translate>Startpoint is not before endpoint.</translate> </small> </span> </div> <div class="d-flex flex-row justify-content-between"> <div class="mt-2 mr-2 w-50 text-left"> <small class="text-muted"> <translate>Object name</translate> </small> <input id="objbn" type="text" class="form-control" placeholder="" aria-label="objbn" v-model="objbn" /> <span class="text-left text-danger"> <small v-if="objbnError && !objbn"> <translate>Please enter an objectname</translate> </small> </span> </div> <div class="mt-2 ml-2 w-50 text-left"> <small class="text-muted"> <translate>National Object name</translate> </small> <input id="nobjbn" type="text" class="form-control" placeholder="" aria-label="nobjbn" v-model="nobjbn" /> </div> </div> <div class="d-flex flex-row justify-content-between"> <div class="mt-2 mr-2 w-50 text-left"> <small class="text-muted"> <translate>Date info</translate> </small> <input id="date_info" type="date" class="form-control" placeholder="date_info" aria-label="date_info" v-model="date_info" /> <span class="text-left text-danger"> <small v-if="date_infoError && !date_info"> <translate>Please enter a date</translate> </small> </span> </div> <div class="mt-2 ml-2 w-50 text-left"> <small class="text-muted"> <translate>Source</translate> </small> <input id="source" type="text" class="form-control" placeholder="source" aria-label="source" v-model="source" /> <span class="text-left text-danger"> <small v-if="sourceError && !source"> <translate>Please enter a source</translate> </small> </span> </div> </div> </div> <div class="text-right mt-2 mr-3 mb-3"> <button @click="edit = false" class="btn btn-warning mr-2">Back</button> <button @click="save" type="submit" class="shadow-sm btn btn-info submit-button" > <translate>Submit</translate> </button> </div> </div> <div class="text-right mr-3"> <button v-if="!edit" @click="startEdit()" class="btn btn-info"> <translate>New stretch</translate> </button> </div> </div> </template> <script> /* 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 * – Österreichische Wasserstraßen-Gesellschaft mbH * Software engineering by Intevation GmbH * * Author(s): * Thomas Junk <thomas.junk@intevation.de> */ import { mapState, mapGetters } from "vuex"; import { displayError, displayInfo } from "@/lib/errors.js"; import { formatSurveyDate } from "@/lib/date.js"; import { LAYERS } from "@/store/map.js"; export default { name: "importstretches", data() { return { edit: false, idEditable: true, id: "", funktion: "", startrhm: "", endrhm: "", objbn: "", nobjbn: "", countryCode: "", date_info: new Date().toISOString().split("T")[0], source: "", pipetteStart: false, pipetteEnd: false, idError: false, funktionError: false, startrhmError: false, endrhmError: false, objbnError: false, nobjbnError: false, date_infoError: false, sourceError: false, countryCodeError: false }; }, mounted() { this.edit = false; this.loadStretches().catch(error => { const { status, data } = error.response; displayError({ title: this.$gettext("Backend Error"), message: `${status}: ${data.message || data}` }); }); this.loadStagingData().catch(error => { const { status, data } = error.response; displayError({ title: this.$gettext("Backend Error"), message: `${status}: ${data.message || data}` }); }); }, methods: { gotoStaging(id) { this.$router.push("/review/" + id); }, isInStaging(stretchname) { for (let s of this.stretchesInStaging) { if (s.name == stretchname) return true; } return false; }, getStagingLink(stretchname) { for (let s of this.stretchesInStaging) { if (s.name == stretchname) return s.id; } }, loadStagingData() { return new Promise((resolve, reject) => { this.$store .dispatch("imports/getStaging") .then(response => { resolve(response); }) .catch(error => { reject(error); }); }); }, editStretch(index) { const properties = this.stretches[index].properties; this.date_info = properties.date_info.split("T")[0]; this.id = properties.name; this.nobjbn = properties.nobjnam; this.objbn = properties.objnam; this.countryCode = properties.countries; this.source = properties["source_organization"]; this.edit = true; this.startrhm = properties.lower; this.endrhm = properties.upper; this.idEditable = false; }, deleteStretch(stretch) { this.$store.commit("application/popup", { icon: "trash", title: this.$gettext("Delete Stretch"), content: this.$gettext("Do you really want to delete this stretch:") + `<br> <b>${stretch.properties.name}, ${ stretch.properties.source_organization } (${stretch.properties.countries})</b>`, confirm: { label: this.$gettext("Delete"), icon: "trash", callback: () => { displayInfo({ title: this.$gettext("Not implemented"), message: this.$gettext("Deleting " + stretch.id) }); } }, cancel: { label: this.$gettext("Cancel"), icon: "times" } }); }, moveMapToStretch(index) { this.$store.commit("map/setLayerVisible", LAYERS.STRETCHES); this.$store.commit("map/moveToExtent", { feature: this.stretches[index], zoom: 17, preventZoomOut: true }); }, formatSurveyDate(d) { return formatSurveyDate(d); }, loadStretches() { return new Promise((resolve, reject) => { this.$store .dispatch("imports/loadStretches") .then(response => { resolve(response); }) .catch(error => { reject(error); }); }); }, clean() { this.id = ""; this.edit = false; this.idEditable = true; this.funktion = ""; this.startrhm = ""; this.endrhm = ""; this.objbn = ""; this.nobjbn = ""; this.countryCode = ""; this.date_info = new Date().toISOString().split("T")[0]; this.source = ""; this.pipetteStart = false; this.pipetteEnd = false; this.idError = false; this.funktionError = false; this.startrhmError = false; this.endrhmError = false; this.objbnError = false; this.nobjbnError = false; this.date_infoError = false; this.sourceError = false; this.countryCodeError = false; }, startEdit() { this.clean(); this.edit = true; }, togglePipette(t) { this.$store.commit("map/setLayerVisible", LAYERS.DISTANCEMARKSAXIS); if (t === "start") { this.pipetteStart = !this.pipetteStart; this.pipetteEnd = false; } else { this.pipetteEnd = !this.pipetteEnd; this.pipetteStart = false; } }, validate() { const fields = [ "id", "funktion", "startrhm", "endrhm", "objbn", "nobjbn", "countryCode", "date_info", "source" ]; fields.forEach(field => { if (!this[field]) { this[field + "Error"] = true; } else { this[field + "Error"] = false; } }); }, save() { this.validate(); if (!this.pointsValid) return; if ( !this.id || !this.startrhm || !this.endrhm || !this.source || !this.date_info || !this.objbn || !this.countryCode ) return; const data = { name: this.id, from: this.startrhm, to: this.endrhm, "source-organization": this.source, "date-info": this.date_info, objnam: this.objbn, nobjnam: this.nobjbn, countries: this.countryCode.split(",").map(x => { return x.trim(); }) }; this.$store .dispatch("imports/saveStretch", data) .then(() => { displayInfo({ title: this.$gettext("Import"), message: this.$gettext("Starting import of stretch") }); this.clean(); this.loadStretches().then(() => { this.edit = false; }); }) .catch(error => { const { status, data } = error.response; displayError({ title: this.$gettext("Backend Error"), message: `${status}: ${data.message || data}` }); }); } }, watch: { identifiedFeatures() { const filterDistanceMarks = x => { return /^distance_marks/.test(x["id_"]); }; const distanceMark = this.identifiedFeatures.filter(filterDistanceMarks); if (distanceMark.length > 0) { const value = distanceMark[0].getProperties()["location"]; this.startrhm = this.pipetteStart ? value : this.startrhm; this.endrhm = this.pipetteEnd ? value : this.endrhm; this.pipetteStart = false; this.pipetteEnd = false; } } }, computed: { ...mapState("map", ["identifiedFeatures", "currentMeasurement"]), ...mapGetters("user", ["isSysAdmin"]), ...mapState("imports", ["stretches", "staging"]), stretchesInStaging() { const result = []; for (let stretch of this.stretches) { for (let s of this.staging) { if (s.kind == "st" && s.summary.stretch == stretch.properties.name) { result.push({ name: s.summary.stretch, id: s.id }); } } } return result; }, pointsValid() { if (!this.startrhm || !this.endrhm) return true; const start = this.startrhm.replace(/\D+/g, "") * 1; const end = this.endrhm.replace(/\D+/g, "") * 1; const result = start < end; return result; } } }; </script> <style lang="scss" scoped> .linkto { cursor: pointer; } </style>