Resolve most type conflicts
This commit is contained in:
parent
e7da8b5f43
commit
436a76928f
|
@ -41,7 +41,7 @@ defineProps<Props>()
|
|||
>
|
||||
<strong>{{ source.track.title }}</strong><br>
|
||||
<span>
|
||||
{{ source.track.artist.name }}
|
||||
{{ source.track.artist?.name }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -219,10 +219,10 @@ onMounted(() => {
|
|||
<div class="item">
|
||||
<div class="ui user-dropdown dropdown">
|
||||
<img
|
||||
v-if="$store.state.auth.authenticated && $store.state.auth.profile.avatar && $store.state.auth.profile.avatar.urls.medium_square_crop"
|
||||
v-if="$store.state.auth.authenticated && $store.state.auth.profile?.avatar && $store.state.auth.profile?.avatar.urls.medium_square_crop"
|
||||
class="ui avatar image"
|
||||
alt=""
|
||||
:src="$store.getters['instance/absoluteUrl']($store.state.auth.profile.avatar.urls.medium_square_crop)"
|
||||
:src="$store.getters['instance/absoluteUrl']($store.state.auth.profile?.avatar.urls.medium_square_crop)"
|
||||
>
|
||||
<actor-avatar
|
||||
v-else-if="$store.state.auth.authenticated"
|
||||
|
|
|
@ -6,7 +6,7 @@ import { useClipboard } from '@vueuse/core'
|
|||
|
||||
interface Props {
|
||||
type: string
|
||||
id: string
|
||||
id: number
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
|
|
@ -234,7 +234,7 @@ const updatePage = (page: number) => {
|
|||
|
||||
<track-row
|
||||
v-for="(track, index) in allTracks"
|
||||
:key="track.id + track.position"
|
||||
:key="track.id + (track.position ?? 0)"
|
||||
:data-track-id="track.id"
|
||||
:data-track-position="track.position"
|
||||
:track="track"
|
||||
|
|
|
@ -42,16 +42,15 @@ const submit = async () => {
|
|||
isLoading.value = true
|
||||
|
||||
try {
|
||||
const event = props.app !== null
|
||||
? 'updated'
|
||||
: 'created'
|
||||
|
||||
const request = props.app !== null
|
||||
const isUpdating = props.app !== null
|
||||
const request = isUpdating
|
||||
? () => axios.patch(`oauth/apps/${props.app?.client_id}/`, fields)
|
||||
: () => axios.post('oauth/apps/', fields)
|
||||
|
||||
const response = await request()
|
||||
emit(event, response.data as Application)
|
||||
|
||||
if (isUpdating) emit('updated', response.data as Application)
|
||||
else emit('created', response.data as Application)
|
||||
} catch (error) {
|
||||
errors.value = (error as BackendError).backendErrors
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ const submitAndScan = async () => {
|
|||
</translate>
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="plugin.conf?.length > 0">
|
||||
<template v-if="(plugin.conf?.length ?? 0) > 0">
|
||||
<template
|
||||
v-for="field in plugin.conf"
|
||||
:key="field.name"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import type { BackendError, Application } from '~/types'
|
||||
import type { BackendError, Application, PrivacyLevel } from '~/types'
|
||||
import type { $ElementType } from 'utility-types'
|
||||
|
||||
import axios from 'axios'
|
||||
import $ from 'jquery'
|
||||
|
@ -18,9 +19,9 @@ import PasswordInput from '~/components/forms/PasswordInput.vue'
|
|||
|
||||
const SETTINGS_ORDER: FieldId[] = ['summary', 'privacy_level']
|
||||
|
||||
type FieldId = 'summary' | 'privacy_level'
|
||||
type Field = { id: string, type: 'content', value: { text: string, content_type: 'text/markdown' } }
|
||||
| { id: string, type: 'dropdown', choices: string[], value: string }
|
||||
type Field = { id: 'summary', type: 'content', value: { text: string, content_type: 'text/markdown' } }
|
||||
| { id: 'privacy_level', type: 'dropdown', choices: PrivacyLevel[], value: string }
|
||||
type FieldId = $ElementType<Field, 'id'>
|
||||
|
||||
interface Settings {
|
||||
success: boolean
|
||||
|
@ -157,7 +158,9 @@ const avatar = ref({ uuid: null, ...(store.state.auth.profile?.avatar ?? {}) })
|
|||
const initialAvatar = avatar.value.uuid ?? undefined
|
||||
const avatarErrors = ref([] as string[])
|
||||
const isLoadingAvatar = ref(false)
|
||||
const submitAvatar = async (uuid: string) => {
|
||||
const submitAvatar = async (uuid: string | null) => {
|
||||
if (!uuid) return
|
||||
|
||||
isLoadingAvatar.value = true
|
||||
|
||||
try {
|
||||
|
@ -315,9 +318,9 @@ fetchOwnedApps()
|
|||
:key="f.id"
|
||||
class="field"
|
||||
>
|
||||
<label :for="f.id">{{ sharedLabels.fields[f.id as FieldId].label }}</label>
|
||||
<p v-if="sharedLabels.fields[f.id as FieldId].help">
|
||||
{{ sharedLabels.fields[f.id as FieldId].help }}
|
||||
<label :for="f.id">{{ sharedLabels.fields[f.id].label }}</label>
|
||||
<p v-if="sharedLabels.fields[f.id].help">
|
||||
{{ sharedLabels.fields[f.id].help }}
|
||||
</p>
|
||||
<select
|
||||
v-if="f.type === 'dropdown'"
|
||||
|
@ -330,7 +333,7 @@ fetchOwnedApps()
|
|||
:key="key"
|
||||
:value="c"
|
||||
>
|
||||
{{ sharedLabels.fields[f.id as FieldId].choices[c] }}
|
||||
{{ sharedLabels.fields[f.id].choices?.[c] }}
|
||||
</option>
|
||||
</select>
|
||||
<content-form
|
||||
|
@ -833,7 +836,7 @@ fetchOwnedApps()
|
|||
</p>
|
||||
<p>
|
||||
<translate
|
||||
:translate-params="{email: $store.state.auth.profile.email}"
|
||||
:translate-params="{email: $store.state.auth.profile?.email}"
|
||||
translate-context="Content/Settings/Paragraph'"
|
||||
>
|
||||
Your current e-mail address is %{ email }.
|
||||
|
|
|
@ -48,7 +48,7 @@ const payload = reactive({
|
|||
password1: '',
|
||||
email: '',
|
||||
invitation: props.defaultInvitation,
|
||||
request_fields: {}
|
||||
request_fields: {} as Record<string, string | number | string[]>
|
||||
})
|
||||
|
||||
const submitted = ref(false)
|
||||
|
|
|
@ -19,6 +19,7 @@ watch(show, () => {
|
|||
submittable.value = false
|
||||
})
|
||||
|
||||
const albumForm = ref()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -28,7 +29,7 @@ watch(show, () => {
|
|||
>
|
||||
<h4 class="header">
|
||||
<translate
|
||||
v-if="channel.content_category === 'podcasts'"
|
||||
v-if="channel.content_category === 'podcast'"
|
||||
translate-context="Popup/Channels/Title/Verb"
|
||||
>
|
||||
New series
|
||||
|
@ -58,7 +59,7 @@ watch(show, () => {
|
|||
<button
|
||||
:class="['ui', 'primary', {loading: isLoading}, 'button']"
|
||||
:disabled="!submittable"
|
||||
@click.stop.prevent="$refs.albumForm.submit()"
|
||||
@click.stop.prevent="albumForm.submit()"
|
||||
>
|
||||
<translate translate-context="*/*/Button.Label">
|
||||
Create
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
import type { Channel } from '~/types'
|
||||
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useStore } from '~/store'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import LoginModal from '~/components/common/LoginModal.vue'
|
||||
|
||||
|
@ -34,8 +34,12 @@ const message = computed(() => ({
|
|||
|
||||
const toggle = async () => {
|
||||
await store.dispatch('channels/toggle', props.channel.uuid)
|
||||
emit(isSubscribed.value ? 'unsubscribed' : 'subscribed')
|
||||
|
||||
if (isSubscribed.value) emit('unsubscribed')
|
||||
else emit('subscribed')
|
||||
}
|
||||
|
||||
const loginModal = ref()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -50,7 +54,7 @@ const toggle = async () => {
|
|||
<button
|
||||
v-else
|
||||
:class="['ui', 'pink', 'icon', 'labeled', 'button']"
|
||||
@click="$refs.loginModal.show = true"
|
||||
@click="loginModal.show = true"
|
||||
>
|
||||
<i class="heart icon" />
|
||||
{{ title }}
|
||||
|
@ -59,8 +63,8 @@ const toggle = async () => {
|
|||
class="small"
|
||||
:next-route="$route.fullPath"
|
||||
:message="message.authMessage"
|
||||
:cover="channel.artist.cover!"
|
||||
@created="$refs.loginModal.show = false;"
|
||||
:cover="channel.artist?.cover!"
|
||||
@created="loginModal.show = false"
|
||||
/>
|
||||
</button>
|
||||
</template>
|
||||
|
|
|
@ -579,9 +579,8 @@ const labels = computed(() => ({
|
|||
</div>
|
||||
<upload-metadata-form
|
||||
v-if="selectedUpload"
|
||||
v-model:values="uploadImportData[selectedUploadId]"
|
||||
:upload="selectedUpload"
|
||||
:values="uploadImportData[selectedUploadId]"
|
||||
@values="uploadImportData.selectedUploadId = $event"
|
||||
/>
|
||||
<div
|
||||
v-if="step === 2"
|
||||
|
|
|
@ -1,34 +1,35 @@
|
|||
<script setup lang="ts">
|
||||
import type { Upload } from '~/types'
|
||||
import type { Upload, Tag } from '~/types'
|
||||
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { reactive, computed, watch } from 'vue'
|
||||
import { useVModel } from '@vueuse/core'
|
||||
|
||||
import TagsSelector from '~/components/library/TagsSelector.vue'
|
||||
import AttachmentInput from '~/components/common/AttachmentInput.vue'
|
||||
|
||||
interface Events {
|
||||
(e: 'values', values: Record<string, string>): void
|
||||
(e: 'update:values', values: Values): void
|
||||
}
|
||||
|
||||
interface Props {
|
||||
upload: Upload
|
||||
values?: Record<string, string> | null
|
||||
values: Values
|
||||
}
|
||||
|
||||
type Values = (Record<string, string> & { tags?: Tag[] }) | null
|
||||
|
||||
const emit = defineEmits<Events>()
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
values: null
|
||||
})
|
||||
|
||||
const newValues = ref({ ...(props.values ?? props.upload.import_metadata) } as Record<string, string>)
|
||||
const newValues = reactive<Exclude<Values, null>>({
|
||||
...(props.values ?? props.upload.import_metadata),
|
||||
tags: (props.values ?? props.upload.import_metadata)?.tags ?? [] as Tag[]
|
||||
})
|
||||
|
||||
// computed: {
|
||||
// isLoading () {
|
||||
// return !!this.metadata
|
||||
// }
|
||||
// },
|
||||
const isLoading = computed(() => !props.upload)
|
||||
watch(newValues, (values) => emit('values', values), { immediate: true })
|
||||
watch(newValues, (values) => emit('update:values', values), { immediate: true })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -44,7 +45,7 @@ watch(newValues, (values) => emit('values', values), { immediate: true })
|
|||
</div>
|
||||
<attachment-input
|
||||
v-model="newValues.cover"
|
||||
@delete="newValues.cover = null"
|
||||
@delete="newValues.cover = ''"
|
||||
>
|
||||
<translate translate-context="Content/Channel/*">
|
||||
Track Picture
|
||||
|
|
|
@ -13,7 +13,7 @@ interface Action {
|
|||
allowAll?: boolean
|
||||
confirmColor?: string
|
||||
confirmationMessage?: string
|
||||
filterChackable?: (item: never) => boolean
|
||||
filterChackable?: (item: any) => boolean
|
||||
}
|
||||
|
||||
interface Events {
|
||||
|
@ -22,7 +22,7 @@ interface Events {
|
|||
}
|
||||
|
||||
interface Props {
|
||||
objectsData: { results: [], count: number }
|
||||
objectsData: { results: any[], count: number }
|
||||
actions: Action[]
|
||||
actionUrl: string
|
||||
idField?: string
|
||||
|
|
|
@ -24,6 +24,7 @@ onMounted(() => {
|
|||
...props.message
|
||||
}
|
||||
|
||||
// @ts-expect-error fomantic ui
|
||||
$('body').toast(params)
|
||||
$('.ui.toast.visible').last().attr('role', 'alert')
|
||||
})
|
||||
|
|
|
@ -21,7 +21,7 @@ interface Events {
|
|||
}
|
||||
|
||||
interface Props {
|
||||
id: string
|
||||
id: number
|
||||
}
|
||||
|
||||
const emit = defineEmits<Events>()
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import type { Album, Library } from '~/types'
|
||||
import type { EditObjectType } from '~/composables/moderation/useEditConfigs'
|
||||
import type { Album, Library, Actor } from '~/types'
|
||||
|
||||
import { useStore } from '~/store'
|
||||
|
||||
import EditForm from '~/components/library/EditForm.vue'
|
||||
|
||||
interface Props {
|
||||
objectType: string
|
||||
object: Album
|
||||
objectType: EditObjectType
|
||||
object: Album & { attributed_to: Actor }
|
||||
libraries: Library[]
|
||||
}
|
||||
|
||||
|
@ -46,7 +47,6 @@ const canEdit = store.state.auth.availablePermissions.library
|
|||
v-else
|
||||
:object-type="objectType"
|
||||
:object="object"
|
||||
:can-edit="canEdit"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -41,7 +41,7 @@ const page = ref(+props.defaultPage)
|
|||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
const query = ref(props.defaultQuery)
|
||||
const tags = reactive(props.defaultTags.slice())
|
||||
const tags = reactive(props.defaultTags.map(name => ({ name })))
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
['creation_date', 'creation_date'],
|
||||
|
@ -59,7 +59,7 @@ const updateQueryString = () => router.replace({
|
|||
query: {
|
||||
query: query.value,
|
||||
page: page.value,
|
||||
tag: tags,
|
||||
tag: tags.map(({ name }) => name),
|
||||
paginateBy: paginateBy.value,
|
||||
ordering: orderingString.value
|
||||
}
|
||||
|
|
|
@ -1,22 +1,25 @@
|
|||
<script setup lang="ts">
|
||||
import type { Track, Album, Artist, Library } from '~/types'
|
||||
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import axios from 'axios'
|
||||
import PlayButton from '~/components/audio/PlayButton.vue'
|
||||
import EmbedWizard from '~/components/audio/EmbedWizard.vue'
|
||||
import SemanticModal from '~/components/semantic/Modal.vue'
|
||||
import RadioButton from '~/components/radios/Button.vue'
|
||||
import TagsList from '~/components/tags/List.vue'
|
||||
import useReport from '~/composables/moderation/useReport'
|
||||
import useLogger from '~/composables/useLogger'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { getDomain } from '~/utils'
|
||||
import { useStore } from '~/store'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
||||
import axios from 'axios'
|
||||
|
||||
import EmbedWizard from '~/components/audio/EmbedWizard.vue'
|
||||
import SemanticModal from '~/components/semantic/Modal.vue'
|
||||
import PlayButton from '~/components/audio/PlayButton.vue'
|
||||
import RadioButton from '~/components/radios/Button.vue'
|
||||
import TagsList from '~/components/tags/List.vue'
|
||||
|
||||
import useReport from '~/composables/moderation/useReport'
|
||||
import useLogger from '~/composables/useLogger'
|
||||
|
||||
interface Props {
|
||||
id: string
|
||||
id: number
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import type { EditObjectType } from '~/composables/moderation/useEditConfigs'
|
||||
import type { Artist, Library } from '~/types'
|
||||
|
||||
import { useStore } from '~/store'
|
||||
|
@ -6,7 +7,7 @@ import { useStore } from '~/store'
|
|||
import EditForm from '~/components/library/EditForm.vue'
|
||||
|
||||
interface Props {
|
||||
objectType: string
|
||||
objectType: EditObjectType
|
||||
object: Artist
|
||||
libraries: Library[]
|
||||
}
|
||||
|
@ -46,7 +47,6 @@ const canEdit = store.state.auth.availablePermissions.library
|
|||
v-else
|
||||
:object-type="objectType"
|
||||
:object="object"
|
||||
:can-edit="canEdit"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -41,7 +41,7 @@ const page = ref(+props.defaultPage)
|
|||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
const query = ref(props.defaultQuery)
|
||||
const tags = reactive(props.defaultTags.slice())
|
||||
const tags = reactive(props.defaultTags.map(name => ({ name })))
|
||||
const excludeCompilation = ref(true)
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
|
@ -59,7 +59,7 @@ const updateQueryString = () => router.replace({
|
|||
query: {
|
||||
query: query.value,
|
||||
page: page.value,
|
||||
tag: tags,
|
||||
tag: tags.map(({ name }) => name),
|
||||
paginateBy: paginateBy.value,
|
||||
ordering: orderingString.value,
|
||||
content_category: 'music',
|
||||
|
|
|
@ -19,10 +19,12 @@ import EditCard from '~/components/library/EditCard.vue'
|
|||
interface Props {
|
||||
objectType: EditObjectType
|
||||
object: EditObject
|
||||
licenses: License[]
|
||||
licenses?: License[]
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
licenses: () => []
|
||||
})
|
||||
|
||||
const { $pgettext } = useGettext()
|
||||
const configs = useEditConfigs()
|
||||
|
|
|
@ -53,7 +53,7 @@ const labels = computed(() => ({
|
|||
'Invalid file type, ensure you are uploading an audio file. Supported file extensions are %{ extensions }',
|
||||
{ extensions: supportedExtensions.value.join(', ') }
|
||||
)
|
||||
}
|
||||
} as Record<string, string>
|
||||
}))
|
||||
|
||||
const uploads = reactive({
|
||||
|
@ -113,7 +113,7 @@ const fetchStatus = async () => {
|
|||
|
||||
uploads[status as keyof typeof uploads] = response.data.count
|
||||
} catch (error) {
|
||||
useErrorHandler(error as Error)
|
||||
useErrorHandler(error as Error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -473,7 +473,7 @@ useEventListener(window, 'beforeunload', (event) => {
|
|||
<span
|
||||
v-if="typeof file.error === 'string' && file.error"
|
||||
class="ui tooltip"
|
||||
:data-tooltip="labels.tooltips[file.error as keyof typeof labels.tooltips]"
|
||||
:data-tooltip="labels.tooltips[file.error]"
|
||||
>
|
||||
<span class="ui danger icon label">
|
||||
<i class="question circle outline icon" /> {{ file.error }}
|
||||
|
|
|
@ -44,7 +44,7 @@ const page = ref(+props.defaultPage)
|
|||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
const query = ref(props.defaultQuery)
|
||||
const tags = reactive(props.defaultTags.slice())
|
||||
const tags = reactive(props.defaultTags.map(name => ({ name })))
|
||||
const showSubscribeModal = ref(false)
|
||||
|
||||
const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
||||
|
@ -62,7 +62,7 @@ const updateQueryString = () => router.replace({
|
|||
query: {
|
||||
query: query.value,
|
||||
page: page.value,
|
||||
tag: tags,
|
||||
tag: tags.map(({ name }) => name),
|
||||
paginateBy: paginateBy.value,
|
||||
ordering: orderingString.value,
|
||||
content_category: 'podcast',
|
||||
|
|
|
@ -26,7 +26,7 @@ interface Events {
|
|||
}
|
||||
|
||||
interface Props {
|
||||
id: string
|
||||
id: number
|
||||
}
|
||||
|
||||
const emit = defineEmits<Events>()
|
||||
|
|
|
@ -20,7 +20,7 @@ type Filter = { candidates: { count: number, sample: Track[] } }
|
|||
type ResponseType = { filters: Array<Filter> }
|
||||
|
||||
interface Events {
|
||||
(e: 'update-config', index: number, name: string, value: number[]): void
|
||||
(e: 'update-config', index: number, name: string, value: number[] | boolean): void
|
||||
(e: 'delete', index: number): void
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import type { EditObjectType } from '~/composables/moderation/useEditConfigs'
|
|||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
import type { ReviewState, Review } from '~/types'
|
||||
|
||||
import { ref, reactive, watch, computed } from 'vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
@ -39,9 +40,8 @@ const search = ref()
|
|||
|
||||
const page = ref(1)
|
||||
|
||||
type StateTarget = { id: number, type: keyof typeof targets }
|
||||
type ResponseResult = { uuid: string, is_approved: boolean, target?: StateTarget }
|
||||
type ResponseType = { count: number, results: ResponseResult[] }
|
||||
type StateTarget = Review['target']
|
||||
type ResponseType = { count: number, results: Review[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
|
||||
const { onSearch, query, addSearchToken, getTokenValue } = useSmartSearch(props.defaultQuery, props.updateUrl)
|
||||
|
@ -53,20 +53,23 @@ const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
|||
]
|
||||
|
||||
interface TargetType {
|
||||
payload: ResponseResult
|
||||
payload: Review
|
||||
currentState: Record<EditObjectType, { value: unknown }>
|
||||
}
|
||||
|
||||
type Targets = Exclude<StateTarget, undefined>['type']
|
||||
const targets = reactive({
|
||||
track: {} as Record<string, TargetType>
|
||||
})
|
||||
track: {}
|
||||
}) as Record<Targets, Record<string, TargetType>>
|
||||
|
||||
const fetchTargets = async () => {
|
||||
// we request target data via the API so we can display previous state
|
||||
// additionnal data next to the edit card
|
||||
type Config = { url: string, ids: number[] }
|
||||
const typesAndIds: Record<keyof typeof targets, Config> = {
|
||||
track: { url: 'tracks/', ids: [] }
|
||||
const typesAndIds: Record<Targets, Config> = {
|
||||
artist: { url: 'artists/', ids: [] },
|
||||
track: { url: 'tracks/', ids: [] },
|
||||
album: { url: 'albums/', ids: [] }
|
||||
}
|
||||
|
||||
for (const res of result.value?.results ?? []) {
|
||||
|
@ -85,7 +88,7 @@ const fetchTargets = async () => {
|
|||
id: uniq(config.ids),
|
||||
hidden: 'null'
|
||||
}
|
||||
}).catch(() => {
|
||||
}).catch((error) => {
|
||||
useErrorHandler(error as Error)
|
||||
})
|
||||
|
||||
|
@ -147,8 +150,8 @@ const handle = (type: 'delete' | 'approved', id: string, value: boolean) => {
|
|||
}
|
||||
}
|
||||
|
||||
const getCurrentState = (target?: StateTarget): object => {
|
||||
if (!target) return {}
|
||||
const getCurrentState = (target?: StateTarget): ReviewState => {
|
||||
if (!target || !(target.type in targets)) return {}
|
||||
return targets[target.type]?.[target.id]?.currentState ?? {}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -97,8 +97,7 @@ const labels = computed(() => ({
|
|||
searchPlaceholder: $pgettext('Content/Search/Input.Placeholder', 'Search by name')
|
||||
}))
|
||||
|
||||
// TODO (wvffle): Check if we can remove the prop
|
||||
const detailedUpload = ref({})
|
||||
const detailedUpload = ref()
|
||||
const showUploadDetailModal = ref(false)
|
||||
</script>
|
||||
|
||||
|
@ -157,6 +156,7 @@ const showUploadDetailModal = ref(false)
|
|||
</div>
|
||||
</div>
|
||||
<import-status-modal
|
||||
v-if="detailedUpload"
|
||||
v-model:show="showUploadDetailModal"
|
||||
:upload="detailedUpload"
|
||||
/>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import type { ImportStatus, PrivacyLevel, Upload, BackendResponse } from '~/types'
|
||||
import type { RouteWithPreferences, OrderingField } from '~/store/ui'
|
||||
import type { SmartSearchProps } from '~/composables/useSmartSearch'
|
||||
import type { ImportStatus, PrivacyLevel, Upload } from '~/types'
|
||||
import type { OrderingProps } from '~/composables/useOrdering'
|
||||
|
||||
import { humanSize, truncate } from '~/utils/filters'
|
||||
|
@ -37,8 +37,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|||
const search = ref()
|
||||
|
||||
const page = ref(1)
|
||||
type ResponseType = { count: number, results: any[] }
|
||||
const result = ref<null | ResponseType>(null)
|
||||
const result = ref<BackendResponse<Upload>>()
|
||||
|
||||
const { onSearch, query, addSearchToken, getTokenValue } = useSmartSearch(props.defaultQuery, props.updateUrl)
|
||||
const { onOrderingUpdate, orderingString, paginateBy, ordering, orderingDirection } = useOrdering(props.orderingConfigName)
|
||||
|
@ -84,7 +83,7 @@ const fetchData = async () => {
|
|||
result.value = response.data
|
||||
} catch (error) {
|
||||
useErrorHandler(error as Error)
|
||||
result.value = null
|
||||
result.value = undefined
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
|
@ -104,7 +103,7 @@ const displayName = (upload: Upload): string => {
|
|||
return upload.filename ?? upload.source ?? upload.uuid
|
||||
}
|
||||
|
||||
const detailedUpload = ref({})
|
||||
const detailedUpload = ref<Upload>()
|
||||
const showUploadDetailModal = ref(false)
|
||||
|
||||
const getImportStatusChoice = (importStatus: ImportStatus) => {
|
||||
|
@ -229,8 +228,9 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- TODO (wvffle): Check if :upload shouldn't be v-modl:upload -->
|
||||
<!-- TODO (wvffle): Check if :upload shouldn't be v-model:upload -->
|
||||
<import-status-modal
|
||||
v-if="detailedUpload"
|
||||
v-model:show="showUploadDetailModal"
|
||||
:upload="detailedUpload"
|
||||
/>
|
||||
|
@ -296,9 +296,7 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
</translate>
|
||||
</th>
|
||||
</template>
|
||||
<template
|
||||
#row-cells="scope"
|
||||
>
|
||||
<template #row-cells="scope">
|
||||
<td>
|
||||
<router-link :to="{name: 'manage.library.uploads.detail', params: {id: scope.obj.uuid }}">
|
||||
{{ truncate(displayName(scope.obj), 30, undefined, true) }}
|
||||
|
@ -369,7 +367,7 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
</a>
|
||||
<button
|
||||
class="ui tiny basic icon button"
|
||||
:title="sharedLabels.fields.import_status.detailTitle"
|
||||
:title="sharedLabels.fields.import_status.label"
|
||||
@click="detailedUpload = scope.obj; showUploadDetailModal = true"
|
||||
>
|
||||
<i class="question circle outline icon" />
|
||||
|
|
|
@ -326,7 +326,7 @@ const handleRemovedNote = (uuid: string) => {
|
|||
<router-link
|
||||
v-if="target && configs[target.type].urls.getDetail"
|
||||
class="ui basic button"
|
||||
:to="configs[target.type].urls.getDetail(obj.target_state)"
|
||||
:to="configs[target.type].urls.getDetail?.(obj.target_state) ?? '/'"
|
||||
>
|
||||
<i class="eye icon" />
|
||||
<translate translate-context="Content/Moderation/Link">
|
||||
|
@ -336,7 +336,7 @@ const handleRemovedNote = (uuid: string) => {
|
|||
<router-link
|
||||
v-if="target && configs[target.type].urls.getAdminDetail"
|
||||
class="ui basic button"
|
||||
:to="configs[target.type].urls.getAdminDetail(obj.target_state)"
|
||||
:to="configs[target.type].urls.getAdminDetail?.(obj.target_state) ?? '/'"
|
||||
>
|
||||
<i class="wrench icon" />
|
||||
<translate translate-context="Content/Moderation/Link">
|
||||
|
@ -391,10 +391,10 @@ const handleRemovedNote = (uuid: string) => {
|
|||
</td>
|
||||
<td>
|
||||
<instance-policy-modal
|
||||
v-if="!obj.target_owner.is_local"
|
||||
v-if="!obj.target_owner?.is_local"
|
||||
class="right floated mini basic"
|
||||
type="actor"
|
||||
:target="obj.target_owner.full_username"
|
||||
:target="obj.target_owner?.full_username ?? ''"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -9,7 +9,7 @@ interface Props {
|
|||
customRadioId?: number | null
|
||||
type?: string
|
||||
clientOnly?: boolean
|
||||
objectId?: ObjectId | string | null
|
||||
objectId?: ObjectId | number | string | null
|
||||
radioConfig?: RadioConfig | null
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,10 @@ const running = computed(() => {
|
|||
&& store.state.radios.current?.customRadioId === props.customRadioId
|
||||
&& (
|
||||
typeof props.objectId === 'string'
|
||||
|| store.state.radios.current?.objectId?.fullUsername === props.objectId?.fullUsername
|
||||
|| (
|
||||
typeof props.objectId !== 'number'
|
||||
&& store.state.radios.current?.objectId?.fullUsername === props.objectId?.fullUsername
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
|
|
|
@ -6,12 +6,12 @@ import { reactive, watchEffect, ref } from 'vue'
|
|||
const MAX_PRELOADED = 3
|
||||
|
||||
export interface CachedSound {
|
||||
id: string
|
||||
id: number
|
||||
date: Date
|
||||
howl: Howl
|
||||
}
|
||||
|
||||
const soundCache = reactive(new Map<string, CachedSound>())
|
||||
const soundCache = reactive(new Map<number, CachedSound>())
|
||||
const cleaningCache = ref(false)
|
||||
|
||||
watchEffect(() => {
|
||||
|
|
|
@ -22,7 +22,7 @@ export default () => ({
|
|||
} as Record<PrivacyLevel, string>
|
||||
},
|
||||
import_status: {
|
||||
detailTitle: $pgettext('Content/Library/Link.Title', 'Click to display more information about the import process for this upload'),
|
||||
label: $pgettext('Content/Library/Link.Title', 'Click to display more information about the import process for this upload'),
|
||||
choices: {
|
||||
skipped: {
|
||||
label: $pgettext('Content/Library/*', 'Skipped'),
|
||||
|
@ -57,7 +57,8 @@ export default () => ({
|
|||
}
|
||||
},
|
||||
summary: {
|
||||
label: $pgettext('Content/Account/*', 'Bio')
|
||||
label: $pgettext('Content/Account/*', 'Bio'),
|
||||
help: undefined
|
||||
},
|
||||
content_category: {
|
||||
label: $pgettext('Content/*/Dropdown.Label/Noun', 'Content category'),
|
||||
|
|
|
@ -23,7 +23,7 @@ interface ReportableObject {
|
|||
_obj: Objects[keyof Objects]
|
||||
|
||||
full_username?: string
|
||||
id?: string
|
||||
id?: number
|
||||
uuid?: string
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
import jQuery from 'jquery'
|
||||
|
||||
// NOTE: Workaround for fomantic-ui-css
|
||||
if (import.meta.env.DEV) {
|
||||
window.$ = window.jQuery = jQuery
|
||||
}
|
||||
|
||||
export default jQuery
|
|
@ -1,3 +1,5 @@
|
|||
/// <reference lib="webworker" />
|
||||
|
||||
import { cleanupOutdatedCaches, precacheAndRoute } from 'workbox-precaching'
|
||||
import { NetworkFirst, StaleWhileRevalidate } from 'workbox-strategies'
|
||||
import { ExpirationPlugin } from 'workbox-expiration'
|
||||
|
|
|
@ -31,7 +31,7 @@ export interface ContentFilter {
|
|||
creation_date: Date
|
||||
target: {
|
||||
type: 'artist'
|
||||
id: string
|
||||
id: number
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ export interface ThemeEntry {
|
|||
export type ContentCategory = 'podcast' | 'music'
|
||||
|
||||
export interface Artist {
|
||||
id: string
|
||||
id: number
|
||||
fid: string
|
||||
mbid?: string
|
||||
|
||||
|
@ -65,7 +65,7 @@ export interface Artist {
|
|||
}
|
||||
|
||||
export interface Album {
|
||||
id: string
|
||||
id: number
|
||||
fid: string
|
||||
mbid?: string
|
||||
|
||||
|
@ -84,7 +84,7 @@ export interface Album {
|
|||
}
|
||||
|
||||
export interface Track {
|
||||
id: string
|
||||
id: number
|
||||
fid: string
|
||||
mbid?: string
|
||||
|
||||
|
@ -111,7 +111,7 @@ export interface Track {
|
|||
}
|
||||
|
||||
export interface Channel {
|
||||
id: string
|
||||
id: number
|
||||
uuid: string
|
||||
artist?: Artist
|
||||
actor: Actor
|
||||
|
@ -134,7 +134,7 @@ export interface Channel {
|
|||
export type PrivacyLevel = 'everyone' | 'instance' | 'me'
|
||||
|
||||
export interface Library {
|
||||
id: string
|
||||
id: number
|
||||
uuid: string
|
||||
fid?: string
|
||||
name: string
|
||||
|
@ -182,7 +182,7 @@ export interface License {
|
|||
}
|
||||
|
||||
export interface Playlist {
|
||||
id: string
|
||||
id: number
|
||||
name: string
|
||||
modification_date: string
|
||||
user: User
|
||||
|
@ -206,7 +206,7 @@ export interface Radio {
|
|||
}
|
||||
|
||||
export interface Listening {
|
||||
id: string
|
||||
id: number
|
||||
track: Track
|
||||
user: User
|
||||
actor: Actor
|
||||
|
@ -277,6 +277,7 @@ export interface Form {
|
|||
|
||||
// Upload stuff
|
||||
export interface Upload {
|
||||
id: number
|
||||
uuid: string
|
||||
filename?: string
|
||||
source?: string
|
||||
|
@ -293,12 +294,12 @@ export interface Upload {
|
|||
error_code: string
|
||||
}
|
||||
|
||||
import_metadata?: Record<string, string>
|
||||
import_metadata?: Record<string, string> & { tags?: Tag[] }
|
||||
}
|
||||
|
||||
// Profile stuff
|
||||
export interface Actor {
|
||||
id: string
|
||||
id: number
|
||||
fid?: string
|
||||
name?: string
|
||||
icon?: Cover
|
||||
|
@ -310,7 +311,7 @@ export interface Actor {
|
|||
}
|
||||
|
||||
export interface User {
|
||||
id: string
|
||||
id: number
|
||||
avatar?: Cover
|
||||
email: string
|
||||
summary: { text: string, content_type: string }
|
||||
|
@ -403,7 +404,7 @@ export interface Plugin {
|
|||
export type EntityObjectType = 'artist' | 'album' | 'track' | 'library' | 'playlist' | 'account' | 'channel'
|
||||
|
||||
export interface ReportTarget {
|
||||
id: string
|
||||
id: number
|
||||
type: EntityObjectType
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import type { ListenWSEvent } from '~/types'
|
||||
import type { CurrentRadio, PopulateQueuePayload } from '~/store/radios'
|
||||
import type { ListenWS } from '~/composables/useWebSocketHandler'
|
||||
import type { RootState } from '~/store'
|
||||
import type { Store } from 'vuex'
|
||||
import type { CurrentRadio, PopulateQueuePayload } from '~/store/radios'
|
||||
|
||||
import axios from 'axios'
|
||||
|
||||
import useLogger from '~/composables/useLogger'
|
||||
|
||||
const logger = useLogger()
|
||||
|
@ -14,7 +15,7 @@ export const CLIENT_RADIOS = {
|
|||
account: {
|
||||
offset: 1,
|
||||
populateQueue ({ current, dispatch, playNow }: PopulateQueuePayload) {
|
||||
const params = { scope: `actor:${current.objectId.fullUsername}`, ordering: '-creation_date', page_size: 1, page: this.offset }
|
||||
const params = { scope: `actor:${current.objectId?.fullUsername}`, ordering: '-creation_date', page_size: 1, page: this.offset }
|
||||
axios.get('history/listenings', { params }).then(async (response) => {
|
||||
const latest = response.data.results[0]
|
||||
if (!latest) {
|
||||
|
@ -35,9 +36,9 @@ export const CLIENT_RADIOS = {
|
|||
stop () {
|
||||
this.offset = 1
|
||||
},
|
||||
handleListen (current: CurrentRadio, event: ListenWSEvent, store: Store<RootState>) {
|
||||
handleListen (current: CurrentRadio, event: ListenWS, store: Store<RootState>) {
|
||||
// TODO: handle actors from other pods
|
||||
if (event.actor.local_id === current.objectId.username) {
|
||||
if (event.actor.local_id === current.objectId?.username) {
|
||||
axios.get(`tracks/${event.object.local_id}`).then(async (response) => {
|
||||
if (response.data.uploads.length > 0) {
|
||||
await store.dispatch('queue/append', { track: response.data })
|
||||
|
|
|
@ -12,7 +12,7 @@ import TagsList from '~/components/tags/List.vue'
|
|||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
|
||||
interface Props {
|
||||
id: string
|
||||
id: number
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
|
|
@ -15,7 +15,7 @@ import useLogger from '~/composables/useLogger'
|
|||
const PRIVACY_LEVELS = ['me', 'instance', 'everyone'] as PrivacyLevel[]
|
||||
|
||||
interface Props {
|
||||
id: string
|
||||
id: number
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
|
|
@ -14,7 +14,7 @@ import useSharedLabels from '~/composables/locale/useSharedLabels'
|
|||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
|
||||
interface Props {
|
||||
id: string
|
||||
id: number
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
@ -258,7 +258,7 @@ const showUploadDetailModal = ref(false)
|
|||
{{ importStatus }}
|
||||
<button
|
||||
class="ui tiny basic icon button"
|
||||
:title="sharedLabels.fields.import_status.detailTitle"
|
||||
:title="sharedLabels.fields.import_status.label"
|
||||
@click="showUploadDetailModal = true"
|
||||
>
|
||||
<i class="question circle outline icon" />
|
||||
|
|
|
@ -38,7 +38,7 @@ const allPermissions = computed(() => [
|
|||
|
||||
const isLoadingPolicy = ref(false)
|
||||
const policy = ref()
|
||||
const fetchPolicy = async (id: string) => {
|
||||
const fetchPolicy = async (id: number) => {
|
||||
isLoadingPolicy.value = true
|
||||
|
||||
try {
|
||||
|
|
|
@ -28,7 +28,7 @@ const labels = computed(() => ({
|
|||
|
||||
const isLoadingPolicy = ref(false)
|
||||
const policy = ref()
|
||||
const fetchPolicy = async (id: string) => {
|
||||
const fetchPolicy = async (id: number) => {
|
||||
isLoadingPolicy.value = true
|
||||
|
||||
try {
|
||||
|
|
|
@ -18,6 +18,9 @@ const showCreateModal = ref(false)
|
|||
const loading = ref(false)
|
||||
const submittable = ref(false)
|
||||
const category = ref('podcast')
|
||||
|
||||
const modalContent = ref()
|
||||
const createForm = ref()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -108,7 +111,7 @@ const category = ref('podcast')
|
|||
@loading="loading = $event"
|
||||
@submittable="submittable = $event"
|
||||
@category="category = $event"
|
||||
@errored="$refs.modalContent.scrollTop = 0"
|
||||
@errored="modalContent.scrollTop = 0"
|
||||
@created="$router.push({name: 'channels.detail', params: {id: $event.actor.preferred_username}})"
|
||||
/>
|
||||
<div class="ui hidden divider" />
|
||||
|
@ -145,7 +148,7 @@ const category = ref('podcast')
|
|||
:class="['ui', 'primary button', { loading }]"
|
||||
type="submit"
|
||||
:disabled="!submittable && !loading"
|
||||
@click.prevent.stop="$refs.createForm.submit"
|
||||
@click.prevent.stop="createForm.submit"
|
||||
>
|
||||
<translate translate-context="*/Channels/Button.Label">
|
||||
Create channel
|
||||
|
|
|
@ -23,7 +23,7 @@ interface Events {
|
|||
}
|
||||
|
||||
interface Props {
|
||||
id: string
|
||||
id: number
|
||||
}
|
||||
|
||||
const emit = defineEmits<Events>()
|
||||
|
|
|
@ -124,7 +124,7 @@ const labels = computed(() => ({
|
|||
showStatus: $pgettext('Content/Library/Button.Label/Verb', 'Show information about the upload status for this track')
|
||||
}))
|
||||
|
||||
const detailedUpload = ref({})
|
||||
const detailedUpload = ref()
|
||||
const showUploadDetailModal = ref(false)
|
||||
|
||||
const getImportStatusChoice = (importStatus: ImportStatus) => {
|
||||
|
@ -235,6 +235,7 @@ const getImportStatusChoice = (importStatus: ImportStatus) => {
|
|||
</div>
|
||||
</div>
|
||||
<import-status-modal
|
||||
v-if="detailedUpload"
|
||||
v-model:show="showUploadDetailModal"
|
||||
:upload="detailedUpload"
|
||||
/>
|
||||
|
@ -352,7 +353,7 @@ const getImportStatusChoice = (importStatus: ImportStatus) => {
|
|||
>{{ getImportStatusChoice(scope.obj.import_status).label }}</a>
|
||||
<button
|
||||
class="ui tiny basic icon button"
|
||||
:title="sharedLabels.fields.import_status.detailTitle"
|
||||
:title="sharedLabels.fields.import_status.label"
|
||||
:aria-label="labels.showStatus"
|
||||
@click="detailedUpload = scope.obj; showUploadDetailModal = true"
|
||||
>
|
||||
|
|
|
@ -83,7 +83,6 @@ const libraryCreated = (library: Library) => {
|
|||
</a>
|
||||
<library-form
|
||||
v-if="!hiddenForm"
|
||||
:library="null"
|
||||
@created="libraryCreated"
|
||||
/>
|
||||
<div class="ui hidden divider" />
|
||||
|
|
|
@ -16,7 +16,7 @@ import useErrorHandler from '~/composables/useErrorHandler'
|
|||
import useReport from '~/composables/moderation/useReport'
|
||||
|
||||
interface Props {
|
||||
id: string
|
||||
id: number
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
|
|
@ -17,7 +17,7 @@ import PlayButton from '~/components/audio/PlayButton.vue'
|
|||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
|
||||
interface Props {
|
||||
id: string
|
||||
id: number
|
||||
defaultEdit?: boolean
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import Pagination from '~/components/vui/Pagination.vue'
|
|||
import useErrorHandler from '~/composables/useErrorHandler'
|
||||
|
||||
interface Props {
|
||||
id: string
|
||||
id: number
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
|
Loading…
Reference in New Issue