More Composition conversion and fixes.
This commit is contained in:
parent
1ef68f64fc
commit
e0f5178ba4
|
@ -106,4 +106,8 @@ const update = () => {
|
|||
}
|
||||
|
||||
onMounted(update);
|
||||
|
||||
defineExpose({
|
||||
update
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<div class="col-md-8 buttons">
|
||||
<div class="btn-group dropdown allow-focus">
|
||||
<b-dropdown
|
||||
ref="setPlaylistsDropdown"
|
||||
ref="$setPlaylistsDropdown"
|
||||
v-b-tooltip.hover
|
||||
size="sm"
|
||||
variant="primary"
|
||||
|
@ -69,21 +69,23 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<b-button
|
||||
type="submit"
|
||||
size="sm"
|
||||
variant="primary"
|
||||
>
|
||||
{{ $gettext('Save') }}
|
||||
</b-button>
|
||||
<b-button
|
||||
type="button"
|
||||
size="sm"
|
||||
variant="warning"
|
||||
@click="clearPlaylists()"
|
||||
>
|
||||
{{ $gettext('Clear') }}
|
||||
</b-button>
|
||||
<div class="buttons">
|
||||
<b-button
|
||||
type="submit"
|
||||
size="sm"
|
||||
variant="primary"
|
||||
>
|
||||
{{ $gettext('Save') }}
|
||||
</b-button>
|
||||
<b-button
|
||||
type="button"
|
||||
size="sm"
|
||||
variant="warning"
|
||||
@click="clearPlaylists()"
|
||||
>
|
||||
{{ $gettext('Clear') }}
|
||||
</b-button>
|
||||
</div>
|
||||
</b-dropdown-form>
|
||||
</b-dropdown>
|
||||
</div>
|
||||
|
@ -148,188 +150,200 @@
|
|||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
<script setup>
|
||||
import {forEach, intersection, map} from 'lodash';
|
||||
import Icon from '~/components/Common/Icon';
|
||||
import '~/vendor/sweetalert';
|
||||
import {h, ref, toRef, watch} from "vue";
|
||||
import {useTranslate} from "~/vendor/gettext";
|
||||
import {useNotify} from "~/vendor/bootstrapVue";
|
||||
import {useAxios} from "~/vendor/axios";
|
||||
import {useSweetAlert} from "~/vendor/sweetalert";
|
||||
|
||||
/* TODO Options API */
|
||||
|
||||
export default {
|
||||
name: 'StationMediaToolbar',
|
||||
components: {Icon},
|
||||
props: {
|
||||
currentDirectory: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
selectedItems: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
playlists: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
batchUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
supportsImmediateQueue: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
const props = defineProps({
|
||||
currentDirectory: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
selectedItems: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
playlists: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
emits: ['relist', 'add-playlist'],
|
||||
data() {
|
||||
return {
|
||||
checkedPlaylists: [],
|
||||
newPlaylist: '',
|
||||
};
|
||||
batchUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
computed: {
|
||||
langErrors() {
|
||||
return this.$gettext('The request could not be processed.');
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
selectedItems (items) {
|
||||
// Get all playlists that are active on ALL selected items.
|
||||
let playlistsForItems = map(items.all, (item) => {
|
||||
return map(item.playlists, 'id');
|
||||
});
|
||||
supportsImmediateQueue: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
// Check the checkboxes for those playlists.
|
||||
this.checkedPlaylists = intersection(...playlistsForItems);
|
||||
},
|
||||
newPlaylist (text) {
|
||||
if (text !== '') {
|
||||
if (!this.checkedPlaylists.includes('new')) {
|
||||
this.checkedPlaylists.push('new');
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
doImmediateQueue() {
|
||||
this.doBatch('immediate', this.$gettext('Files played immediately:'));
|
||||
},
|
||||
doQueue() {
|
||||
this.doBatch('queue', this.$gettext('Files queued for playback:'));
|
||||
},
|
||||
doReprocess() {
|
||||
this.doBatch('reprocess', this.$gettext('Files marked for reprocessing:'));
|
||||
},
|
||||
doDelete() {
|
||||
let buttonConfirmText = this.$gettext('Delete %{ num } media files?');
|
||||
let numFiles = this.selectedItems.all.length;
|
||||
const emit = defineEmits(['relist', 'add-playlist']);
|
||||
|
||||
this.$confirmDelete({
|
||||
title: this.$gettextInterpolate(buttonConfirmText, {num: numFiles}),
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
this.doBatch('delete', this.$gettext('Files removed:'));
|
||||
}
|
||||
});
|
||||
},
|
||||
doBatch (action, notifyMessage) {
|
||||
if (this.selectedItems.all.length) {
|
||||
this.$wrapWithLoading(
|
||||
this.axios.put(this.batchUrl, {
|
||||
'do': action,
|
||||
'current_directory': this.currentDirectory,
|
||||
'files': this.selectedItems.files,
|
||||
'dirs': this.selectedItems.directories
|
||||
})
|
||||
).then((resp) => {
|
||||
if (resp.data.success) {
|
||||
let allItemNodes = [];
|
||||
forEach(this.selectedItems.all, (item) => {
|
||||
allItemNodes.push(this.$createElement('div', {}, item.path_short));
|
||||
});
|
||||
const checkedPlaylists = ref([]);
|
||||
const newPlaylist = ref('');
|
||||
|
||||
this.$notifySuccess(allItemNodes, {
|
||||
title: notifyMessage
|
||||
});
|
||||
} else {
|
||||
let errorNodes = [];
|
||||
forEach(resp.data.errors, (error) => {
|
||||
errorNodes.push(this.$createElement('div', {}, error));
|
||||
});
|
||||
const {$gettext} = useTranslate();
|
||||
const langErrors = $gettext('The request could not be processed.');
|
||||
|
||||
this.$notifyError(errorNodes, {
|
||||
title: this.langErrors
|
||||
});
|
||||
}
|
||||
watch(toRef(props, 'selectedItems'), (items) => {
|
||||
// Get all playlists that are active on ALL selected items.
|
||||
let playlistsForItems = map(items.all, (item) => {
|
||||
return map(item.playlists, 'id');
|
||||
});
|
||||
|
||||
this.$emit('relist');
|
||||
});
|
||||
} else {
|
||||
this.notifyNoFiles();
|
||||
}
|
||||
},
|
||||
clearPlaylists () {
|
||||
this.checkedPlaylists = [];
|
||||
this.newPlaylist = '';
|
||||
// Check the checkboxes for those playlists.
|
||||
checkedPlaylists.value = intersection(...playlistsForItems);
|
||||
});
|
||||
|
||||
this.setPlaylists();
|
||||
},
|
||||
setPlaylists () {
|
||||
this.$refs.setPlaylistsDropdown.hide();
|
||||
|
||||
if (this.selectedItems.all.length) {
|
||||
this.$wrapWithLoading(
|
||||
this.axios.put(this.batchUrl, {
|
||||
'do': 'playlist',
|
||||
'playlists': this.checkedPlaylists,
|
||||
'new_playlist_name': this.newPlaylist,
|
||||
'currentDirectory': this.currentDirectory,
|
||||
'files': this.selectedItems.files,
|
||||
'dirs': this.selectedItems.directories
|
||||
})
|
||||
).then((resp) => {
|
||||
if (resp.data.success) {
|
||||
if (resp.data.record) {
|
||||
this.$emit('add-playlist', resp.data.record);
|
||||
}
|
||||
|
||||
let notifyMessage = (this.checkedPlaylists.length > 0)
|
||||
? this.$gettext('Playlists updated for selected files:')
|
||||
: this.$gettext('Playlists cleared for selected files:');
|
||||
|
||||
let allItemNodes = [];
|
||||
forEach(this.selectedItems.all, (item) => {
|
||||
allItemNodes.push(this.$createElement('div', {}, item.path_short));
|
||||
});
|
||||
|
||||
this.$notifySuccess(allItemNodes, {
|
||||
title: notifyMessage
|
||||
});
|
||||
|
||||
this.checkedPlaylists = [];
|
||||
this.newPlaylist = '';
|
||||
} else {
|
||||
let errorNodes = [];
|
||||
forEach(resp.data.errors, (error) => {
|
||||
errorNodes.push(this.$createElement('div', {}, error));
|
||||
});
|
||||
|
||||
this.$notifyError(errorNodes, {
|
||||
title: this.langErrors
|
||||
});
|
||||
}
|
||||
|
||||
this.$emit('relist');
|
||||
});
|
||||
} else {
|
||||
this.notifyNoFiles();
|
||||
}
|
||||
},
|
||||
notifyNoFiles() {
|
||||
this.$notifyError(this.$gettext('No files selected.'));
|
||||
watch(newPlaylist, (text) => {
|
||||
if (text !== '') {
|
||||
if (!checkedPlaylists.value.includes('new')) {
|
||||
checkedPlaylists.value.push('new');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const {wrapWithLoading, notifySuccess, notifyError} = useNotify();
|
||||
const {axios} = useAxios();
|
||||
|
||||
const notifyNoFiles = () => {
|
||||
notifyError($gettext('No files selected.'));
|
||||
};
|
||||
|
||||
const doBatch = (action, notifyMessage) => {
|
||||
if (props.selectedItems.all.length) {
|
||||
wrapWithLoading(
|
||||
axios.put(props.batchUrl, {
|
||||
'do': action,
|
||||
'current_directory': props.currentDirectory,
|
||||
'files': props.selectedItems.files,
|
||||
'dirs': props.selectedItems.directories
|
||||
})
|
||||
).then((resp) => {
|
||||
if (resp.data.success) {
|
||||
let allItemNodes = [];
|
||||
forEach(props.selectedItems.all, (item) => {
|
||||
allItemNodes.push(h('div', {}, item.path_short));
|
||||
});
|
||||
|
||||
notifySuccess(allItemNodes, {
|
||||
title: notifyMessage
|
||||
});
|
||||
} else {
|
||||
let errorNodes = [];
|
||||
forEach(resp.data.errors, (error) => {
|
||||
errorNodes.push(h('div', {}, error));
|
||||
});
|
||||
|
||||
notifyError(errorNodes, {
|
||||
title: langErrors
|
||||
});
|
||||
}
|
||||
|
||||
emit('relist');
|
||||
});
|
||||
} else {
|
||||
notifyNoFiles();
|
||||
}
|
||||
};
|
||||
|
||||
const doImmediateQueue = () => {
|
||||
doBatch('immediate', $gettext('Files played immediately:'));
|
||||
};
|
||||
|
||||
const doQueue = () => {
|
||||
doBatch('queue', $gettext('Files queued for playback:'));
|
||||
};
|
||||
|
||||
const doReprocess = () => {
|
||||
doBatch('reprocess', $gettext('Files marked for reprocessing:'));
|
||||
};
|
||||
|
||||
const {confirmDelete} = useSweetAlert();
|
||||
|
||||
const doDelete = () => {
|
||||
let numFiles = this.selectedItems.all.length;
|
||||
let buttonConfirmText = $gettext(
|
||||
'Delete %{ num } media files?',
|
||||
{num: numFiles}
|
||||
);
|
||||
|
||||
confirmDelete({
|
||||
title: buttonConfirmText,
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
doBatch('delete', $gettext('Files removed:'));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const $setPlaylistsDropdown = ref(); // Template Ref
|
||||
|
||||
const setPlaylists = () => {
|
||||
$setPlaylistsDropdown.value.hide();
|
||||
|
||||
if (props.selectedItems.all.length) {
|
||||
wrapWithLoading(
|
||||
axios.put(props.batchUrl, {
|
||||
'do': 'playlist',
|
||||
'playlists': checkedPlaylists.value,
|
||||
'new_playlist_name': newPlaylist.value,
|
||||
'currentDirectory': props.currentDirectory,
|
||||
'files': props.selectedItems.files,
|
||||
'dirs': props.selectedItems.directories
|
||||
})
|
||||
).then((resp) => {
|
||||
if (resp.data.success) {
|
||||
if (resp.data.record) {
|
||||
emit('add-playlist', resp.data.record);
|
||||
}
|
||||
|
||||
let notifyMessage = (checkedPlaylists.value.length > 0)
|
||||
? $gettext('Playlists updated for selected files:')
|
||||
: $gettext('Playlists cleared for selected files:');
|
||||
|
||||
let allItemNodes = [];
|
||||
forEach(props.selectedItems.all, (item) => {
|
||||
allItemNodes.push(h('div', {}, item.path_short));
|
||||
});
|
||||
|
||||
notifySuccess(allItemNodes, {
|
||||
title: notifyMessage
|
||||
});
|
||||
|
||||
checkedPlaylists.value = [];
|
||||
newPlaylist.value = '';
|
||||
} else {
|
||||
let errorNodes = [];
|
||||
forEach(resp.data.errors, (error) => {
|
||||
errorNodes.push(h('div', {}, error));
|
||||
});
|
||||
|
||||
notifyError(errorNodes, {
|
||||
title: langErrors
|
||||
});
|
||||
}
|
||||
|
||||
emit('relist');
|
||||
});
|
||||
} else {
|
||||
notifyNoFiles();
|
||||
}
|
||||
};
|
||||
|
||||
const clearPlaylists = () => {
|
||||
checkedPlaylists.value = [];
|
||||
newPlaylist.value = '';
|
||||
|
||||
setPlaylists();
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
size="sm"
|
||||
variant="outline-light"
|
||||
class="py-2 pr-0"
|
||||
@click.prevent="$emit('remove')"
|
||||
@click.prevent="doRemove()"
|
||||
>
|
||||
<icon icon="remove" />
|
||||
{{ $gettext('Remove') }}
|
||||
|
@ -27,7 +27,7 @@
|
|||
<b-wrapped-form-group
|
||||
:id="'edit_form_start_time_'+index"
|
||||
class="col-md-4"
|
||||
:field="v$.row.start_time"
|
||||
:field="v$.start_time"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Start Time') }}
|
||||
|
@ -47,7 +47,7 @@
|
|||
<b-wrapped-form-group
|
||||
:id="'edit_form_end_time_'+index"
|
||||
class="col-md-4"
|
||||
:field="v$.row.end_time"
|
||||
:field="v$.end_time"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('End Time') }}
|
||||
|
@ -81,7 +81,7 @@
|
|||
<b-wrapped-form-group
|
||||
:id="'edit_form_start_date_'+index"
|
||||
class="col-md-4"
|
||||
:field="v$.row.start_date"
|
||||
:field="v$.start_date"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Start Date') }}
|
||||
|
@ -104,7 +104,7 @@
|
|||
<b-wrapped-form-group
|
||||
:id="'edit_form_end_date_'+index"
|
||||
class="col-md-4"
|
||||
:field="v$.row.end_date"
|
||||
:field="v$.end_date"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('End Date') }}
|
||||
|
@ -122,7 +122,7 @@
|
|||
<b-wrapped-form-checkbox
|
||||
:id="'edit_form_loop_once_'+index"
|
||||
class="col-md-4"
|
||||
:field="v$.row.loop_once"
|
||||
:field="v$.loop_once"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Loop Once') }}
|
||||
|
@ -146,7 +146,7 @@
|
|||
<template #default>
|
||||
<b-checkbox-group
|
||||
:id="'edit_form_days_'+index"
|
||||
v-model="v$.row.days.$model"
|
||||
v-model="v$.days.$model"
|
||||
stacked
|
||||
:options="dayOptions"
|
||||
/>
|
||||
|
@ -158,59 +158,56 @@
|
|||
</b-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import PlaylistTime from '~/components/Common/TimeCode';
|
||||
import Icon from "~/components/Common/Icon.vue";
|
||||
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
|
||||
import {required} from "@vuelidate/validators";
|
||||
import useVuelidate from "@vuelidate/core";
|
||||
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox.vue";
|
||||
import {toRef} from "vue";
|
||||
import {useTranslate} from "~/vendor/gettext";
|
||||
|
||||
/* TODO Options API */
|
||||
const props = defineProps({
|
||||
index: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
row: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
stationTimeZone: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
});
|
||||
|
||||
export default {
|
||||
name: 'PlaylistsFormScheduleRow',
|
||||
components: {BWrappedFormCheckbox, BWrappedFormGroup, Icon, PlaylistTime},
|
||||
props: {
|
||||
index: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
row: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
stationTimeZone: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
const emit = defineEmits(['remove']);
|
||||
|
||||
const v$ = useVuelidate(
|
||||
{
|
||||
'start_time': {required},
|
||||
'end_time': {required},
|
||||
'start_date': {},
|
||||
'end_date': {},
|
||||
'loop_once': {}
|
||||
},
|
||||
emits: ['remove'],
|
||||
setup() {
|
||||
return {v$: useVuelidate()}
|
||||
},
|
||||
validations: {
|
||||
row: {
|
||||
'start_time': {required},
|
||||
'end_time': {required},
|
||||
'start_date': {},
|
||||
'end_date': {},
|
||||
'days': {},
|
||||
'loop_once': {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dayOptions: [
|
||||
{value: 1, text: this.$gettext('Monday')},
|
||||
{value: 2, text: this.$gettext('Tuesday')},
|
||||
{value: 3, text: this.$gettext('Wednesday')},
|
||||
{value: 4, text: this.$gettext('Thursday')},
|
||||
{value: 5, text: this.$gettext('Friday')},
|
||||
{value: 6, text: this.$gettext('Saturday')},
|
||||
{value: 7, text: this.$gettext('Sunday')}
|
||||
]
|
||||
};
|
||||
},
|
||||
}
|
||||
toRef(props, 'row')
|
||||
);
|
||||
|
||||
const {$gettext} = useTranslate();
|
||||
|
||||
const dayOptions = [
|
||||
{value: 1, text: $gettext('Monday')},
|
||||
{value: 2, text: $gettext('Tuesday')},
|
||||
{value: 3, text: $gettext('Wednesday')},
|
||||
{value: 4, text: $gettext('Thursday')},
|
||||
{value: 5, text: $gettext('Friday')},
|
||||
{value: 6, text: $gettext('Saturday')},
|
||||
{value: 7, text: $gettext('Sunday')}
|
||||
];
|
||||
|
||||
const doRemove = () => {
|
||||
emit('remove');
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
class="text-right text-white-50"
|
||||
>
|
||||
<stations-common-quota
|
||||
ref="quota"
|
||||
ref="$quota"
|
||||
:quota-url="quotaUrl"
|
||||
/>
|
||||
</b-col>
|
||||
|
@ -54,7 +54,7 @@
|
|||
|
||||
<data-table
|
||||
id="station_podcast_episodes"
|
||||
ref="datatable"
|
||||
ref="$datatable"
|
||||
paginated
|
||||
:fields="fields"
|
||||
:responsive="false"
|
||||
|
@ -107,7 +107,7 @@
|
|||
</b-card>
|
||||
|
||||
<edit-modal
|
||||
ref="editEpisodeModal"
|
||||
ref="$editEpisodeModal"
|
||||
:create-url="podcast.links.episodes"
|
||||
:station-time-zone="stationTimeZone"
|
||||
:new-art-url="podcast.links.episode_new_art"
|
||||
|
@ -118,68 +118,77 @@
|
|||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import DataTable from '~/components/Common/DataTable';
|
||||
import EditModal from './EpisodeEditModal';
|
||||
import Icon from '~/components/Common/Icon';
|
||||
import AlbumArt from '~/components/Common/AlbumArt';
|
||||
import StationsCommonQuota from "~/components/Stations/Common/Quota";
|
||||
import episodesViewProps from "~/components/Stations/Podcasts/episodesViewProps";
|
||||
import {useTranslate} from "~/vendor/gettext";
|
||||
import {ref} from "vue";
|
||||
import {useSweetAlert} from "~/vendor/sweetalert";
|
||||
import {useNotify} from "~/vendor/bootstrapVue";
|
||||
import {useAxios} from "~/vendor/axios";
|
||||
|
||||
/* TODO Options API */
|
||||
const props = defineProps({
|
||||
...episodesViewProps,
|
||||
podcast: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
export default {
|
||||
name: 'EpisodesView',
|
||||
components: {StationsCommonQuota, AlbumArt, Icon, EditModal, DataTable},
|
||||
props: {
|
||||
...episodesViewProps,
|
||||
podcast: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
emits: ['clear-podcast'],
|
||||
data() {
|
||||
return {
|
||||
fields: [
|
||||
{key: 'art', label: this.$gettext('Art'), sortable: false, class: 'shrink pr-0'},
|
||||
{key: 'title', label: this.$gettext('Episode'), sortable: false},
|
||||
{key: 'podcast_media', label: this.$gettext('File Name'), sortable: false},
|
||||
{key: 'explicit', label: this.$gettext('Explicit'), sortable: false},
|
||||
{key: 'actions', label: this.$gettext('Actions'), sortable: false, class: 'shrink'}
|
||||
]
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
relist () {
|
||||
this.$refs.quota.update();
|
||||
if (this.$refs.datatable) {
|
||||
this.$refs.datatable.refresh();
|
||||
}
|
||||
},
|
||||
doCreate () {
|
||||
this.$refs.editEpisodeModal.create();
|
||||
},
|
||||
doEdit (url) {
|
||||
this.$refs.editEpisodeModal.edit(url);
|
||||
},
|
||||
doClearPodcast () {
|
||||
this.$emit('clear-podcast');
|
||||
},
|
||||
doDelete (url) {
|
||||
this.$confirmDelete({
|
||||
title: this.$gettext('Delete Episode?'),
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
this.$wrapWithLoading(
|
||||
this.axios.delete(url)
|
||||
).then((resp) => {
|
||||
this.$notifySuccess(resp.data.message);
|
||||
this.relist();
|
||||
});
|
||||
}
|
||||
const emit = defineEmits(['clear-podcast']);
|
||||
|
||||
const {$gettext} = useTranslate();
|
||||
|
||||
const fields = [
|
||||
{key: 'art', label: $gettext('Art'), sortable: false, class: 'shrink pr-0'},
|
||||
{key: 'title', label: $gettext('Episode'), sortable: false},
|
||||
{key: 'podcast_media', label: $gettext('File Name'), sortable: false},
|
||||
{key: 'explicit', label: $gettext('Explicit'), sortable: false},
|
||||
{key: 'actions', label: $gettext('Actions'), sortable: false, class: 'shrink'}
|
||||
];
|
||||
|
||||
const $quota = ref(); // Template Ref
|
||||
const $datatable = ref(); // Template Ref
|
||||
|
||||
const relist = () => {
|
||||
$quota.value.update();
|
||||
$datatable.value?.refresh();
|
||||
};
|
||||
|
||||
const $editEpisodeModal = ref(); // Template Ref
|
||||
|
||||
const doCreate = () => {
|
||||
$editEpisodeModal.value.create();
|
||||
};
|
||||
|
||||
const doEdit = (url) => {
|
||||
$editEpisodeModal.value.edit(url);
|
||||
};
|
||||
|
||||
const doClearPodcast = () => {
|
||||
emit('clear-podcast');
|
||||
};
|
||||
|
||||
const {confirmDelete} = useSweetAlert();
|
||||
const {wrapWithLoading, notifySuccess} = useNotify();
|
||||
const {axios} = useAxios();
|
||||
|
||||
const doDelete = (url) => {
|
||||
confirmDelete({
|
||||
title: $gettext('Delete Episode?'),
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
wrapWithLoading(
|
||||
axios.delete(url)
|
||||
).then((resp) => {
|
||||
notifySuccess(resp.data.message);
|
||||
relist();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
class="text-right text-white-50"
|
||||
>
|
||||
<stations-common-quota
|
||||
ref="quota"
|
||||
ref="$quota"
|
||||
:quota-url="quotaUrl"
|
||||
/>
|
||||
</b-col>
|
||||
|
@ -36,7 +36,7 @@
|
|||
|
||||
<data-table
|
||||
id="station_podcasts"
|
||||
ref="datatable"
|
||||
ref="$datatable"
|
||||
paginated
|
||||
:fields="fields"
|
||||
:responsive="false"
|
||||
|
@ -58,9 +58,6 @@
|
|||
target="_blank"
|
||||
>{{ $gettext('RSS Feed') }}</a>
|
||||
</template>
|
||||
<template #cell(num_episodes)="row">
|
||||
{{ countEpisodes(row.item.episodes) }}
|
||||
</template>
|
||||
<template #cell(actions)="row">
|
||||
<b-button-group size="sm">
|
||||
<b-button
|
||||
|
@ -90,7 +87,7 @@
|
|||
</b-card>
|
||||
|
||||
<edit-modal
|
||||
ref="editPodcastModal"
|
||||
ref="$editPodcastModal"
|
||||
:create-url="listUrl"
|
||||
:station-time-zone="stationTimeZone"
|
||||
:new-art-url="newArtUrl"
|
||||
|
@ -100,65 +97,78 @@
|
|||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import DataTable from '~/components/Common/DataTable';
|
||||
import EditModal from './PodcastEditModal';
|
||||
import AlbumArt from '~/components/Common/AlbumArt';
|
||||
import StationsCommonQuota from "~/components/Stations/Common/Quota";
|
||||
import listViewProps from "./listViewProps";
|
||||
import {useTranslate} from "~/vendor/gettext";
|
||||
import {ref} from "vue";
|
||||
import {useSweetAlert} from "~/vendor/sweetalert";
|
||||
import {useNotify} from "~/vendor/bootstrapVue";
|
||||
import {useAxios} from "~/vendor/axios";
|
||||
|
||||
/* TODO Options API */
|
||||
const props = defineProps({
|
||||
...listViewProps
|
||||
});
|
||||
|
||||
export default {
|
||||
name: 'ListView',
|
||||
components: {StationsCommonQuota, AlbumArt, EditModal, DataTable},
|
||||
props: {
|
||||
...listViewProps
|
||||
const emit = defineEmits(['select-podcast']);
|
||||
|
||||
const {$gettext} = useTranslate();
|
||||
|
||||
const fields = [
|
||||
{key: 'art', label: $gettext('Art'), sortable: false, class: 'shrink pr-0'},
|
||||
{key: 'title', label: $gettext('Podcast'), sortable: false},
|
||||
{
|
||||
key: 'episodes',
|
||||
label: $gettext('# Episodes'),
|
||||
sortable: false,
|
||||
formatter: (val) => {
|
||||
return val.length;
|
||||
}
|
||||
},
|
||||
emits: ['select-podcast'],
|
||||
data() {
|
||||
return {
|
||||
fields: [
|
||||
{key: 'art', label: this.$gettext('Art'), sortable: false, class: 'shrink pr-0'},
|
||||
{key: 'title', label: this.$gettext('Podcast'), sortable: false},
|
||||
{key: 'num_episodes', label: this.$gettext('# Episodes'), sortable: false},
|
||||
{key: 'actions', label: this.$gettext('Actions'), sortable: false, class: 'shrink'}
|
||||
]
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
countEpisodes (episodes) {
|
||||
return episodes.length;
|
||||
},
|
||||
relist () {
|
||||
this.$refs.quota.update();
|
||||
if (this.$refs.datatable) {
|
||||
this.$refs.datatable.refresh();
|
||||
}
|
||||
},
|
||||
doCreate () {
|
||||
this.$refs.editPodcastModal.create();
|
||||
},
|
||||
doEdit (url) {
|
||||
this.$refs.editPodcastModal.edit(url);
|
||||
},
|
||||
doSelectPodcast (podcast) {
|
||||
this.$emit('select-podcast', podcast);
|
||||
},
|
||||
doDelete (url) {
|
||||
this.$confirmDelete({
|
||||
title: this.$gettext('Delete Podcast?'),
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
this.$wrapWithLoading(
|
||||
this.axios.delete(url)
|
||||
).then((resp) => {
|
||||
this.$notifySuccess(resp.data.message);
|
||||
this.relist();
|
||||
});
|
||||
}
|
||||
{key: 'actions', label: $gettext('Actions'), sortable: false, class: 'shrink'}
|
||||
];
|
||||
|
||||
const $quota = ref(); // Template Ref
|
||||
const $datatable = ref(); // Template Ref
|
||||
|
||||
const relist = () => {
|
||||
$quota.value.update();
|
||||
$datatable.value?.refresh();
|
||||
};
|
||||
|
||||
const $editPodcastModal = ref(); // Template Ref
|
||||
|
||||
const doCreate = () => {
|
||||
$editPodcastModal.value.create();
|
||||
};
|
||||
|
||||
const doEdit = (url) => {
|
||||
$editPodcastModal.value.edit(url);
|
||||
};
|
||||
|
||||
const doSelectPodcast = (podcast) => {
|
||||
emit('select-podcast', podcast);
|
||||
};
|
||||
|
||||
const {confirmDelete} = useSweetAlert();
|
||||
const {wrapWithLoading, notifySuccess} = useNotify();
|
||||
const {axios} = useAxios();
|
||||
|
||||
const doDelete = (url) => {
|
||||
confirmDelete({
|
||||
title: $gettext('Delete Podcast?'),
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
wrapWithLoading(
|
||||
axios.delete(url)
|
||||
).then((resp) => {
|
||||
notifySuccess(resp.data.message);
|
||||
relist();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -132,74 +132,57 @@
|
|||
</b-tab>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
<script setup>
|
||||
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
|
||||
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
|
||||
import {map} from "lodash";
|
||||
import {computed} from "vue";
|
||||
|
||||
/* TODO Options API */
|
||||
|
||||
export default {
|
||||
name: 'RemoteFormAutoDj',
|
||||
components: {BWrappedFormCheckbox, BWrappedFormGroup},
|
||||
props: {
|
||||
form: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
stationFrontendType: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
const props = defineProps({
|
||||
form: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
computed: {
|
||||
formatOptions() {
|
||||
return [
|
||||
{
|
||||
value: 'mp3',
|
||||
text: 'MP3'
|
||||
},
|
||||
{
|
||||
value: 'ogg',
|
||||
text: 'OGG Vorbis'
|
||||
},
|
||||
{
|
||||
value: 'opus',
|
||||
text: 'OGG Opus'
|
||||
},
|
||||
{
|
||||
value: 'aac',
|
||||
text: 'AAC+ (MPEG4 HE-AAC v2)'
|
||||
},
|
||||
{
|
||||
value: 'flac',
|
||||
text: 'FLAC (OGG FLAC)'
|
||||
}
|
||||
];
|
||||
},
|
||||
bitrateOptions() {
|
||||
let options = [];
|
||||
[32, 48, 64, 96, 128, 192, 256, 320].forEach((val) => {
|
||||
options.push({
|
||||
value: val,
|
||||
text: val
|
||||
});
|
||||
});
|
||||
return options;
|
||||
},
|
||||
formatSupportsBitrateOptions() {
|
||||
switch (this.form.autodj_format.$model) {
|
||||
case 'flac':
|
||||
return false;
|
||||
|
||||
case 'mp3':
|
||||
case 'ogg':
|
||||
case 'opus':
|
||||
case 'aac':
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
stationFrontendType: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const formatOptions = [
|
||||
{
|
||||
value: 'mp3',
|
||||
text: 'MP3'
|
||||
},
|
||||
{
|
||||
value: 'ogg',
|
||||
text: 'OGG Vorbis'
|
||||
},
|
||||
{
|
||||
value: 'opus',
|
||||
text: 'OGG Opus'
|
||||
},
|
||||
{
|
||||
value: 'aac',
|
||||
text: 'AAC+ (MPEG4 HE-AAC v2)'
|
||||
},
|
||||
{
|
||||
value: 'flac',
|
||||
text: 'FLAC (OGG FLAC)'
|
||||
}
|
||||
];
|
||||
|
||||
const bitrateOptions = map(
|
||||
[32, 48, 64, 96, 128, 192, 256, 320],
|
||||
(val) => {
|
||||
return {
|
||||
value: val,
|
||||
text: val
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
const formatSupportsBitrateOptions = computed(() => {
|
||||
return props.form.autodj_format.$model !== 'flac';
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -103,39 +103,30 @@
|
|||
</b-tab>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import {REMOTE_ICECAST, REMOTE_SHOUTCAST1, REMOTE_SHOUTCAST2} from '~/components/Entity/RadioAdapters';
|
||||
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
|
||||
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
|
||||
|
||||
/* TODO Options API */
|
||||
|
||||
export default {
|
||||
name: 'RemoteFormBasicInfo',
|
||||
components: {BWrappedFormCheckbox, BWrappedFormGroup},
|
||||
props: {
|
||||
form: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
typeOptions() {
|
||||
return [
|
||||
{
|
||||
value: REMOTE_ICECAST,
|
||||
text: 'Icecast v2.4+',
|
||||
},
|
||||
{
|
||||
value: REMOTE_SHOUTCAST1,
|
||||
text: 'Shoutcast v1',
|
||||
},
|
||||
{
|
||||
value: REMOTE_SHOUTCAST2,
|
||||
text: 'Shoutcast v2',
|
||||
}
|
||||
];
|
||||
},
|
||||
const props = defineProps({
|
||||
form: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const typeOptions = [
|
||||
{
|
||||
value: REMOTE_ICECAST,
|
||||
text: 'Icecast v2.4+',
|
||||
},
|
||||
{
|
||||
value: REMOTE_SHOUTCAST1,
|
||||
text: 'Shoutcast v1',
|
||||
},
|
||||
{
|
||||
value: REMOTE_SHOUTCAST2,
|
||||
text: 'Shoutcast v2',
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
|
|
@ -86,6 +86,7 @@ import {computed, ref} from "vue";
|
|||
import {useTranslate} from "~/vendor/gettext";
|
||||
import {useSweetAlert} from "~/vendor/sweetalert";
|
||||
import {useNotify} from "~/vendor/bootstrapVue";
|
||||
import {useAxios} from "~/vendor/axios";
|
||||
|
||||
const props = defineProps({
|
||||
listUrl: {
|
||||
|
@ -150,6 +151,7 @@ const formatTime = (time) => {
|
|||
|
||||
const {confirmDelete} = useSweetAlert();
|
||||
const {wrapWithLoading, notifySuccess} = useNotify();
|
||||
const {axios} = useAxios();
|
||||
|
||||
const doDelete = (url) => {
|
||||
confirmDelete({
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
<b-wrapped-form-group
|
||||
id="form_start_date"
|
||||
name="start_date"
|
||||
:field="v$.form.start_date"
|
||||
:field="v$.start_date"
|
||||
input-type="date"
|
||||
>
|
||||
<template #label>
|
||||
|
@ -75,7 +75,7 @@
|
|||
<b-wrapped-form-group
|
||||
id="form_end_date"
|
||||
name="end_date"
|
||||
:field="v$.form.end_date"
|
||||
:field="v$.end_date"
|
||||
input-type="date"
|
||||
>
|
||||
<template #label>
|
||||
|
@ -86,7 +86,7 @@
|
|||
<b-wrapped-form-checkbox
|
||||
id="form_edit_fetch_isrc"
|
||||
name="fetch_isrc"
|
||||
:field="v$.form.fetch_isrc"
|
||||
:field="v$.fetch_isrc"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Attempt to Automatically Retrieve ISRC When Missing') }}
|
||||
|
@ -102,7 +102,7 @@
|
|||
<b-button
|
||||
type="submit"
|
||||
size="lg"
|
||||
:variant="(v$.form.$invalid) ? 'danger' : 'primary'"
|
||||
:variant="(v$.$invalid) ? 'danger' : 'primary'"
|
||||
class="mt-2"
|
||||
>
|
||||
{{ $gettext('Generate Report') }}
|
||||
|
@ -112,52 +112,38 @@
|
|||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import useVuelidate from "@vuelidate/core";
|
||||
<script setup>
|
||||
import {required} from '@vuelidate/validators';
|
||||
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
|
||||
import BFormFieldset from "~/components/Form/BFormFieldset";
|
||||
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
|
||||
import {useVuelidateOnForm} from "~/functions/useVuelidateOnForm";
|
||||
|
||||
/* TODO Options API */
|
||||
|
||||
export default {
|
||||
name: 'StationsReportsSoundExchange',
|
||||
components: {BWrappedFormGroup, BFormFieldset, BWrappedFormCheckbox},
|
||||
props: {
|
||||
apiUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
startDate: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
endDate: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
const props = defineProps({
|
||||
apiUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
setup() {
|
||||
return {v$: useVuelidate()}
|
||||
startDate: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
validations() {
|
||||
return {
|
||||
form: {
|
||||
start_date: {required},
|
||||
end_date: {required},
|
||||
fetch_isrc: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
start_date: this.startDate,
|
||||
end_date: this.endDate,
|
||||
fetch_isrc: false
|
||||
}
|
||||
}
|
||||
endDate: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const {v$} = useVuelidateOnForm(
|
||||
{
|
||||
start_date: {required},
|
||||
end_date: {required},
|
||||
fetch_isrc: {}
|
||||
},
|
||||
{
|
||||
start_date: props.startDate,
|
||||
end_date: props.endDate,
|
||||
fetch_isrc: false
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
size="sm"
|
||||
variant="outline-light"
|
||||
class="py-2 pr-0"
|
||||
@click.prevent="$emit('remove')"
|
||||
@click.prevent="doRemove()"
|
||||
>
|
||||
<icon icon="remove" />
|
||||
{{ $gettext('Remove') }}
|
||||
|
@ -27,7 +27,7 @@
|
|||
<b-wrapped-form-group
|
||||
:id="'edit_form_start_time_'+index"
|
||||
class="col-md-4"
|
||||
:field="v$.row.start_time"
|
||||
:field="v$.start_time"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Start Time') }}
|
||||
|
@ -44,7 +44,7 @@
|
|||
<b-wrapped-form-group
|
||||
:id="'edit_form_end_time_'+index"
|
||||
class="col-md-4"
|
||||
:field="v$.row.end_time"
|
||||
:field="v$.end_time"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('End Time') }}
|
||||
|
@ -78,7 +78,7 @@
|
|||
<b-wrapped-form-group
|
||||
:id="'edit_form_start_date_'+index"
|
||||
class="col-md-4"
|
||||
:field="v$.row.start_date"
|
||||
:field="v$.start_date"
|
||||
input-type="date"
|
||||
>
|
||||
<template #label>
|
||||
|
@ -94,7 +94,7 @@
|
|||
<b-wrapped-form-group
|
||||
:id="'edit_form_end_date_'+index"
|
||||
class="col-md-4"
|
||||
:field="v$.row.end_date"
|
||||
:field="v$.end_date"
|
||||
input-type="date"
|
||||
>
|
||||
<template #label>
|
||||
|
@ -105,7 +105,7 @@
|
|||
<b-wrapped-form-group
|
||||
:id="'edit_form_days_'+index"
|
||||
class="col-md-4"
|
||||
:field="v$.row.days"
|
||||
:field="v$.days"
|
||||
>
|
||||
<template #label>
|
||||
{{ $gettext('Scheduled Play Days of Week') }}
|
||||
|
@ -128,57 +128,56 @@
|
|||
</b-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import PlaylistTime from '~/components/Common/TimeCode';
|
||||
import Icon from "~/components/Common/Icon.vue";
|
||||
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
|
||||
import {required} from "@vuelidate/validators";
|
||||
import useVuelidate from "@vuelidate/core";
|
||||
import {toRef} from "vue";
|
||||
import {useTranslate} from "~/vendor/gettext";
|
||||
|
||||
/* TODO Options API */
|
||||
const props = defineProps({
|
||||
index: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
row: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
stationTimeZone: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
});
|
||||
|
||||
export default {
|
||||
name: 'StreamersFormScheduleRow',
|
||||
components: {BWrappedFormGroup, Icon, PlaylistTime},
|
||||
props: {
|
||||
index: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
row: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
stationTimeZone: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
const emit = defineEmits(['remove']);
|
||||
|
||||
const v$ = useVuelidate(
|
||||
{
|
||||
'start_time': {required},
|
||||
'end_time': {required},
|
||||
'start_date': {},
|
||||
'end_date': {},
|
||||
'days': {}
|
||||
},
|
||||
emits: ['remove'],
|
||||
setup() {
|
||||
return {v$: useVuelidate()}
|
||||
},
|
||||
validations: {
|
||||
row: {
|
||||
'start_time': {required},
|
||||
'end_time': {required},
|
||||
'start_date': {},
|
||||
'end_date': {},
|
||||
'days': {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dayOptions: [
|
||||
{value: 1, text: this.$gettext('Monday')},
|
||||
{value: 2, text: this.$gettext('Tuesday')},
|
||||
{value: 3, text: this.$gettext('Wednesday')},
|
||||
{value: 4, text: this.$gettext('Thursday')},
|
||||
{value: 5, text: this.$gettext('Friday')},
|
||||
{value: 6, text: this.$gettext('Saturday')},
|
||||
{value: 7, text: this.$gettext('Sunday')}
|
||||
]
|
||||
};
|
||||
},
|
||||
}
|
||||
toRef(props, 'row')
|
||||
);
|
||||
|
||||
const {$gettext} = useTranslate();
|
||||
|
||||
const dayOptions = [
|
||||
{value: 1, text: $gettext('Monday')},
|
||||
{value: 2, text: $gettext('Tuesday')},
|
||||
{value: 3, text: $gettext('Wednesday')},
|
||||
{value: 4, text: $gettext('Thursday')},
|
||||
{value: 5, text: $gettext('Friday')},
|
||||
{value: 6, text: $gettext('Saturday')},
|
||||
{value: 7, text: $gettext('Sunday')}
|
||||
];
|
||||
|
||||
const doRemove = () => {
|
||||
emit('remove');
|
||||
};
|
||||
</script>
|
||||
|
|
Loading…
Reference in New Issue