Resolve most type conflicts

This commit is contained in:
wvffle 2022-08-31 16:39:24 +00:00 committed by Georg Krause
parent e7da8b5f43
commit 436a76928f
50 changed files with 168 additions and 151 deletions

View File

@ -41,7 +41,7 @@ defineProps<Props>()
>
<strong>{{ source.track.title }}</strong><br>
<span>
{{ source.track.artist.name }}
{{ source.track.artist?.name }}
</span>
</button>
</div>

View File

@ -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"

View File

@ -6,7 +6,7 @@ import { useClipboard } from '@vueuse/core'
interface Props {
type: string
id: string
id: number
}
const props = defineProps<Props>()

View File

@ -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"

View File

@ -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
}

View File

@ -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"

View File

@ -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 }.

View File

@ -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)

View File

@ -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

View File

@ -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>

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -24,6 +24,7 @@ onMounted(() => {
...props.message
}
// @ts-expect-error fomantic ui
$('body').toast(params)
$('.ui.toast.visible').last().attr('role', 'alert')
})

View File

@ -21,7 +21,7 @@ interface Events {
}
interface Props {
id: string
id: number
}
const emit = defineEmits<Events>()

View File

@ -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>

View File

@ -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
}

View File

@ -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>()

View File

@ -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>

View File

@ -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',

View File

@ -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()

View File

@ -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 }}

View File

@ -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',

View File

@ -26,7 +26,7 @@ interface Events {
}
interface Props {
id: string
id: number
}
const emit = defineEmits<Events>()

View File

@ -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
}

View File

@ -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>

View File

@ -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"
/>

View File

@ -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" />

View File

@ -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>

View File

@ -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
)
)
})

View File

@ -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(() => {

View File

@ -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'),

View File

@ -23,7 +23,7 @@ interface ReportableObject {
_obj: Objects[keyof Objects]
full_username?: string
id?: string
id?: number
uuid?: string
}
}

View File

@ -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

View File

@ -1,3 +1,5 @@
/// <reference lib="webworker" />
import { cleanupOutdatedCaches, precacheAndRoute } from 'workbox-precaching'
import { NetworkFirst, StaleWhileRevalidate } from 'workbox-strategies'
import { ExpirationPlugin } from 'workbox-expiration'

View File

@ -31,7 +31,7 @@ export interface ContentFilter {
creation_date: Date
target: {
type: 'artist'
id: string
id: number
}
}

View File

@ -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
}

View File

@ -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 })

View File

@ -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>()

View File

@ -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>()

View File

@ -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" />

View File

@ -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 {

View File

@ -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 {

View File

@ -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

View File

@ -23,7 +23,7 @@ interface Events {
}
interface Props {
id: string
id: number
}
const emit = defineEmits<Events>()

View File

@ -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"
>

View File

@ -83,7 +83,6 @@ const libraryCreated = (library: Library) => {
</a>
<library-form
v-if="!hiddenForm"
:library="null"
@created="libraryCreated"
/>
<div class="ui hidden divider" />

View File

@ -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>()

View File

@ -17,7 +17,7 @@ import PlayButton from '~/components/audio/PlayButton.vue'
import useErrorHandler from '~/composables/useErrorHandler'
interface Props {
id: string
id: number
defaultEdit?: boolean
}

View File

@ -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>()