view client/src/components/ImportSoundingresults.vue @ 2432:851c904416f6

client: import soundingresults: html cleanup
author Markus Kottlaender <markus@intevation.de>
date Fri, 01 Mar 2019 07:58:02 +0100
parents 4625ae70f076
children 64be06696899
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"
                    :key="bottleneck"
                    >{{ bottleneck }}</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.$options.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="buttons text-right" v-if="editState">
            <a
              download="meta.json"
              :href="dataLink"
              class="btn btn-outline-info pull-left mt-4"
            >
              <translate>Download Meta.json</translate>
            </a>
            <button
              @click="deleteTempData"
              class="btn btn-danger mt-4"
              type="button"
            >
              <translate>Cancel Upload</translate>
            </button>
            <button
              :disabled="disableUploadButton"
              @click="confirm"
              class="btn btn-info mt-4"
              type="button"
            >
              <translate>Confirm</translate>
            </button>
          </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 = "";
      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 = 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);
      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
          });
          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.map(x => x.properties.name);
    },
    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,
            date: this.importDate
          })
        )
      );
    }
  },
  depthReferenceOptions: [
    "",
    // "NAP",
    // "KP",
    // "FZP",
    // "ADR",
    // "TAW",
    // "PUL",
    // "NGM",
    // "ETRS",
    // "POT",
    "LDC",
    // "HDC",
    // "ZPG",
    // "GLW",
    // "HSW",
    "LNWL" //,
    // "HNW",
    // "IGN",
    // "WGS",
    // "RN",
    // "HBO"
  ]
};
</script>

<style lang="scss" scoped>
.projectionLabel {
  margin-left: $small-offset;
}

.depthreferencelabel {
  margin-left: $small-offset;
}

.offset-r {
  margin-right: $small-offset;
}

.buttons button {
  margin-left: $offset !important;
}

.label-text {
  width: 5rem;
  text-align: left;
  line-height: 2.25rem;
}
</style>