view client/src/components/ImportStretches.vue @ 3044:c71373594719

client: map: prepared store to hold multiple map objects This will be necessary to sync maps, toggle layers per map, etc. Therefore the methods to move the map (moveToExtent, etc.) became actions instead of mutations.
author Markus Kottlaender <markus@intevation.de>
date Sat, 13 Apr 2019 16:02:06 +0200
parents 4b9e83cf82ea
children 1ef2f4179d30
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/moveToExtent", {
        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>