Mercurial > gemma
view client/src/components/importschedule/Importscheduledetail.vue @ 2377:fdec7a652f34
client: imports: avoid error when cron string cannot be parsed when trying to edit imports
To prefill the form fields that generate the cron string, the currently stored cron string needs to be parsed back.
This parsing only handles numerical values for each of the six cron fields. In case of something like */15 the
regular expression does not match, leading to a null value. The cronMode select now has an empty option for cases
where the cronString does not match any known pattern.
author | Markus Kottlaender <markus@intevation.de> |
---|---|
date | Fri, 22 Feb 2019 12:28:14 +0100 |
parents | b9c317236ebc |
children | f185503ef35a |
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" class="pointer"></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>Waterway area</translate></option > <option :value="$options.IMPORTTYPES.FAIRWAYDIMENSION" ><translate>Fairway dimension</translate></option > <option :value="$options.IMPORTTYPES.WATERWAYGAUGES" ><translate>Waterway gauges</translate></option > <option :value="$options.IMPORTTYPES.DISTANCEMARKSVIRTUAL" ><translate>Distance marks virtual</translate></option > <option :value="$options.IMPORTTYPES.DISTANCEMARKSASHORE" ><translate>Distance marks ashore</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> <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"> <toggle-button 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" ></Availablefairwaydepth> <Bottleneck v-if="import_ == $options.IMPORTTYPES.BOTTLENECK && !directImport" @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> <Distancemarksashore v-if="import_ == $options.IMPORTTYPES.DISTANCEMARKSASHORE" @urlChanged="setUrl" @featureTypeChanged="setFeatureType" @sortByChanged="setSortBy" :url="url" :featureType="featureType" :sortBy="sortBy" ></Distancemarksashore> <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 && !directImport " @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 v-if="!directImport" 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 v-if="!directImport" 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> <div v-if="directImport" 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> <button v-if="!directImport" :disabled="!isValid" type="submit" class="shadow-sm btn btn-info submit-button" > <translate>Save</translate> </button> <button @click="triggerManualImport" type="button" class="shadow-sm btn btn-outline-info trigger" :disabled="!triggerActive || !isValid" > <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/importschedule"; import { mapState } from "vuex"; import { displayInfo, displayError } from "@/lib/errors.js"; import app from "@/main.js"; import { HTTP } from "@/lib/http"; export default { name: "importscheduledetail", components: { Availablefairwaydepth: () => import("@/components/importschedule/importtypes/Availablefairwaydepth"), Bottleneck: () => import("@/components/importschedule/importtypes/Bottleneck"), Distancemarksvirtual: () => import("@/components/importschedule/importtypes/Distancemarksvirtual"), Distancemarksashore: () => import("@/components/importschedule/importtypes/Distancemarksashore"), 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 { 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" ]), 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; } }, isValid() { if (!this.import_) 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: { 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; }, 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.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; 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: 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.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.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/setImportScheduleDetailInvisible"); } }, 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; } .trigger { position: absolute; left: $large-offset; bottom: $offset; } .submit-button { position: absolute; right: $large-offset; bottom: $offset; } </style>