Vue fixes and Composition API updates.
This commit is contained in:
parent
10c8069719
commit
f15ef56f6d
|
@ -34,9 +34,6 @@
|
|||
:fields="fields"
|
||||
:api-url="apiUrl"
|
||||
>
|
||||
<template #cell(owner)="row">
|
||||
{{ row.item.user.email }}
|
||||
</template>
|
||||
<template #cell(actions)="row">
|
||||
<b-button-group size="sm">
|
||||
<b-button
|
||||
|
@ -83,7 +80,7 @@ const fields = ref([
|
|||
sortable: false
|
||||
},
|
||||
{
|
||||
key: 'owner',
|
||||
key: 'user.email',
|
||||
label: $gettext('Owner'),
|
||||
sortable: false
|
||||
},
|
||||
|
|
|
@ -112,12 +112,6 @@
|
|||
:fields="fields"
|
||||
:api-url="listUrl"
|
||||
>
|
||||
<template #cell(timestamp)="row">
|
||||
{{ toLocaleTime(row.item.timestamp) }}
|
||||
</template>
|
||||
<template #cell(size)="row">
|
||||
{{ formatFileSize(row.item.size) }}
|
||||
</template>
|
||||
<template #cell(actions)="row">
|
||||
<b-button-group size="sm">
|
||||
<b-button
|
||||
|
@ -211,6 +205,7 @@ const blankSettings = {
|
|||
const settings = ref({...blankSettings});
|
||||
|
||||
const {$gettext} = useTranslate();
|
||||
const {timeConfig} = useAzuraCast();
|
||||
|
||||
const fields = [
|
||||
{
|
||||
|
@ -222,12 +217,18 @@ const fields = [
|
|||
{
|
||||
key: 'timestamp',
|
||||
label: $gettext('Last Modified'),
|
||||
sortable: false
|
||||
sortable: false,
|
||||
formatter: (value) => {
|
||||
return DateTime.fromSeconds(value).toLocaleString(
|
||||
{...DateTime.DATETIME_SHORT, ...timeConfig}
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'size',
|
||||
label: $gettext('Size'),
|
||||
sortable: false
|
||||
sortable: false,
|
||||
formatter: (value) => formatFileSize(value)
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
|
@ -264,14 +265,6 @@ const toRelativeTime = (timestamp) => {
|
|||
return DateTime.fromSeconds(timestamp).toRelative();
|
||||
};
|
||||
|
||||
const toLocaleTime = (timestamp) => {
|
||||
const {timeConfig} = useAzuraCast();
|
||||
|
||||
return DateTime.fromSeconds(timestamp).toLocaleString(
|
||||
{...DateTime.DATETIME_SHORT, ...timeConfig}
|
||||
);
|
||||
};
|
||||
|
||||
const $lastOutputModal = ref(); // AdminBackupsLastOutputModal
|
||||
const showLastOutput = () => {
|
||||
$lastOutputModal.value.show();
|
||||
|
|
|
@ -34,9 +34,6 @@
|
|||
<template #cell(name)="row">
|
||||
{{ row.item.name }} <code>{{ row.item.short_name }}</code>
|
||||
</template>
|
||||
<template #cell(auto_assign)="row">
|
||||
{{ getAutoAssignName(row.item.auto_assign) }}
|
||||
</template>
|
||||
<template #cell(actions)="row">
|
||||
<b-button-group size="sm">
|
||||
<b-button
|
||||
|
@ -92,15 +89,28 @@ const props = defineProps({
|
|||
const {$gettext} = useTranslate();
|
||||
|
||||
const fields = [
|
||||
{key: 'name', isRowHeader: true, label: $gettext('Field Name'), sortable: false},
|
||||
{key: 'auto_assign', label: $gettext('Auto-Assign Value'), sortable: false},
|
||||
{key: 'actions', label: $gettext('Actions'), sortable: false, class: 'shrink'}
|
||||
{
|
||||
key: 'name',
|
||||
isRowHeader: true,
|
||||
label: $gettext('Field Name'),
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
key: 'auto_assign',
|
||||
label: $gettext('Auto-Assign Value'),
|
||||
sortable: false,
|
||||
formatter: (value) => {
|
||||
return get(props.autoAssignTypes, value, $gettext('None'));
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
label: $gettext('Actions'),
|
||||
sortable: false,
|
||||
class: 'shrink'
|
||||
}
|
||||
];
|
||||
|
||||
const getAutoAssignName = (autoAssign) => {
|
||||
return get(props.autoAssignTypes, autoAssign, $gettext('None'));
|
||||
};
|
||||
|
||||
const $dataTable = ref(); // DataTable
|
||||
|
||||
const relist = () => {
|
||||
|
|
|
@ -29,12 +29,6 @@
|
|||
</div>
|
||||
<code>{{ row.item.short_name }}</code>
|
||||
</template>
|
||||
<template #cell(frontend_type)="row">
|
||||
{{ getFrontendName(row.item.frontend_type) }}
|
||||
</template>
|
||||
<template #cell(backend_type)="row">
|
||||
{{ getBackendName(row.item.backend_type) }}
|
||||
</template>
|
||||
<template #cell(actions)="row">
|
||||
<b-button-group size="sm">
|
||||
<b-button
|
||||
|
@ -117,20 +111,36 @@ const props = defineProps({
|
|||
const {$gettext} = useTranslate();
|
||||
|
||||
const fields = [
|
||||
{key: 'name', isRowHeader: true, label: $gettext('Name'), sortable: true},
|
||||
{key: 'frontend_type', label: $gettext('Broadcasting'), sortable: false},
|
||||
{key: 'backend_type', label: $gettext('AutoDJ'), sortable: false},
|
||||
{key: 'actions', label: $gettext('Actions'), sortable: false, class: 'shrink'}
|
||||
{
|
||||
key: 'name',
|
||||
isRowHeader: true,
|
||||
label: $gettext('Name'),
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
key: 'frontend_type',
|
||||
label: $gettext('Broadcasting'),
|
||||
sortable: false,
|
||||
formatter: (value) => {
|
||||
return get(props.frontendTypes, [value, 'name'], '');
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'backend_type',
|
||||
label: $gettext('AutoDJ'),
|
||||
sortable: false,
|
||||
formatter: (value) => {
|
||||
return get(props.backendTypes, [value, 'name'], '');
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
label: $gettext('Actions'),
|
||||
sortable: false,
|
||||
class: 'shrink'
|
||||
}
|
||||
];
|
||||
|
||||
const getFrontendName = (frontend_type) => {
|
||||
return get(props.frontendTypes, [frontend_type, 'name'], '');
|
||||
};
|
||||
|
||||
const getBackendName = (backend_type) => {
|
||||
return get(props.backendTypes, [backend_type, 'name'], '');
|
||||
};
|
||||
|
||||
const $datatable = ref(); // Template Ref
|
||||
|
||||
const relist = () => {
|
||||
|
|
|
@ -20,76 +20,90 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import mergeExisting from "~/functions/mergeExisting";
|
||||
import {computed, onMounted, ref, shallowRef} from "vue";
|
||||
import {useTranslate} from "~/vendor/gettext";
|
||||
import {useAxios} from "~/vendor/axios";
|
||||
|
||||
export default {
|
||||
name: 'StationsCommonQuota',
|
||||
props: {
|
||||
quotaUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
emits: ['updated'],
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
quota: {
|
||||
used: null,
|
||||
used_bytes: null,
|
||||
used_percent: null,
|
||||
available: null,
|
||||
available_bytes: null,
|
||||
quota: null,
|
||||
quota_bytes: null,
|
||||
is_full: null,
|
||||
num_files: null
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
progressVariant() {
|
||||
if (this.quota.used_percent > 85) {
|
||||
return 'danger';
|
||||
} else if (this.quota.used_percent > 65) {
|
||||
return 'warning';
|
||||
} else {
|
||||
return 'default';
|
||||
}
|
||||
},
|
||||
langSpaceUsed() {
|
||||
const lang = (this.quota.available)
|
||||
? this.$gettext('%{spaceUsed} of %{spaceTotal} Used')
|
||||
: this.$gettext('%{spaceUsed} Used');
|
||||
|
||||
const langParsed = this.$gettextInterpolate(lang, {
|
||||
spaceUsed: this.quota.used,
|
||||
spaceTotal: this.quota.available
|
||||
});
|
||||
|
||||
if (null !== this.quota.num_files) {
|
||||
const langNumFiles = this.$ngettext('%{filesCount} File', '%{filesCount} Files', this.quota.num_files);
|
||||
const langNumFilesParsed = this.$gettextInterpolate(langNumFiles, {filesCount: this.quota.num_files});
|
||||
return langParsed + ' (' + langNumFilesParsed + ')';
|
||||
}
|
||||
|
||||
return langParsed;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.update();
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.axios.get(this.quotaUrl)
|
||||
.then((resp) => {
|
||||
this.quota = mergeExisting(this.quota, resp.data);
|
||||
this.loading = false;
|
||||
|
||||
this.$emit('updated', this.quota);
|
||||
});
|
||||
}
|
||||
const props = defineProps({
|
||||
quotaUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['updated']);
|
||||
|
||||
const loading = ref(true);
|
||||
const quota = shallowRef({
|
||||
used: null,
|
||||
used_bytes: null,
|
||||
used_percent: null,
|
||||
available: null,
|
||||
available_bytes: null,
|
||||
quota: null,
|
||||
quota_bytes: null,
|
||||
is_full: null,
|
||||
num_files: null
|
||||
});
|
||||
|
||||
const progressVariant = computed(() => {
|
||||
if (quota.value.used_percent > 85) {
|
||||
return 'danger';
|
||||
} else if (quota.value.used_percent > 65) {
|
||||
return 'warning';
|
||||
} else {
|
||||
return 'default';
|
||||
}
|
||||
});
|
||||
|
||||
const {$gettext, $ngettext} = useTranslate();
|
||||
|
||||
const langSpaceUsed = computed(() => {
|
||||
let langSpaceUsed;
|
||||
|
||||
if (quota.value.available) {
|
||||
langSpaceUsed = $gettext(
|
||||
'%{spaceUsed} of %{spaceTotal} Used',
|
||||
{
|
||||
spaceUsed: quota.value.used,
|
||||
spaceTotal: quota.value.available
|
||||
}
|
||||
);
|
||||
} else {
|
||||
langSpaceUsed = $gettext(
|
||||
'%{spaceUsed} Used',
|
||||
{
|
||||
spaceUsed: quota.value.used,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (null !== quota.value.num_files) {
|
||||
const langNumFiles = $ngettext(
|
||||
'%{filesCount} File',
|
||||
'%{filesCount} Files',
|
||||
quota.value.num_files,
|
||||
{filesCount: quota.value.num_files}
|
||||
);
|
||||
|
||||
return langSpaceUsed + ' (' + langNumFiles + ')';
|
||||
}
|
||||
|
||||
return langSpaceUsed;
|
||||
});
|
||||
|
||||
const {axios} = useAxios();
|
||||
|
||||
const update = () => {
|
||||
axios.get(props.quotaUrl).then((resp) => {
|
||||
quota.value = mergeExisting(quota.value, resp.data);
|
||||
loading.value = false;
|
||||
|
||||
emit('updated', quota.value);
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(update);
|
||||
</script>
|
||||
|
|
|
@ -9,55 +9,42 @@
|
|||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import FlowUpload from '~/components/Common/FlowUpload';
|
||||
|
||||
export default {
|
||||
name: 'FileUpload',
|
||||
components: {FlowUpload},
|
||||
props: {
|
||||
uploadUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
currentDirectory: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
searchPhrase: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
validMimeTypes: {
|
||||
type: Array,
|
||||
default() {
|
||||
return ['audio/*'];
|
||||
}
|
||||
}
|
||||
const props = defineProps({
|
||||
uploadUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
emits: ['relist'],
|
||||
data() {
|
||||
return {
|
||||
flow: null,
|
||||
files: []
|
||||
};
|
||||
currentDirectory: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
computed: {
|
||||
flowConfiguration() {
|
||||
return {
|
||||
query: () => {
|
||||
return {
|
||||
'currentDirectory': this.currentDirectory,
|
||||
'searchPhrase': this.searchPhrase
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
searchPhrase: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
methods: {
|
||||
onFlowUpload() {
|
||||
this.$emit('relist');
|
||||
validMimeTypes: {
|
||||
type: Array,
|
||||
default() {
|
||||
return ['audio/*'];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['relist']);
|
||||
|
||||
const flowConfiguration = {
|
||||
query: () => {
|
||||
return {
|
||||
'currentDirectory': props.currentDirectory,
|
||||
'searchPhrase': props.searchPhrase
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const onFlowUpload = () => {
|
||||
emit('relist');
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<b-modal
|
||||
id="create_directory"
|
||||
ref="modal"
|
||||
ref="$modal"
|
||||
centered
|
||||
:title="$gettext('New Directory')"
|
||||
>
|
||||
|
@ -32,62 +32,63 @@
|
|||
</template>
|
||||
</b-modal>
|
||||
</template>
|
||||
<script>
|
||||
import useVuelidate from "@vuelidate/core";
|
||||
|
||||
<script setup>
|
||||
import {required} from '@vuelidate/validators';
|
||||
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
|
||||
import {useVuelidateOnForm} from "~/functions/useVuelidateOnForm";
|
||||
import {ref} from "vue";
|
||||
import {useNotify} from "~/vendor/bootstrapVue";
|
||||
import {useAxios} from "~/vendor/axios";
|
||||
import {useTranslate} from "~/vendor/gettext";
|
||||
|
||||
export default {
|
||||
name: 'NewDirectoryModal',
|
||||
components: {BWrappedFormGroup},
|
||||
props: {
|
||||
currentDirectory: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
mkdirUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
const props = defineProps({
|
||||
currentDirectory: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
emits: ['relist'],
|
||||
setup() {
|
||||
return {v$: useVuelidate()}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
newDirectory: null
|
||||
};
|
||||
},
|
||||
validations: {
|
||||
newDirectory: {
|
||||
required
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.newDirectory = null;
|
||||
this.v$.$reset();
|
||||
this.$refs.modal.hide();
|
||||
},
|
||||
doMkdir() {
|
||||
this.v$.$touch();
|
||||
if (this.v$.$errors.length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$wrapWithLoading(
|
||||
this.axios.post(this.mkdirUrl, {
|
||||
'currentDirectory': this.currentDirectory,
|
||||
'name': this.newDirectory
|
||||
})
|
||||
).then(() => {
|
||||
this.$notifySuccess(this.$gettext('New directory created.'));
|
||||
}).finally(() => {
|
||||
this.$emit('relist');
|
||||
this.close();
|
||||
});
|
||||
}
|
||||
mkdirUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['relist']);
|
||||
|
||||
const {form, v$, resetForm, ifValid} = useVuelidateOnForm(
|
||||
{
|
||||
newDirectory: {required}
|
||||
},
|
||||
{
|
||||
newDirectory: null
|
||||
}
|
||||
);
|
||||
|
||||
const $modal = ref(); // Template Ref
|
||||
|
||||
const close = () => {
|
||||
resetForm();
|
||||
|
||||
$modal.value.hide();
|
||||
};
|
||||
|
||||
const {wrapWithLoading, notifySuccess} = useNotify();
|
||||
const {axios} = useAxios();
|
||||
const {$gettext} = useTranslate();
|
||||
|
||||
const doMkdir = () => {
|
||||
ifValid(() => {
|
||||
wrapWithLoading(
|
||||
axios.post(props.mkdirUrl, {
|
||||
'currentDirectory': props.currentDirectory,
|
||||
'name': form.value.newDirectory
|
||||
})
|
||||
).then(() => {
|
||||
notifySuccess($gettext('New directory created.'));
|
||||
}).finally(() => {
|
||||
emit('relist');
|
||||
close();
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<b-modal
|
||||
id="rename_file"
|
||||
ref="modal"
|
||||
ref="$modal"
|
||||
centered
|
||||
:title="$gettext('Rename File/Directory')"
|
||||
>
|
||||
|
@ -32,63 +32,69 @@
|
|||
</template>
|
||||
</b-modal>
|
||||
</template>
|
||||
<script>
|
||||
import useVuelidate from "@vuelidate/core";
|
||||
|
||||
<script setup>
|
||||
import {required} from '@vuelidate/validators';
|
||||
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
|
||||
import {ref} from "vue";
|
||||
import {useVuelidateOnForm} from "~/functions/useVuelidateOnForm";
|
||||
import {useNotify} from "~/vendor/bootstrapVue";
|
||||
import {useAxios} from "~/vendor/axios";
|
||||
|
||||
export default {
|
||||
name: 'RenameModal',
|
||||
components: {BWrappedFormGroup},
|
||||
props: {
|
||||
renameUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
emits: ['relist'],
|
||||
setup() {
|
||||
return {v$: useVuelidate()}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
file: null,
|
||||
newPath: null
|
||||
}
|
||||
};
|
||||
},
|
||||
validations: {
|
||||
form: {
|
||||
newPath: {
|
||||
required
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
open(filePath) {
|
||||
this.form.file = filePath;
|
||||
this.form.newPath = filePath;
|
||||
|
||||
this.$refs.modal.show();
|
||||
},
|
||||
close() {
|
||||
this.v$.$reset();
|
||||
this.$refs.modal.hide();
|
||||
},
|
||||
doRename() {
|
||||
this.v$.$touch();
|
||||
if (this.v$.$errors.length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$wrapWithLoading(
|
||||
this.axios.put(this.renameUrl, this.form)
|
||||
).finally(() => {
|
||||
this.$refs.modal.hide();
|
||||
this.$emit('relist');
|
||||
});
|
||||
}
|
||||
const props = defineProps({
|
||||
renameUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['relist']);
|
||||
|
||||
const file = ref(null);
|
||||
|
||||
const {form, v$, resetForm, ifValid} = useVuelidateOnForm(
|
||||
{
|
||||
newPath: {required}
|
||||
},
|
||||
{
|
||||
newPath: null
|
||||
}
|
||||
);
|
||||
|
||||
const $modal = ref(); // Template Ref
|
||||
|
||||
const open = (filePath) => {
|
||||
file.value = filePath;
|
||||
form.value.newPath = filePath;
|
||||
|
||||
$modal.value.show();
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
resetForm();
|
||||
file.value = null;
|
||||
|
||||
$modal.value.hide();
|
||||
};
|
||||
|
||||
const {wrapWithLoading} = useNotify();
|
||||
const {axios} = useAxios();
|
||||
|
||||
const doRename = () => {
|
||||
ifValid(() => {
|
||||
wrapWithLoading(
|
||||
axios.put(props.renameUrl, {
|
||||
file: file.value,
|
||||
...form.value
|
||||
})
|
||||
).finally(() => {
|
||||
$modal.value.hide();
|
||||
emit('relist');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
open
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -44,27 +44,23 @@
|
|||
</b-tab>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import {FRONTEND_ICECAST} from '~/components/Entity/RadioAdapters';
|
||||
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
|
||||
import {computed} from "vue";
|
||||
|
||||
export default {
|
||||
name: 'MountFormAdvanced',
|
||||
components: {BWrappedFormGroup},
|
||||
props: {
|
||||
form: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
stationFrontendType: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
const props = defineProps({
|
||||
form: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
computed: {
|
||||
isIcecast() {
|
||||
return FRONTEND_ICECAST === this.stationFrontendType;
|
||||
}
|
||||
stationFrontendType: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const isIcecast = computed(() => {
|
||||
return FRONTEND_ICECAST === props.stationFrontendType;
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -62,72 +62,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";
|
||||
|
||||
export default {
|
||||
name: 'MountFormAutoDj',
|
||||
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>
|
||||
|
|
|
@ -147,37 +147,36 @@
|
|||
</b-tab>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import {FRONTEND_ICECAST, FRONTEND_SHOUTCAST} from '~/components/Entity/RadioAdapters';
|
||||
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
|
||||
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
|
||||
import {useTranslate} from "~/vendor/gettext";
|
||||
import {computed} from "vue";
|
||||
|
||||
export default {
|
||||
name: 'MountFormBasicInfo',
|
||||
components: {BWrappedFormCheckbox, BWrappedFormGroup},
|
||||
props: {
|
||||
form: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
stationFrontendType: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
const props = defineProps({
|
||||
form: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
computed: {
|
||||
langAuthhashDesc() {
|
||||
return this.$gettext(
|
||||
'If your stream is set to advertise to YP directories above, you must specify an authorization hash. You can manage authhashes <a href="%{ url }" target="_blank">on the Shoutcast web site</a>.',
|
||||
{url: 'https://radiomanager.shoutcast.com/'}
|
||||
);
|
||||
},
|
||||
isIcecast () {
|
||||
return FRONTEND_ICECAST === this.stationFrontendType;
|
||||
},
|
||||
isShoutcast () {
|
||||
return FRONTEND_SHOUTCAST === this.stationFrontendType;
|
||||
}
|
||||
stationFrontendType: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const {$gettext} = useTranslate();
|
||||
|
||||
const langAuthhashDesc = $gettext(
|
||||
'If your stream is set to advertise to YP directories above, you must specify an authorization hash. You can manage authhashes <a href="%{ url }" target="_blank">on the Shoutcast web site</a>.',
|
||||
{url: 'https://radiomanager.shoutcast.com/'}
|
||||
);
|
||||
|
||||
const isIcecast = computed(() => {
|
||||
return FRONTEND_ICECAST === props.stationFrontendType;
|
||||
});
|
||||
|
||||
const isShoutcast = computed(() => {
|
||||
return FRONTEND_SHOUTCAST === props.stationFrontendType;
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
<template>
|
||||
<modal-form
|
||||
id="clone_modal"
|
||||
ref="modal"
|
||||
ref="$modal"
|
||||
:title="$gettext('Duplicate Playlist')"
|
||||
:error="error"
|
||||
:disable-save-button="v$.form.$invalid"
|
||||
@submit="doSubmit"
|
||||
@hidden="clearContents"
|
||||
|
@ -46,80 +45,73 @@
|
|||
</modal-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import useVuelidate from "@vuelidate/core";
|
||||
<script setup>
|
||||
import {required} from '@vuelidate/validators';
|
||||
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
|
||||
import ModalForm from "~/components/Common/ModalForm";
|
||||
import {useVuelidateOnForm} from "~/functions/useVuelidateOnForm";
|
||||
import {ref} from "vue";
|
||||
import {useTranslate} from "~/vendor/gettext";
|
||||
import {useNotify} from "~/vendor/bootstrapVue";
|
||||
import {useAxios} from "~/vendor/axios";
|
||||
|
||||
export default {
|
||||
name: 'CloneModal',
|
||||
components: {ModalForm, BWrappedFormGroup},
|
||||
emits: ['relist', 'needs-restart'],
|
||||
setup() {
|
||||
return {v$: useVuelidate()}
|
||||
const emit = defineEmits(['relist', 'needs-restart']);
|
||||
|
||||
const cloneUrl = ref(null);
|
||||
|
||||
const {form, v$, resetForm, ifValid} = useVuelidateOnForm(
|
||||
{
|
||||
'name': {required},
|
||||
'clone': {}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
error: null,
|
||||
cloneUrl: null,
|
||||
form: {}
|
||||
};
|
||||
},
|
||||
validations: {
|
||||
form: {
|
||||
'name': { required },
|
||||
'clone': {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
resetForm () {
|
||||
this.form = {
|
||||
'name': '',
|
||||
'clone': []
|
||||
};
|
||||
},
|
||||
open (name, cloneUrl) {
|
||||
this.error = null;
|
||||
|
||||
this.resetForm();
|
||||
this.cloneUrl = cloneUrl;
|
||||
|
||||
this.form.name = this.$gettext(
|
||||
'%{name} - Copy',
|
||||
{name: name}
|
||||
);
|
||||
|
||||
this.$refs.modal.show();
|
||||
},
|
||||
async doSubmit() {
|
||||
this.v$.$touch();
|
||||
if (this.v$.$errors.length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.error = null;
|
||||
|
||||
this.$wrapWithLoading(
|
||||
this.axios({
|
||||
method: 'POST',
|
||||
url: this.cloneUrl,
|
||||
data: this.form
|
||||
})
|
||||
).then(() => {
|
||||
this.$notifySuccess();
|
||||
this.$emit('needs-restart');
|
||||
this.$emit('relist');
|
||||
this.$refs.modal.hide();
|
||||
});
|
||||
},
|
||||
clearContents() {
|
||||
this.error = null;
|
||||
this.cloneUrl = null;
|
||||
this.resetForm();
|
||||
|
||||
this.v$.$reset();
|
||||
}
|
||||
{
|
||||
'name': '',
|
||||
'clone': []
|
||||
}
|
||||
);
|
||||
|
||||
const clearContents = () => {
|
||||
cloneUrl.value = null;
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const {$gettext} = useTranslate();
|
||||
|
||||
const $modal = ref(); // Template Ref
|
||||
|
||||
const open = (name, newCloneUrl) => {
|
||||
clearContents();
|
||||
|
||||
cloneUrl.value = newCloneUrl;
|
||||
form.value.name = $gettext(
|
||||
'%{name} - Copy',
|
||||
{name: name}
|
||||
);
|
||||
|
||||
$modal.value.show();
|
||||
};
|
||||
|
||||
const {wrapWithLoading, notifySuccess} = useNotify();
|
||||
const {axios} = useAxios();
|
||||
|
||||
const doSubmit = () => {
|
||||
ifValid(() => {
|
||||
wrapWithLoading(
|
||||
axios({
|
||||
method: 'POST',
|
||||
url: cloneUrl.value,
|
||||
data: form.value
|
||||
})
|
||||
).then(() => {
|
||||
notifySuccess();
|
||||
emit('needs-restart');
|
||||
emit('relist');
|
||||
$modal.value.hide();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
open
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -419,35 +419,26 @@
|
|||
</b-tab>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import BWrappedFormGroup from "~/components/Form/BWrappedFormGroup";
|
||||
import BWrappedFormCheckbox from "~/components/Form/BWrappedFormCheckbox";
|
||||
import BFormFieldset from "~/components/Form/BFormFieldset";
|
||||
import {map, range} from "lodash";
|
||||
|
||||
export default {
|
||||
name: 'PlaylistEditBasicInfo',
|
||||
components: {BFormFieldset, BWrappedFormCheckbox, BWrappedFormGroup},
|
||||
props: {
|
||||
form: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
let weightOptions = [
|
||||
{value: 1, text: '1 - ' + this.$gettext('Low')},
|
||||
{value: 2, text: '2'},
|
||||
{value: 3, text: '3 - ' + this.$gettext('Default')},
|
||||
{value: 4, text: '4'},
|
||||
{value: 5, text: '5 - ' + this.$gettext('High')}
|
||||
];
|
||||
for (let i = 6; i <= 25; i++) {
|
||||
weightOptions.push({value: i, text: i});
|
||||
}
|
||||
|
||||
return {
|
||||
weightOptions: weightOptions
|
||||
};
|
||||
const props = defineProps({
|
||||
form: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const weightOptions = map(
|
||||
range(1, 26),
|
||||
(val) => {
|
||||
return {
|
||||
value: val,
|
||||
text: val
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<b-modal
|
||||
id="import_modal"
|
||||
ref="modal"
|
||||
ref="$modal"
|
||||
:title="$gettext('Import from PLS/M3U')"
|
||||
@hidden="onHidden"
|
||||
>
|
||||
|
@ -91,51 +91,58 @@
|
|||
</b-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import InvisibleSubmitButton from '~/components/Common/InvisibleSubmitButton';
|
||||
import {ref} from "vue";
|
||||
import {useNotify} from "~/vendor/bootstrapVue";
|
||||
import {useAxios} from "~/vendor/axios";
|
||||
|
||||
export default {
|
||||
name: 'PlaylistImportModal',
|
||||
components: {InvisibleSubmitButton},
|
||||
emits: ['relist'],
|
||||
data() {
|
||||
return {
|
||||
importPlaylistUrl: null,
|
||||
playlistFile: null,
|
||||
results: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
open(importPlaylistUrl) {
|
||||
this.playlistFile = null;
|
||||
this.importPlaylistUrl = importPlaylistUrl;
|
||||
const emit = defineEmits(['relist']);
|
||||
|
||||
this.$refs.modal.show();
|
||||
},
|
||||
doSubmit () {
|
||||
let formData = new FormData();
|
||||
formData.append('playlist_file', this.playlistFile);
|
||||
const importPlaylistUrl = ref(null);
|
||||
const playlistFile = ref(null);
|
||||
const results = ref(null);
|
||||
|
||||
this.$wrapWithLoading(
|
||||
this.axios.post(this.importPlaylistUrl, formData)
|
||||
).then((resp) => {
|
||||
if (resp.data.success) {
|
||||
this.results = resp.data;
|
||||
const $modal = ref(); // Template Ref
|
||||
|
||||
this.$notifySuccess(resp.data.message);
|
||||
} else {
|
||||
this.$notifyError(resp.data.message);
|
||||
this.close();
|
||||
}
|
||||
});
|
||||
},
|
||||
close () {
|
||||
this.$refs.modal.hide();
|
||||
},
|
||||
onHidden () {
|
||||
this.$emit('relist');
|
||||
this.results = null;
|
||||
}
|
||||
}
|
||||
const open = (newImportPlaylistUrl) => {
|
||||
playlistFile.value = null;
|
||||
importPlaylistUrl.value = newImportPlaylistUrl;
|
||||
|
||||
$modal.value.show();
|
||||
};
|
||||
|
||||
const {wrapWithLoading, notifySuccess, notifyError} = useNotify();
|
||||
const {axios} = useAxios();
|
||||
|
||||
const doSubmit = () => {
|
||||
let formData = new FormData();
|
||||
formData.append('playlist_file', playlistFile.value);
|
||||
|
||||
wrapWithLoading(
|
||||
axios.post(importPlaylistUrl.value, formData)
|
||||
).then((resp) => {
|
||||
if (resp.data.success) {
|
||||
results.value = resp.data;
|
||||
|
||||
notifySuccess(resp.data.message);
|
||||
} else {
|
||||
notifyError(resp.data.message);
|
||||
close();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
$modal.value.hide();
|
||||
};
|
||||
|
||||
const onHidden = () => {
|
||||
emit('relist');
|
||||
results.value = null;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
open
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<b-modal
|
||||
id="queue_modal"
|
||||
ref="modal"
|
||||
ref="$modal"
|
||||
size="lg"
|
||||
:title="$gettext('Playback Queue')"
|
||||
:busy="loading"
|
||||
|
@ -62,43 +62,52 @@
|
|||
</b-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import {ref} from "vue";
|
||||
import {useAxios} from "~/vendor/axios";
|
||||
import {useNotify} from "~/vendor/bootstrapVue";
|
||||
import {useTranslate} from "~/vendor/gettext";
|
||||
|
||||
export default {
|
||||
name: 'QueueModal',
|
||||
data () {
|
||||
return {
|
||||
loading: true,
|
||||
queueUrl: null,
|
||||
media: []
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
open (queueUrl) {
|
||||
this.$refs.modal.show();
|
||||
this.queueUrl = queueUrl;
|
||||
this.loading = true;
|
||||
const loading = ref(true);
|
||||
const queueUrl = ref(null);
|
||||
const media = ref([]);
|
||||
|
||||
this.axios.get(this.queueUrl).then((resp) => {
|
||||
this.media = resp.data;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
doClear () {
|
||||
this.$wrapWithLoading(
|
||||
this.axios.delete(this.queueUrl)
|
||||
).then(() => {
|
||||
this.$notifySuccess(this.$gettext('Playlist queue cleared.'));
|
||||
this.close();
|
||||
});
|
||||
},
|
||||
close () {
|
||||
this.loading = false;
|
||||
this.error = null;
|
||||
this.queueUrl = null;
|
||||
const $modal = ref(); // Template Ref
|
||||
|
||||
this.$refs.modal.hide();
|
||||
}
|
||||
}
|
||||
const {axios} = useAxios();
|
||||
|
||||
const open = (newQueueUrl) => {
|
||||
queueUrl.value = newQueueUrl;
|
||||
loading.value = true;
|
||||
|
||||
axios.get(newQueueUrl).then((resp) => {
|
||||
media.value = resp.data;
|
||||
loading.value = false;
|
||||
});
|
||||
|
||||
$modal.value.show();
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
loading.value = false;
|
||||
queueUrl.value = null;
|
||||
|
||||
$modal.value.hide();
|
||||
}
|
||||
|
||||
const {wrapWithLoading, notifySuccess} = useNotify();
|
||||
const {$gettext} = useTranslate();
|
||||
|
||||
const doClear = () => {
|
||||
wrapWithLoading(
|
||||
axios.delete(queueUrl.value)
|
||||
).then(() => {
|
||||
notifySuccess($gettext('Playlist queue cleared.'));
|
||||
close();
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
open
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -18,9 +18,3 @@
|
|||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inheritAttrs: false,
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -92,12 +92,6 @@
|
|||
</b-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inheritAttrs: false
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup>
|
||||
import CopyToClipboardButton from '~/components/Common/CopyToClipboardButton';
|
||||
import {computed, ref} from "vue";
|
||||
|
|
|
@ -48,12 +48,6 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inheritAttrs: false
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup>
|
||||
import {DateTime} from "luxon";
|
||||
import {map} from "lodash";
|
||||
|
|
|
@ -167,12 +167,6 @@
|
|||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inheritAttrs: false
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup>
|
||||
import Icon from '~/components/Common/Icon';
|
||||
import PlayButton from "~/components/Common/PlayButton";
|
||||
|
|
Loading…
Reference in New Issue