More Composition conversion and fixes.

This commit is contained in:
Buster Neece 2023-01-07 10:04:08 -06:00
parent 1ef68f64fc
commit e0f5178ba4
No known key found for this signature in database
GPG Key ID: F1D2E64A0005E80E
10 changed files with 535 additions and 540 deletions

View File

@ -106,4 +106,8 @@ const update = () => {
} }
onMounted(update); onMounted(update);
defineExpose({
update
});
</script> </script>

View File

@ -6,7 +6,7 @@
<div class="col-md-8 buttons"> <div class="col-md-8 buttons">
<div class="btn-group dropdown allow-focus"> <div class="btn-group dropdown allow-focus">
<b-dropdown <b-dropdown
ref="setPlaylistsDropdown" ref="$setPlaylistsDropdown"
v-b-tooltip.hover v-b-tooltip.hover
size="sm" size="sm"
variant="primary" variant="primary"
@ -69,21 +69,23 @@
</div> </div>
</div> </div>
<b-button <div class="buttons">
type="submit" <b-button
size="sm" type="submit"
variant="primary" size="sm"
> variant="primary"
{{ $gettext('Save') }} >
</b-button> {{ $gettext('Save') }}
<b-button </b-button>
type="button" <b-button
size="sm" type="button"
variant="warning" size="sm"
@click="clearPlaylists()" variant="warning"
> @click="clearPlaylists()"
{{ $gettext('Clear') }} >
</b-button> {{ $gettext('Clear') }}
</b-button>
</div>
</b-dropdown-form> </b-dropdown-form>
</b-dropdown> </b-dropdown>
</div> </div>
@ -148,188 +150,200 @@
</div> </div>
</div> </div>
</template> </template>
<script>
<script setup>
import {forEach, intersection, map} from 'lodash'; import {forEach, intersection, map} from 'lodash';
import Icon from '~/components/Common/Icon'; import Icon from '~/components/Common/Icon';
import '~/vendor/sweetalert'; 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 */ const props = defineProps({
currentDirectory: {
export default { type: String,
name: 'StationMediaToolbar', required: true
components: {Icon}, },
props: { selectedItems: {
currentDirectory: { type: Object,
type: String, required: true
required: true },
}, playlists: {
selectedItems: { type: Array,
type: Object, default: () => {
required: true return [];
},
playlists: {
type: Array,
default: () => {
return [];
}
},
batchUrl: {
type: String,
required: true
},
supportsImmediateQueue: {
type: Boolean,
required: true
} }
}, },
emits: ['relist', 'add-playlist'], batchUrl: {
data() { type: String,
return { required: true
checkedPlaylists: [],
newPlaylist: '',
};
}, },
computed: { supportsImmediateQueue: {
langErrors() { type: Boolean,
return this.$gettext('The request could not be processed.'); required: true
}, }
}, });
watch: {
selectedItems (items) {
// Get all playlists that are active on ALL selected items.
let playlistsForItems = map(items.all, (item) => {
return map(item.playlists, 'id');
});
// Check the checkboxes for those playlists. const emit = defineEmits(['relist', 'add-playlist']);
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;
this.$confirmDelete({ const checkedPlaylists = ref([]);
title: this.$gettextInterpolate(buttonConfirmText, {num: numFiles}), const newPlaylist = ref('');
}).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));
});
this.$notifySuccess(allItemNodes, { const {$gettext} = useTranslate();
title: notifyMessage const langErrors = $gettext('The request could not be processed.');
});
} else {
let errorNodes = [];
forEach(resp.data.errors, (error) => {
errorNodes.push(this.$createElement('div', {}, error));
});
this.$notifyError(errorNodes, { watch(toRef(props, 'selectedItems'), (items) => {
title: this.langErrors // Get all playlists that are active on ALL selected items.
}); let playlistsForItems = map(items.all, (item) => {
} return map(item.playlists, 'id');
});
this.$emit('relist'); // Check the checkboxes for those playlists.
}); checkedPlaylists.value = intersection(...playlistsForItems);
} else { });
this.notifyNoFiles();
}
},
clearPlaylists () {
this.checkedPlaylists = [];
this.newPlaylist = '';
this.setPlaylists(); watch(newPlaylist, (text) => {
}, if (text !== '') {
setPlaylists () { if (!checkedPlaylists.value.includes('new')) {
this.$refs.setPlaylistsDropdown.hide(); checkedPlaylists.value.push('new');
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.'));
} }
} }
});
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> </script>

View File

@ -14,7 +14,7 @@
size="sm" size="sm"
variant="outline-light" variant="outline-light"
class="py-2 pr-0" class="py-2 pr-0"
@click.prevent="$emit('remove')" @click.prevent="doRemove()"
> >
<icon icon="remove" /> <icon icon="remove" />
{{ $gettext('Remove') }} {{ $gettext('Remove') }}
@ -27,7 +27,7 @@
<b-wrapped-form-group <b-wrapped-form-group
:id="'edit_form_start_time_'+index" :id="'edit_form_start_time_'+index"
class="col-md-4" class="col-md-4"
:field="v$.row.start_time" :field="v$.start_time"
> >
<template #label> <template #label>
{{ $gettext('Start Time') }} {{ $gettext('Start Time') }}
@ -47,7 +47,7 @@
<b-wrapped-form-group <b-wrapped-form-group
:id="'edit_form_end_time_'+index" :id="'edit_form_end_time_'+index"
class="col-md-4" class="col-md-4"
:field="v$.row.end_time" :field="v$.end_time"
> >
<template #label> <template #label>
{{ $gettext('End Time') }} {{ $gettext('End Time') }}
@ -81,7 +81,7 @@
<b-wrapped-form-group <b-wrapped-form-group
:id="'edit_form_start_date_'+index" :id="'edit_form_start_date_'+index"
class="col-md-4" class="col-md-4"
:field="v$.row.start_date" :field="v$.start_date"
> >
<template #label> <template #label>
{{ $gettext('Start Date') }} {{ $gettext('Start Date') }}
@ -104,7 +104,7 @@
<b-wrapped-form-group <b-wrapped-form-group
:id="'edit_form_end_date_'+index" :id="'edit_form_end_date_'+index"
class="col-md-4" class="col-md-4"
:field="v$.row.end_date" :field="v$.end_date"
> >
<template #label> <template #label>
{{ $gettext('End Date') }} {{ $gettext('End Date') }}
@ -122,7 +122,7 @@
<b-wrapped-form-checkbox <b-wrapped-form-checkbox
:id="'edit_form_loop_once_'+index" :id="'edit_form_loop_once_'+index"
class="col-md-4" class="col-md-4"
:field="v$.row.loop_once" :field="v$.loop_once"
> >
<template #label> <template #label>
{{ $gettext('Loop Once') }} {{ $gettext('Loop Once') }}
@ -146,7 +146,7 @@
<template #default> <template #default>
<b-checkbox-group <b-checkbox-group
:id="'edit_form_days_'+index" :id="'edit_form_days_'+index"
v-model="v$.row.days.$model" v-model="v$.days.$model"
stacked stacked
:options="dayOptions" :options="dayOptions"
/> />
@ -158,59 +158,56 @@
</b-card> </b-card>
</template> </template>
<script> <script setup>
import PlaylistTime from '~/components/Common/TimeCode'; import PlaylistTime from '~/components/Common/TimeCode';
import Icon from "~/components/Common/Icon.vue"; import Icon from "~/components/Common/Icon.vue";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue"; import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import {required} from "@vuelidate/validators"; import {required} from "@vuelidate/validators";
import useVuelidate from "@vuelidate/core"; 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 { const emit = defineEmits(['remove']);
name: 'PlaylistsFormScheduleRow',
components: {BWrappedFormCheckbox, BWrappedFormGroup, Icon, PlaylistTime}, const v$ = useVuelidate(
props: { {
index: { 'start_time': {required},
type: Number, 'end_time': {required},
required: true 'start_date': {},
}, 'end_date': {},
row: { 'loop_once': {}
type: Object,
required: true
},
stationTimeZone: {
type: String,
required: true
},
}, },
emits: ['remove'], toRef(props, 'row')
setup() { );
return {v$: useVuelidate()}
}, const {$gettext} = useTranslate();
validations: {
row: { const dayOptions = [
'start_time': {required}, {value: 1, text: $gettext('Monday')},
'end_time': {required}, {value: 2, text: $gettext('Tuesday')},
'start_date': {}, {value: 3, text: $gettext('Wednesday')},
'end_date': {}, {value: 4, text: $gettext('Thursday')},
'days': {}, {value: 5, text: $gettext('Friday')},
'loop_once': {} {value: 6, text: $gettext('Saturday')},
} {value: 7, text: $gettext('Sunday')}
}, ];
data() {
return { const doRemove = () => {
dayOptions: [ emit('remove');
{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')}
]
};
},
}
</script> </script>

View File

@ -22,7 +22,7 @@
class="text-right text-white-50" class="text-right text-white-50"
> >
<stations-common-quota <stations-common-quota
ref="quota" ref="$quota"
:quota-url="quotaUrl" :quota-url="quotaUrl"
/> />
</b-col> </b-col>
@ -54,7 +54,7 @@
<data-table <data-table
id="station_podcast_episodes" id="station_podcast_episodes"
ref="datatable" ref="$datatable"
paginated paginated
:fields="fields" :fields="fields"
:responsive="false" :responsive="false"
@ -107,7 +107,7 @@
</b-card> </b-card>
<edit-modal <edit-modal
ref="editEpisodeModal" ref="$editEpisodeModal"
:create-url="podcast.links.episodes" :create-url="podcast.links.episodes"
:station-time-zone="stationTimeZone" :station-time-zone="stationTimeZone"
:new-art-url="podcast.links.episode_new_art" :new-art-url="podcast.links.episode_new_art"
@ -118,68 +118,77 @@
/> />
</template> </template>
<script> <script setup>
import DataTable from '~/components/Common/DataTable'; import DataTable from '~/components/Common/DataTable';
import EditModal from './EpisodeEditModal'; import EditModal from './EpisodeEditModal';
import Icon from '~/components/Common/Icon'; import Icon from '~/components/Common/Icon';
import AlbumArt from '~/components/Common/AlbumArt'; import AlbumArt from '~/components/Common/AlbumArt';
import StationsCommonQuota from "~/components/Stations/Common/Quota"; import StationsCommonQuota from "~/components/Stations/Common/Quota";
import episodesViewProps from "~/components/Stations/Podcasts/episodesViewProps"; 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 { const emit = defineEmits(['clear-podcast']);
name: 'EpisodesView',
components: {StationsCommonQuota, AlbumArt, Icon, EditModal, DataTable}, const {$gettext} = useTranslate();
props: {
...episodesViewProps, const fields = [
podcast: { {key: 'art', label: $gettext('Art'), sortable: false, class: 'shrink pr-0'},
type: Object, {key: 'title', label: $gettext('Episode'), sortable: false},
required: true {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'}
emits: ['clear-podcast'], ];
data() {
return { const $quota = ref(); // Template Ref
fields: [ const $datatable = ref(); // Template Ref
{key: 'art', label: this.$gettext('Art'), sortable: false, class: 'shrink pr-0'},
{key: 'title', label: this.$gettext('Episode'), sortable: false}, const relist = () => {
{key: 'podcast_media', label: this.$gettext('File Name'), sortable: false}, $quota.value.update();
{key: 'explicit', label: this.$gettext('Explicit'), sortable: false}, $datatable.value?.refresh();
{key: 'actions', label: this.$gettext('Actions'), sortable: false, class: 'shrink'} };
]
}; const $editEpisodeModal = ref(); // Template Ref
},
methods: { const doCreate = () => {
relist () { $editEpisodeModal.value.create();
this.$refs.quota.update(); };
if (this.$refs.datatable) {
this.$refs.datatable.refresh(); const doEdit = (url) => {
} $editEpisodeModal.value.edit(url);
}, };
doCreate () {
this.$refs.editEpisodeModal.create(); const doClearPodcast = () => {
}, emit('clear-podcast');
doEdit (url) { };
this.$refs.editEpisodeModal.edit(url);
}, const {confirmDelete} = useSweetAlert();
doClearPodcast () { const {wrapWithLoading, notifySuccess} = useNotify();
this.$emit('clear-podcast'); const {axios} = useAxios();
},
doDelete (url) { const doDelete = (url) => {
this.$confirmDelete({ confirmDelete({
title: this.$gettext('Delete Episode?'), title: $gettext('Delete Episode?'),
}).then((result) => { }).then((result) => {
if (result.value) { if (result.value) {
this.$wrapWithLoading( wrapWithLoading(
this.axios.delete(url) axios.delete(url)
).then((resp) => { ).then((resp) => {
this.$notifySuccess(resp.data.message); notifySuccess(resp.data.message);
this.relist(); relist();
});
}
}); });
} }
} });
}; };
</script> </script>

View File

@ -12,7 +12,7 @@
class="text-right text-white-50" class="text-right text-white-50"
> >
<stations-common-quota <stations-common-quota
ref="quota" ref="$quota"
:quota-url="quotaUrl" :quota-url="quotaUrl"
/> />
</b-col> </b-col>
@ -36,7 +36,7 @@
<data-table <data-table
id="station_podcasts" id="station_podcasts"
ref="datatable" ref="$datatable"
paginated paginated
:fields="fields" :fields="fields"
:responsive="false" :responsive="false"
@ -58,9 +58,6 @@
target="_blank" target="_blank"
>{{ $gettext('RSS Feed') }}</a> >{{ $gettext('RSS Feed') }}</a>
</template> </template>
<template #cell(num_episodes)="row">
{{ countEpisodes(row.item.episodes) }}
</template>
<template #cell(actions)="row"> <template #cell(actions)="row">
<b-button-group size="sm"> <b-button-group size="sm">
<b-button <b-button
@ -90,7 +87,7 @@
</b-card> </b-card>
<edit-modal <edit-modal
ref="editPodcastModal" ref="$editPodcastModal"
:create-url="listUrl" :create-url="listUrl"
:station-time-zone="stationTimeZone" :station-time-zone="stationTimeZone"
:new-art-url="newArtUrl" :new-art-url="newArtUrl"
@ -100,65 +97,78 @@
/> />
</template> </template>
<script> <script setup>
import DataTable from '~/components/Common/DataTable'; import DataTable from '~/components/Common/DataTable';
import EditModal from './PodcastEditModal'; import EditModal from './PodcastEditModal';
import AlbumArt from '~/components/Common/AlbumArt'; import AlbumArt from '~/components/Common/AlbumArt';
import StationsCommonQuota from "~/components/Stations/Common/Quota"; import StationsCommonQuota from "~/components/Stations/Common/Quota";
import listViewProps from "./listViewProps"; 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 { const emit = defineEmits(['select-podcast']);
name: 'ListView',
components: {StationsCommonQuota, AlbumArt, EditModal, DataTable}, const {$gettext} = useTranslate();
props: {
...listViewProps 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'], {key: 'actions', label: $gettext('Actions'), sortable: false, class: 'shrink'}
data() { ];
return {
fields: [ const $quota = ref(); // Template Ref
{key: 'art', label: this.$gettext('Art'), sortable: false, class: 'shrink pr-0'}, const $datatable = ref(); // Template Ref
{key: 'title', label: this.$gettext('Podcast'), sortable: false},
{key: 'num_episodes', label: this.$gettext('# Episodes'), sortable: false}, const relist = () => {
{key: 'actions', label: this.$gettext('Actions'), sortable: false, class: 'shrink'} $quota.value.update();
] $datatable.value?.refresh();
}; };
},
methods: { const $editPodcastModal = ref(); // Template Ref
countEpisodes (episodes) {
return episodes.length; const doCreate = () => {
}, $editPodcastModal.value.create();
relist () { };
this.$refs.quota.update();
if (this.$refs.datatable) { const doEdit = (url) => {
this.$refs.datatable.refresh(); $editPodcastModal.value.edit(url);
} };
},
doCreate () { const doSelectPodcast = (podcast) => {
this.$refs.editPodcastModal.create(); emit('select-podcast', podcast);
}, };
doEdit (url) {
this.$refs.editPodcastModal.edit(url); const {confirmDelete} = useSweetAlert();
}, const {wrapWithLoading, notifySuccess} = useNotify();
doSelectPodcast (podcast) { const {axios} = useAxios();
this.$emit('select-podcast', podcast);
}, const doDelete = (url) => {
doDelete (url) { confirmDelete({
this.$confirmDelete({ title: $gettext('Delete Podcast?'),
title: this.$gettext('Delete Podcast?'), }).then((result) => {
}).then((result) => { if (result.value) {
if (result.value) { wrapWithLoading(
this.$wrapWithLoading( axios.delete(url)
this.axios.delete(url) ).then((resp) => {
).then((resp) => { notifySuccess(resp.data.message);
this.$notifySuccess(resp.data.message); relist();
this.relist();
});
}
}); });
} }
} });
}; };
</script> </script>

View File

@ -132,74 +132,57 @@
</b-tab> </b-tab>
</template> </template>
<script> <script setup>
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup"; import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox"; import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
import {map} from "lodash";
import {computed} from "vue";
/* TODO Options API */ const props = defineProps({
form: {
export default { type: Object,
name: 'RemoteFormAutoDj', required: true
components: {BWrappedFormCheckbox, BWrappedFormGroup},
props: {
form: {
type: Object,
required: true
},
stationFrontendType: {
type: String,
required: true
}
}, },
computed: { stationFrontendType: {
formatOptions() { type: String,
return [ required: true
{
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;
}
}
} }
}; });
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> </script>

View File

@ -103,39 +103,30 @@
</b-tab> </b-tab>
</template> </template>
<script> <script setup>
import {REMOTE_ICECAST, REMOTE_SHOUTCAST1, REMOTE_SHOUTCAST2} from '~/components/Entity/RadioAdapters'; import {REMOTE_ICECAST, REMOTE_SHOUTCAST1, REMOTE_SHOUTCAST2} from '~/components/Entity/RadioAdapters';
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup"; import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox"; import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
/* TODO Options API */ const props = defineProps({
form: {
export default { type: Object,
name: 'RemoteFormBasicInfo', required: true
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 typeOptions = [
{
value: REMOTE_ICECAST,
text: 'Icecast v2.4+',
},
{
value: REMOTE_SHOUTCAST1,
text: 'Shoutcast v1',
},
{
value: REMOTE_SHOUTCAST2,
text: 'Shoutcast v2',
}
];
</script> </script>

View File

@ -86,6 +86,7 @@ import {computed, ref} from "vue";
import {useTranslate} from "~/vendor/gettext"; import {useTranslate} from "~/vendor/gettext";
import {useSweetAlert} from "~/vendor/sweetalert"; import {useSweetAlert} from "~/vendor/sweetalert";
import {useNotify} from "~/vendor/bootstrapVue"; import {useNotify} from "~/vendor/bootstrapVue";
import {useAxios} from "~/vendor/axios";
const props = defineProps({ const props = defineProps({
listUrl: { listUrl: {
@ -150,6 +151,7 @@ const formatTime = (time) => {
const {confirmDelete} = useSweetAlert(); const {confirmDelete} = useSweetAlert();
const {wrapWithLoading, notifySuccess} = useNotify(); const {wrapWithLoading, notifySuccess} = useNotify();
const {axios} = useAxios();
const doDelete = (url) => { const doDelete = (url) => {
confirmDelete({ confirmDelete({

View File

@ -64,7 +64,7 @@
<b-wrapped-form-group <b-wrapped-form-group
id="form_start_date" id="form_start_date"
name="start_date" name="start_date"
:field="v$.form.start_date" :field="v$.start_date"
input-type="date" input-type="date"
> >
<template #label> <template #label>
@ -75,7 +75,7 @@
<b-wrapped-form-group <b-wrapped-form-group
id="form_end_date" id="form_end_date"
name="end_date" name="end_date"
:field="v$.form.end_date" :field="v$.end_date"
input-type="date" input-type="date"
> >
<template #label> <template #label>
@ -86,7 +86,7 @@
<b-wrapped-form-checkbox <b-wrapped-form-checkbox
id="form_edit_fetch_isrc" id="form_edit_fetch_isrc"
name="fetch_isrc" name="fetch_isrc"
:field="v$.form.fetch_isrc" :field="v$.fetch_isrc"
> >
<template #label> <template #label>
{{ $gettext('Attempt to Automatically Retrieve ISRC When Missing') }} {{ $gettext('Attempt to Automatically Retrieve ISRC When Missing') }}
@ -102,7 +102,7 @@
<b-button <b-button
type="submit" type="submit"
size="lg" size="lg"
:variant="(v$.form.$invalid) ? 'danger' : 'primary'" :variant="(v$.$invalid) ? 'danger' : 'primary'"
class="mt-2" class="mt-2"
> >
{{ $gettext('Generate Report') }} {{ $gettext('Generate Report') }}
@ -112,52 +112,38 @@
</section> </section>
</template> </template>
<script> <script setup>
import useVuelidate from "@vuelidate/core";
import {required} from '@vuelidate/validators'; import {required} from '@vuelidate/validators';
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup"; import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
import BFormFieldset from "~/components/Form/BFormFieldset"; import BFormFieldset from "~/components/Form/BFormFieldset";
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox"; import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
import {useVuelidateOnForm} from "~/functions/useVuelidateOnForm";
/* TODO Options API */ const props = defineProps({
apiUrl: {
export default { type: String,
name: 'StationsReportsSoundExchange', required: true
components: {BWrappedFormGroup, BFormFieldset, BWrappedFormCheckbox},
props: {
apiUrl: {
type: String,
required: true
},
startDate: {
type: String,
required: true
},
endDate: {
type: String,
required: true
}
}, },
setup() { startDate: {
return {v$: useVuelidate()} type: String,
required: true
}, },
validations() { endDate: {
return { type: String,
form: { required: true
start_date: {required},
end_date: {required},
fetch_isrc: {}
}
}
},
data() {
return {
form: {
start_date: this.startDate,
end_date: this.endDate,
fetch_isrc: false
}
}
} }
} });
const {v$} = useVuelidateOnForm(
{
start_date: {required},
end_date: {required},
fetch_isrc: {}
},
{
start_date: props.startDate,
end_date: props.endDate,
fetch_isrc: false
}
);
</script> </script>

View File

@ -14,7 +14,7 @@
size="sm" size="sm"
variant="outline-light" variant="outline-light"
class="py-2 pr-0" class="py-2 pr-0"
@click.prevent="$emit('remove')" @click.prevent="doRemove()"
> >
<icon icon="remove" /> <icon icon="remove" />
{{ $gettext('Remove') }} {{ $gettext('Remove') }}
@ -27,7 +27,7 @@
<b-wrapped-form-group <b-wrapped-form-group
:id="'edit_form_start_time_'+index" :id="'edit_form_start_time_'+index"
class="col-md-4" class="col-md-4"
:field="v$.row.start_time" :field="v$.start_time"
> >
<template #label> <template #label>
{{ $gettext('Start Time') }} {{ $gettext('Start Time') }}
@ -44,7 +44,7 @@
<b-wrapped-form-group <b-wrapped-form-group
:id="'edit_form_end_time_'+index" :id="'edit_form_end_time_'+index"
class="col-md-4" class="col-md-4"
:field="v$.row.end_time" :field="v$.end_time"
> >
<template #label> <template #label>
{{ $gettext('End Time') }} {{ $gettext('End Time') }}
@ -78,7 +78,7 @@
<b-wrapped-form-group <b-wrapped-form-group
:id="'edit_form_start_date_'+index" :id="'edit_form_start_date_'+index"
class="col-md-4" class="col-md-4"
:field="v$.row.start_date" :field="v$.start_date"
input-type="date" input-type="date"
> >
<template #label> <template #label>
@ -94,7 +94,7 @@
<b-wrapped-form-group <b-wrapped-form-group
:id="'edit_form_end_date_'+index" :id="'edit_form_end_date_'+index"
class="col-md-4" class="col-md-4"
:field="v$.row.end_date" :field="v$.end_date"
input-type="date" input-type="date"
> >
<template #label> <template #label>
@ -105,7 +105,7 @@
<b-wrapped-form-group <b-wrapped-form-group
:id="'edit_form_days_'+index" :id="'edit_form_days_'+index"
class="col-md-4" class="col-md-4"
:field="v$.row.days" :field="v$.days"
> >
<template #label> <template #label>
{{ $gettext('Scheduled Play Days of Week') }} {{ $gettext('Scheduled Play Days of Week') }}
@ -128,57 +128,56 @@
</b-card> </b-card>
</template> </template>
<script> <script setup>
import PlaylistTime from '~/components/Common/TimeCode'; import PlaylistTime from '~/components/Common/TimeCode';
import Icon from "~/components/Common/Icon.vue"; import Icon from "~/components/Common/Icon.vue";
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue"; import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup.vue";
import {required} from "@vuelidate/validators"; import {required} from "@vuelidate/validators";
import useVuelidate from "@vuelidate/core"; 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 { const emit = defineEmits(['remove']);
name: 'StreamersFormScheduleRow',
components: {BWrappedFormGroup, Icon, PlaylistTime}, const v$ = useVuelidate(
props: { {
index: { 'start_time': {required},
type: Number, 'end_time': {required},
required: true 'start_date': {},
}, 'end_date': {},
row: { 'days': {}
type: Object,
required: true
},
stationTimeZone: {
type: String,
required: true
},
}, },
emits: ['remove'], toRef(props, 'row')
setup() { );
return {v$: useVuelidate()}
}, const {$gettext} = useTranslate();
validations: {
row: { const dayOptions = [
'start_time': {required}, {value: 1, text: $gettext('Monday')},
'end_time': {required}, {value: 2, text: $gettext('Tuesday')},
'start_date': {}, {value: 3, text: $gettext('Wednesday')},
'end_date': {}, {value: 4, text: $gettext('Thursday')},
'days': {} {value: 5, text: $gettext('Friday')},
} {value: 6, text: $gettext('Saturday')},
}, {value: 7, text: $gettext('Sunday')}
data() { ];
return {
dayOptions: [ const doRemove = () => {
{value: 1, text: this.$gettext('Monday')}, emit('remove');
{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')}
]
};
},
}
</script> </script>