view client/src/components/importschedule/Importscheduledetail.vue @ 1998:ceb6aaff6c8b importschedulerefac

Backed out changeset 74c03fec0a91
author Thomas Junk <thomas.junk@intevation.de>
date Thu, 24 Jan 2019 14:10:08 +0100
parents 74c03fec0a91
children c420add2dec2
line wrap: on
line source

<template>
  <div
    class="importscheduledetails  fadeIn animated"
    v-if="importScheduleDetailVisible"
  >
    <div class="card shadow-xs importscheduledetailscard pb-5">
      <h6
        class="mb-0 py-2 px-3 border-bottom d-flex text-info align-items-center"
      >
        {{ dialogLabel }}
        <span @click="closeDetailview" class="closebutton">
          <font-awesome-icon icon="times"></font-awesome-icon>
        </span>
      </h6>
      <div class="card-body">
        <form @submit.prevent="save" class="ml-2 mr-2">
          <div class="d-flex flex-row">
            <div class="flex-column w-50 mr-3">
              <div class="flex-row text-left">
                <small class="text-muted">
                  <translate>Imports</translate>
                </small>
              </div>
              <select v-model="import_" class="custom-select" id="importtype">
                <option :value="$options.IMPORTTYPES.BOTTLENECK"
                  ><translate>Bottlenecks</translate></option
                >
                <option :value="$options.IMPORTTYPES.WATERWAYAXIS"
                  ><translate>Waterway axis</translate></option
                >
                <option :value="$options.IMPORTTYPES.GAUGEMEASUREMENT"
                  ><translate>Gauge measurement</translate></option
                >
                <option :value="$options.IMPORTTYPES.FAIRWAYAVAILABILITY"
                  ><translate>Available Fairway Depths</translate></option
                >
                <option :value="$options.IMPORTTYPES.WATERWAYAREA"
                  ><translate>Waterwayarea</translate></option
                >
                <option :value="$options.IMPORTTYPES.FAIRWAYDIMENSION"
                  ><translate>Fairwaydimension</translate></option
                >
                <option :value="$options.IMPORTTYPES.WATERWAYGAUGES"
                  ><translate>Waterway gauges</translate></option
                >
                <option :value="$options.IMPORTTYPES.DISTANCEMARKSVIRTUAL"
                  ><translate>Distance Marks Virtual</translate></option
                >
              </select>
            </div>
            <div class="flex-column ml-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>

          <Availablefairwaydepth
            v-if="import_ == $options.IMPORTTYPES.FAIRWAYAVAILABILITY"
            @urlChanged="setUrl"
            :url="url"
          ></Availablefairwaydepth>
          <Bottleneck
            v-if="import_ == $options.IMPORTTYPES.BOTTLENECK"
            @urlChanged="setUrl"
            :url="url"
          ></Bottleneck>
          <Distancemarksvirtual
            v-if="import_ == $options.IMPORTTYPES.DISTANCEMARKSVIRTUAL"
            @urlChanged="setUrl"
            @usernameChanged="setUsername"
            @passwordChanged="setPassword"
            :url="url"
            :username="username"
            :password="password"
          ></Distancemarksvirtual>
          <Faiwaydimensions
            v-if="import_ == $options.IMPORTTYPES.FAIRWAYDIMENSION"
            @urlChanged="setUrl"
            @featureTypeChanged="setFeatureType"
            @sortByChanged="setSortBy"
            @LOSChanged="setLOS"
            @depthChanged="setDepth"
            @minWidthChanged="setMinWidth"
            @maxWidthChanged="setMaxWidth"
            @sourceOrganizationChanged="setSourceOrganization"
            :url="url"
            :featureType="featureType"
            :sortBy="sortBy"
            :LOS="LOS"
            :minWidth="minWidth"
            :maxWidth="maxWidth"
            :sourceOrganization="sourceOrganization"
            :depth="depth"
          ></Faiwaydimensions>
          <Gaugemeasurement
            v-if="import_ == $options.IMPORTTYPES.GAUGEMEASUREMENT"
            @urlChanged="setUrl"
            :url="url"
          ></Gaugemeasurement>
          <Waterwayarea
            v-if="import_ == $options.IMPORTTYPES.WATERWAYAREA"
            @urlChanged="setUrl"
            @featureTypeChanged="setFeatureType"
            @sortByChanged="setSortBy"
            :url="url"
            :featureType="featureType"
            :sortBy="sortBy"
          ></Waterwayarea>
          <Waterwaygauges
            v-if="import_ == $options.IMPORTTYPES.WATERWAYGAUGES"
            @urlChanged="setUrl"
            @usernameChanged="setUsername"
            @passwordChanged="setPassword"
            :url="url"
            :username="username"
            :password="password"
          ></Waterwaygauges>
          <Waterwayaxis
            v-if="import_ == $options.IMPORTTYPES.WATERWAYAXIS"
            @urlChanged="setUrl"
            @featureTypeChanged="setFeatureType"
            @sortByChanged="setSortBy"
            :url="url"
            :featureType="featureType"
            :sortBy="sortBy"
          ></Waterwayaxis>

          <div class="d-flex flex-row">
            <div class="flex-column mt-3 mr-4">
              <div class="flex-row text-left">
                <small class="text-muted">
                  <translate>Scheduled</translate>?
                </small>
              </div>
              <div class="flex-flex-row text-left">
                <toggle-button
                  v-model="scheduled"
                  class="mt-2"
                  :speed="100"
                  :labels="{
                    checked: this.$options.on,
                    unchecked: this.$options.off
                  }"
                  :width="60"
                  :height="30"
                />
              </div>
            </div>
            <div class="flex-column mt-3 mr-2">
              <div class="flex-row text-left">
                <small class="text-muted">
                  <translate>Simple Schedule</translate>
                </small>
              </div>
              <div class="flex-flex-row text-left">
                <toggle-button
                  :disabled="!scheduled"
                  v-model="easyCron"
                  class="mt-2"
                  :speed="100"
                  :labels="{
                    checked: this.$options.on,
                    unchecked: this.$options.off
                  }"
                  :width="60"
                  :height="30"
                />
              </div>
            </div>
          </div>
          <div class="flex-column w-100 mr-2">
            <div class="flex-row text-left">
              <small class="text-muted">
                <translate>Schedule</translate>
              </small>
            </div>
            <div v-if="easyCron" class="text-left w-50">
              <select
                :disabled="!scheduled"
                v-model="simple"
                class="form-control"
                ><option value="weekly"><translate>Weekly</translate></option>
                <option value="monthly"><translate>Monthly</translate></option>
              </select>
            </div>
            <div v-if="!easyCron" class="text-left w-100">
              <div class="d-flex flex-row">
                <h4 class="mt-auto mb-auto mr-2">{{ $options.EVERY }}</h4>
                <select
                  :disabled="!scheduled"
                  style="width: 130px;"
                  v-model="cronMode"
                  class="form-control"
                  @change="clearInputs"
                >
                  <option
                    v-for="(option, key) in $options.CRONMODE"
                    :value="key"
                    :key="key"
                    >{{ option }}</option
                  >
                </select>
                <div v-if="cronMode == 'hour'" class="ml-1 d-flex flex-row">
                  <h4 class="mt-auto mb-auto">{{ $options.ON }}</h4>
                  <input
                    :disabled="!scheduled"
                    v-model="minutes"
                    class="cronfield ml-1 mr-1 form-control"
                    type="number"
                  />
                  <h4 class="mt-auto mb-auto">{{ $options.MINUTESPAST }}</h4>
                </div>
                <div v-if="cronMode == 'day'" class="ml-1 d-flex flex-row">
                  <h4 class="mt-auto mb-auto">{{ $options.AT }}</h4>
                  <input
                    :disabled="!scheduled"
                    v-model="hour"
                    class="cronfield ml-1 mr-1 form-control"
                    type="number"
                  />
                  <input
                    :disabled="!scheduled"
                    v-model="minutes"
                    class="cronfield ml-1 mr-1 form-control"
                    type="number"
                  />
                  <h4 class="mt-auto mb-auto">{{ $options.OCLOCK }}</h4>
                </div>
                <div v-if="cronMode == 'week'" class="ml-1 d-flex flex-row">
                  <h4 class="ml-1 mr-1 mt-auto mb-auto">{{ $options.ON }}</h4>
                  <select
                    :disabled="!scheduled"
                    v-model="day"
                    class="form-control"
                  >
                    <option
                      v-for="(option, key) in $options.DAYSOFWEEK"
                      :key="key"
                      :value="key"
                      >{{ option }}</option
                    >
                  </select>
                  <h4 class="ml-1 mt-auto mb-auto">{{ $options.AT }}</h4>
                  <input
                    :disabled="!scheduled"
                    v-model="hour"
                    class="cronfield ml-1 mr-1 form-control"
                    type="number"
                  />
                  <input
                    :disabled="!scheduled"
                    v-model="minutes"
                    class="cronfield ml-1 mr-1 form-control"
                    type="number"
                  />
                </div>
                <div v-if="cronMode == 'month'" class="ml-1 d-flex flex-row">
                  <h4 class="ml-1 mt-auto mb-auto">{{ $options.ON }}</h4>
                  <input
                    :disabled="!scheduled"
                    v-model="dayOfMonth"
                    class="cronfield ml-1 mr-1 form-control"
                    type="number"
                  />
                  <h4 class="mt-auto mb-auto">{{ $options.AT }}</h4>
                  <input
                    :disabled="!scheduled"
                    v-model="hour"
                    class="cronfield ml-1 mr-2 form-control"
                    type="number"
                  />
                  <input
                    :disabled="!scheduled"
                    v-model="minutes"
                    class="cronfield ml-1 mr-2 form-control"
                    type="number"
                  />
                  <h4 class="mt-auto mb-auto">{{ $options.OCLOCK }}</h4>
                </div>
                <div v-if="cronMode == 'year'" class="ml-1 d-flex flex-row">
                  <h4 class="ml-1 mt-auto mb-auto">{{ $options.ON }}</h4>
                  <input
                    :disabled="!scheduled"
                    v-model="dayOfMonth"
                    class="cronfield ml-1 mr-1 form-control"
                    type="number"
                  />
                  <h4 class="mt-auto mb-auto">{{ $options.OF }}</h4>
                  <select
                    :disabled="!scheduled"
                    v-model="month"
                    class="ml-1 mr-1 form-control"
                  >
                    <option
                      v-for="(option, key) in $options.MONTHS"
                      :value="key"
                      :key="key"
                      >{{ option }}</option
                    >
                  </select>
                  <h4 class="mt-auto mb-auto">{{ $options.ON }}</h4>
                  <input
                    :disabled="!scheduled"
                    v-model="hour"
                    class="cronfield ml-1 mr-1 form-control"
                    type="number"
                  />
                  <input
                    :disabled="!scheduled"
                    v-model="minutes"
                    class="cronfield ml-1 mr-1 form-control"
                    type="number"
                  />
                </div>
              </div>
              <div class="mt-3 w-50 d-flex flex-row">
                <h5 class="mt-auto mb-auto mr-2">
                  <translate>Cronstring</translate>
                </h5>
                <input
                  :disabled="!scheduled"
                  class="form-control"
                  v-model="cronString"
                  type="text"
                />
              </div>
            </div>
          </div>
          <button type="submit" class="shadow-sm btn btn-info submit-button">
            <translate>Submit</translate>
          </button>
          <button
            @click="triggerManualImport"
            type="button"
            class="shadow-sm btn btn-outline-info trigger"
            :disabled="!triggerActive"
          >
            <font-awesome-icon
              class="fa-fw mr-2"
              fixed-width
              icon="play"
            ></font-awesome-icon
            ><translate>Trigger import</translate>
          </button>
        </form>
      </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>
 */
import {
  IMPORTTYPES,
  IMPORTTYPEKIND,
  initializeCurrentSchedule
} from "@/store/imports.js";
import { mapState } from "vuex";
import { displayInfo, displayError } from "@/lib/errors.js";
import app from "@/main.js";

export default {
  name: "importscheduledetail",
  components: {
    Availablefairwaydepth: () =>
      import("@/components/importschedule/importtypes/Availablefairwaydepth"),
    Bottleneck: () =>
      import("@/components/importschedule/importtypes/Bottleneck"),
    Distancemarksvirtual: () =>
      import("@/components/importschedule/importtypes/Distancemarksvirtual"),
    Faiwaydimensions: () =>
      import("@/components/importschedule/importtypes/Fairwaydimensions"),
    Gaugemeasurement: () =>
      import("@/components/importschedule/importtypes/Gaugemeasurement"),
    Waterwayarea: () =>
      import("@/components/importschedule/importtypes/Waterwayarea"),
    Waterwaygauges: () =>
      import("@/components/importschedule/importtypes/Waterwaygauges"),
    Waterwayaxis: () =>
      import("@/components/importschedule/importtypes/Waterwayaxis")
  },
  data() {
    return {
      passwordVisible: false,
      ...initializeCurrentSchedule()
    };
  },
  IMPORTTYPES: IMPORTTYPES,
  EVERY: app.$gettext("Every"),
  MINUTESPAST: app.$gettext("minutes past"),
  ON: app.$gettext("on"),
  OF: app.$gettext("of"),
  AT: app.$gettext("at"),
  OCLOCK: app.$gettext("o' clock"),
  CRONMODE: {
    "15minutes": app.$gettext("15 minutes"),
    hour: app.$gettext("hour"),
    day: app.$gettext("day"),
    week: app.$gettext("week"),
    month: app.$gettext("month"),
    year: app.$gettext("year")
  },
  DAYSOFWEEK: {
    1: app.$gettext("Monday"),
    2: app.$gettext("Tuesday"),
    3: app.$gettext("Wednesday"),
    4: app.$gettext("Thursday"),
    5: app.$gettext("Friday"),
    6: app.$gettext("Saturday"),
    0: app.$gettext("Sunday")
  },
  MONTHS: {
    1: app.$gettext("January"),
    2: app.$gettext("February"),
    3: app.$gettext("March"),
    4: app.$gettext("April"),
    5: app.$gettext("May"),
    6: app.$gettext("June"),
    7: app.$gettext("July"),
    8: app.$gettext("August"),
    9: app.$gettext("September"),
    10: app.$gettext("October"),
    11: app.$gettext("November"),
    12: app.$gettext("December")
  },
  mounted() {
    this.initialize();
  },
  watch: {
    cronMode() {
      this.cronString = this.calcCronString();
    },
    minutes() {
      this.cronString = this.calcCronString();
    },
    hour() {
      this.cronString = this.calcCronString();
    },
    month() {
      this.cronString = this.calcCronString();
    },
    day() {
      this.cronString = this.calcCronString();
    },
    dayOfMonth() {
      this.cronString = this.calcCronString();
    },
    importScheduleDetailVisible() {
      this.initialize();
    },
    cronString() {
      if (this.isWeekly(this.cronString)) {
        this.simple = "weekly";
      }
      if (this.isMonthly(this.cronString)) {
        this.simple = "monthly";
      }
    }
  },
  computed: {
    ...mapState("imports", ["importScheduleDetailVisible", "currentSchedule"]),
    dialogLabel() {
      if (this.id) return this.$gettext("Import") + " " + this.id;
      return this.$gettext("New Import");
    }
  },
  methods: {
    setUrl(value) {
      this.url = value;
    },
    setFeatureType(value) {
      this.featureType = value;
    },
    setSortBy(value) {
      this.sortBy = value;
    },
    setUsername(value) {
      this.username = value;
    },
    setPassword(value) {
      this.password = value;
    },
    setLOS(value) {
      this.LOS = value;
    },
    setMinWidth(value) {
      this.minWidth = value;
    },
    setMaxWidth(value) {
      this.maxWidth = value;
    },
    setDepth(value) {
      this.depth = value;
    },
    setSourceOrganization(value) {
      this.sourceOrganization = value;
    },
    calcCronString() {
      let getValue = value => {
        return this[value] ? this[value] : "*";
      };
      if (this.cronMode === "15minutes") return "0 */15 * * * *";
      const min = getValue("minutes");
      const h = getValue("hour");
      const dm = getValue("dayOfMonth");
      const m = getValue("month");
      const wd = getValue("day");
      return `0 ${min} ${h} ${dm} ${m} ${wd}`;
    },
    validateBottleneckfields() {
      return !!this.url;
    },
    initialize() {
      this.id = this.currentSchedule.id;
      this.importType = this.currentSchedule.importType;
      this.schedule = this.currentSchedule.schedule;
      this.scheduled = this.currentSchedule.scheduled;
      this.import_ = this.currentSchedule.import_;
      this.importSource = this.currentSchedule.importSource;
      this.eMailNotification = this.currentSchedule.eMailNotification;
      this.easyCron = this.currentSchedule.easyCron;
      this.cronMode = this.currentSchedule.cronMode;
      this.minutes = this.currentSchedule.minutes;
      this.month = this.currentSchedule.month;
      this.hour = this.currentSchedule.hour;
      this.day = this.currentSchedule.day;
      this.dayOfMonth = this.currentSchedule.dayOfMonth;
      this.simple = this.currentSchedule.simple;
      this.url = this.currentSchedule.url;
      this.insecure = this.currentSchedule.insecure;
      this.cronString = this.currentSchedule.cronString;
      this.featureType = this.currentSchedule.featureType;
      this.sortBy = this.currentSchedule.sortBy;
      this.username = this.currentSchedule.username;
      this.password = this.currentSchedule.password;
      this.LOS = this.currentSchedule.LOS;
      this.minWidth = this.currentSchedule.minWidth;
      this.maxWidth = this.currentSchedule.maxWidth;
      this.depth = this.currentSchedule.depth;
      this.sourceOrganization = this.currentSchedule.sourceOrganization;
    },
    isWeekly(cron) {
      return /0 \d{1,2} \d{1,2} \* \* \d{1}/.test(cron);
    },
    isMonthly(cron) {
      return /0 \d{1,2} \d{1,2} \d{1,2} \* \*/.test(cron);
    },
    clearInputs() {
      this.minutes = null;
      this.month = null;
      this.hour = null;
      this.day = null;
      this.dayOfMonth = null;
    },
    triggerManualImport() {
      if (!this.triggerActive) return;
      if (!this.import_) return;
      let data = {};
      if (this.isURLRequired) {
        if (!this.url) return;
        data["url"] = this.url;
        data["insecure"] = this.insecure;
      }
      if (this.isFeatureTypeRequired) {
        if (!this.featureType) return;
        data["feature-type"] = this.featureType;
      }
      if (this.isSortbyRequired) {
        if (!this.sortBy) return;
        data["sort-by"] = this.sortBy;
      }
      if (this.isCredentialsRequired) {
        if (!this.username || !this.password) return;
        data["username"] = this.username;
        data["password"] = this.password;
      }
      if (this.import_ == this.$options.IMPORTTYPES.FAIRWAYDIMENSION) {
        if (
          !this.LOS ||
          !this.minWidth ||
          !this.maxWidth ||
          !this.depth ||
          !this.sourceOrganization
        )
          return;
        data["feature-type"] = this.featureType;
        data["sort-by"] = this.sortBy;
        data["los"] = this.LOS * 1;
        data["min-width"] = this.minWidth * 1;
        data["max-width"] = this.maxWidth * 1;
        data["depth"] = this.depth * 1;
        data["source-organization"] = this.sourceOrganization;
      }
      this.triggerActive = false;
      this.$store
        .dispatch("imports/triggerImport", { type: this.import_, data })
        .then(response => {
          const { id } = response.data;
          displayInfo({
            title: this.$gettext("Import"),
            message: this.$gettext("Manually triggered import: #") + id
          });
        })
        .catch(error => {
          const { status, data } = error.response;
          displayError({
            title: this.$gettext("Backend Error"),
            message: `${status}: ${data.message || data}`
          });
        })
        .finally(() => {
          this.triggerActive = true;
        });
    },
    save() {
      const addAttribute = (data, attribute) => {
        if (!data["attributes"]) data.attributes = {};
        data["attributes"] = { ...data["attributes"], ...attribute };
      };
      if (!this.import_) return;
      let cron = this.cronString;
      if (this.easyCron) {
        if (this.simple === "weekly") cron = "0 0 0 * * 0";
        if (this.simple === "monthly") cron = "0 0 0 1 * *";
      }
      let data = {};
      if (this.isURLRequired) {
        if (!this.url) return;
        data["url"] = this.url;
        addAttribute(data, {
          insecure: this.insecure + ""
        });
      }
      if (this.isSortbyRequired) {
        if (!this.sortBy) return;
        addAttribute(data, {
          "sort-by": this.sortBy
        });
      }
      if (this.isFeatureTypeRequired) {
        if (!this.featureType) return;
        addAttribute(data, {
          "feature-type": this.featureType
        });
      }
      if (this.isCredentialsRequired) {
        if (!this.username || !this.password) return;
        addAttribute(data, {
          username: this.username,
          password: this.password
        });
      }
      if (this.import_ == this.$options.IMPORTTYPES.FAIRWAYDIMENSION) {
        if (
          !this.LOS ||
          !this.minWidth ||
          !this.maxWidth ||
          !this.depth ||
          !this.sourceOrganization
        )
          return;
        const values = {
          los: this.LOS,
          depth: this.depth
        };
        values["min-width"] = this.minWidth;
        values["max-width"] = this.maxWidth;
        values["source-organization"] = this.sourceOrganization;
        addAttribute(data, values);
      }
      if (this.scheduled) data["cron"] = cron;
      data["kind"] = IMPORTTYPEKIND[this.import_];
      data["send-email"] = this.eMailNotification;
      if (!this.id) {
        this.$store
          .dispatch("imports/saveCurrentSchedule", data)
          .then(response => {
            const { id } = response.data;
            displayInfo({
              title: this.$gettext("Import"),
              message: this.$gettext("Saved import: #") + id
            });
            this.closeDetailview();
            this.$store.dispatch("imports/loadSchedules").catch(error => {
              const { status, data } = error.response;
              displayError({
                title: this.gettext("Backend Error"),
                message: `${status}: ${data.message || data}`
              });
            });
          })
          .catch(error => {
            const { status, data } = error.response;
            displayError({
              title: this.$gettext("Backend Error"),
              message: `${status}: ${data.message || data}`
            });
          });
      } else {
        this.$store
          .dispatch("imports/updateCurrentSchedule", {
            data: data,
            id: this.id
          })
          .then(response => {
            const { id } = response.data;
            displayInfo({
              title: this.$gettext("Import"),
              message: this.$gettext("update import: #") + id
            });
            this.closeDetailview();
            this.$store.dispatch("imports/loadSchedules").catch(error => {
              const { status, data } = error.response;
              displayError({
                title: this.gettext("Backend Error"),
                message: `${status}: ${data.message || data}`
              });
            });
          })
          .catch(error => {
            const { status, data } = error.response;
            displayError({
              title: this.$gettext("Backend Error"),
              message: `${status}: ${data.message || data}`
            });
          });
      }
    },
    closeDetailview() {
      this.$store.commit("imports/clearCurrentSchedule");
      this.$store.commit("imports/setImportScheduleDetailInvisible");
    }
  },
  imports: [],
  on: "on",
  off: "off",
  periods: {
    DAILY: "daily",
    MONTHLY: "monthly"
  }
};
</script>

<style lang="scss" scoped>
.cronfield {
  width: 55px;
}

.importscheduledetailscard {
  min-height: 550px;
}

.importscheduledetails {
  width: 100%;
  margin-top: $offset;
  margin-right: $offset;
}

.trigger {
  position: absolute;
  left: $large-offset;
  bottom: $offset;
}

.submit-button {
  position: absolute;
  right: $large-offset;
  bottom: $offset;
}
</style>