Commit a8014ba0 authored by Ernesto Rico Schmidt's avatar Ernesto Rico Schmidt
Browse files

Merge branch 'kmohrf/cleanup' into 'master'

Update toolchain and cleanup code

See merge request !9
parents 1ce5ecbc 1140b802
Pipeline #1870 passed with stages
in 9 minutes and 30 seconds
......@@ -7,8 +7,17 @@
- Dockerfile
stages:
- test
- release
lint:
image: node:14-alpine
stage: test
before_script:
- npm ci
script:
- npm run lint -- --no-fix
docker-push:
# Use the official docker image.
image: docker:latest
......
module.exports = {
presets: [
'@vue/app'
'@vue/cli-plugin-babel/preset'
]
}
This diff is collapsed.
{
"name": "aura-dashboard",
"version": "1.0.0-alpha-1",
"license": "AGPL-3.0-only",
"homepage": "https://gitlab.servus.at/aura/dashboard",
"scripts": {
"serve": "TAILWIND_MODE=watch NODE_ENV=development vue-cli-service serve --open",
"serve": "NODE_ENV=development vue-cli-service serve --open",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"@tailwindcss/ui": "^0.6.2",
"axios": "^0.18.1",
"bootstrap-vue": "^2.16.0",
"core-js": "^3.8.3",
"dompurify": "^2.0.12",
"filesize": "^4.2.1",
"jquery": "3.4.1",
"moment": "^2.27.0",
"node-polyglot": "^2.4.0",
"oidc-client": "^1.10.1",
......@@ -26,20 +23,20 @@
"vuex": "^3.5.1"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.12.1",
"@vue/cli-plugin-eslint": "^3.12.1",
"@vue/cli-service": "^4.5.7",
"@vue/cli-plugin-babel": "~5.0.4",
"@vue/cli-plugin-eslint": "~5.0.4",
"@vue/cli-service": "~5.0.4",
"@vue/devtools": "^5.3.3",
"autoprefixer": "^9.8.6",
"autoprefixer": "^10.4.4",
"babel-eslint": "^10.1.0",
"copy-webpack-plugin": "^6.0.3",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.2.3",
"copy-webpack-plugin": "^9.1.0",
"eslint": "^7.32.0",
"eslint-plugin-vue": "^8.6.0",
"minimist": "^1.2.5",
"postcss": "^7.0.36",
"postcss": "^8.4.12",
"sass": "^1.30.0",
"sass-loader": "^10.1.0",
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.4",
"sass-loader": "^12.6.0",
"tailwindcss": "^3.0.24",
"vue-template-compiler": "^2.6.12"
},
"eslintConfig": {
......@@ -56,13 +53,13 @@
"curly": "error",
"block-spacing": "error",
"keyword-spacing": "error",
"semi": ["error", "never"],
"vue/html-indent": [
"warning",
4,
{
"baseIndent": 1
}
]
"warn",
4
],
"vue/no-v-html": "off",
"vue/multi-word-component-names": "off"
},
"parserOptions": {
"parser": "babel-eslint"
......@@ -72,5 +69,7 @@
"> 1%",
"last 2 versions",
"not ie <= 8"
]
],
"homepage": "https://gitlab.servus.at/aura/dashboard",
"license": "AGPL-3.0-only"
}
......@@ -5,8 +5,8 @@
class="tw-flex tw-flex-col tw-min-h-screen"
>
<app-header
:modules="modules"
:user="user"
:modules="modules"
:user="user"
/>
<div
......@@ -24,8 +24,8 @@
class="tw-flex-1 tw-flex tw-my-8"
>
<home
:modules="modules"
:user="user"
:modules="modules"
:user="user"
/>
</div>
......@@ -38,7 +38,7 @@
import header from './components/Header.vue'
import footer from './components/Footer.vue'
import Home from "./Pages/Home";
import Home from "./Pages/Home"
export default {
name: 'App',
......
<style></style>
<template>
<div
v-if="!selectedShow"
class="tw-text-center tw-my-8"
v-if="!selectedShow"
class="tw-text-center tw-my-8"
>
{{ $t('loading') }}
</div>
<b-container
v-else
class="tw-mb-8"
v-else
class="tw-mb-8"
>
<h1>
<template v-if="id">
{{ $t('playlistEditor.titleExisting', { id: playlistEditor.id, show: selectedShow.name }) }}
</template>
<template v-else>
{{ $t('playlistEditor.titleNew', { show: selectedShow.name } ) }}
......@@ -29,9 +26,9 @@
<b-col>
<b-form-input
v-model="playlistEditor.description"
type="text"
:placeholder="$t('showMeta.descriptionPlaceholder')"
v-model="playlistEditor.description"
type="text"
:placeholder="$t('showMeta.descriptionPlaceholder')"
/>
</b-col>
</b-row>
......@@ -39,8 +36,8 @@
<!-- 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"
v-if="playlistEditor.entries.length === 0"
align="center"
>
{{ $t('playlistEditor.noEntriesAvailable') }}
</div>
......@@ -48,16 +45,16 @@
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"
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">
<template #cell(id)="data">
{{ data.index + 1 }}.
</template>
......@@ -65,28 +62,28 @@
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">
<template #cell(type)="data">
<b-badge
v-if="data.item.file"
variant="primary"
v-if="data.item.file"
variant="primary"
>
{{ $t('playlistEditor.types.file') }}
</b-badge>
<b-badge
v-else-if="data.item.uri.startsWith('line://')"
variant="primary"
v-else-if="data.item.uri.startsWith('line://')"
variant="primary"
>
{{ $t('playlistEditor.types.lineIn') }}
</b-badge>
<b-badge
v-else-if="data.item.uri.startsWith('http://') || data.item.uri.startsWith('https://')"
variant="primary"
v-else-if="data.item.uri.startsWith('http://') || data.item.uri.startsWith('https://')"
variant="primary"
>
{{ $t('playlistEditor.types.stream') }}
</b-badge>
<b-badge
v-else
variant="dark"
v-else
variant="dark"
>
{{ $t('playlistEditor.types.other') }}
</b-badge>
......@@ -95,7 +92,7 @@
<!-- Column: Source
Here we display where this playlist entry is coming from
-->
<template v-slot:cell(source)="data">
<template #cell(source)="data">
<span v-if="data.item.file">
<span class="tw-font-bold">{{ getFileTitleForPlaylist(data.item.file.show, data.item.file.id) }}</span><br>
<span class="tw-text-gray-700">(file://{{ data.item.file.show }}/{{ data.item.file.id }})</span>
......@@ -109,7 +106,7 @@
<!-- Column: Duration
Here we give the user the ability to edit the duration of an entry.
-->
<template v-slot:cell(duration)="data">
<template #cell(duration)="data">
<span v-if="playlistEditor.durationField === data.index">
<input
ref="durationField"
......@@ -137,9 +134,9 @@
<span v-else>
<span
v-b-tooltip="'Klicken um zu bearbeiten'"
class="tw-text-gray-700 tw-underline hover:tw-no-underline tw-cursor-pointer"
@click="toggleDurationField(data.index)"
v-b-tooltip="'Klicken um zu bearbeiten'"
class="tw-text-gray-700 tw-underline hover:tw-no-underline tw-cursor-pointer"
@click="toggleDurationField(data.index)"
>
{{ $t('playlistEditor.unknownDuration') }}
</span>
......@@ -150,24 +147,24 @@
<!-- Column: Actions
Finally some buttons to reorder or delete playlist entries
-->
<template v-slot:cell(actions)="data">
<template #cell(actions)="data">
<b-button-group size="sm">
<b-button
:disabled="data.index === 0"
@click="movePlaylistItemUp(data.index)"
:disabled="data.index === 0"
@click="movePlaylistItemUp(data.index)"
>
<b class="upDownArrows">&uarr;</b>
</b-button>
<b-button
:disabled="data.index === playlistEditor.entries.length - 1"
@click="movePlaylistItemDown(data.index)"
:disabled="data.index === playlistEditor.entries.length - 1"
@click="movePlaylistItemDown(data.index)"
>
<b class="upDownArrows">&darr;</b>
</b-button>
<b-button
variant="danger"
@click="deletePlaylistItem(data.index)"
variant="danger"
@click="deletePlaylistItem(data.index)"
>
{{ $t('delete') }}
</b-button>
......@@ -185,8 +182,8 @@
<hr>
<div
v-if="playlistExceedsAllowedUnknowns"
class="tw-text-red-600 tw-my-4"
v-if="playlistExceedsAllowedUnknowns"
class="tw-text-red-600 tw-my-4"
>
{{ $t('playlistEditor.tooManyUnknowns') }}
</div>
......@@ -200,28 +197,27 @@
TODO: make the inputs configurable
-->
<b-modal
id="modal-edit-playlist-add-stream"
:title="$t('playlistEditor.addStream')"
:cancel-title="$t('cancel')"
@ok="addPlaylistItemStream('save')"
id="modal-edit-playlist-add-stream"
:title="$t('playlistEditor.addStream')"
:cancel-title="$t('cancel')"
@ok="addPlaylistItemStream('save')"
>
<b-input
v-model="playlistEditor.newStreamURL"
type="url"
>
</b-input>
v-model="playlistEditor.newStreamURL"
type="url"
/>
</b-modal>
<div class="tw-flex tw-justify-between">
<b-button-group>
<b-dropdown :text="$t('playlistEditor.types.file')">
<b-dropdown-item
v-for="(file, index) in files"
:key="index"
@click="addPlaylistItemFile(file.show, file.id)"
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 }})
prettyNanoseconds(file.duration) }}, {{ prettyFileSize(file.size) }}, {{ file.source.uri }})
</b-dropdown-item>
</b-dropdown>
<b-dropdown :text="$t('playlistEditor.types.lineIn')">
......@@ -238,16 +234,16 @@
</b-dropdown-item>
</b-dropdown>
<b-button
@click="addPlaylistItemStream('openModal')"
@click="addPlaylistItemStream('openModal')"
>
{{ $t('playlistEditor.types.stream') }}
</b-button>
</b-button-group>
<b-button
variant="success"
:disabled="playlistExceedsAllowedUnknowns"
@click="storePlaylist"
variant="success"
:disabled="playlistExceedsAllowedUnknowns"
@click="storePlaylist"
>
{{ $t('save') }}
</b-button>
......@@ -315,9 +311,9 @@
}
return !entry.duration
});
})
return unknowns.length > 1;
return unknowns.length > 1
},
playlistDuration() {
......@@ -337,7 +333,7 @@
return newDuration
}, 0)
const durationInNanoseconds = totalDuration * 1000 * 1000 * 1000;
const durationInNanoseconds = totalDuration * 1000 * 1000 * 1000
return this.prettyNanoseconds(durationInNanoseconds)
},
......@@ -350,7 +346,7 @@
},
created() {
this.$store.dispatch('shows/fetchShows');
this.$store.dispatch('shows/fetchShows')
this.id
? this.editPlaylist()
: this.addPlaylist()
......@@ -360,48 +356,48 @@
// Checks if the duration entered is in a valid format and updates the corresponding
// entrys data in the playlist.
checkAndUpdateDuration() {
const regex = /^\d{2}:\d{2}$/;
const entryIndex = this.playlistEditor.durationField;
const entry = this.playlistEditor.entries[entryIndex];
let duration = this.playlistEditor.newDuration;
const regex = /^\d{2}:\d{2}$/
const entryIndex = this.playlistEditor.durationField
const entry = this.playlistEditor.entries[entryIndex]
let duration = this.playlistEditor.newDuration
this.$refs.durationField.setCustomValidity('');
this.$refs.durationField.setCustomValidity('')
// Setting an empty string is okay.
if (!duration) {
this.playlistEditor.durationField = false;
this.playlistEditor.newDuration = '';
this.playlistEditor.durationField = false
this.playlistEditor.newDuration = ''
Vue.delete(this.playlistEditor.entries[entryIndex], 'duration');
return;
Vue.delete(this.playlistEditor.entries[entryIndex], 'duration')
return
}
if (!this.$refs.durationField.checkValidity()) {
this.$refs.durationField.setCustomValidity(this.$t('playlistEditor.invalidDurationFormat'));
this.$refs.durationField.reportValidity();
return;
this.$refs.durationField.setCustomValidity(this.$t('playlistEditor.invalidDurationFormat'))
this.$refs.durationField.reportValidity()
return
}
if (regex.test(duration)) {
duration = `00:${duration}`
}
Vue.set(entry, 'duration', this.hmsToNanoseconds(duration));
Vue.set(this.playlistEditor.entries, entryIndex, entry);
Vue.set(entry, 'duration', this.hmsToNanoseconds(duration))
Vue.set(this.playlistEditor.entries, entryIndex, entry)
this.playlistEditor.durationField = false;
this.playlistEditor.newDuration = '';
this.playlistEditor.durationField = false
this.playlistEditor.newDuration = ''
},
// Toggles an editable duration field for adding durations to streams and line-ins.
toggleDurationField(id = false) {
const entry = this.playlistEditor.entries[id];
const entry = this.playlistEditor.entries[id]
if (entry && entry.duration) {
this.playlistEditor.newDuration = this.prettyNanoseconds(entry.duration);
this.playlistEditor.newDuration = this.prettyNanoseconds(entry.duration)
}
this.playlistEditor.durationField = id;
this.playlistEditor.durationField = id
this.$nextTick(() => this.$refs.durationField.focus())
},
......@@ -488,11 +484,11 @@
},
editPlaylist() {
let playlist = this.getPlaylistById(this.id);
let playlist = this.getPlaylistById(this.id)
if (!playlist) {
this.$router.push({name: 'addPlaylist'})
return;
return
}
this.playlistEditor.mode = 'edit'
......@@ -519,15 +515,15 @@
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,
callback: () => {
this.$root.$emit('bv::refresh::table', 'playlistsTable');
this.$router.push('/files');
this.$root.$emit('bv::refresh::table', 'playlistsTable')
this.$router.push('/files')
this.$toast.success(this.$t('playlistEditor.saved'))
}
})
......@@ -537,8 +533,8 @@
id: this.playlistEditor.id,
playlist: playlist,
callback: () => {
this.$root.$emit('bv::refresh::table', 'playlistsTable');
this.$router.push('/files');
this.$root.$emit('bv::refresh::table', 'playlistsTable')
this.$router.push('/files')
this.$toast.success(this.$t('playlistEditor.saved'))
}
})
......@@ -548,3 +544,5 @@
},
}
</script>
<style></style>
This diff is collapsed.
......@@ -26,7 +26,7 @@
<div
v-else-if="loaded.shows && !selectedShow"
class="tw-text-center"
v-html="this.$t('noAssignedShows', { adminUrl })"
v-html="$t('noAssignedShows', { adminUrl })"
/>
</b-container>
</template>
......@@ -76,7 +76,7 @@
this.$store.dispatch('shows/fetchShows', {
callback: () => {
if (!this.selectedShow) {
return;
return
}
this.$nextTick(() => {
......
......@@ -2,7 +2,10 @@
<b-container class="tw-self-center">
<div v-if="user.logged_in === true && user.steeringUser">
<div class="tw-text-center tw-mb-8 sm:tw-mb-16 md:tw-mb-32">
<img src="/assets/logo.svg" class="tw-w-2/3 lg:tw-w-1/3">
<img
src="/assets/logo.svg"
class="tw-w-2/3 lg:tw-w-1/3"
>
</div>
<div
......@@ -13,21 +16,27 @@
}"
>
<router-link
v-for="mod in modules.main"
:key="mod.slug"
:to="mod.slug"
v-for="mod in modules.main"
:key="mod.slug"
:to="mod.slug"
>
<img :src="mod.icon" class="tw-w-32 tw-mb-4">
<img
:src="mod.icon"
class="tw-w-32 tw-mb-4"
>
<p>{{ mod.title }}</p>
</router-link>
</div>
</div>
<div
v-else
class="tw-mx-auto tw-max-w-md tw-space-y-6"
v-else
class="tw-mx-auto tw-max-w-md tw-space-y-6"
>
<div class="tw-mb-12">
<img src="/assets/logo.svg" class="tw-w-2/3">
<img
src="/assets/logo.svg"
class="tw-w-2/3"
>
</div>
<h1>{{ $t('home.welcome') }}</h1>
......@@ -35,9 +44,9 @@
<p>{{ $t('home.notLoggedIn') }}</p>
<b-button
size="lg"
variant="outline-secondary"
@click="$parent.signIn"
size="lg"
variant="outline-secondary"
@click="$parent.signIn"
>
{{ $t('auth.signIn') }}
</b-button>
......
......@@ -3,9 +3,9 @@
<template v-if="loaded.shows">
<template v-if="selectedShow">