Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
AURA
dashboard
Commits
cc783ec6
Commit
cc783ec6
authored
Sep 08, 2020
by
Richard Blechinger
Browse files
Start implementing show repetitions
parent
3b244ed6
Changes
25
Expand all
Hide whitespace changes
Inline
Side-by-side
package-lock.json
View file @
cc783ec6
This diff is collapsed.
Click to expand it.
package.json
View file @
cc783ec6
...
...
@@ -9,30 +9,31 @@
},
"dependencies"
:
{
"
axios
"
:
"
^0.18.1
"
,
"
bootstrap-vue
"
:
"
^2.1
5
.0
"
,
"
dompurify
"
:
"
^2.0.1
4
"
,
"
bootstrap-vue
"
:
"
^2.1
6
.0
"
,
"
dompurify
"
:
"
^2.0.1
2
"
,
"
filesize
"
:
"
^4.2.1
"
,
"
jquery
"
:
"
^
3.
5
.1
"
,
"
moment
"
:
"
^2.2
4
.0
"
,
"
oidc-client
"
:
"
^1.
9
.1
"
,
"
vue
"
:
"
^2.6.1
0
"
,
"
vue-full-calendar
"
:
"
^2.
7
.0
"
,
"
vue-router
"
:
"
^3.
1
.3
"
,
"
vuejs-logger
"
:
"
^1.5.
3
"
,
"
vuex
"
:
"
^3.
1.2
"
"
jquery
"
:
"
3.
4
.1
"
,
"
moment
"
:
"
^2.2
7
.0
"
,
"
oidc-client
"
:
"
^1.
10
.1
"
,
"
vue
"
:
"
^2.6.1
2
"
,
"
vue-full-calendar
"
:
"
^2.
8
.0
"
,
"
vue-router
"
:
"
^3.
4
.3
"
,
"
vuejs-logger
"
:
"
^1.5.
4
"
,
"
vuex
"
:
"
^3.
5.1
"
},
"devDependencies"
:
{
"
@vue/cli-plugin-babel
"
:
"
^3.1
1.0
"
,
"
@vue/cli-plugin-eslint
"
:
"
^3.1
1.0
"
,
"
@vue/cli-plugin-babel
"
:
"
^3.1
2.1
"
,
"
@vue/cli-plugin-eslint
"
:
"
^3.1
2.1
"
,
"
@vue/cli-service
"
:
"
^4.5.4
"
,
"
@vue/devtools
"
:
"
^5.
1.1
"
,
"
babel-eslint
"
:
"
^10.
0.3
"
,
"
copy-webpack-plugin
"
:
"
^6.0.
4
"
,
"
@vue/devtools
"
:
"
^5.
3.3
"
,
"
babel-eslint
"
:
"
^10.
1.0
"
,
"
copy-webpack-plugin
"
:
"
^6.0.
3
"
,
"
eslint
"
:
"
^5.16.0
"
,
"
eslint-plugin-vue
"
:
"
^5.2.3
"
,
"
tailwindcss
"
:
"
^1.7.6
"
,
"
minimist
"
:
"
^1.2.5
"
,
"
vue-template-compiler
"
:
"
^2.6.10
"
"
tailwindcss
"
:
"
^1.7.6
"
,
"
vue-cli-plugin-tailwind
"
:
"
~1.4.2
"
,
"
vue-template-compiler
"
:
"
^2.6.12
"
},
"eslintConfig"
:
{
"root"
:
true
,
...
...
@@ -55,6 +56,8 @@
},
"postcss"
:
{
"plugins"
:
{
"tailwindcss"
:
{},
"vue-cli-plugin-tailwind/purgecss"
:
{},
"autoprefixer"
:
{}
}
},
...
...
src/App.vue
View file @
cc783ec6
...
...
@@ -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
'
...
...
@@ -54,7 +56,7 @@ export default {
}
}
},
moun
ted
()
{
crea
ted
()
{
this
.
$store
.
dispatch
(
'
auth/oidcInit
'
)
},
methods
:
{
...
...
src/assets/styles/main.css
0 → 100644
View file @
cc783ec6
src/assets/tailwind.css
0 → 100644
View file @
cc783ec6
@tailwind
components
;
@tailwind
utilities
;
src/components/EmissionManager.vue
View file @
cc783ec6
...
...
@@ -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
,
...
...
src/components/FileManager.vue
View file @
cc783ec6
...
...
@@ -78,7 +78,6 @@ export default {
// This switches the UI elements to reflect another show and fetches all
// relevent data from the tank API.
showHasSwitched
()
{
this
.
$log
.
debug
(
'
show has switched to
'
,
this
.
selectedShow
.
name
)
this
.
$store
.
dispatch
(
'
files/fetchFiles
'
,
{
slug
:
this
.
selectedShow
.
slug
})
...
...
src/components/ShowManager.vue
View file @
cc783ec6
...
...
@@ -25,6 +25,8 @@
<!-- When all show data is loaded, here we display all the rest -->
<div
v-else
>
<show-schedules
/>
<!-- include the modals to edit show and timeslot entries from the modal compontents -->
<show-timeslots
ref=
"timeslotsComponent"
/>
...
...
@@ -44,6 +46,7 @@
<
script
>
import
showJumbotron
from
'
./shows/Jumbotron.vue
'
import
showTimeslots
from
'
./shows/Timeslots.vue
'
import
showSchedules
from
'
./shows/Schedules.vue
'
import
showMetaSimpleTypes
from
'
./shows/MetaSimpleTypes.vue
'
import
showMetaArrays
from
'
./shows/MetaArrays.vue
'
import
showMetaOwners
from
'
./shows/MetaOwners.vue
'
...
...
@@ -57,6 +60,7 @@ export default {
components
:
{
'
show-jumbotron
'
:
showJumbotron
,
'
show-timeslots
'
:
showTimeslots
,
'
show-schedules
'
:
showSchedules
,
'
show-metaArrays
'
:
showMetaArrays
,
'
show-metaSimpleTypes
'
:
showMetaSimpleTypes
,
'
show-metaOwners
'
:
showMetaOwners
,
...
...
@@ -90,26 +94,38 @@ export default {
// Right after this component is set up, we want to fetch all available shows
// and the arrays for the show meta info from the AuRa steering module.
created
()
{
this
.
$store
.
dispatch
(
'
shows/fetchShows
'
,
{
callback
:
()
=>
{
this
.
$store
.
dispatch
(
'
playlists/fetch
'
,
{
slug
:
this
.
selectedShow
.
slug
})
this
.
$refs
.
showSelector
.
updateInputSelector
()
}
})
this
.
$store
.
dispatch
(
'
shows/fetchMetaArray
'
,
{
property
:
'
types
'
,
onlyActive
:
true
})
this
.
$store
.
dispatch
(
'
shows/fetchMetaArray
'
,
{
property
:
'
fundingcategories
'
,
onlyActive
:
true
})
this
.
$store
.
dispatch
(
'
shows/fetchMetaArray
'
,
{
property
:
'
categories
'
})
this
.
$store
.
dispatch
(
'
shows/fetchMetaArray
'
,
{
property
:
'
topics
'
})
this
.
$store
.
dispatch
(
'
shows/fetchMetaArray
'
,
{
property
:
'
musicfocus
'
})
this
.
$store
.
dispatch
(
'
shows/fetchMetaArray
'
,
{
property
:
'
languages
'
})
this
.
$store
.
dispatch
(
'
shows/fetchMetaArray
'
,
{
property
:
'
hosts
'
})
if
(
this
.
isSuperuser
)
{
this
.
$store
.
dispatch
(
'
auth/fetchUsers
'
)
}
if
(
this
.
$store
.
state
.
auth
.
user
.
steeringUser
)
{
this
.
loadShowInfos
()
}
else
{
this
.
$store
.
watch
(
(
state
)
=>
state
.
auth
.
user
.
steeringUser
,
()
=>
{
this
.
loadShowInfos
()
}
)
}
},
methods
:
{
showHasSwitched
()
{
this
.
$refs
.
timeslotsComponent
.
showHasSwitched
()
},
loadShowInfos
()
{
this
.
$store
.
dispatch
(
'
shows/fetchShows
'
,
{
callback
:
()
=>
{
this
.
$store
.
dispatch
(
'
playlists/fetch
'
,
{
slug
:
this
.
selectedShow
.
slug
})
this
.
$refs
.
showSelector
.
updateInputSelector
()
}
})
this
.
$store
.
dispatch
(
'
shows/fetchMetaArray
'
,
{
property
:
'
types
'
,
onlyActive
:
true
})
this
.
$store
.
dispatch
(
'
shows/fetchMetaArray
'
,
{
property
:
'
fundingcategories
'
,
onlyActive
:
true
})
this
.
$store
.
dispatch
(
'
shows/fetchMetaArray
'
,
{
property
:
'
categories
'
})
this
.
$store
.
dispatch
(
'
shows/fetchMetaArray
'
,
{
property
:
'
topics
'
})
this
.
$store
.
dispatch
(
'
shows/fetchMetaArray
'
,
{
property
:
'
musicfocus
'
})
this
.
$store
.
dispatch
(
'
shows/fetchMetaArray
'
,
{
property
:
'
languages
'
})
this
.
$store
.
dispatch
(
'
shows/fetchMetaArray
'
,
{
property
:
'
hosts
'
})
if
(
this
.
isSuperuser
)
{
this
.
$store
.
dispatch
(
'
auth/fetchUsers
'
)
}
},
}
}
</
script
>
...
...
src/components/ShowSelector.vue
View file @
cc783ec6
...
...
@@ -98,7 +98,10 @@ export default {
},
computed
:
{
isSuperuser
()
{
return
this
.
$store
.
state
.
auth
.
user
.
steeringUser
.
is_superuser
},
isSuperuser
()
{
const
user
=
this
.
$store
.
state
.
auth
.
user
.
steeringUser
;
return
user
&&
user
.
is_superuser
;
},
loaded
()
{
return
{
shows
:
this
.
$store
.
state
.
shows
.
loaded
.
shows
,
...
...
src/components/emissions/ModalEdit.vue
View file @
cc783ec6
...
...
@@ -6,7 +6,7 @@
size=
"lg"
>
<p
v-if=
"loaded.shows"
>
Editing a timeslot/s
chedule for
show
:
<b>
{{
selectedShow
.
name
}}
</b>
S
chedule for:
<b>
{{
selectedShow
.
name
}}
</b>
</p>
<div
v-if=
"timeslot && loaded.schedule"
>
...
...
@@ -66,39 +66,107 @@
</li>
</ul>
</div>
</div>
<div
v-else
>
<img
src=
"../../assets/radio.gif"
alt=
"loading schedule data"
>
</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>
<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
>
...
...
@@ -107,13 +175,7 @@
alt=
"loading timeslot data"
>
</div>
</div>
<div
v-else
>
<img
src=
"../../assets/radio.gif"
alt=
"loading schedule data"
>
</div>
</
template
>
</b-modal>
<b-modal
...
...
@@ -125,7 +187,7 @@
no-close-on-esc
no-close-on-backdrop
>
<div
align=
"center"
>
<div>
<img
src=
"../../assets/radio.gif"
alt=
"loading schedule data"
...
...
@@ -155,7 +217,17 @@ export default {
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 +248,49 @@ export default {
},
methods
:
{
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 +366,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
...
...
src/components/filemanager/EditPlaylistModal.vue
View file @
cc783ec6
...
...
@@ -31,7 +31,10 @@
<hr>
<p>
Playlist entries:
</p>
<p
class=
"d-flex justify-content-between"
>
<span
class=
"font-weight-bold"
>
Playlist entries
</span>
<span>
Duration:
{{
playlistDuration
}}
</span>
</p>
<!-- If no entries are here (i.e. we add a new playlist), only show
a hint that there's nothing here yet. -->
...
...
@@ -221,6 +224,15 @@ export default {
}
},
playlistDuration
()
{
const
totalDuration
=
this
.
playlistEditor
.
entries
.
reduce
((
acc
,
entry
)
=>
{
const
file
=
this
.
getFileById
(
entry
.
file
.
id
)
return
acc
+
file
.
duration
;
},
0
);
return
this
.
prettyNanoseconds
(
totalDuration
)
},
...
mapGetters
({
selectedShow
:
'
shows/selectedShow
'
,
getPlaylistById
:
'
playlists/getPlaylistById
'
,
...
...
src/components/filemanager/Playlists.vue
View file @
cc783ec6
...
...
@@ -68,6 +68,13 @@
</b-button>
</
template
>
<!-- Column: Duration
This column displays the duration of all playlist entries combined
-->
<
template
v-slot:cell(duration)=
"data"
>
{{
playlistDuration
(
data
)
}}
</
template
>
<!-- Column: Last edit
This column lists the last date this playlist was changed.
-->
...
...
@@ -128,6 +135,7 @@ export default {
{
key
:
'
id
'
,
label
:
'
Index
'
},
{
key
:
'
description
'
,
label
:
'
Description
'
},
{
key
:
'
entries
'
,
label
:
'
Entries
'
},
{
key
:
'
duration
'
,
label
:
'
Duration
'
},
{
key
:
'
updated
'
,
label
:
'
Last edit
'
},
{
key
:
'
actions
'
,
label
:
'
Actions
'
,
class
:
'
text-right
'
},
],
...
...
@@ -179,6 +187,12 @@ export default {
editPlaylist
(
id
)
{
this
.
$refs
.
editPlaylistsModal
.
editPlaylist
(
id
)
},
playlistDuration
({
item
})
{
const
totalDuration
=
item
.
entries
.
reduce
((
acc
,
entry
)
=>
acc
+
entry
.
duration
,
0
)
return
this
.
prettyNanoseconds
(
totalDuration
)
}
},
}
</
script
>
src/components/shows/FallbackSelector.vue
0 → 100644
View file @
cc783ec6
<
template
>
<b-modal
ref=
"modalFallbackSelector"
title=
"Choose a fallback playlist for this show"
size=
"lg"
>
<p
v-if=
"loaded"
>
Currently chosen playlist ID:
<span
v-if=
"selectedShow.fallback_id === null"
>
<i><small>
(none set)
</small></i>
</span>
<span
v-else
>
{{
selectedShow
.
fallback_id
}}
<span
v-if=
"currentPlaylistDescription"
>
, Description:
<b>
{{
currentPlaylistDescription
}}
</b>
</span>
</span>
</p>
<p>
Available playlists:
</p>
<div
v-if=
"loaded"
>
<b-table
ref=
"playlistsTable"
striped
:fields=
"playlistsTableFields"
:items=
"playlists"
>
<!-- Column: Entries
This column displays the number of entries of the playlist.
-->
<template
v-slot:cell(entries)=
"data"
>
{{
data
.
value
.
length
}}
items
<b-button
v-b-tooltip.html=
"playlistToolTip(data.value)"
variant=
"outline-success"
size=
"sm"
>
show entries
</b-button>
</
template
>
<!-- Column: Actions
This column displays the available buttons for actions the user can
take on this playlist (e.g. editing and deleting).
-->
<
template
v-slot:cell(actions)=
"data"
>
<b-button-group
size=
"sm"
>
<b-button
v-if=
"data.item.id !== selectedShow.fallback_id"
variant=
"info"
@
click=
"choose(data.item.id)"
>
Take it!
</b-button>
<b-button
v-else
variant=
"danger"
@
click=
"choose(null)"
>
Unset
</b-button>
</b-button-group>
</
template
>