Mercurial > gemma
view client/src/components/importconfiguration/types/Soundingresults.vue @ 5402:f5063fa7f666 marking-single-beam
Add schema change for marking vessel single beam scans.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Tue, 06 Jul 2021 00:30:39 +0200 |
parents | 08dc7e5de1f5 |
children | 47b12e8308bf |
line wrap: on
line source
<template> <div> <div v-if="editState" class="mb-2 p-2"> <div v-for="(message, index) in messages" :key="index" class="alert alert-warning small" > {{ message }} </div> <div class="d-flex"> <div class="text-left mr-3"> <small class="text-muted"> <translate>Bottleneck</translate> </small> <select class="form-control font-weight-bold" v-model="bottleneck"> <option :value="null">{{ placeholder }}</option> <optgroup v-for="(bottlenecksForCountry, cc) in orderedBottlenecks" :key="cc" :label="cc" > <option v-for="bn in bottlenecksForCountry" :key="bn.properties.objnam" :value="bn" > {{ bn.properties.objnam }} </option> </optgroup> </select> <span class="text-danger"> <small v-if="!bottleneck"> <translate>Please select a bottleneck</translate> </small> </span> </div> <div class="text-left ml-2 mr-1"> <small class="text-muted"> <translate>Projection</translate> (EPSG) </small> <input class="form-control form-control-sm" v-model="projection" value="4326" placeholder="e.g. 4326" type="number" /> <span class="text-left text-danger"> <small v-if="!projection"> <translate>Please enter a projection</translate> </small> </span> </div> <div class="text-left ml-1"> <small class="text-muted"> <translate>BeamType</translate> </small> <select v-model="beamType" class="custom-select custom-select-sm" id="beamtype" > <option v-for="option in Object.keys($options.BEAMTYPES)" :key="option" >{{ $options.BEAMTYPES[option] }}</option > </select> </div> </div> <div class="d-flex flex-row w-100 mt-3"> <div class="mr-2 text-left"> <small class="text-muted"> <translate>Depthreference</translate> </small> <select v-model="depthReference" class="custom-select custom-select-sm" id="depthreference" > <option v-for="option in this.depthReferenceOptions" :key="option" >{{ option }}</option > </select> <span class="text-left text-danger"> <small v-if="!depthReference"> <translate>Please enter a reference</translate> </small> </span> </div> <div class="ml-3 text-left"> <small class="text-muted"> <translate>Date</translate> </small> <input id="importdate" type="date" class="form-control form-control-sm" placeholder="Date of import" v-model="importDate" /> <span class="text-left text-danger"> <small v-if="!importDate"> <translate>Please enter a date</translate> </small> </span> </div> <div class="ml-3 text-left d-flex flex-column"> <div class="text-left"> <small class="text-muted"> <translate>Negate Z values in XYZ files</translate> </small> </div> <div class="ml-4 mt-2 text-left"> <input id="negatez" type="checkbox" class="form-check-input" v-model="negateZ" /> </div> </div> </div> </div> <div class="mt-2"> <div v-if="uploadState" class="input-group px-2"> <div :key="1" class="flex-column mr-4"> <div class="flex-row text-left"> <small class="text-muted"> <translate>Email Notification</translate> </small> </div> <div class="flex-flex-row text-left"> <toggle-button v-model="eMailNotification" class="mt-2" :speed="100" :labels="{ checked: this.$options.on, unchecked: this.$options.off }" :width="60" :height="30" /> </div> </div> <div class="custom-file mt-4"> <input accept=".zip,.txt" type="file" @change="fileSelected" class="custom-file-input" id="uploadFile" /> <label class="pointer custom-file-label" for="uploadFile"> {{ uploadLabel }} </label> </div> </div> <div class="d-flex justify-content-between mt-2 p-2 border-top" v-if="editState" > <button :key="1" @click="deleteTempData()" class="btn btn-sm btn-warning" > Back </button> <span> <a download="meta.json" :href="dataLink" :class="[ 'btn btn-sm btn-outline-info', { disabled: !bottleneck || !importDate || !depthReference } ]" > <translate>Download Meta.json</translate> </a> <button :disabled="disableUploadButton" @click="confirm" class="btn btn-sm btn-info ml-2" type="button" > <translate>Confirm</translate> </button> </span> </div> <div v-if="uploadState" class="d-flex mt-2 p-2 border-top"> <button :key="2" @click="back()" class="btn btn-sm btn-warning"> Back </button> </div> </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> * Markus Kottländer <markus.kottlaender@intevation.de> */ import { HTTP } from "@/lib/http"; import { displayError, displayInfo } from "@/lib/errors"; import { mapState, mapGetters } from "vuex"; const IMPORTSTATE = { UPLOAD: "UPLOAD", EDIT: "EDIT" }; export default { data() { return { beamType: this.$options.BEAMTYPES.MULTIBEAM, importState: IMPORTSTATE.UPLOAD, depthReference: "", bottleneck: "", projection: "4326", importDate: "", uploadLabel: this.$gettext(this.$options.UPLOADLABEL), uploadFile: null, disableUpload: false, token: null, messages: [], eMailNotification: false, negateZ: false }; }, methods: { back() { this.$store.commit("importschedule/setListMode"); }, initialState() { this.importState = IMPORTSTATE.UPLOAD; this.depthReference = ""; this.bottleneck = null; this.projection = "4326"; this.importDate = ""; this.uploadLabel = this.$gettext(this.$options.UPLOADLABEL); this.uploadFile = null; this.disableUpload = false; this.token = null; this.eMailNotification = false; this.messages = []; }, fileSelected(e) { const files = e.target.files || e.dataTransfer.files; if (!files) return; this.uploadLabel = files[0].name; this.uploadFile = files[0]; this.upload(); }, deleteTempData() { HTTP.delete("/imports/sr-upload/" + this.token, { headers: { "X-Gemma-Auth": localStorage.getItem("token") } }) .then(() => { this.initialState(); }) .catch(error => { let message = "Backend not reachable"; if (error.response) { const { status, data } = error.response; message = `${status}: ${data.message || data}`; } displayError({ title: this.$gettext("Backend Error"), message: message }); }); }, upload() { let formData = new FormData(); formData.append("soundingresult", this.uploadFile); if (this.eMailNotification) { formData.append("send-email", this.eMailNotification); } HTTP.post("/imports/sr-upload", formData, { headers: { "X-Gemma-Auth": localStorage.getItem("token"), "Content-Type": "multipart/form-data" } }) .then(response => { if (response.data.meta) { const { bottleneck, date, epsg } = response.data.meta; const depthReference = response.data.meta["depth-reference"]; const singlebeam = response.data.meta["single-beam"]; this.negateZ = response.data.meta["negate-z"]; this.bottleneck = this.bottlenecks.find( bn => bn.properties.objnam === bottleneck ); this.depthReference = depthReference; this.importDate = new Date(date).toISOString().split("T")[0]; this.projection = epsg; this.beamType = singlebeam ? this.$options.BEAMTYPES.SINGLEBEAM : this.$options.BEAMTYPES.MULTIBEAM; } this.importState = IMPORTSTATE.EDIT; this.token = response.data.token; this.messages = response.data.messages; }) .catch(error => { let message = "Backend not reachable"; if (error.response) { const { status, data } = error.response; message = `${status}: ${data.message || data}`; } displayError({ title: this.$gettext("Backend Error"), message: message }); }); }, confirm() { let formData = new FormData(); formData.append("token", this.token); if (this.bottleneck) formData.append("bottleneck", this.bottleneck.properties.objnam); if (this.importDate) formData.append("date", this.importDate.split("T")[0]); if (this.depthReference) formData.append("depth-reference", this.depthReference); if (this.projection) formData.append("epsg", this.projection); if (this.beamType) formData.append( "single-beam", this.beamType === this.$options.BEAMTYPES.SINGLEBEAM ); formData.append("negate-z", this.negateZ == true); HTTP.post("/imports/sr", formData, { headers: { "X-Gemma-Auth": localStorage.getItem("token"), "Content-Type": "multipart/form-data" } }) .then(() => { displayInfo({ title: this.$gettext("Import"), message: this.$gettext("Starting import for ") + this.bottleneck.properties.objnam }); this.initialState(); }) .catch(error => { let message = "Backend not reachable"; if (error.response) { const { status, data } = error.response; message = `${status}: ${data.message || data}`; } displayError({ title: this.$gettext("Backend Error"), message: message }); }); } }, mounted() { this.$store.dispatch("bottlenecks/loadBottlenecks"); }, watch: { showContextBox() { if (!this.showContextBox && this.token) this.deleteTempData(); } }, computed: { ...mapState("application", ["showContextBox"]), ...mapState("bottlenecks", ["bottlenecks"]), ...mapState("user", ["user"]), ...mapGetters("usermanagement", ["userCountries"]), ...mapGetters("user", ["isSysAdmin"]), importSoundingresultsLabel() { return this.$gettext("Import Soundingresults"); }, disableUploadButton() { if (this.importState === IMPORTSTATE.UPLOAD) return this.disableUpload; if ( !this.bottleneck || !this.importDate || !this.depthReference || !this.projection ) return true; return this.disableUpload; }, availableBottlenecks() { const userCountrycode = this.userCountries[this.user]; if (userCountrycode === "global" || this.isSysAdmin) return this.bottlenecks; return this.bottlenecks.filter( bn => bn.properties.responsible_country === userCountrycode ); }, placeholder() { return this.$gettext("Select bottleneck"); }, orderedBottlenecks() { let groupedBottlenecks = {}, orderedGroups = {}; // group bottlenecks by cc this.availableBottlenecks.forEach(bn => { let cc = bn.properties.responsible_country; if (groupedBottlenecks.hasOwnProperty(cc)) { groupedBottlenecks[cc].push(bn); } else { groupedBottlenecks[cc] = [bn]; } }); // order groups by cc Object.keys(groupedBottlenecks) .sort() .forEach(cc => (orderedGroups[cc] = groupedBottlenecks[cc])); return orderedGroups; }, editState() { return this.importState === IMPORTSTATE.EDIT; }, uploadState() { return this.importState === IMPORTSTATE.UPLOAD; }, Upload() { return this.$gettext("Upload"); }, Confirm() { return this.$gettext("Confirm"); }, dataLink() { if ( this.bottleneck && this.depthReference && this.importDate && this.beamType && this.projection ) { return ( "data:text/json;charset=utf-8," + encodeURIComponent( JSON.stringify({ "depth-reference": this.depthReference, bottleneck: this.bottleneck.properties.objnam, date: this.importDate, "single-beam": this.beamType === this.$options.BEAMTYPES.SINGLEBEAM, epsg: Number(this.projection), "negate-z": this.negateZ == true }) ) ); } }, depthReferenceOptions() { if (this.bottleneck) { const bnProperties = this.bottleneck.properties; const referenceLevels = JSON.parse(bnProperties.reference_water_levels) || {}; const result = Object.keys(referenceLevels); const bottleneckBGorRO = bnProperties.responsible_country == "BG" || bnProperties.responsible_country == "RO"; const hasLDC = referenceLevels.hasOwnProperty("LDC"); const hasZPG = referenceLevels.hasOwnProperty("ZPG"); if ((hasLDC && !hasZPG) || (!hasLDC && !hasZPG && bottleneckBGorRO)) { result.push("ZPG"); } return result; } return []; } }, BEAMTYPES: { MULTIBEAM: "multi-beam", SINGLEBEAM: "single-beam" }, UPLOADLABEL: "choose a .zip or .txt file", on: "on", off: "off" }; </script>