Commit 6b9ea06f authored by Richard Blechinger's avatar Richard Blechinger
Browse files

Merge branch 'feature/meta-validation' into develop

parents 71a795e8 f1757e6a
......@@ -30,6 +30,9 @@
"copy-webpack-plugin": "^6.0.3",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.2.3",
"minimist": "^1.2.5",
"tailwindcss": "^1.7.6",
"vue-cli-plugin-tailwind": "~1.4.2",
"vue-template-compiler": "^2.6.12"
},
"eslintConfig": {
......@@ -53,6 +56,8 @@
},
"postcss": {
"plugins": {
"tailwindcss": {},
"vue-cli-plugin-tailwind/purgecss": {},
"autoprefixer": {}
}
},
......
......@@ -10,8 +10,10 @@
</template>
<script>
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
import header from './components/Header.vue'
import footer from './components/Footer.vue'
......
@tailwind components;
@tailwind utilities;
......@@ -465,6 +465,8 @@ export default {
// submit a conflict-resolved schedule to steering
resolveSubmit () {
console.log("before", this.resolveData);
// TODO: check why steering retourns undefined and null values here
if (this.resolveData.schedule.add_business_days_only === undefined) { this.resolveData.schedule.add_business_days_only = false }
if (this.resolveData.schedule.add_days_no === null) { this.resolveData.schedule.add_days_no = 0 }
......@@ -472,6 +474,9 @@ export default {
if (this.resolveData.schedule.fallback_id === null) { this.resolveData.schedule.fallback_id = 0 }
if (this.resolveData.schedule.automation_id === null) { this.resolveData.schedule.automation_id = 0 }
if (this.resolveData.schedule.byweekday === undefined) { this.resolveData.schedule.byweekday = 0 }
console.log("after", this.resolveData);
// create the resolved schedule object including solutions
let resolvedSchedule = {
schedule: this.resolveData.schedule,
......
......@@ -6,7 +6,7 @@
size="lg"
>
<p v-if="loaded.shows">
Editing a timeslot/schedule for show: <b>{{ selectedShow.name }}</b>
Schedule for: <b>{{ selectedShow.name }}</b>
</p>
<div v-if="timeslot && loaded.schedule">
......@@ -50,62 +50,34 @@
<div v-else>
<p>This is a recurring event: <b>{{ rruleRender(schedule.rrule) }}</b>, until: {{ prettyDate(schedule.until) }}</p>
<p>All timeslots of this schedule:</p>
<ul v-if="loaded.scheduleTimeslots">
<li
v-for="slot in scheduleTimeslots"
:key="slot.id"
>
from
<b-badge :variant="timeslot.id === slot.id ? 'info' : 'light'">
{{ prettyDateTime(slot.start) }}
</b-badge>
to
<b-badge :variant="timeslot.id === slot.id ? 'info' : 'light'">
{{ prettyDateTime(slot.end) }}
</b-badge>
</li>
</ul>
</div>
<div v-if="loaded.scheduleTimeslots">
<p>What do you want to do?</p>
<div align="center">
<b-button-group>
<b-button
variant="danger"
size="sm"
@click="deleteFullSchedule(schedule.id)"
>
<span v-if="scheduleTimeslots.length === 1">Delete</span>
<span v-else-if="schedule.rrule === 1">Delete both</span>
<span v-else>Delete schedule + all timeslots</span>
</b-button>
<b-button
v-if="schedule.rrule > 1 && scheduleTimeslots.length > 1"
variant="danger"
size="sm"
@click="deleteSingleTimeslot(schedule.id, timeslot.id)"
>
Delete only this timeslot
</b-button>
<b-button
v-if="schedule.rrule > 1 && scheduleTimeslots.length > 1"
variant="danger"
size="sm"
@click="deleteAllFutureTimeslots(schedule.id, timeslot.id)"
>
Delete this + all future timeslots
</b-button>
</b-button-group>
</div>
</div>
<div v-else>
<img
src="../../assets/radio.gif"
alt="loading timeslot data"
<b-table
id="emission-table"
striped
:per-page="perPage"
:current-page="currentPage"
:fields="['start', 'end']"
:items="scheduleTimeslots"
:busy="!loaded.scheduleTimeslots"
:tbody-tr-class="trClass"
>
<template v-slot:cell(start)="data">
{{ prettyDateTime(data.item.start) }}
</template>
<template v-slot:cell(end)="data">
{{ prettyDateTime(data.item.end) }}
</template>
</b-table>
<div class="tw-w-full tw-flex tw-justify-end">
<b-pagination
v-model="currentPage"
:total-rows="scheduleTimeslots.length"
:per-page="perPage"
aria-controls="emission-table"
/>
</div>
</div>
</div>
<div v-else>
......@@ -114,6 +86,109 @@
alt="loading schedule data"
>
</div>
<hr>
<h4>Add repetition of schedule</h4>
<b-row>
<b-col cols="6">
<label class="tw-leading-loose">
When to repeat?
<b-form-select
v-model="repetitionRule"
:options="repetitionOptions"
>
</b-form-select>
</label>
<b-checkbox v-model="useSameTime">
Use same start and end time
</b-checkbox>
</b-col>
<b-col cols="6" v-if="!useSameTime">
<label class="tw-leading-loose">
Repeat at
<b-form-input type="time" />
</label>
</b-col>
</b-row>
<b-row
v-if="repetitionRule === 3"
class="tw-mt-4"
>
<b-col cols="6">
<label class="tw-leading-loose">
How many days later?
<b-form-input
v-model="addNoOfDays"
type="number"
/>
</label>
<b-checkbox v-model="onlyBusinessDays">
Only count business days
</b-checkbox>
</b-col>
</b-row>
<b-row class="mt-4">
<b-col>
<b-button
variant="primary"
size="sm"
@click="createRepetitionSchedule"
>
Create repetition schedule
</b-button>
</b-col>
</b-row>
<template v-slot:modal-footer>
<div
v-if="loaded.scheduleTimeslots"
class="tw-w-full tw-flex tw-justify-between tw-items-center"
>
<div class="tw-space-x-2">
<b-button
variant="danger"
size="sm"
@click="deleteFullSchedule(schedule.id)"
>
<span v-if="scheduleTimeslots.length === 1">Delete</span>
<span v-else-if="schedule.rrule === 1">Delete both</span>
<span v-else>Delete schedule and all timeslots</span>
</b-button>
<b-button
v-if="schedule.rrule > 1 && scheduleTimeslots.length > 1"
variant="danger"
size="sm"
@click="deleteSingleTimeslot(schedule.id, timeslot.id)"
>
Delete this timeslot
</b-button>
<b-button
v-if="schedule.rrule > 1 && scheduleTimeslots.length > 1"
variant="danger"
size="sm"
@click="deleteAllFutureTimeslots(schedule.id, timeslot.id)"
>
Delete all timeslots
</b-button>
</div>
</div>
<div v-else>
<img
src="../../assets/radio.gif"
alt="loading timeslot data"
>
</div>
</template>
</b-modal>
<b-modal
......@@ -125,7 +200,7 @@
no-close-on-esc
no-close-on-backdrop
>
<div align="center">
<div>
<img
src="../../assets/radio.gif"
alt="loading schedule data"
......@@ -151,11 +226,23 @@ export default {
data () {
return {
currentPage: 1,
perPage: 5,
timeslot: null,
deletion: {
amount: 0,
count: 0,
}
},
useSameTime: true,
onlyBusinessDays: false,
addNoOfDays: 1,
repetitionRule: 1,
repetitionOptions: [
{ value: 1, text: "On the following day" },
{ value: 2, text: "On the following business day" },
{ value: 3, text: "Number of days later" },
{ value: 4, text: "Custom (WIP)" },
]
}
},
......@@ -176,12 +263,59 @@ export default {
},
methods: {
trClass(item, type) {
if (!item || type !== 'row') {
return '';
}
return item.id === this.timeslot.id
? 'table-info'
: ''
},
createRepetitionSchedule() {
const { onlyBusinessDays, addNoOfDays } = this.getRepetitionParameters();
const { dstart, tstart, tend, rrule, until, fallback_id, automation_id, byweekday } = this.schedule;
const newSchedule = {
schedule: {
dstart,
tstart,
tend,
rrule,
until,
fallback_id,
automation_id,
byweekday,
is_repetition: true,
add_business_days_only: onlyBusinessDays,
add_days_no: addNoOfDays,
}
};
console.log(newSchedule);
this.$store.dispatch('shows/submitSchedule', {
showId: this.selectedShow.id,
schedule: newSchedule,
callback: (response) => {
if (response.data.projected === undefined) {
this.$parent.renderView(null)
} else {
this.$log.debug('Timeslot conflict. Switching to resolve mode.');
this.$parent.resolve(response.data)
}
this.$refs.modalEmissionManagerEdit.hide()
},
});
},
deleteFullSchedule (id) {
this.$store.dispatch('shows/deleteSchedule', {
show: this.selectedShow.id,
schedule: id,
callback: () => {
this.$refs.modalEmissionManagerEdit.hide()
this.$refs.modalEmissionManagerEdit.hide();
this.$parent.renderView(null)
}
})
......@@ -257,6 +391,29 @@ export default {
})
},
getRepetitionParameters() {
console.log(typeof this.repetitionRule);
if (this.repetitionRule == 1) {
return {
onlyBusinessDays: false,
addNoOfDays: 1,
}
}
if (this.repetitionRule == 2) {
return {
onlyBusinessDays: true,
addNoOfDays: 1,
}
}
return {
onlyBusinessDays: this.onlyBusinessDays,
addNoOfDays: this.addNoOfDays,
}
},
// initialise a new schedule and open the modal
open (timeslot) {
this.timeslot = timeslot
......
......@@ -125,34 +125,58 @@
</b-col>
</b-row>
<!-- TODO: use b-form outside the b-form-input, so that
simple input validation works automagically -->
<b-modal
ref="modalEmail"
title="E-Mail"
size="lg"
@ok="saveEmail"
@ok="(modalEvt) => { modalEvt.preventDefault(); saveEmail() }"
>
<b-form-input
v-model="string"
type="email"
placeholder="Put a contact address of your show here"
/>
<form
ref="emailForm"
@submit.stop.prevent="saveEmail"
>
<b-form-group
:state="emailState"
label="Name"
label-for="show-email"
invalid-feedback="Please enter a valid email address"
>
<b-form-input
id="show-email"
v-model="email"
type="email"
:state="emailState"
placeholder="Put a contact address of your show here"
/>
</b-form-group>
</form>
</b-modal>
<!-- TODO: use b-form outside the b-form-input, so that
simple input validation works automagically -->
<b-modal
ref="modalWebsite"
title="Website"
size="lg"
@ok="saveWebsite"
@ok="(modalEvt) => { modalEvt.preventDefault(); saveWebsite() }"
>
<b-form-input
v-model="string"
type="url"
placeholder="Put the website of your show here"
/>
<form
ref="urlForm"
@submit.stop.prevent="saveWebsite"
>
<b-form-group
:state="urlState"
label="Name"
label-for="show-url"
invalid-feedback="Please enter a valid URL"
>
<b-form-input
id="show-url"
v-model="url"
type="url"
:state="urlState"
placeholder="Put the website of your show here"
/>
</b-form-group>
</form>
</b-modal>
<b-modal
......@@ -243,7 +267,10 @@ export default {
data () {
return {
string: '',
email: '',
url: '',
emailState: null,
urlState: null,
id: 0,
}
},
......@@ -332,14 +359,18 @@ export default {
},
methods: {
openModalEmail () {
if (this.selectedShow.email !== null) { this.string = this.selectedShow.email }
else { this.string = '' }
this.emailState = null;
if (this.selectedShow.email !== null) { this.email = this.selectedShow.email }
else { this.email = '' }
this.$refs.modalEmail.show()
},
openModalWebsite() {
if (this.selectedShow.website !== null) { this.string = this.selectedShow.website }
else { this.string = '' }
this.urlState = null;
if (this.selectedShow.website !== null) { this.url = this.selectedShow.website }
else { this.url = '' }
this.$refs.modalWebsite.show()
},
......@@ -367,26 +398,48 @@ export default {
this.$refs.modalType.show()
},
saveProperty (property, value, modal, event) {
saveProperty (property, value, modal) {
if (value !== this.selectedShow[property]) {
if (event) { event.preventDefault() }
this.$store.dispatch('shows/updateProperty', {
id: this.selectedShow.id,
property: property,
value: value,
callback: () => {
modal.hide()
},
callbackCancel: (error) => {
if (error.data.email) {
this.emailState = false;
}
if (error.data.website) {
this.urlState = false;
}
}
})
}
},
saveEmail (event) {
this.saveProperty('email', this.string, this.$refs.modalEmail, event)
saveEmail () {
const valid = this.$refs.emailForm.checkValidity();
this.emailState = valid;
if (!valid) {
return;
}
this.saveProperty('email', this.email, this.$refs.modalEmail)
},
saveWebsite (event) {
this.saveProperty('website', this.string, this.$refs.modalWebsite, event)
saveWebsite () {
const valid = this.$refs.urlForm.checkValidity();
this.urlState = valid;
if (!valid) {
return;
}
this.saveProperty('website', this.url, this.$refs.modalWebsite)
},
saveCBAid (event) {
......@@ -400,7 +453,7 @@ export default {
},
saveFallback (id) {
this.saveProperty('fallback_id', id, this.$refs.modalFallback, event)
this.saveProperty('fallback_id', id, this.$refs.modalFallback)
this.$log.debug(this.playlists)
},
......
......@@ -4,6 +4,7 @@ import router from './router'
import store from './store'
import BootstrapVue from 'bootstrap-vue'
import VueLogger from 'vuejs-logger';
import './assets/tailwind.css'
// Use this if you also have to debug a production build
// Only use it temporarily!
......
......@@ -367,8 +367,7 @@ const actions = {
}).then(response => {
if (data && typeof(data.callback) === 'function') { data.callback(response) }
}).catch(error => {
handleApiError(this, error, 'could not update show')
if (data && typeof(data.callbackCancel) === 'function') { data.callbackCancel() }
if (data && typeof(data.callbackCancel) === 'function') { data.callbackCancel(error.response) }
})
},
......@@ -384,7 +383,11 @@ const actions = {
property: data.property,
value: data.value
})
if (typeof(data.callback) === 'function') { data.callback() }
},
callbackCancel: error => {
if (typeof(data.callbackCancel) === 'function') { data.callbackCancel(error) }
}
})
},
......
module.exports = {
prefix: 'tw-',
future: {
removeDeprecatedGapUtilities: true,
},
theme: {
screens: {
'sm': '576px',
'md': '768px',
'lg': '992px',
'xl': '1200px',
}
},
variants: {},
plugins: [],
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment