view client/src/components/ImportStretches.vue @ 3254:08b117aca4cc

client: import stretches: fixed selection of start/end rhm
author Markus Kottlaender <markus@intevation.de>
date Tue, 14 May 2019 16:48:05 +0200
parents 0374197c384f
children ccd1f03ed18a
line wrap: on
line source

<template>
  <div class="d-flex flex-column mb-3">
    <UIBoxHeader
      icon="road"
      :title="defineStretchesLabel"
      :closeCallback="$parent.close"
    />
    <div class="position-relative">
      <UISpinnerOverlay v-if="loading" />
      <div v-if="!edit" class="mb-3">
        <UITableHeader
          :columns="[
            { id: 'properties.name', title: `${nameLabel}`, class: 'col-4' },
            {
              id: 'properties.date_info',
              title: `${dateLabel}`,
              class: 'col-2'
            },
            {
              id: 'properties.source_organization',
              title: `${sourceorganizationLabel}`,
              class: 'col-3'
            }
          ]"
        />
        <UITableBody
          :data="filteredStretches() | sortTable(sortColumn, sortDirection)"
        >
          <template v-slot:row="{ item: stretch }">
            <div class="py-1 col-4 ">
              <a
                class="pointer 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(stretch)" href="#">{{
                stretch.properties.name
              }}</a>
            </div>
            <div class="py-1 col-2">
              {{ stretch.properties.date_info | surveyDate }}
            </div>
            <div class="py-1 col-3">
              {{ stretch.properties.source_organization }}
            </div>
            <div class="py-1 col text-right">
              <button
                class="btn btn-xs btn-dark mr-1"
                @click="editStretch(stretch)"
              >
                <font-awesome-icon icon="pencil-alt" fixed-width />
              </button>
              <button
                class="btn btn-xs btn-dark"
                @click="deleteStretch(stretch)"
              >
                <font-awesome-icon icon="trash" fixed-width />
              </button>
            </div>
          </template>
        </UITableBody>
      </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="editExistingStretch"
              />
              <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"
                  />
                </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"
                  />
                </span>
              </div>
              <span class="text-left text-danger">
                <small v-if="endrhmError && !endrhm">
                  <translate>Please enter an end point</translate>
                </small>
              </span>
            </div>
          </div>
          <div
            v-if="!editExistingStretch"
            class="d-flex flex-row justify-content-between"
          >
            <div class="mt-2  mr-2 w-50  text-left">
              <small class="text-muted">
                <translate
                  >Tolerance for snapping of waterway axis [m]</translate
                >
              </small>
              <input
                class="form-control"
                v-model.number="tolerance"
                placeholder=""
                type="number"
                min="0"
                step="any"
                aria-label="tolerance"
                id="tolerance"
              />
              <span class="text-left text-danger">
                <small v-if="toleranceError && !tolerance">
                  <translate>Please enter a tolerance value</translate>
                </small>
              </span>
            </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>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>
  </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, 2019 by via donau
 *   – Österreichische Wasserstraßen-Gesellschaft mbH
 * Software engineering by Intevation GmbH
 *
 * Author(s):
 * Thomas Junk <thomas.junk@intevation.de>
 * Tom Gottfried <tom.gottfried@intevation.de>
 */
import { mapState, mapGetters } from "vuex";
import { displayError, displayInfo } from "@/lib/errors";
import { HTTP } from "@/lib/http";
import { sortTable } from "@/lib/mixins";

export default {
  name: "importstretches",
  mixins: [sortTable],
  data() {
    return {
      staging: [],
      edit: false,
      editExistingStretch: false,
      id: "",
      funktion: "",
      startrhm: "",
      endrhm: "",
      tolerance: 5,
      objbn: "",
      nobjbn: "",
      countryCode: "",
      date_info: new Date().toISOString().split("T")[0],
      source: "",
      pipetteStart: false,
      pipetteEnd: false,
      idError: false,
      funktionError: false,
      startrhmError: false,
      endrhmError: false,
      toleranceError: false,
      objbnError: false,
      nobjbnError: false,
      date_infoError: false,
      sourceError: false,
      countryCodeError: false,
      loading: false
    };
  },
  computed: {
    ...mapState("application", ["searchQuery"]),
    ...mapState("map", ["identifiedFeatures", "currentMeasurement"]),
    ...mapGetters("map", ["openLayersMap"]),
    ...mapGetters("user", ["isSysAdmin"]),
    ...mapState("imports", ["stretches"]),
    defineStretchesLabel() {
      return this.$gettext("Define Stretches");
    },
    nameLabel() {
      return this.$gettext("Name");
    },
    dateLabel() {
      return this.$gettext("Date");
    },
    sourceorganizationLabel() {
      return this.$gettext("Source organization");
    },
    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;
    }
  },
  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;
      }
    }
  },
  methods: {
    filteredStretches() {
      return this.stretches.filter(s => {
        return (s.properties.name + s.properties.source_organization)
          .toLowerCase()
          .includes(this.searchQuery.toLowerCase());
      });
    },
    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) => {
        HTTP.get("/imports?states=pending", {
          headers: { "X-Gemma-Auth": localStorage.getItem("token") }
        })
          .then(response => {
            const { imports } = response.data;
            this.staging = imports;
            resolve(response);
          })
          .catch(error => {
            reject(error);
          });
      });
    },
    editStretch(stretch) {
      const properties = stretch.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.editExistingStretch = true;
    },
    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(stretch) {
      this.$store.commit("imports/selectedStretchId", stretch.id);
      this.openLayersMap()
        .getLayer("STRETCHES")
        .setVisible(true);
      this.$store.dispatch("map/moveToFeauture", {
        feature: stretch,
        zoom: 17,
        preventZoomOut: true
      });
    },
    clean() {
      this.id = "";
      this.edit = false;
      this.editExistingStretch = false;
      this.funktion = "";
      this.startrhm = "";
      this.tolerance = 5;
      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.toleranceError = 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.openLayersMap()
        .getLayer("DISTANCEMARKSAXIS")
        .setVisible(true);
      if (t === "start") {
        this.pipetteStart = !this.pipetteStart;
        this.pipetteEnd = false;
      } else {
        this.pipetteEnd = !this.pipetteEnd;
        this.pipetteStart = false;
      }
    },
    validate() {
      const fields = [
        "id",
        "funktion",
        "startrhm",
        "tolerance",
        "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.id ||
        !this.startrhm ||
        !this.endrhm ||
        (!this.tolerance && this.editExistingStretch) ||
        !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();
        })
      };
      if (!this.editExistingStretch) {
        data["tolerance"] = this.tolerance;
      }
      this.$store
        .dispatch("imports/saveStretch", data)
        .then(() => {
          displayInfo({
            title: this.$gettext("Import"),
            message: this.$gettext("Starting import of stretch")
          });
          this.clean();
          this.$store.dispatch("imports/loadStretches").then(() => {
            this.edit = false;
          });
        })
        .catch(error => {
          const { status, data } = error.response;
          displayError({
            title: this.$gettext("Backend Error"),
            message: `${status}: ${data.message || data}`
          });
        });
    }
  },
  mounted() {
    this.edit = false;
    this.loading = true;
    this.$store
      .dispatch("imports/loadStretches")
      .catch(error => {
        const { status, data } = error.response;
        displayError({
          title: this.$gettext("Backend Error"),
          message: `${status}: ${data.message || data}`
        });
      })
      .finally(() => (this.loading = false));
    this.loadStagingData().catch(error => {
      const { status, data } = error.response;
      displayError({
        title: this.$gettext("Backend Error"),
        message: `${status}: ${data.message || data}`
      });
    });
  }
};
</script>