view client/src/components/ImportSoundingresults.vue @ 2438:bbc31150248c

client: import soundingresults: depthreferences from selected bottleneck and preselect depthreference from uploaded import
author Markus Kottlaender <markus@intevation.de>
date Fri, 01 Mar 2019 10:31:24 +0100
parents 64ff5984351e
children e0f423606929
line wrap: on
line source

<template>
  <div class="main d-flex flex-column">
    <div class="d-flex flex-row">
      <Spacer></Spacer>
      <div class="card shadow-xs mt-3 mr-3 w-100 h-100">
        <UIBoxHeader icon="upload" title="Import Soundingresults" />
        <div v-if="editState">
          <div
            v-for="(message, index) in messages"
            :key="index"
            class="alert alert-warning small rounded-0"
          >
            {{ message }}
          </div>
          <div class="container">
            <div class="row">
              <div class="col-5">
                <small class="text-muted">
                  <translate>Bottleneck</translate>
                </small>
                <select v-model="bottleneck" class="custom-select">
                  <option
                    v-for="bottleneck in availableBottlenecks"
                    :value="bottleneck"
                    :key="bottleneck.properties.objnam"
                  >
                    {{ bottleneck.properties.objnam }}
                  </option>
                </select>
                <span class="text-danger">
                  <small v-if="!bottleneck">
                    <translate>Please select a bottleneck</translate>
                  </small>
                </span>
              </div>
              <div class="col-2">
                <small class="text-muted">
                  <translate>Projection</translate>&nbsp;(EPSG)
                </small>
                <input
                  class="form-control"
                  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="col-2">
                <small class="text-muted">
                  <translate>Depthreference</translate>
                </small>
                <select
                  v-model="depthReference"
                  class="custom-select"
                  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="col-3">
                <small class="text-muted"> <translate>Date</translate> </small>
                <input
                  id="importdate"
                  type="date"
                  class="form-control"
                  placeholder="Date of import"
                  aria-label="bottleneck"
                  aria-describedby="bottlenecklabel"
                  v-model="importDate"
                />
                <span class="text-left text-danger">
                  <small v-if="!importDate">
                    <translate>Please enter a date</translate>
                  </small>
                </span>
              </div>
            </div>
            <div class="row"></div>
          </div>
        </div>
        <div class="container py-5">
          <div v-if="uploadState" class="input-group">
            <div class="custom-file">
              <input
                accept=".zip"
                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" v-if="editState">
            <a
              download="meta.json"
              :href="dataLink"
              class="btn btn-outline-info"
            >
              <translate>Download Meta.json</translate>
            </a>
            <span>
              <button
                @click="deleteTempData"
                class="btn btn-danger"
                type="button"
              >
                <translate>Cancel Upload</translate>
              </button>
              <button
                :disabled="disableUploadButton"
                @click="confirm"
                class="btn btn-info ml-2"
                type="button"
              >
                <translate>Confirm</translate>
              </button>
            </span>
          </div>
        </div>
      </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.js";
import { mapState } from "vuex";
import Spacer from "./Spacer";

const IMPORTSTATE = { UPLOAD: "UPLOAD", EDIT: "EDIT" };

export default {
  name: "imports",
  components: {
    Spacer
  },
  data() {
    return {
      importState: IMPORTSTATE.UPLOAD,
      depthReference: "",
      bottleneck: "",
      projection: "",
      importDate: "",
      uploadLabel: this.$gettext("choose .zip- file"),
      uploadFile: null,
      disableUpload: false,
      token: null,
      messages: []
    };
  },
  methods: {
    initialState() {
      this.importState = IMPORTSTATE.UPLOAD;
      this.depthReference = "";
      this.bottleneck = null;
      this.projection = "";
      this.importDate = "";
      this.uploadLabel = this.$gettext("choose .zip- file");
      this.uploadFile = null;
      this.disableUpload = false;
      this.token = null;
      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 => {
          const { status, data } = error.response;
          displayError({
            title: this.$gettext("Backend Error"),
            message: `${status}: ${data.message || data}`
          });
        });
    },
    upload() {
      let formData = new FormData();
      formData.append("soundingresult", this.uploadFile);
      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"];
            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.importState = IMPORTSTATE.EDIT;
          this.token = response.data.token;
          this.messages = response.data.messages;
        })
        .catch(error => {
          const { status, data } = error.response;
          const messages = data.messages ? data.messages.join(", ") : "";
          displayError({
            title: this.$gettext("Backend Error"),
            message: `${status}: ${messages}`
          });
        });
    },
    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("", this.projection);

      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 => {
          const { status, data } = error.response;
          displayError({
            title: this.$gettext("Backend Error"),
            message: `${status}: ${data.message || data}`
          });
        });
    }
  },
  mounted() {
    this.$store.dispatch("bottlenecks/loadBottlenecks");
  },
  watch: {
    showContextBox() {
      if (!this.showContextBox && this.token) this.deleteTempData();
    }
  },
  computed: {
    ...mapState("application", ["showContextBox"]),
    ...mapState("bottlenecks", ["bottlenecks"]),
    disableUploadButton() {
      if (this.importState === IMPORTSTATE.UPLOAD) return this.disableUpload;
      if (
        !this.bottleneck ||
        !this.importDate ||
        !this.depthReference ||
        !this.projection
      )
        return true;
      return this.disableUpload;
    },
    availableBottlenecks() {
      return this.bottlenecks;
    },
    editState() {
      return this.importState === IMPORTSTATE.EDIT;
    },
    uploadState() {
      return this.importState === IMPORTSTATE.UPLOAD;
    },
    Upload() {
      return this.$gettext("Upload");
    },
    Confirm() {
      return this.$gettext("Confirm");
    },
    dataLink() {
      return (
        "data:text/json;charset=utf-8," +
        encodeURIComponent(
          JSON.stringify({
            depthReference: this.depthReference,
            bottleneck: this.bottleneck.properties.objnam,
            date: this.importDate
          })
        )
      );
    },
    depthReferenceOptions() {
      if (
        this.bottleneck &&
        this.bottleneck.properties.reference_water_levels
      ) {
        return Object.keys(
          JSON.parse(this.bottleneck.properties.reference_water_levels)
        );
      }
      return [];
    }
  }
};
</script>