diff client/src/components/importconfiguration/ScheduledImports.vue @ 2993:ec3196e2d579

imports: moved scheduled imports component in filesystem
author Thomas Junk <thomas.junk@intevation.de>
date Wed, 10 Apr 2019 14:28:45 +0200
parents client/src/components/importconfiguration/types/ScheduledImports.vue@1b8bb4f89227
children 5124644494df
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/components/importconfiguration/ScheduledImports.vue	Wed Apr 10 14:28:45 2019 +0200
@@ -0,0 +1,957 @@
+<template>
+  <form @submit.prevent="save" class="w-100">
+    <div v-if="directImportAvailable" class="flex-column">
+      <div class="flex-row text-left">
+        <small class="text-muted">
+          <translate>Import via</translate>
+        </small>
+      </div>
+      <div class="flex-flex-row text-left">
+        <!-- '#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>
+    <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"
+    />
+    <Gaugemeasurement
+      v-if="import_ == $options.IMPORTTYPES.GAUGEMEASUREMENT && !directImport"
+      @urlChanged="setUrl"
+      :url="url"
+    />
+    <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 flex-row mt-3">
+        <div class="flex-column mr-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 class="flex-column 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 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 :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">
+              <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>
+    </template>
+    <div v-else class="d-flex flex-row text-left">
+      <div class="mt-3 mb-3 flex-column w-100">
+        <div class="custom-file">
+          <input
+            accept=".xml"
+            type="file"
+            @change="fileSelected"
+            class="custom-file-input"
+            id="uploadFile"
+          />
+          <label class="pointer custom-file-label" for="uploadFile">
+            {{ uploadLabel }}
+          </label>
+        </div>
+      </div>
+    </div>
+    <div class="w-100 d-flex flex-row mt-3">
+      <button
+        @click="triggerManualImport"
+        type="button"
+        class="shadow-sm btn btn-outline-info"
+        :disabled="!triggerActive || !isValid"
+      >
+        <font-awesome-icon class="fa-fw mr-2" fixed-width icon="play" />
+        <translate>Trigger import</translate>
+      </button>
+      <button
+        :disabled="!isValid"
+        type="submit"
+        class="ml-auto shadow-sm btn btn-info mr-3"
+      >
+        <translate>Save</translate>
+      </button>
+      <button :key="1" @click="back()" class="btn btn-warning">
+        Back
+      </button>
+    </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 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"),
+    Gaugemeasurement: () => import("./types/Gaugemeasurement"),
+    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,
+      ...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";
+      }
+    }
+  },
+  computed: {
+    ...mapState("importschedule", [
+      "importScheduleDetailVisible",
+      "currentSchedule"
+    ]),
+    import_() {
+      return this.currentSchedule.importType;
+    },
+    dialogLabel() {
+      if (this.id) return this.$gettext("Import") + " " + this.id;
+      return this.$gettext("New Import");
+    },
+    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.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.FAIRWAYDIMENSION:
+        case this.$options.IMPORTTYPES.DISTANCEMARKSASHORE:
+          return true;
+        default:
+          return false;
+      }
+    },
+    isSortbyRequired() {
+      switch (this.import_) {
+        case this.$options.IMPORTTYPES.WATERWAYAXIS:
+        case this.$options.IMPORTTYPES.WATERWAYAREA:
+        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;
+      }
+    },
+    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.isSortbyRequired && !this.sortBy) return false;
+        if (this.isFeatureTypeRequired && !this.featureType) return false;
+        if (this.isCredentialsRequired && (!this.username || !this.password))
+          return false;
+        if (this.import_ == this.$options.IMPORTTYPES.FAIRWAYDIMENSION) {
+          if (
+            !this.LOS ||
+            !this.minWidth ||
+            !this.maxWidth ||
+            !this.depth ||
+            !this.sourceOrganization
+          )
+            return false;
+        }
+      }
+      return true;
+    }
+  },
+  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];
+    },
+    setUrl(value) {
+      this.url = value;
+    },
+    setFeatureType(value) {
+      this.featureType = value;
+    },
+    setSortBy(value) {
+      this.sortBy = 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 = value;
+    },
+    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;
+    },
+    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);
+      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 => {
+            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}`
+          });
+        });
+    },
+    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.isSortbyRequired) {
+        if (!this.sortBy) return;
+        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;
+      }
+      data["send-email"] = this.eMailNotification;
+      this.triggerActive = false;
+      this.$store
+        .dispatch("importschedule/triggerImport", {
+          type: IMPORTTYPEKIND[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() {
+      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"] = IMPORTTYPEKIND[this.import_];
+
+      if (this.isURLRequired) {
+        if (!this.url) return;
+        config["url"] = this.url;
+        config["insecure"] = this.insecure;
+      }
+      if (this.isSortbyRequired) {
+        if (!this.sortBy) return;
+        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.username || !this.password) return;
+        config = {
+          ...config,
+          user: this.username,
+          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;
+      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 => {
+                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("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 => {
+                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("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>