Commit e317a564 authored by jackie / Andrea Ida Malkah Klaura's avatar jackie / Andrea Ida Malkah Klaura
Browse files

improve FileManager structure & comments

parent 975ab7bd
<template>
<b-container>
<!-- This first row is so far only used to provide a dropdown for
choosing one of the loaded shows (which the user has access to) -->
<b-row>
<b-col>
<h3>Dateien und Playlists</h3>
......@@ -21,6 +23,10 @@
</b-col>
</b-row>
<hr>
<!-- The jumbotron is used to display the name and short description of the
currently selected show and let the user choose between editing files and
playlists -->
<b-jumbotron>
<template slot="header">
<span v-if="loaded.shows">
......@@ -52,7 +58,10 @@
</div>
</b-jumbotron>
<!-- All the UI for uploading and editing files is only shown if the user
choose to edit files in the jumbotron above -->
<div v-if="mode === 'files'">
<!-- Only display a spinner if the files are not loaded yet -->
<div v-if="!loaded.files">
<b-row>
<b-col align="center">
......@@ -63,12 +72,22 @@
</b-col>
</b-row>
</div>
<!-- If all file data is loaded we can present an upload button and
a table of files (if there are already any or if there are any already
being uploaded/imported )-->
<div v-else>
<!-- Modal: Add new file
This is the modal that is used when the user clicks on the
"Upload or add a file" button. When the user hits the OK button,
the addFile method will be called. -->
<b-modal
id="modal-add-file"
title="Add new file"
@ok="addFile"
>
<!-- If the checkbox below is checked we only need a simple input
for entering an URI, instead of a complete file upload dialogue -->
<div v-if="addNewFileURI">
<b-row>
<b-col md="2">
......@@ -83,6 +102,8 @@
</b-col>
</b-row>
</div>
<!-- If the checkbox is not checked, we provide a file selection
dialogue instead of a simple input for an URI -->
<div v-else>
<b-form-file
v-model="uploadSourceFile"
......@@ -91,7 +112,11 @@
drop-placeholder="Drop file here..."
/>
</div>
<hr>
<!-- This checkbox determines whether there is just a simple input
or a file selection dialogue (see above) -->
<div align="center">
<b-form-checkbox
v-model="addNewFileURI"
......@@ -102,12 +127,18 @@
</b-form-checkbox>
</div>
</b-modal>
<!-- Modal: Edit meta information
This modal lets the user change a file's meta information (artist,
album, title). When the user hits OK, the saveFile method is called.
-->
<b-modal
id="modal-edit-file"
title="Edit meta information"
size="lg"
@ok="saveFile"
>
<!-- Input element: Artist -->
<b-row>
<b-col md="2">
Artist:
......@@ -119,6 +150,8 @@
/>
</b-col>
</b-row>
<!-- Input element: Album -->
<b-row>
<b-col md="2">
Album:
......@@ -130,6 +163,8 @@
/>
</b-col>
</b-row>
<!-- Input element: Title -->
<b-row>
<b-col md="2">
Title:
......@@ -141,7 +176,13 @@
/>
</b-col>
</b-row>
<hr>
<!-- As additional orientation we provide the source this file was
uploaded/imported from. This might help the user to manage all files
and set the meta information accordingly.
-->
<b-row>
<b-col md="2">
Sourced from:
......@@ -149,6 +190,9 @@
<b-col>{{ temp.uri }}</b-col>
</b-row>
</b-modal>
<!-- Now for the files. If there are none yet, just show an alert and
a button for uploading/importing a new file -->
<div
v-if="files.length === 0"
align="center"
......@@ -166,7 +210,11 @@
Upload or add a file
</b-button>
</div>
<!-- If there already are files for this show we'll show the button
for uploading/importing a new file and then a table with all files -->
<div v-else>
<!-- This is the button -->
<div
align="center"
style="padding-bottom: 1.5em;"
......@@ -178,12 +226,24 @@
Upload or add a file
</b-button>
</div>
<!-- And here comes the table -->
<b-table
ref="filesTable"
striped
:fields="filesTableFields"
:items="files"
>
<!-- The first two columns in the table (Index & Artist) are filled
in automatically, because we do not use these fields for displaying
upload/import progress information.
-->
<!-- Column: Album
This column displays either the album meta information or, in case
the file is just being uploaded/imported, a spinner visualising an
ongoing import.
-->
<template
slot="metadata.album"
slot-scope="data"
......@@ -195,6 +255,12 @@
></span>
<span v-else>{{ data.value }}</span>
</template>
<!-- Column: Title
This column displays either the title meta information or, in case
the file is just being uploaded/imported, the current phase
of the ongoing import (fetching or normalizing).
-->
<template
slot="metadata.title"
slot-scope="data"
......@@ -202,40 +268,49 @@
<span v-if="data.item.source.import.state === 'done'">{{ data.value }}</span>
<span v-else-if="data.item.source.import.progress !== undefined">{{ data.item.source.import.progress.step }} :</span>
</template>
<!-- Column: Duration
This column displays either the duration of the audio file, or, if
the file is just being uploaded/imported, the current progress.
-->
<template
slot="duration"
slot-scope="data"
>
<!-- In case the import is already done just print a pretty duration -->
<div v-if="data.item.source.import.state === 'done'">
{{ prettyNanoseconds(data.value) }}
</div>
<!-- Or print the progress for ongoing imports. We use the variant
prop of the b-progress to display the bar in different colours -
either the info variant for the fetching phase or the success
variant for the normalizing phase -->
<div v-else-if="data.item.source.import.progress !== undefined">
<div v-if="data.item.source.import.progress.step === 'fetching'">
<b-progress
:value="data.item.source.import.progress.progress"
:max="1"
show-progress
variant="info"
:variant="data.item.source.import.progress.step === 'fetching' ? 'info' : 'success'"
animated
/>
</div>
<div v-else>
<b-progress
:value="data.item.source.import.progress.progress"
:max="1"
show-progress
variant="success"
animated
/>
</div>
</div>
</template>
<!-- Column: Size
This column displays the size of the audio file, if the file is
already fully imported. Otherwise we'll just leave it empty.
-->
<template
slot="size"
slot-scope="data"
>
<span v-if="data.item.source.import.state === 'done'">{{ prettyFileSize(data.value) }}</span>
</template>
<!-- Column: Actions
This column displays the available button for actions the user can
take on this file (e.g. editing and deleting).
-->
<template
slot="actions"
slot-scope="data"
......@@ -254,10 +329,14 @@
</template>
</b-table>
</div>
<!-- End of files table -->
</div>
</div>
<!-- All the UI for creating and editing playlists is only shown if the user
choose to edit playlists in the jumbotron above -->
<div v-if="mode === 'playlists'">
<!-- Only display a spinner if the playlists are not loaded yet -->
<div v-if="!loaded.playlists">
<b-row>
<b-col align="center">
......@@ -268,6 +347,9 @@
</b-col>
</b-row>
</div>
<!-- If all playlist data is loaded we can present an create button and
a table of playlists (if there are already any)-->
<div v-else>
<div
v-if="playlists.length === 0"
......@@ -303,7 +385,11 @@ import filesize from 'filesize'
import prettyDate from '../mixins/prettyDate'
export default {
// generic functions that we want to use from our mixins folder
mixins: [ prettyDate ],
// the data this component will be handling: mostly flags and local versions
// of the data fetched from the AuRa tank API
data () {
return {
shows: [], // an array of objects describing our shows (empty at load, will be populated on created())
......@@ -312,25 +398,35 @@ export default {
files: [],
playlists: [],
mode: 'files',
addNewFileURI: false,
uploadSourceURI: '',
uploadSourceFile: null,
uploadInterval: null,
// some flags to signal if API data is already fully loaded
loaded: {
shows: false,
files: false,
playlists: false
},
// variables used by file upload/import modal
addNewFileURI: false,
uploadSourceURI: '',
uploadSourceFile: null,
// we need this for the modal to edit a file's meta information
temp: {
id: null,
artist: '',
album: '',
title: ''
},
// for formatting the buttons - this way we could customize it later
button: {
files: 'info',
playlists: 'outline-info'
},
// configuration of the files table, which will use the files array as data
filesTableFields: [
{ key: 'id', label: 'Index' },
{ key: 'metadata.artist', label: 'Artist' },
......@@ -342,6 +438,9 @@ export default {
]
}
},
// TODO: if we can use the playlists object itself (similar to the files in
// in the files table, we can get rid of the computed properties)
computed: {
playlistsTable: function (){
var arr = []
......@@ -356,6 +455,11 @@ export default {
return arr
}
},
// Right after this component is set up, we want to fetch all available shows
// from the AuRa tank module. This works quite similar to the ShowManager.
// We also want to load the files and playlists as soon as the shows are
// loaded.
created () {
// when we enter this module, we want to load all shows of the current user
// before we search for corresponding shows in the tank
......@@ -383,13 +487,24 @@ export default {
alert('There was an error fetching shows from steering: ' + error)
})
},
// Now for our hotchpotch of methods, mostly for fetching data from and
// posting/updating data to the AuRa tank API
methods: {
// Just a placeholder function we can use in the UI, to signal if something
// is not yet implemented
notYetImplemented: function () {
alert('By the mighty witchcraftry of the mother of time!\n\nThis feature is not implemented yet.')
},
// 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)
},
// Returns a file object from the files array, given a file ID
getFileById: function (id) {
for (var i in this.files) {
if (this.files[i].id === id) {
......@@ -398,6 +513,10 @@ export default {
}
return null
},
// To start modifying the meta information for a file we have to set our
// temporary data (which will be used to check if anything changed) and
// then open the editing modal
editFile: function (id) {
var file = this.getFileById(id)
this.temp.id = file.id
......@@ -407,6 +526,10 @@ export default {
this.temp.uri = file.source.uri
this.$bvModal.show('modal-edit-file')
},
// Once the OK button is hit in the file editing modal, we have to check
// if anything changed and then send an appropriate metadata obecjt to
// the AuRa tank API to update it
saveFile: function (){
var file = this.getFileById(this.temp.id)
// we only want to send a PATCH request if some metadata actually changed
......@@ -432,6 +555,9 @@ export default {
})
}
},
// Deletes a file with a specific, calling the AuRa tank API and afterwards
// fetching a fresh list of files from it.
deleteFile: function (id) {
var uri = process.env.VUE_APP_API_TANK + 'shows/' + this.shows[this.currentShow].slug + '/files/' + id
// TODO: add mechanism to indicate the running delete request in the files table
......@@ -446,6 +572,12 @@ export default {
alert('Error: could not delete file. See console log for details.')
})
},
// With this function we add a new file in the AuRa tank by calling its API.
// Depending on wheter we add a remote file which tank then imports by itself,
// or if we want to upload a local file, we source-uri has to look different.
// And for uploading a local file this is just the first step. Afterwards the
// actual upload has to be started with the startUpload function.
addFile: function () {
var uri = process.env.VUE_APP_API_TANK + 'shows/' + this.shows[this.currentShow].slug + '/files'
if (this.addNewFileURI) {
......@@ -483,6 +615,10 @@ export default {
alert('Something is wrong. You have choosen to upload a file, but the corresponding file object does not exist.')
}
},
// When a new file was added with the addFile function we can start an upload
// fetching the import endpoint of this file and then call the upload
// function, which atually puts the file onto the server.
startUpload: function (id) {
var uri = process.env.VUE_APP_API_TANK + 'shows/' + this.shows[this.currentShow].slug + '/files/' + id + '/import'
axios.get(uri, {
......@@ -497,6 +633,9 @@ export default {
alert('Error: could not start the file upload. See console log for details.')
})
},
// Upload a file to the AuRa tank API - given it was created with the addFile
// and started with the startUpload methods.
upload: function (id) {
/*
* NOTE: there is no npm package for flow.js and importing it manually did not
......@@ -538,12 +677,18 @@ export default {
alert('Error: could not start the file upload. See console log for details.')
})
},
// This switches the UI elements to reflect another show and fetches all
// relevent data from the tank API.
switchShow: function (index) {
// set the current show and its ID to whatever we want to switch to now
this.currentShow = index
this.currentShowID = this.shows[this.currentShow].id
this.fetchShow(this.shows[this.currentShow].slug)
},
// This function is used to visually switch between the files and playlists
// editing mode.
switchMode: function (mode) {
if (this.mode !== mode) {
this.mode = mode
......@@ -553,6 +698,11 @@ export default {
}
}
},
// This function fetches all running imports for a given show. It should
// be called periodically to reflect the upload/import progress. When no
// more active imports are available the corresponding updateInterval
// should be cleared again.
fetchImports: function (slug){
var uri = process.env.VUE_APP_API_TANK + 'shows/' + slug + '/imports'
axios.get(uri, {
......@@ -587,10 +737,14 @@ export default {
alert('There was an error fetching current imports. See console for details.')
})
},
// Just a wrapper to fetch both, files and playlists information.
fetchShow: function (slug) {
this.fetchFiles(slug)
this.fetchPlaylists(slug)
},
// Fetch all files for a given show from the AuRa tank API
fetchFiles: function (slug) {
this.loaded.files = false
var uri = process.env.VUE_APP_API_TANK + 'shows/' + slug + '/files'
......@@ -606,6 +760,8 @@ export default {
alert('There was an error fetching files from tank: ' + error)
})
},
// Fetch all playlists for a given show from the AuRa tank API
fetchPlaylists: function (slug) {
this.loaded.playlists = false
var uri = process.env.VUE_APP_API_TANK + 'shows/' + slug + '/playlists'
......
Supports Markdown
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