Skip to content
GitLab
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
30a9c80d
Commit
30a9c80d
authored
May 29, 2020
by
jackie / Andrea Ida Malkah Klaura
Browse files
move all playlist related actions to store
parent
772b16bd
Changes
4
Expand all
Hide whitespace changes
Inline
Side-by-side
src/components/FileManager.vue
View file @
30a9c80d
This diff is collapsed.
Click to expand it.
src/components/filemanager/EditPlaylistModal.vue
0 → 100644
View file @
30a9c80d
<
template
>
<b-modal
id=
"modal-edit-playlist"
size=
"lg"
:title=
"playlistEditor.mode === 'edit' ? 'Edit playlist' : 'Add new playlist'"
@
ok=
"storePlaylist"
>
<b-row
v-if=
"playlistEditor.mode === 'edit'"
style=
"padding-bottom: 1em;"
>
<b-col
cols=
"3"
>
Playlist index:
</b-col>
<b-col>
{{
playlistEditor
.
id
}}
</b-col>
</b-row>
<b-row>
<b-col
cols=
"3"
>
Description:
</b-col>
<b-col>
<b-form-input
v-model=
"playlistEditor.description"
type=
"text"
/>
</b-col>
</b-row>
<hr>
<p>
Playlist entries:
</p>
<!-- If no entries are here (i.e. we add a new playlist), only show
a hint that there's nothing here yet. -->
<div
v-if=
"playlistEditor.entries.length === 0"
align=
"center"
>
No entries yet. Add some.
</div>
<!-- As soon as we have at least one entry in our temporary playlist
we can display a table with all the info and action buttons -->
<div
v-else
>
<b-table
ref=
"playlistEditTable"
striped
:items=
"playlistEditor.entries"
:fields=
"playlistEditTableFields"
>
<!-- Column: Index
Here we just use the array index, because the playlist entries
are ordered as an array, without the need for an extra id field
-->
<template
v-slot:cell(id)=
"data"
>
{{
data
.
index
+
1
}}
.
</
template
>
<!-- Column: Type
Based on the entry content (either file or uri), we display
a small badge indicating which type of source this is
-->
<
template
v-slot:cell(type)=
"data"
>
<b-badge
v-if=
"data.item.file"
variant=
"success"
>
File
</b-badge>
<b-badge
v-else-if=
"data.item.uri.startsWith('line://')"
variant=
"info"
>
Line-in
</b-badge>
<b-badge
v-else-if=
"data.item.uri.startsWith('http://') || data.item.uri.startsWith('https://')"
variant=
"light"
>
Stream
</b-badge>
<b-badge
v-else
variant=
"dark"
>
Other
</b-badge>
</
template
>
<!-- Column: Source
Here we display where this playlist entry is coming from
-->
<
template
v-slot:cell(source)=
"data"
>
<span
v-if=
"data.item.file"
>
{{
getFileTitleForPlaylist
(
data
.
item
.
file
.
show
,
data
.
item
.
file
.
id
)
}}
<small><i>
( file://
{{
data
.
item
.
file
.
show
}}
/
{{
data
.
item
.
file
.
id
}}
)
</i></small>
</span>
<span
v-else
>
{{
data
.
item
.
uri
}}
</span>
</
template
>
<!-- Column: Actions
Finally some buttons to reorder or delete playlist entries
-->
<
template
v-slot:cell(actions)=
"data"
>
<b-button-group
size=
"sm"
>
<b-button
:disabled=
"data.index === 0"
@
click=
"movePlaylistItemUp(data.index)"
>
<b
class=
"upDownArrows"
>
↑
</b>
</b-button>
<b-button
:disabled=
"data.index === playlistEditor.entries.length - 1"
@
click=
"movePlaylistItemDown(data.index)"
>
<b
class=
"upDownArrows"
>
↓
</b>
</b-button>
<b-button
variant=
"danger"
@
click=
"deletePlaylistItem(data.index)"
>
Delete
</b-button>
</b-button-group>
</
template
>
</b-table>
</div>
<hr>
<!-- Below the table with the playlists entry we display buttons to
add new entries to the table - these can either be files from our
uploaded/imported files, or one of the preconfigured inputs, or a
stream.
TODO: should we disable choosing files that are still being imported?
TODO: make the inputs configurable
-->
<div>
<b-modal
id=
"modal-edit-playlist-add-stream"
title=
"Add stream to the playlist"
@
ok=
"addPlaylistItemStream('save')"
>
<b-input
v-model=
"playlistEditor.newStreamURL"
type=
"url"
>
...
</b-input>
</b-modal>
Add:
<b-button-group>
<b-dropdown
text=
"File"
>
<b-dropdown-item
v-for=
"(file, index) in files"
:key=
"index"
@
click=
"addPlaylistItemFile(file.show, file.id)"
>
{{ file.id }}: {{ file.metadata.title ? file.metadata.title : "" }} ({{ prettyNanoseconds(file.duration) }}, {{ prettyFileSize(file.size) }}, {{ file.source.uri }})
</b-dropdown-item>
</b-dropdown>
<b-dropdown
text=
"Line-in"
>
<b-dropdown-item
@
click=
"addPlaylistItemLine('0')"
>
Studio 1
</b-dropdown-item>
<b-dropdown-item
@
click=
"addPlaylistItemLine('1')"
>
Preprod
</b-dropdown-item>
<b-dropdown-item
@
click=
"addPlaylistItemLine('2')"
>
Line 2
</b-dropdown-item>
</b-dropdown>
<b-button
@
click=
"addPlaylistItemStream('openModal')"
>
Stream
</b-button>
</b-button-group>
</div>
</b-modal>
</template>
<
script
>
import
{
mapGetters
}
from
'
vuex
'
import
prettyDate
from
'
../../mixins/prettyDate
'
import
filesize
from
'
filesize
'
export
default
{
mixins
:
[
prettyDate
],
// include the modal for displaying file import logs
data
()
{
return
{
// for adding and editing the playlists we need some temporary storage
playlistEditor
:
{
id
:
null
,
mode
:
'
add
'
,
// should be either 'add' or 'edit'
description
:
''
,
entries
:
[],
newStreamURL
:
null
},
// configuration of the playlists entries table
playlistEditTableFields
:
[
{
key
:
'
id
'
,
label
:
'
Index
'
},
{
key
:
'
type
'
,
label
:
'
Type
'
},
{
key
:
'
source
'
,
label
:
'
Source
'
},
{
key
:
'
actions
'
,
label
:
'
Actions
'
,
class
:
'
text-right
'
},
]
}
},
computed
:
{
loaded
()
{
return
{
playlists
:
this
.
$store
.
state
.
playlists
.
loaded
.
playlists
,
}
},
...
mapGetters
({
selectedShow
:
'
shows/selectedShow
'
,
getPlaylistById
:
'
playlists/getPlaylistById
'
,
files
:
'
files/files
'
,
getFileById
:
'
files/getFileById
'
,
})
},
methods
:
{
// We want to have a nice format for the file size, given a size in Bytes.
// For that we're useing the filesize npm module.
prettyFileSize
:
function
(
s
)
{
return
filesize
(
s
)
},
// return a string representing a file entry for the playlist editor
getFileTitleForPlaylist
(
show
,
id
)
{
// TODO: change structure of files array, so we can access all shows
// the user has access to.
let
file
=
this
.
getFileById
(
id
)
if
(
file
&&
file
.
metadata
.
title
)
{
return
show
+
"
:
"
+
file
.
metadata
.
title
}
else
{
return
""
}
},
movePlaylistItemUp
(
index
)
{
if
(
index
>
0
&&
index
<
this
.
playlistEditor
.
entries
.
length
)
{
let
temp
=
this
.
playlistEditor
.
entries
[
index
-
1
]
this
.
playlistEditor
.
entries
[
index
-
1
]
=
this
.
playlistEditor
.
entries
[
index
]
this
.
playlistEditor
.
entries
[
index
]
=
temp
this
.
$refs
.
playlistEditTable
.
refresh
()
}
},
movePlaylistItemDown
(
index
)
{
if
(
index
<
this
.
playlistEditor
.
entries
.
length
-
1
&&
index
>=
0
)
{
let
temp
=
this
.
playlistEditor
.
entries
[
index
+
1
]
this
.
playlistEditor
.
entries
[
index
+
1
]
=
this
.
playlistEditor
.
entries
[
index
]
this
.
playlistEditor
.
entries
[
index
]
=
temp
this
.
$refs
.
playlistEditTable
.
refresh
()
}
},
deletePlaylistItem
(
index
)
{
if
(
index
>=
0
&&
index
<
this
.
playlistEditor
.
entries
.
length
)
{
this
.
playlistEditor
.
entries
.
splice
(
index
,
1
)
this
.
$refs
.
playlistEditTable
.
refresh
()
}
},
// add a file from the file manager to the playlist that is being edited
addPlaylistItemFile
(
show
,
id
)
{
let
item
=
{}
item
.
file
=
{
show
:
show
,
id
:
id
}
this
.
playlistEditor
.
entries
.
push
(
item
)
},
// add a line input to the playlist that is being edited
addPlaylistItemLine
(
line
)
{
this
.
playlistEditor
.
entries
.
push
({
uri
:
'
line://
'
+
line
})
},
// controls sub-modal to add a new URI to the playlist editor
addPlaylistItemStream
(
action
)
{
if
(
action
===
'
openModal
'
)
{
// the function gets called with the action 'openModal' when the users
// clicks on the add new stream button. then we clear all temp data and
// open the modal
this
.
playlistEditor
.
newStreamURL
=
''
this
.
$bvModal
.
show
(
'
modal-edit-playlist-add-stream
'
)
}
else
{
// when the user hits ok to add the new uri, this function gets called
// with the action 'save' and the modal closes automagically. so we
// just have to push a new entry to the playlist in the editor
if
(
this
.
playlistEditor
.
newStreamURL
.
trim
().
length
>
0
)
{
this
.
playlistEditor
.
entries
.
push
({
uri
:
this
.
playlistEditor
.
newStreamURL
})
}
// if an empty string was provided, we just do nothing
}
},
addPlaylist
()
{
this
.
playlistEditor
.
mode
=
'
add
'
this
.
playlistEditor
.
id
=
null
this
.
playlistEditor
.
description
=
''
this
.
playlistEditor
.
entries
=
[]
this
.
$bvModal
.
show
(
'
modal-edit-playlist
'
)
},
editPlaylist
(
id
)
{
this
.
playlistEditor
.
mode
=
'
edit
'
this
.
playlistEditor
.
entries
=
[]
this
.
playlistEditor
.
id
=
id
let
playlist
=
this
.
getPlaylistById
(
id
)
this
.
playlistEditor
.
description
=
playlist
.
description
for
(
let
i
in
playlist
.
entries
)
{
let
entry
=
{}
if
(
playlist
.
entries
[
i
].
file
)
{
entry
.
file
=
{}
entry
.
file
.
show
=
playlist
.
entries
[
i
].
file
.
show
entry
.
file
.
id
=
playlist
.
entries
[
i
].
file
.
id
}
else
{
entry
.
uri
=
playlist
.
entries
[
i
].
uri
}
this
.
playlistEditor
.
entries
.
push
(
entry
)
}
this
.
$bvModal
.
show
(
'
modal-edit-playlist
'
)
},
storePlaylist
()
{
// TODO: add some spinner or other visualisation while the playlist is added/updated
let
playlist
=
{
description
:
this
.
playlistEditor
.
description
,
entries
:
this
.
playlistEditor
.
entries
}
if
(
this
.
playlistEditor
.
mode
===
'
add
'
)
{
this
.
$store
.
dispatch
(
'
playlists/add
'
,
{
slug
:
this
.
selectedShow
.
slug
,
playlist
:
playlist
})
}
else
if
(
this
.
playlistEditor
.
mode
===
'
edit
'
)
{
this
.
$store
.
dispatch
(
'
playlists/update
'
,
{
slug
:
this
.
selectedShow
.
slug
,
id
:
this
.
playlistEditor
.
id
,
playlist
:
playlist
,
callback
:
()
=>
{
this
.
$root
.
$emit
(
'
bv::refresh::table
'
,
'
playlistsTable
'
)
}
})
}
},
},
}
</
script
>
src/components/filemanager/Playlists.vue
0 → 100644
View file @
30a9c80d
<
template
>
<div>
<edit-playlists-modal
ref=
"editPlaylistsModal"
/>
<!-- Only display a spinner if the playlists are not loaded yet -->
<div
v-if=
"!loaded.playlists"
>
<b-row>
<b-col
align=
"center"
>
<img
src=
"../../assets/radio.gif"
alt=
"loading data"
>
</b-col>
</b-row>
</div>
<!-- If all playlist data is loaded we can present a create button and
a table of playlists (if there are already any)-->
<div
v-else
>
<!-- If no playlists are available, only show an alert and a create button -->
<div
v-if=
"playlists.length === 0"
align=
"center"
>
<b-alert
show
variant=
"warning"
>
There are no playlists for this show yet.
</b-alert>
<b-button
variant=
"success"
@
click=
"addPlaylist"
>
Create a playlist
</b-button>
</div>
<!-- In case there are playlists, show the button and then the table -->
<div
v-else
>
<div
align=
"center"
style=
"padding-bottom: 1.5em;"
>
<b-button
variant=
"success"
@
click=
"addPlaylist"
>
Create a playlist
</b-button>
</div>
<b-table
id=
"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: Last edit
This column lists the last date this playlist was changed.
-->
<
template
v-slot:cell(updated)=
"data"
>
{{
prettyDateTime
(
data
.
value
)
}}
</
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
@
click=
"editPlaylist(data.item.id)"
>
Edit
</b-button>
<b-button
variant=
"danger"
@
click=
"deletePlaylist(data.item.id)"
>
Delete
</b-button>
</b-button-group>
</
template
>
</b-table>
</div>
<!-- End of playlists table -->
</div>
</div>
</template>
<
script
>
import
{
mapGetters
}
from
'
vuex
'
import
prettyDate
from
'
../../mixins/prettyDate
'
import
editPlaylistsModal
from
'
./EditPlaylistModal.vue
'
export
default
{
components
:
{
'
edit-playlists-modal
'
:
editPlaylistsModal
,
},
mixins
:
[
prettyDate
],
// include the modal for displaying file import logs
data
()
{
return
{
// for adding and editing the playlists we need some temporary stuff
playlistEditor
:
{
id
:
null
,
mode
:
'
add
'
,
// should be either 'add' or 'edit'
description
:
''
,
entries
:
[],
newStreamURL
:
null
},
// configuration of the playlists table, which will use the playlists array as data
playlistsTableFields
:
[
{
key
:
'
id
'
,
label
:
'
Index
'
},
{
key
:
'
description
'
,
label
:
'
Description
'
},
{
key
:
'
entries
'
,
label
:
'
Entries
'
},
{
key
:
'
updated
'
,
label
:
'
Last edit
'
},
{
key
:
'
actions
'
,
label
:
'
Actions
'
,
class
:
'
text-right
'
},
],
playlistEditTableFields
:
[
{
key
:
'
id
'
,
label
:
'
Index
'
},
{
key
:
'
type
'
,
label
:
'
Type
'
},
{
key
:
'
source
'
,
label
:
'
Source
'
},
{
key
:
'
actions
'
,
label
:
'
Actions
'
,
class
:
'
text-right
'
},
]
}
},
computed
:
{
loaded
()
{
return
{
playlists
:
this
.
$store
.
state
.
playlists
.
loaded
.
playlists
,
}
},
...
mapGetters
({
selectedShow
:
'
shows/selectedShow
'
,
playlists
:
'
playlists/playlists
'
,
})
},
methods
:
{
playlistToolTip
(
entries
)
{
let
text
=
'
<div style="white-space: nowrap;" align="left">
'
for
(
var
i
in
entries
)
{
text
+=
i
+
'
:
'
+
entries
[
i
].
uri
+
'
<br>
'
}
text
+=
'
</div>
'
return
text
},
deletePlaylist
(
id
)
{
// TODO: add mechanism to indicate the running delete request in the files table
this
.
$store
.
dispatch
(
'
playlists/delete
'
,
{
slug
:
this
.
selectedShow
.
slug
,
id
:
id
})
},
addPlaylist
()
{
this
.
$refs
.
editPlaylistsModal
.
addPlaylist
()
},
editPlaylist
(
id
)
{
this
.
$refs
.
editPlaylistsModal
.
editPlaylist
(
id
)
},
},
}
</
script
>
src/store/modules/playlists.js
View file @
30a9c80d
import
axios
from
'
axios
'
import
handleApiError
from
'
../handleApiError
'
const
state
=
{
playlists
:
[],
loaded
:
{
playlists
:
false
,
}
}
const
mutations
=
{
loading
(
state
,
item
)
{
state
.
loaded
[
item
]
=
false
},
finishLoading
(
state
,
item
)
{
state
.
loaded
[
item
]
=
true
},
setPlaylists
(
state
,
lists
)
{
state
.
playlists
=
lists
},
addPlaylist
(
state
,
list
)
{
state
.
playlists
.
push
(
list
)
},
updatePlaylist
(
state
,
data
)
{
let
i
=
state
.
playlists
.
findIndex
(
p
=>
p
.
id
===
data
.
id
)
if
(
i
>=
0
)
{
state
.
playlists
[
i
]
=
data
.
playlist
}
else
{
console
.
log
(
'
[ERROR] updatePlaylist: trying to update a non-existing list
'
)
}
},
deletePlaylist
(
state
,
id
)
{
let
i
=
state
.
playlists
.
findIndex
(
p
=>
p
.
id
===
id
)
if
(
i
>=
0
)
{
state
.
playlists
.
splice
(
i
,
1
)
}
else
{
console
.
log
(
'
[ERROR] deletePlaylist: trying to delete a non-existing list
'
)
}
}
}
const
getters
=
{
playlists
:
state
=>
state
.
playlists
,
playlistCount
:
state
=>
state
.
playlists
.
length
,
getPlaylistById
:
state
=>
id
=>
{
let
list
if
(
id
!==
undefined
)
{
list
=
state
.
playlists
.
find
(
l
=>
l
.
id
===
id
)
if
(
list
===
undefined
)
{
console
.
log
(
'
[ERROR] getPlaylistById: ID not found in store!
'
)
}
}
return
list
}
}
const
actions
=
{
}
fetch
(
ctx
,
data
)
{
ctx
.
commit
(
'
loading
'
,
'
playlists
'
)
let
uri
=
process
.
env
.
VUE_APP_API_TANK
+
'
shows/
'
+
data
.
slug
+
'
/playlists
'
axios
.
get
(
uri
,
{
withCredentials
:
true
,
headers
:
{
'
Authorization
'
:
'
Bearer
'
+
ctx
.
rootState
.
auth
.
user
.
access_token
}
}).
then
(
response
=>
{
// we don't have to check separately, if there are playlists, because tank
// always provides an empty array if there are no playlists (or even if there is no corresponding show)
ctx
.
commit
(
'
setPlaylists
'
,
response
.
data
.
results
)
ctx
.
commit
(
'
finishLoading
'
,
'
playlists
'
)
if
(
data
&&
typeof
(
data
.
callback
)
===
'
function
'
)
{
data
.
callback
()
}