Fix router warnings
This commit is contained in:
parent
dbe762d71c
commit
e608089557
|
@ -1,3 +1,51 @@
|
|||
<script setup lang="ts">
|
||||
import Modal from '~/components/semantic/Modal.vue'
|
||||
import ChannelUploadForm from '~/components/channels/UploadForm.vue'
|
||||
import { humanSize } from '~/utils/filters'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useStore } from '~/store'
|
||||
import { ref, computed } from 'vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
const store = useStore()
|
||||
const router = useRouter()
|
||||
router.beforeEach(() => store.commit('channels/showUploadModal', { show: false }))
|
||||
|
||||
const update = (value: boolean) => store.commit('channels/showUploadModal', { show: value })
|
||||
|
||||
const { $npgettext, $gettext } = useGettext()
|
||||
|
||||
const statusData = ref()
|
||||
const statusInfo = computed(() => {
|
||||
if (!statusData.value) {
|
||||
return []
|
||||
}
|
||||
|
||||
const info = []
|
||||
if (statusData.value.totalSize) {
|
||||
info.push(humanSize(statusData.value.totalSize))
|
||||
}
|
||||
|
||||
if (statusData.value.totalFiles) {
|
||||
const msg = $npgettext('*/*/*', '%{ count } file', '%{ count } files', statusData.value.totalFiles)
|
||||
info.push($gettext(msg, { count: statusData.value.totalFiles }))
|
||||
}
|
||||
|
||||
if (statusData.value.progress) {
|
||||
info.push(`${statusData.value.progress}%`)
|
||||
}
|
||||
|
||||
if (statusData.value.speed) {
|
||||
info.push(`${humanSize(statusData.value.speed)}/s`)
|
||||
}
|
||||
|
||||
return info
|
||||
})
|
||||
|
||||
const step = ref(1)
|
||||
const isLoading = ref(false)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<modal
|
||||
v-model:show="$store.state.channels.showUploadModal"
|
||||
|
@ -37,7 +85,6 @@
|
|||
@loading="isLoading = $event"
|
||||
@published="$store.commit('channels/publish', $event)"
|
||||
@status="statusData = $event"
|
||||
@submittable="submittable = $event"
|
||||
/>
|
||||
</div>
|
||||
<div class="actions">
|
||||
|
@ -96,7 +143,7 @@
|
|||
<button
|
||||
:class="['ui', 'primary button', {loading: isLoading}]"
|
||||
type="submit"
|
||||
:disabled="!statusData || !statusData.canSubmit || null"
|
||||
:disabled="!statusData?.canSubmit || undefined"
|
||||
@click.prevent.stop="$refs.uploadForm.publish"
|
||||
>
|
||||
<translate translate-context="*/Channels/Button.Label">
|
||||
|
@ -107,7 +154,7 @@
|
|||
ref="dropdown"
|
||||
v-dropdown
|
||||
class="ui floating dropdown icon button"
|
||||
:disabled="!statusData || !statusData.canSubmit || null"
|
||||
:disabled="!statusData?.canSubmit || undefined"
|
||||
>
|
||||
<i class="dropdown icon" />
|
||||
<div class="menu">
|
||||
|
@ -135,67 +182,3 @@
|
|||
</div>
|
||||
</modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Modal from '~/components/semantic/Modal.vue'
|
||||
import ChannelUploadForm from '~/components/channels/UploadForm.vue'
|
||||
import { humanSize } from '~/utils/filters'
|
||||
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Modal,
|
||||
ChannelUploadForm
|
||||
},
|
||||
setup () {
|
||||
const guard = () => {
|
||||
this.$store.commit('channels/showUploadModal', { show: false })
|
||||
}
|
||||
|
||||
onBeforeRouteUpdate(guard)
|
||||
onBeforeRouteLeave(guard)
|
||||
|
||||
return { humanSize }
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
step: 1,
|
||||
isLoading: false,
|
||||
submittable: true,
|
||||
statusData: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
labels () {
|
||||
return {}
|
||||
},
|
||||
statusInfo () {
|
||||
if (!this.statusData) {
|
||||
return []
|
||||
}
|
||||
const info = []
|
||||
if (this.statusData.totalSize) {
|
||||
info.push(humanSize(this.statusData.totalSize))
|
||||
}
|
||||
if (this.statusData.totalFiles) {
|
||||
const msg = this.$npgettext('*/*/*', '%{ count } file', '%{ count } files', this.statusData.totalFiles)
|
||||
info.push(
|
||||
this.$gettextInterpolate(msg, { count: this.statusData.totalFiles })
|
||||
)
|
||||
}
|
||||
if (this.statusData.progress) {
|
||||
info.push(`${this.statusData.progress}%`)
|
||||
}
|
||||
if (this.statusData.speed) {
|
||||
info.push(`${humanSize(this.statusData.speed)}/s`)
|
||||
}
|
||||
return info
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update (v) {
|
||||
this.$store.commit('channels/showUploadModal', { show: v })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -26,7 +26,7 @@ const value = useVModel(props, 'modelValue', emit)
|
|||
|
||||
const attachment = ref()
|
||||
const isLoading = ref(false)
|
||||
const errors = reactive<string[]>([])
|
||||
const errors = reactive([] as Error[])
|
||||
const attachmentId = Math.random().toString(36).substring(7)
|
||||
|
||||
const input = ref()
|
||||
|
|
|
@ -1,3 +1,82 @@
|
|||
<script setup lang="ts">
|
||||
import { filter, sortBy, flow } from 'lodash-es'
|
||||
|
||||
import axios, { AxiosError } from 'axios'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import Modal from '~/components/semantic/Modal.vue'
|
||||
import PlaylistForm from '~/components/playlists/Form.vue'
|
||||
import useLogger from '~/composables/useLogger'
|
||||
import { useStore } from '~/store'
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { BackendError, Playlist } from '~/types'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const logger = useLogger()
|
||||
const store = useStore()
|
||||
|
||||
const showDuplicateTrackAddConfirmation = ref(false)
|
||||
|
||||
const router = useRouter()
|
||||
router.beforeEach(() => {
|
||||
store.commit('playlists/showModal', false)
|
||||
showDuplicateTrackAddConfirmation.value = false
|
||||
})
|
||||
|
||||
const playlists = computed(() => store.state.playlists.playlists)
|
||||
const track = computed(() => store.state.playlists.modalTrack)
|
||||
|
||||
const { $pgettext } = useGettext()
|
||||
const labels = computed(() => ({
|
||||
addToPlaylist: $pgettext('Popup/Playlist/Table.Button.Tooltip/Verb', 'Add to this playlist'),
|
||||
filterPlaylistField: $pgettext('Popup/Playlist/Form/Placeholder', 'Enter playlist name')
|
||||
}))
|
||||
|
||||
const playlistNameFilter = ref('')
|
||||
|
||||
const sortedPlaylists = computed(() => flow(
|
||||
filter((playlist: Playlist) => playlist.name.match(new RegExp(playlistNameFilter.value, 'i')) !== null),
|
||||
sortBy((playlist: Playlist) => { return playlist.modification_date })
|
||||
)(playlists.value).reverse())
|
||||
|
||||
const formKey = ref(new Date().toString())
|
||||
watch(() => store.state.playlists.showModal, () => {
|
||||
formKey.value = new Date().toString()
|
||||
showDuplicateTrackAddConfirmation.value = false
|
||||
})
|
||||
|
||||
const lastSelectedPlaylist = ref(-1)
|
||||
const errors = ref([] as AxiosError[])
|
||||
const duplicateTrackAddInfo = ref({} as { playlist_name?: string })
|
||||
|
||||
const addToPlaylist = async (playlistId: number, allowDuplicates: boolean) => {
|
||||
lastSelectedPlaylist.value = playlistId
|
||||
|
||||
try {
|
||||
await axios.post(`playlists/${playlistId}/add`, {
|
||||
tracks: [track.value?.id].filter(i => i),
|
||||
allow_duplicates: allowDuplicates
|
||||
})
|
||||
|
||||
logger.info('Successfully added track to playlist')
|
||||
store.state.playlists.showModal = false
|
||||
store.dispatch('playlists/fetchOwn')
|
||||
} catch (error) {
|
||||
if (error as BackendError) {
|
||||
const { backendErrors } = error as BackendError
|
||||
|
||||
if (backendErrors.length === 1 && backendErrors[0].code === 'tracks_already_exist_in_playlist') {
|
||||
duplicateTrackAddInfo.value = backendErrors[0] as unknown as { playlist_name: string }
|
||||
showDuplicateTrackAddConfirmation.value = true
|
||||
} else {
|
||||
errors.value = backendErrors
|
||||
showDuplicateTrackAddConfirmation.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<modal
|
||||
v-model:show="$store.state.playlists.showModal"
|
||||
|
@ -35,15 +114,15 @@
|
|||
class="ui warning message"
|
||||
>
|
||||
<p
|
||||
v-translate="{track: track.title, playlist: duplicateTrackAddInfo.playlist_name}"
|
||||
v-translate="{track: track?.title, playlist: duplicateTrackAddInfo.playlist_name}"
|
||||
translate-context="Popup/Playlist/Paragraph"
|
||||
:translate-params="{track: track.title, playlist: duplicateTrackAddInfo.playlist_name}"
|
||||
:translate-params="{track: track?.title, playlist: duplicateTrackAddInfo.playlist_name}"
|
||||
>
|
||||
<strong>%{ track }</strong> is already in <strong>%{ playlist }</strong>.
|
||||
</p>
|
||||
<button
|
||||
class="ui small basic cancel button"
|
||||
@click="duplicateTrackAddConfirm(false)"
|
||||
@click="showDuplicateTrackAddConfirmation = false"
|
||||
>
|
||||
<translate translate-context="*/*/Button.Label/Verb">
|
||||
Cancel
|
||||
|
@ -189,98 +268,3 @@
|
|||
</div>
|
||||
</modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { filter, sortBy, flow } from 'lodash-es'
|
||||
|
||||
import axios from 'axios'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
import Modal from '~/components/semantic/Modal.vue'
|
||||
import PlaylistForm from '~/components/playlists/Form.vue'
|
||||
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
|
||||
import useLogger from '~/composables/useLogger'
|
||||
|
||||
const logger = useLogger()
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Modal,
|
||||
PlaylistForm
|
||||
},
|
||||
setup () {
|
||||
const guard = () => {
|
||||
this.$store.commit('playlists/showModal', false)
|
||||
this.showDuplicateTrackAddConfirmation = false
|
||||
}
|
||||
|
||||
onBeforeRouteUpdate(guard)
|
||||
onBeforeRouteLeave(guard)
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
formKey: String(new Date()),
|
||||
errors: [],
|
||||
playlistNameFilter: '',
|
||||
duplicateTrackAddInfo: {},
|
||||
showDuplicateTrackAddConfirmation: false,
|
||||
lastSelectedPlaylist: -1
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
playlists: state => state.playlists.playlists,
|
||||
track: state => state.playlists.modalTrack
|
||||
}),
|
||||
labels () {
|
||||
return {
|
||||
addToPlaylist: this.$pgettext('Popup/Playlist/Table.Button.Tooltip/Verb', 'Add to this playlist'),
|
||||
filterPlaylistField: this.$pgettext('Popup/Playlist/Form/Placeholder', 'Enter playlist name')
|
||||
}
|
||||
},
|
||||
sortedPlaylists () {
|
||||
const regexp = new RegExp(this.playlistNameFilter, 'i')
|
||||
const p = flow(
|
||||
filter((e) => e.name.match(regexp) !== null),
|
||||
sortBy((e) => { return e.modification_date })
|
||||
)(this.playlists)
|
||||
p.reverse()
|
||||
return p
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'$store.state.playlists.showModal' () {
|
||||
this.formKey = String(new Date())
|
||||
this.showDuplicateTrackAddConfirmation = false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addToPlaylist (playlistId, allowDuplicate) {
|
||||
const self = this
|
||||
const payload = {
|
||||
tracks: [this.track.id],
|
||||
allow_duplicates: allowDuplicate
|
||||
}
|
||||
|
||||
self.lastSelectedPlaylist = playlistId
|
||||
|
||||
return axios.post(`playlists/${playlistId}/add`, payload).then(response => {
|
||||
logger.info('Successfully added track to playlist')
|
||||
self.$store.state.playlists.showModal = false
|
||||
self.$store.dispatch('playlists/fetchOwn')
|
||||
}, error => {
|
||||
if (error.backendErrors.length === 1 && error.backendErrors[0].code === 'tracks_already_exist_in_playlist') {
|
||||
self.duplicateTrackAddInfo = error.backendErrors[0]
|
||||
self.showDuplicateTrackAddConfirmation = true
|
||||
} else {
|
||||
self.errors = error.backendErrors
|
||||
self.showDuplicateTrackAddConfirmation = false
|
||||
}
|
||||
})
|
||||
},
|
||||
duplicateTrackAddConfirm (v) {
|
||||
this.showDuplicateTrackAddConfirmation = v
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import axios from 'axios'
|
||||
import { Module } from 'vuex'
|
||||
import { RootState } from '~/store/index'
|
||||
import { Playlist, Track } from '~/types'
|
||||
|
||||
export interface State {
|
||||
playlists: any[]
|
||||
playlists: Playlist[]
|
||||
showModal: boolean
|
||||
modalTrack: null
|
||||
modalTrack: null | Track
|
||||
}
|
||||
|
||||
const store: Module<State, RootState> = {
|
||||
|
|
|
@ -87,13 +87,19 @@ export interface License {
|
|||
url: string
|
||||
}
|
||||
|
||||
export interface Playlist {
|
||||
id: string
|
||||
name: string
|
||||
modification_date: Date // TODO (wvffle): Find correct type
|
||||
}
|
||||
|
||||
// API stuff
|
||||
export interface APIErrorResponse {
|
||||
[key: string]: APIErrorResponse | string[]
|
||||
}
|
||||
|
||||
export interface BackendError extends AxiosError {
|
||||
backendErrors: string[]
|
||||
export interface BackendError {
|
||||
backendErrors: AxiosError[]
|
||||
rawPayload?: object
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue