view client/src/components/importconfiguration/ScheduledImports.vue @ 5388:60bba8e6322b extented-report

Add import for updating stats. Rationale: Due to performance optimization it seems advised to decouple updating the stats for the DQL report from the actual consumption while generating the report. -- Therefore we have a new import kind "statsupdate" which is selectable for sysadmins only. It could be scheduled as any other import. The available names for which stats to update are dynamically queried from the backend.
author Thomas Junk <thomas.junk@intevation.de>
date Fri, 02 Jul 2021 13:56:51 +0200
parents 80d7e38acaff
children 661e8a2deed9
line wrap: on
line source

<template>
  <form @submit.prevent="save" class="w-100">
    <div class="d-flex px-2">
      <div :key="1" class="flex-column">
        <small class="text-muted">
          <translate>Email Notification</translate>
        </small>
        <div class="flex-flex-row text-left">
          <toggle-button
            :value="eMailNotification"
            v-model="eMailNotification"
            :sync="true"
            class="mt-2"
            :speed="100"
            :labels="{
              checked: this.$options.on,
              unchecked: this.$options.off
            }"
            :width="60"
            :height="30"
          />
        </div>
      </div>
      <div
        :key="2"
        v-if="directImportAvailable"
        class="flex-column text-left ml-3"
      >
        <small class="text-muted">
          <translate>Import via</translate>
        </small>
        <div>
          <!-- '#75c791' is the DEFAULT_COLOR_CHECKED
                  from vue-js-toggle-button as here both states are active -->
          <toggle-button
            :color="{ unchecked: '#75c791' }"
            v-model="directImport"
            class="mt-2"
            :speed="100"
            :labels="{
              checked: this.$options.FILE,
              unchecked: this.$options.URL
            }"
            :width="60"
            :height="30"
          />
        </div>
      </div>
    </div>
    <Availablefairwaydepth
      v-if="
        import_ == $options.IMPORTTYPES.FAIRWAYAVAILABILITY && !directImport
      "
      @urlChanged="setUrl"
      :url="url"
    />
    <Bottleneck
      v-if="import_ == $options.IMPORTTYPES.BOTTLENECK"
      @urlChanged="setUrl"
      @toleranceChanged="setTolerance"
      :url="url"
      :tolerance="tolerance"
      :directImport="directImport"
    />
    <Distancemarksvirtual
      v-if="import_ == $options.IMPORTTYPES.DISTANCEMARKSVIRTUAL"
      @urlChanged="setUrl"
      @usernameChanged="setUsername"
      @passwordChanged="setPassword"
      :url="url"
      :username="username"
      :password="password"
    />
    <Distancemarksashore
      v-if="import_ == $options.IMPORTTYPES.DISTANCEMARKSASHORE"
      @urlChanged="setUrl"
      @featureTypeChanged="setFeatureType"
      @sortByChanged="setSortBy"
      :url="url"
      :featureType="featureType"
      :sortBy="sortBy"
    />
    <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"
    />
    <Fairwaymarks
      v-if="import_ == $options.IMPORTTYPES.FAIRWAYMARKS"
      @urlChanged="setUrl"
      @featureTypeChanged="setFeatureType"
      @sortByChanged="setSortBy"
      @selectedMarkChanged="setSelectedMark"
      :isUpdate="!this.id"
      :url="url"
      :featureType="featureType"
      :sortBy="sortBy"
      :mark="selectedMark"
    />
    <Gaugemeasurement
      v-if="import_ == $options.IMPORTTYPES.GAUGEMEASUREMENT && !directImport"
      @urlChanged="setUrl"
      :url="url"
    />
    <Statsupdate
      v-if="import_ == $options.IMPORTTYPES.STATSUPDATE && !directImport"
      @statsUpdateChanged="setStatsUpdate"
      :statsUpdate="statsUpdate"
    />
    <Waterwayarea
      v-if="import_ == $options.IMPORTTYPES.WATERWAYAREA"
      @urlChanged="setUrl"
      @featureTypeChanged="setFeatureType"
      @sortByChanged="setSortBy"
      :url="url"
      :featureType="featureType"
      :sortBy="sortBy"
    />
    <Waterwaygauges
      v-if="import_ == $options.IMPORTTYPES.WATERWAYGAUGES"
      @urlChanged="setUrl"
      @usernameChanged="setUsername"
      @passwordChanged="setPassword"
      :url="url"
      :username="username"
      :password="password"
    />
    <Waterwayaxis
      v-if="import_ == $options.IMPORTTYPES.WATERWAYAXIS"
      @urlChanged="setUrl"
      @featureTypeChanged="setFeatureType"
      @sortByChanged="setSortBy"
      :url="url"
      :featureType="featureType"
      :sortBy="sortBy"
    />

    <template v-if="!directImport || !directImportAvailable">
      <div class="d-flex p-2">
        <div class="flex-column w-50">
          <div class="d-flex flex-row">
            <div class="flex-column mr-4">
              <div class="flex-row text-left">
                <small class="text-muted">
                  <translate>Scheduled</translate>?
                </small>
              </div>
              <div class="flex-row text-left">
                <toggle-button
                  :value="scheduled"
                  v-model="scheduled"
                  :sync="true"
                  class="mt-2"
                  :speed="100"
                  :labels="{
                    checked: this.$options.on,
                    unchecked: this.$options.off
                  }"
                  :width="60"
                  :height="30"
                />
              </div>
            </div>
            <div class="flex-column mr-2">
              <div class="flex-row text-left">
                <small class="text-muted">
                  <translate>Simple</translate>
                </small>
              </div>
              <div class="flex-flex-row text-left">
                <toggle-button
                  :disabled="!scheduled"
                  :value="easyCron"
                  v-model="easyCron"
                  :sync="true"
                  class="mt-2"
                  :speed="100"
                  :labels="{
                    checked: this.$options.on,
                    unchecked: this.$options.off
                  }"
                  :width="60"
                  :height="30"
                />
              </div>
            </div>
          </div>
        </div>
        <div class="flex-column ml-2">
          <div class="ml-auto flex-column">
            <div class="flex-row text-left">
              <small class="text-muted">
                <translate>Retry on failure</translate>
              </small>
            </div>
            <div class="flex-row text-left">
              <toggle-button
                :value="retry"
                v-model="retry"
                :sync="true"
                class="mt-2"
                :speed="100"
                :labels="{
                  checked: this.$options.on,
                  unchecked: this.$options.off
                }"
                v-tooltip.bottom="ttRetry"
                :width="60"
                :height="30"
              />
            </div>
          </div>
        </div>
      </div>
    </template>
    <template v-if="!directImport || !directImportAvailable">
      <div class="d-flex flex-row">
        <div class="flex-column w-50 px-2 pb-3">
          <div class="flex-row text-left">
            <small class="text-muted">
              <translate>Schedule</translate>
            </small>
          </div>
          <div v-if="easyCron" class="text-left w-100">
            <select
              :disabled="!scheduled"
              v-model="simple"
              class="form-control form-control-sm"
            >
              <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">
              <div class="my-auto mr-2">{{ $options.EVERY }}</div>
              <select
                :disabled="!scheduled"
                style="width: 130px;"
                v-model="cronMode"
                class="form-control form-control-sm"
                @change="clearInputs"
              >
                <option :value="null"></option>
                <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">
                <div class="mt-auto mb-auto">{{ $options.ON }}</div>
                <input
                  :disabled="!scheduled"
                  v-model="minutes"
                  class="cronfield ml-1 mr-1 form-control form-control-sm"
                  type="number"
                />
                <div class="mt-auto mb-auto">{{ $options.MINUTESPAST }}</div>
              </div>
              <div v-if="cronMode == 'day'" class="ml-1 d-flex flex-row">
                <div class="mt-auto mb-auto">{{ $options.AT }}</div>
                <input
                  :disabled="!scheduled"
                  v-model="hour"
                  class="cronfield ml-1 mr-1 form-control form-control-sm"
                  type="number"
                />
                <input
                  :disabled="!scheduled"
                  v-model="minutes"
                  class="cronfield ml-1 mr-1 form-control form-control-sm"
                  type="number"
                />
                <div class="mt-auto mb-auto">{{ $options.OCLOCK }}</div>
              </div>
              <div v-if="cronMode == 'week'" class="ml-1 d-flex flex-row">
                <div class="ml-1 mr-1 mt-auto mb-auto">{{ $options.ON }}</div>
                <select
                  :disabled="!scheduled"
                  v-model="day"
                  class="form-control form-control-sm"
                >
                  <option
                    v-for="(option, key) in $options.DAYSOFWEEK"
                    :key="key"
                    :value="key"
                    >{{ option }}</option
                  >
                </select>
                <div class="ml-1 mt-auto mb-auto">{{ $options.AT }}</div>
                <input
                  :disabled="!scheduled"
                  v-model="hour"
                  class="cronfield ml-1 mr-1 form-control form-control-sm"
                  type="number"
                />
                <input
                  :disabled="!scheduled"
                  v-model="minutes"
                  class="cronfield ml-1 mr-1 form-control form-control-sm"
                  type="number"
                />
              </div>
              <div v-if="cronMode == 'month'" class="ml-1 d-flex flex-row">
                <div class="ml-1 mt-auto mb-auto">{{ $options.ON }}</div>
                <input
                  :disabled="!scheduled"
                  v-model="dayOfMonth"
                  class="cronfield ml-1 mr-1 form-control form-control-sm"
                  type="number"
                />
                <div class="mt-auto mb-auto">{{ $options.AT }}</div>
                <input
                  :disabled="!scheduled"
                  v-model="hour"
                  class="cronfield ml-1 mr-2 form-control form-control-sm"
                  type="number"
                />
                <input
                  :disabled="!scheduled"
                  v-model="minutes"
                  class="cronfield ml-1 mr-2 form-control form-control-sm"
                  type="number"
                />
                <div class="mt-auto mb-auto">{{ $options.OCLOCK }}</div>
              </div>
              <div v-if="cronMode == 'year'" class="ml-1 d-flex flex-row">
                <div class="ml-1 mt-auto mb-auto">{{ $options.ON }}</div>
                <input
                  :disabled="!scheduled"
                  v-model="dayOfMonth"
                  class="cronfield ml-1 mr-1 form-control form-control-sm"
                  type="number"
                />
                <div class="mt-auto mb-auto">{{ $options.OF }}</div>
                <select
                  :disabled="!scheduled"
                  v-model="month"
                  class="ml-1 mr-1 form-control form-control-sm"
                >
                  <option
                    v-for="(option, key) in $options.MONTHS"
                    :value="key"
                    :key="key"
                    >{{ option }}</option
                  >
                </select>
                <div class="mt-auto mb-auto">{{ $options.ON }}</div>
                <input
                  :disabled="!scheduled"
                  v-model="hour"
                  class="cronfield ml-1 mr-1 form-control form-control-sm"
                  type="number"
                />
                <input
                  :disabled="!scheduled"
                  v-model="minutes"
                  class="cronfield ml-1 mr-1 form-control form-control-sm"
                  type="number"
                />
              </div>
            </div>
            <div class="mt-3 w-50 d-flex">
              <div class="my-auto mr-2">
                <translate>Cronstring</translate>
              </div>
              <input
                :disabled="!scheduled"
                class="form-control form-control-sm"
                v-model="cronString"
                type="text"
              />
            </div>
          </div>
        </div>
        <div class="d-flex flex-column ml-2">
          <div class="d-flex flex-row ">
            <div class="ml-1 flex-column">
              <div class="flex-row text-left">
                <small class="text-muted">
                  <translate>Tries</translate>
                </small>
              </div>
              <div>
                <input
                  :disabled="!retry"
                  style="width:120px;"
                  v-model="trys"
                  class="mr-1 form-control form-control-sm"
                  v-tooltip.bottom="ttRetries"
                  type="number"
                />
              </div>
            </div>
            <div class="flex-column">
              <div class="flex-row text-left">
                <small class="text-muted">
                  <translate>Wait to retry</translate>
                </small>
              </div>
              <div>
                <input
                  :disabled="!retry"
                  style="width:120px;"
                  v-model="waitRetry"
                  v-tooltip.bottom="ttWaitRetry"
                  class="ml-1 form-control form-control-sm"
                />
              </div>
            </div>
          </div>
        </div>
      </div>
    </template>
    <div v-else class="d-flex text-left px-2 pb-3">
      <div class="flex-column w-100">
        <div class="custom-file">
          <input
            accept=".xml"
            type="file"
            @change="fileSelected"
            class="custom-file-input custom-file-input-sm"
            id="uploadFile"
          />
          <label class="pointer custom-file-label" for="uploadFile">
            {{ uploadLabel }}
          </label>
        </div>
      </div>
    </div>
    <div class="d-flex justify-content-between p-2 border-top">
      <button :key="1" @click="back()" class="btn btn-sm btn-warning">
        Back
      </button>
      <div>
        <button
          @click="triggerManualImport"
          type="button"
          class="btn btn-sm btn-outline-info"
          :disabled="!triggerActive || !isValid"
        >
          <font-awesome-icon fixed-width icon="play" />
          <translate>Trigger import</translate>
        </button>
        <button
          v-if="!directImport || !directImportAvailable"
          :disabled="!isValid"
          type="submit"
          class="btn btn-sm btn-info ml-3"
        >
          <translate>Save</translate>
        </button>
      </div>
    </div>
  </form>
</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, 2020 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 {
  IMPORTTYPES,
  IMPORTTYPEKIND,
  initializeCurrentSchedule
} from "@/store/importschedule";
import { mapState } from "vuex";
import { displayInfo, displayError } from "@/lib/errors";
import app from "@/main";
import { HTTP } from "@/lib/http";

export default {
  name: "importscheduledetail",
  components: {
    Availablefairwaydepth: () => import("./types/Availablefairwaydepth"),
    Bottleneck: () => import("./types/Bottleneck"),
    Distancemarksvirtual: () => import("./types/Distancemarksvirtual"),
    Distancemarksashore: () => import("./types/Distancemarksashore"),
    Faiwaydimensions: () => import("./types/Fairwaydimensions"),
    Fairwaymarks: () => import("./types/Fairwaymarks"),
    Gaugemeasurement: () => import("./types/Gaugemeasurement"),
    Statsupdate: () => import("./types/Statsupdate"),
    Waterwayarea: () => import("./types/Waterwayarea"),
    Waterwaygauges: () => import("./types/Waterwaygauges"),
    Waterwayaxis: () => import("./types/Waterwayaxis")
  },
  data() {
    return {
      directImport: false,
      passwordVisible: false,
      uploadLabel: this.$gettext("choose file to upload"),
      uploadFile: null,
      retry: false,
      ...initializeCurrentSchedule()
    };
  },
  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";
      }
    },
    retry() {
      if (!this.retry) {
        this.trys = 0;
        this.waitRetry = "";
      }
    }
  },
  computed: {
    ...mapState("importschedule", [
      "importScheduleDetailVisible",
      "currentSchedule"
    ]),
    import_() {
      return this.currentSchedule.importType;
    },
    directImportAvailable() {
      switch (this.import_) {
        case this.$options.IMPORTTYPES.BOTTLENECK:
        case this.$options.IMPORTTYPES.FAIRWAYAVAILABILITY:
        case this.$options.IMPORTTYPES.GAUGEMEASUREMENT:
          return true;
        default:
          return false;
      }
    },
    isCredentialsRequired() {
      switch (this.import_) {
        case this.$options.IMPORTTYPES.WATERWAYGAUGES:
        case this.$options.IMPORTTYPES.DISTANCEMARKSVIRTUAL:
          return true;
        default:
          return false;
      }
    },
    isURLRequired() {
      switch (this.import_) {
        case this.$options.IMPORTTYPES.BOTTLENECK:
        case this.$options.IMPORTTYPES.WATERWAYAXIS:
        case this.$options.IMPORTTYPES.GAUGEMEASUREMENT:
        case this.$options.IMPORTTYPES.FAIRWAYAVAILABILITY:
        case this.$options.IMPORTTYPES.WATERWAYAREA:
        case this.$options.IMPORTTYPES.FAIRWAYMARKS:
        case this.$options.IMPORTTYPES.FAIRWAYDIMENSION:
        case this.$options.IMPORTTYPES.WATERWAYGAUGES:
        case this.$options.IMPORTTYPES.DISTANCEMARKSVIRTUAL:
        case this.$options.IMPORTTYPES.DISTANCEMARKSASHORE:
          return true;
        default:
          return false;
      }
    },
    isFeatureTypeRequired() {
      switch (this.import_) {
        case this.$options.IMPORTTYPES.WATERWAYAXIS:
        case this.$options.IMPORTTYPES.WATERWAYAREA:
        case this.$options.IMPORTTYPES.FAIRWAYMARKS:
        case this.$options.IMPORTTYPES.FAIRWAYDIMENSION:
        case this.$options.IMPORTTYPES.DISTANCEMARKSASHORE:
          return true;
        default:
          return false;
      }
    },
    isToleranceRequired() {
      switch (this.import_) {
        case this.$options.IMPORTTYPES.BOTTLENECK:
          return true;
        default:
          return false;
      }
    },
    usernamePasswordFilled() {
      if (
        this.isCredentialsRequired &&
        this.currentSchedule.id &&
        this.username
      )
        return true;
      if (
        this.isCredentialsRequired &&
        !this.currentSchedule.id &&
        this.username &&
        this.password
      )
        return true;
      return false;
    },
    isValid() {
      if (!this.import_) return false;
      if (this.isToleranceRequired && !this.tolerance) return false;
      if (this.directImport && !this.uploadFile) return false;
      else if (!this.directImport) {
        if (this.isURLRequired && !this.url) return false;
        if (this.isFeatureTypeRequired && !this.featureType) return false;
        if (this.isCredentialsRequired && !this.usernamePasswordFilled)
          return false;
        if (this.import_ == this.$options.IMPORTTYPES.FAIRWAYDIMENSION) {
          if (
            !this.LOS ||
            !this.minWidth ||
            !this.maxWidth ||
            !this.depth ||
            !this.sourceOrganization
          )
            return false;
        }
      }
      return true;
    },
    ttWaitRetry() {
      return `${this.$gettext(
        "Time between retries. Valid units are 's' , 'm' and 'h' "
      )}<div style="text-align:left;">${this.$gettext(
        "Examples:"
      )}<ul><li>${this.$gettext("60 for 60 Seconds ")}
      </li><li> ${this.$gettext("30m for 30 Minutes")}</li><li> ${this.$gettext(
        "2h45m for for two hours and 45 Minutes"
      )}</li></ul></div>`;
    },
    ttRetries() {
      return ` ${this.$gettext("Maximum retry count")}<br> ${this.$gettext(
        "If there is no error during import, there will be no retry"
      )}
        <br><div style="margin-left:45px;text-align:left;"<ul><li> ${this.$gettext(
          "Negative values mean endless retry"
        )}
        </li><li> ${this.$gettext("0 means no retry")}</li><li> ${this.$gettext(
        "Positive values are the upper limit for retries"
      )}
        </li></ul></div>`;
    },
    ttRetry() {
      return this.$gettext("retryDescription");
    }
  },
  methods: {
    back() {
      this.$store.commit("importschedule/setListMode");
    },
    fileSelected(e) {
      const files = e.target.files || e.dataTransfer.files;
      if (!files) return;
      this.uploadLabel = files[0].name;
      this.uploadFile = files[0];
    },
    setStatsUpdate(value) {
      this.statsUpdate = value;
    },
    setUrl(value) {
      this.url = value;
    },
    setFeatureType(value) {
      this.featureType = value;
    },
    setSortBy(value) {
      this.sortBy = value;
    },
    setSelectedMark(value) {
      this.selectedMark = value;
    },
    setTolerance(value) {
      this.tolerance = 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 = parseInt(value * 100);
    },
    setSourceOrganization(value) {
      this.sourceOrganization = value;
    },
    calcCronString() {
      let getValue = value => {
        return this[value] !== null ? this[value] : "*";
      };

      const min = getValue("minutes");
      const h = getValue("hour");
      const dm = getValue("dayOfMonth");
      const m = getValue("month");
      const wd = getValue("day");

      if (this.cronMode === "15minutes") return "0 */15 * * * *";
      if (this.cronMode === "hour") return `0 ${min} * * * *`;
      if (this.cronMode === "day") return `0 ${min} ${h} * * *`;
      if (this.cronMode === "week") return `0 ${min} ${h} * * ${wd}`;
      if (this.cronMode === "month") return `0 ${min} ${h} ${dm} * *`;
      if (this.cronMode === "year") return `0 ${min} ${h} ${dm} ${m} *`;
      return this.cronString;
    },
    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.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.tolerance = this.currentSchedule.tolerance;
      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;
      this.directImport = false;
      this.trys = this.currentSchedule.trys;
      this.waitRetry = this.currentSchedule.waitRetry;
      this.selectedMark = this.currentSchedule.selectedMark;
      this.statsUpdate = this.currentSchedule.statsUpdate;
      this.retry =
        this.currentSchedule.trys === null ||
        this.currentSchedule.trys === undefined ||
        this.currentSchedule === 0
          ? false
          : true;
    },
    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 = this.currentSchedule.minutes;
      this.month = this.currentSchedule.month;
      this.hour = this.currentSchedule.hour;
      this.day = this.currentSchedule.day;
      this.dayOfMonth = this.currentSchedule.dayOfMonth;
    },
    triggerFileUpload() {
      if (!this.uploadFile) return;
      let formData = new FormData();
      let routeParam = "";
      switch (this.import_) {
        case this.$options.IMPORTTYPES.BOTTLENECK:
          formData.append("tolerance", this.tolerance);
          routeParam = "ubn";
          break;
        case this.$options.IMPORTTYPES.FAIRWAYAVAILABILITY:
          routeParam = "ufa";
          break;
        case this.$options.IMPORTTYPES.GAUGEMEASUREMENT:
          routeParam = "ugm";
          break;
        default:
          throw new Error("invalid importroute");
      }

      formData.append(routeParam, this.uploadFile);
      if (this.eMailNotification) {
        formData.append("send-email", this.eMailNotification);
      }
      HTTP.post("/imports/" + routeParam, formData, {
        headers: {
          "X-Gemma-Auth": localStorage.getItem("token"),
          "Content-Type": "multipart/form-data"
        }
      })
        .then(response => {
          const { id } = response.data;
          displayInfo({
            title: this.$gettext("File Import"),
            message: this.$gettext("Import import: #") + id
          });
          this.closeDetailview();
          this.$store.dispatch("importschedule/loadSchedules").catch(error => {
            let message = "Backend not reachable";
            if (error.response) {
              const { status, data } = error.response;
              message = `${status}: ${data.message || data}`;
            }
            displayError({
              title: this.$gettext("Backend Error"),
              message: message
            });
          });
        })
        .catch(error => {
          let message = "Backend not reachable";
          if (error.response) {
            const { status, data } = error.response;
            message = `${status}: ${data.message || data}`;
          }
          displayError({
            title: this.$gettext("Backend Error"),
            message: message
          });
        });
    },
    triggerManualImport() {
      if (!this.triggerActive) return;
      if (!this.import_) return;
      if (this.directImport) {
        if (!this.uploadFile) return;
        this.triggerFileUpload();
        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.sortBy) {
        data["sort-by"] = this.sortBy;
      }
      if (this.isToleranceRequired) {
        if (!this.tolerance) return;
        data["tolerance"] = parseFloat(this.tolerance);
      }
      if (this.isCredentialsRequired) {
        if (!this.username || !this.password) return;
        data["user"] = 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;
      }
      if (this.waitRetry) data["wait-retry"] = this.waitRetry;
      if (this.trys) data["trys"] = Number(this.trys);

      if (this.import_ === this.$options.IMPORTTYPES.REPORT) {
        data["name"] = "data-quality-report";
      }
      if (this.import_ === this.$options.IMPORTTYPES.STATSUPDATE) {
        data["name"] = this.statsUpdate;
      }
      data["send-email"] = this.eMailNotification;
      this.triggerActive = false;
      const type =
        this.import_ === "fairwaymarks"
          ? `fm_${this.selectedMark.toLowerCase()}`
          : IMPORTTYPEKIND[this.import_];
      this.$store
        .dispatch("importschedule/triggerImport", {
          type: type,
          data
        })
        .then(response => {
          const { id } = response.data;
          displayInfo({
            title: this.$gettext("Import"),
            message: this.$gettext("Manually triggered import: #") + id
          });
        })
        .catch(error => {
          let message = "Backend not reachable";
          if (error.response) {
            const { status, data } = error.response;
            message = `${status}: ${data.message || data}`;
          }
          displayError({
            title: this.$gettext("Backend Error"),
            message: message
          });
        })
        .finally(() => {
          this.triggerActive = true;
        });
    },
    save() {
      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 = {};
      let config = {};
      data["kind"] =
        this.import_ === "fairwaymarks"
          ? `fm_${this.selectedMark.toLowerCase()}`
          : IMPORTTYPEKIND[this.import_];
      if (this.isURLRequired) {
        if (!this.url) return;
        config["url"] = this.url;
        config["insecure"] = this.insecure;
      }
      if (this.sortBy) {
        config["sort-by"] = this.sortBy;
      }
      if (this.isFeatureTypeRequired) {
        if (!this.featureType) return;
        config["feature-type"] = this.featureType;
      }
      if (this.isToleranceRequired) {
        if (!this.tolerance) return;
        config["tolerance"] = parseFloat(this.tolerance);
      }
      if (this.isCredentialsRequired) {
        if (!this.usernamePasswordFilled) return;
        config = {
          ...config,
          user: this.username
        };
        if (this.password) {
          config["password"] = this.password;
        }
      }
      if (this.import_ == this.$options.IMPORTTYPES.FAIRWAYDIMENSION) {
        if (
          !this.LOS ||
          !this.minWidth ||
          !this.maxWidth ||
          !this.depth ||
          !this.sourceOrganization
        )
          return;
        config = { ...config, los: this.LOS, depth: this.depth };
        config["min-width"] = this.minWidth;
        config["max-width"] = this.maxWidth;
        config["source-organization"] = this.sourceOrganization;
      }
      if (this.scheduled) {
        config["cron"] = cron;
      }
      if (this.waitRetry) config["wait-retry"] = this.waitRetry;
      if (this.trys) config["trys"] = Number(this.trys);
      if (this.import_ === this.$options.IMPORTTYPES.REPORT) {
        config["name"] = "data-quality-report";
      }
      if (this.import_ === this.$options.IMPORTTYPES.STATSUPDATE) {
        config["name"] = this.statsUpdate;
      }
      config["send-email"] = this.eMailNotification;
      if (!this.id) {
        data["config"] = config;
        this.$store
          .dispatch("importschedule/saveCurrentSchedule", data)
          .then(response => {
            const { id } = response.data;
            displayInfo({
              title: this.$gettext("Import"),
              message: this.$gettext("Saved import: #") + id
            });
            this.closeDetailview();
            this.$store
              .dispatch("importschedule/loadSchedules")
              .catch(error => {
                let message = "Backend not reachable";
                if (error.response) {
                  const { status, data } = error.response;
                  message = `${status}: ${data.message || data}`;
                }
                displayError({
                  title: this.$gettext("Backend Error"),
                  message: message
                });
              });
          })
          .catch(error => {
            let message = "Backend not reachable";
            if (error.response) {
              const { status, data } = error.response;
              message = `${status}: ${data.message || data}`;
            }
            displayError({
              title: this.$gettext("Backend Error"),
              message: message
            });
          });
      } else {
        this.$store
          .dispatch("importschedule/updateCurrentSchedule", {
            data: config,
            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("importschedule/loadSchedules")
              .catch(error => {
                let message = "Backend not reachable";
                if (error.response) {
                  const { status, data } = error.response;
                  message = `${status}: ${data.message || data}`;
                }
                displayError({
                  title: this.$gettext("Backend Error"),
                  message: message
                });
              });
          })
          .catch(error => {
            let message = "Backend not reachable";
            if (error.response) {
              const { status, data } = error.response;
              message = `${status}: ${data.message || data}`;
            }
            displayError({
              title: this.$gettext("Backend Error"),
              message: message
            });
          });
      }
    },
    closeDetailview() {
      this.$store.commit("importschedule/clearCurrentSchedule");
      this.$store.commit("importschedule/setListMode");
    }
  },
  IMPORTTYPES: IMPORTTYPES,
  on: "on",
  off: "off",
  FILE: app.$gettext("File"),
  URL: app.$gettext("URL"),
  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")
  }
};
</script>

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

.importscheduledetailscard {
  min-height: 550px;
}

.importscheduledetails {
  width: 100%;
  margin-top: $offset;
  margin-right: $offset;
}
</style>