Move *.js to *.ts
This commit is contained in:
parent
8ff0bb937b
commit
9e0596d136
|
@ -28,11 +28,7 @@ module.exports = {
|
||||||
// NOTE: Handled by typescript
|
// NOTE: Handled by typescript
|
||||||
'no-undef': 'off',
|
'no-undef': 'off',
|
||||||
'no-unused-vars': 'off',
|
'no-unused-vars': 'off',
|
||||||
|
'no-use-before-define': 'off',
|
||||||
// TODO (wvffle): Migrate to VUI
|
|
||||||
// We're using `// @ts-ignore` in jQuery extensions
|
|
||||||
// and gettext for vue 2
|
|
||||||
'@typescript-eslint/ban-ts-comment': 'off',
|
|
||||||
|
|
||||||
// TODO (wvffle): Enable these rules later
|
// TODO (wvffle): Enable these rules later
|
||||||
'vue/multi-word-component-names': 'off',
|
'vue/multi-word-component-names': 'off',
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
const Album = {
|
|
||||||
clean (album) {
|
|
||||||
// we manually rebind the album and artist to each child track
|
|
||||||
album.tracks = album.tracks.map((track) => {
|
|
||||||
track.album = album
|
|
||||||
return track
|
|
||||||
})
|
|
||||||
return album
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const Artist = {
|
|
||||||
clean (artist) {
|
|
||||||
// clean data as given by the API
|
|
||||||
artist.albums = artist.albums.map((album) => {
|
|
||||||
return Album.clean(album)
|
|
||||||
})
|
|
||||||
return artist
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default {
|
|
||||||
Artist: Artist,
|
|
||||||
Album: Album
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
export default {
|
|
||||||
formats: [
|
|
||||||
// 'audio/ogg',
|
|
||||||
'audio/mpeg'
|
|
||||||
],
|
|
||||||
formatsMap: {
|
|
||||||
'audio/ogg': 'ogg',
|
|
||||||
'audio/mpeg': 'mp3',
|
|
||||||
'audio/x-flac': 'flac'
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
const DYNAMIC_RANGE = 40 // dB
|
|
||||||
|
|
||||||
export function toLinearVolumeScale (v) {
|
|
||||||
if (v <= 0.0) {
|
|
||||||
return 0.0
|
|
||||||
}
|
|
||||||
|
|
||||||
// (1.0; 0.0) -> (0; -DYNAMIC_RANGE) dB
|
|
||||||
const dB = (v - 1) * DYNAMIC_RANGE
|
|
||||||
|
|
||||||
return Math.pow(10, dB / 20)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toLogarithmicVolumeScale (v) {
|
|
||||||
if (v <= 0.0) {
|
|
||||||
return 0.0
|
|
||||||
}
|
|
||||||
|
|
||||||
const dB = 20 * Math.log10(v)
|
|
||||||
|
|
||||||
// (0; -DYNAMIC_RANGE) [dB] -> (1.0; 0.0)
|
|
||||||
return 1 - (dB / -DYNAMIC_RANGE)
|
|
||||||
}
|
|
|
@ -51,8 +51,8 @@
|
||||||
</template>
|
</template>
|
||||||
<content-form
|
<content-form
|
||||||
v-if="setting.fieldType === 'markdown'"
|
v-if="setting.fieldType === 'markdown'"
|
||||||
v-model="values[setting.identifier]"
|
|
||||||
v-bind="setting.fieldParams"
|
v-bind="setting.fieldParams"
|
||||||
|
v-model="values[setting.identifier]"
|
||||||
/>
|
/>
|
||||||
<signup-form-builder
|
<signup-form-builder
|
||||||
v-else-if="setting.fieldType === 'formBuilder'"
|
v-else-if="setting.fieldType === 'formBuilder'"
|
||||||
|
|
|
@ -321,7 +321,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { useStore, mapState, mapGetters, mapActions } from 'vuex'
|
import { useStore, mapState, mapGetters, mapActions } from 'vuex'
|
||||||
import { toLinearVolumeScale } from '~/audio/volume.js'
|
import toLinearVolumeScale from '~/composables/audio/toLinearVolumeScale'
|
||||||
import { Howl, Howler } from 'howler'
|
import { Howl, Howler } from 'howler'
|
||||||
import { throttle, reverse } from 'lodash-es'
|
import { throttle, reverse } from 'lodash-es'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
|
@ -27,17 +27,15 @@
|
||||||
class="ui center aligned basic segment desktop-and-up"
|
class="ui center aligned basic segment desktop-and-up"
|
||||||
>
|
>
|
||||||
<pagination
|
<pagination
|
||||||
|
v-bind="$attrs"
|
||||||
:total="total"
|
:total="total"
|
||||||
:current="page"
|
:current="page"
|
||||||
:paginate-by="paginateBy"
|
:paginate-by="paginateBy"
|
||||||
v-bind="$attrs"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div :class="['track-table', 'ui', 'unstackable', 'grid', 'tablet-and-below']">
|
||||||
:class="['track-table', 'ui', 'unstackable', 'grid', 'tablet-and-below']"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
v-if="isLoading"
|
v-if="isLoading"
|
||||||
class="ui inverted active dimmer"
|
class="ui inverted active dimmer"
|
||||||
|
@ -66,10 +64,10 @@
|
||||||
>
|
>
|
||||||
<pagination
|
<pagination
|
||||||
v-if="paginateResults"
|
v-if="paginateResults"
|
||||||
|
v-bind="$attrs"
|
||||||
:total="total"
|
:total="total"
|
||||||
:current="page"
|
:current="page"
|
||||||
:compact="true"
|
:compact="true"
|
||||||
v-bind="$attrs"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -121,7 +121,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { uniq } from 'lodash-es'
|
import { uniq } from 'lodash-es'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import useSharedLabels from '../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
|
|
|
@ -145,7 +145,7 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
import { checkRedirectToLogin } from '~/utils'
|
import { checkRedirectToLogin } from '~/utils'
|
||||||
import useSharedLabels from '../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
clientId: { type: String, required: true },
|
clientId: { type: String, required: true },
|
||||||
|
|
|
@ -717,7 +717,7 @@ import PasswordInput from '~/components/forms/PasswordInput.vue'
|
||||||
import SubsonicTokenForm from '~/components/auth/SubsonicTokenForm.vue'
|
import SubsonicTokenForm from '~/components/auth/SubsonicTokenForm.vue'
|
||||||
import AttachmentInput from '~/components/common/AttachmentInput.vue'
|
import AttachmentInput from '~/components/common/AttachmentInput.vue'
|
||||||
import useLogger from '~/composables/useLogger'
|
import useLogger from '~/composables/useLogger'
|
||||||
import useSharedLabels from '../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
const logger = useLogger()
|
const logger = useLogger()
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ const remove = async (uuid: string, sendEvent = true) => {
|
||||||
const initialValue = ref(props.initialValue ?? props.modelValue)
|
const initialValue = ref(props.initialValue ?? props.modelValue)
|
||||||
watch(value, (to, from) => {
|
watch(value, (to, from) => {
|
||||||
// NOTE: Remove old attachment if it's not the original one
|
// NOTE: Remove old attachment if it's not the original one
|
||||||
if (from !== initialValue.value) {
|
if (from !== initialValue.value && typeof from === 'string') {
|
||||||
remove(from, false)
|
remove(from, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,33 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
import { useToggle } from '@vueuse/core'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
content: string
|
||||||
|
length?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
length: 150
|
||||||
|
})
|
||||||
|
|
||||||
|
const [expanded, toggleExpanded] = useToggle(false)
|
||||||
|
const truncated = computed(() => props.content.slice(0, props.length))
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="expandable-wrapper">
|
<div class="expandable-wrapper">
|
||||||
<div :class="['expandable-content', {expandable: truncated.length < content.length}, {expanded: isExpanded}]">
|
<div :class="['expandable-content', { expandable: truncated.length < content.length, expanded }]">
|
||||||
<slot>{{ content }}</slot>
|
<slot>{{ content }}</slot>
|
||||||
</div>
|
</div>
|
||||||
<a
|
<a
|
||||||
v-if="truncated.length < content.length"
|
v-if="truncated.length < content.length"
|
||||||
role="button"
|
role="button"
|
||||||
@click.prevent="isExpanded = !isExpanded"
|
@click.prevent="toggleExpanded()"
|
||||||
>
|
>
|
||||||
<br>
|
<br>
|
||||||
<translate
|
<translate
|
||||||
v-if="isExpanded"
|
v-if="expanded"
|
||||||
key="1"
|
key="1"
|
||||||
translate-context="*/*/Button,Label"
|
translate-context="*/*/Button,Label"
|
||||||
>Show less</translate>
|
>Show less</translate>
|
||||||
|
@ -22,23 +39,3 @@
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
|
||||||
// import sanitize from "~/sanitize"
|
|
||||||
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
content: { type: String, required: true },
|
|
||||||
length: { type: Number, default: 150, required: false }
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
isExpanded: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
truncated () {
|
|
||||||
return this.content.substring(0, this.length)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ interface Props {
|
||||||
duration: number
|
duration: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const { duration } = toRefs(defineProps<Props>())
|
const props = defineProps<Props>()
|
||||||
|
const { duration } = toRefs(props)
|
||||||
const parsedDuration = computed(() => time.parse(duration.value))
|
const parsedDuration = computed(() => time.parse(duration.value))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ onMounted(() => {
|
||||||
...props.message
|
...props.message
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error
|
// @ts-expect-error toast is from semantic ui
|
||||||
$('body').toast(params)
|
$('body').toast(params)
|
||||||
$('.ui.toast.visible').last().attr('role', 'alert')
|
$('.ui.toast.visible').last().attr('role', 'alert')
|
||||||
})
|
})
|
||||||
|
|
|
@ -142,7 +142,7 @@ import PaginationMixin from '~/components/mixins/Pagination.vue'
|
||||||
import { checkRedirectToLogin } from '~/utils'
|
import { checkRedirectToLogin } from '~/utils'
|
||||||
import TrackTable from '~/components/audio/track/Table.vue'
|
import TrackTable from '~/components/audio/track/Table.vue'
|
||||||
import useLogger from '~/composables/useLogger'
|
import useLogger from '~/composables/useLogger'
|
||||||
import useSharedLabels from '../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
const logger = useLogger()
|
const logger = useLogger()
|
||||||
|
|
||||||
|
|
|
@ -157,7 +157,7 @@ import AlbumCard from '~/components/audio/album/Card.vue'
|
||||||
import Pagination from '~/components/Pagination.vue'
|
import Pagination from '~/components/Pagination.vue'
|
||||||
import TagsSelector from '~/components/library/TagsSelector.vue'
|
import TagsSelector from '~/components/library/TagsSelector.vue'
|
||||||
import useLogger from '~/composables/useLogger'
|
import useLogger from '~/composables/useLogger'
|
||||||
import useSharedLabels from '../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
const logger = useLogger()
|
const logger = useLogger()
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,7 @@ import ArtistCard from '~/components/audio/artist/Card.vue'
|
||||||
import Pagination from '~/components/Pagination.vue'
|
import Pagination from '~/components/Pagination.vue'
|
||||||
import TagsSelector from '~/components/library/TagsSelector.vue'
|
import TagsSelector from '~/components/library/TagsSelector.vue'
|
||||||
import useLogger from '~/composables/useLogger'
|
import useLogger from '~/composables/useLogger'
|
||||||
import useSharedLabels from '../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
const logger = useLogger()
|
const logger = useLogger()
|
||||||
|
|
||||||
|
|
|
@ -219,7 +219,7 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { diffWordsWithSpace } from 'diff'
|
import { diffWordsWithSpace } from 'diff'
|
||||||
|
|
||||||
import edits from '~/edits.js'
|
import useEditConfigs from '~/composables/moderation/useEditConfigs'
|
||||||
|
|
||||||
function castValue (value) {
|
function castValue (value) {
|
||||||
if (value === null || value === undefined) {
|
if (value === null || value === undefined) {
|
||||||
|
@ -233,15 +233,28 @@ export default {
|
||||||
obj: { type: Object, required: true },
|
obj: { type: Object, required: true },
|
||||||
currentState: { type: Object, required: false, default: function () { return { } } }
|
currentState: { type: Object, required: false, default: function () { return { } } }
|
||||||
},
|
},
|
||||||
|
setup () {
|
||||||
|
return { configs: useEditConfigs() }
|
||||||
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
isLoading: false
|
isLoading: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
configs: edits.getConfigs,
|
canApprove () {
|
||||||
canApprove: edits.getCanApprove,
|
if (this.obj.is_applied) return false
|
||||||
canDelete: edits.getCanDelete,
|
if (!this.$store.state.auth.authenticated) return false
|
||||||
|
return this.$store.state.auth.availablePermissions.library
|
||||||
|
},
|
||||||
|
canDelete () {
|
||||||
|
if (this.obj.is_applied || this.obj.is_approved) return false
|
||||||
|
if (!this.$store.state.auth.authenticated) return false
|
||||||
|
|
||||||
|
// TODO (wvffle): Is it better to compare ids? Is full_username unique?
|
||||||
|
return this.obj.created_by.full_username === this.$store.state.auth.fullUsername ||
|
||||||
|
this.$store.state.auth.availablePermissions.library
|
||||||
|
},
|
||||||
previousState () {
|
previousState () {
|
||||||
if (this.obj.is_applied) {
|
if (this.obj.is_applied) {
|
||||||
// mutation was applied, we use the previous state that is stored
|
// mutation was applied, we use the previous state that is stored
|
||||||
|
@ -279,7 +292,7 @@ export default {
|
||||||
const fields = Object.keys(payload)
|
const fields = Object.keys(payload)
|
||||||
const self = this
|
const self = this
|
||||||
return fields.map((f) => {
|
return fields.map((f) => {
|
||||||
const fieldConfig = edits.getFieldConfig(self.configs, this.obj.target.type, f)
|
const fieldConfig = configs[this.obj.target.type].fields.find(({ id }) => id === f)
|
||||||
const dummyRepr = (v) => { return v }
|
const dummyRepr = (v) => { return v }
|
||||||
const getValueRepr = fieldConfig.getValueRepr || dummyRepr
|
const getValueRepr = fieldConfig.getValueRepr || dummyRepr
|
||||||
const d = {
|
const d = {
|
||||||
|
|
|
@ -1,5 +1,46 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import axios from 'axios'
|
||||||
|
import useEditConfigs, { EditObject, EditObjectType } from '~/composables/moderation/useEditConfigs'
|
||||||
|
import EditCard from '~/components/library/EditCard.vue'
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
object: EditObject
|
||||||
|
objectType: EditObjectType
|
||||||
|
editId: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
|
const configs = useEditConfigs()
|
||||||
|
const config = computed(() => configs[props.objectType])
|
||||||
|
|
||||||
|
const currentState = computed(() => config.value.fields.reduce((state: Record<string, unknown>, field) => {
|
||||||
|
state[field.id] = { value: field.getValue(props.object) }
|
||||||
|
return state
|
||||||
|
}, {}))
|
||||||
|
|
||||||
|
const isLoading = ref(false)
|
||||||
|
const obj = ref()
|
||||||
|
const fetchData = async () => {
|
||||||
|
isLoading.value = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`mutations/${props.editId}/`)
|
||||||
|
obj.value = response.data
|
||||||
|
} catch (error) {
|
||||||
|
// TODO (wvffle): Handle error
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchData()
|
||||||
|
// TODO (wvffle): Check if we want to watch for editId change and refetch data
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section :class="['ui', 'vertical', 'stripe', {loading: isLoading}, 'segment']">
|
<section :class="['ui', 'vertical', 'stripe', { loading: isLoading }, 'segment']">
|
||||||
<div class="ui text container">
|
<div class="ui text container">
|
||||||
<edit-card
|
<edit-card
|
||||||
v-if="obj"
|
v-if="obj"
|
||||||
|
@ -9,50 +50,3 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
|
||||||
import axios from 'axios'
|
|
||||||
import edits from '~/edits.js'
|
|
||||||
import EditCard from '~/components/library/EditCard.vue'
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
EditCard
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
object: { type: Object, required: true },
|
|
||||||
objectType: { type: String, required: true },
|
|
||||||
editId: { type: Number, required: true }
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
isLoading: true,
|
|
||||||
obj: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
configs: edits.getConfigs,
|
|
||||||
config: edits.getConfig,
|
|
||||||
currentState () {
|
|
||||||
const self = this
|
|
||||||
const s = {}
|
|
||||||
this.config.fields.forEach(f => {
|
|
||||||
s[f.id] = { value: f.getValue(self.object) }
|
|
||||||
})
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created () {
|
|
||||||
this.fetchData()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
fetchData () {
|
|
||||||
const self = this
|
|
||||||
this.isLoading = true
|
|
||||||
axios.get(`mutations/${this.editId}/`).then(response => {
|
|
||||||
self.obj = response.data
|
|
||||||
self.isLoading = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
|
@ -249,7 +249,8 @@ import AttachmentInput from '~/components/common/AttachmentInput.vue'
|
||||||
import EditList from '~/components/library/EditList.vue'
|
import EditList from '~/components/library/EditList.vue'
|
||||||
import EditCard from '~/components/library/EditCard.vue'
|
import EditCard from '~/components/library/EditCard.vue'
|
||||||
import TagsSelector from '~/components/library/TagsSelector.vue'
|
import TagsSelector from '~/components/library/TagsSelector.vue'
|
||||||
import edits from '~/edits.js'
|
import useEditConfigs from '~/composables/useEditConfigs'
|
||||||
|
import { computed } from 'vue/dist/vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -263,6 +264,16 @@ export default {
|
||||||
object: { type: Object, required: true },
|
object: { type: Object, required: true },
|
||||||
licenses: { type: Array, required: true }
|
licenses: { type: Array, required: true }
|
||||||
},
|
},
|
||||||
|
setup (props) {
|
||||||
|
const configs = useEditConfigs()
|
||||||
|
const config = computed(() => configs[props.objectType])
|
||||||
|
const currentState = computed(() => config.value.fields.reduce((state/*: Record<string, unknown> */, field) => {
|
||||||
|
state[field.id] = { value: field.getValue(props.object) }
|
||||||
|
return state
|
||||||
|
}, {}))
|
||||||
|
|
||||||
|
return { config, currentState, configs }
|
||||||
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
|
@ -275,10 +286,15 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
configs: edits.getConfigs,
|
canEdit () {
|
||||||
config: edits.getConfig,
|
if (!this.$store.state.auth.authenticated) return false
|
||||||
currentState: edits.getCurrentState,
|
|
||||||
canEdit: edits.getCanEdit,
|
const isOwner = this.object.attributed_to &&
|
||||||
|
// TODO (wvffle): Is it better to compare ids? Is full_username unique?
|
||||||
|
this.$store.state.auth.fullUsername === this.object.attributed_to.full_username
|
||||||
|
|
||||||
|
return isOwner || this.$store.state.auth.availablePermissions.library
|
||||||
|
},
|
||||||
labels () {
|
labels () {
|
||||||
return {
|
return {
|
||||||
summaryPlaceholder: this.$pgettext('*/*/Placeholder', 'A short summary describing your changes.')
|
summaryPlaceholder: this.$pgettext('*/*/Placeholder', 'A short summary describing your changes.')
|
||||||
|
|
|
@ -207,7 +207,7 @@ import TagsSelector from '~/components/library/TagsSelector.vue'
|
||||||
import Modal from '~/components/semantic/Modal.vue'
|
import Modal from '~/components/semantic/Modal.vue'
|
||||||
import RemoteSearchForm from '~/components/RemoteSearchForm.vue'
|
import RemoteSearchForm from '~/components/RemoteSearchForm.vue'
|
||||||
import useLogger from '~/composables/useLogger'
|
import useLogger from '~/composables/useLogger'
|
||||||
import useSharedLabels from '../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
const logger = useLogger()
|
const logger = useLogger()
|
||||||
|
|
||||||
|
|
|
@ -182,7 +182,7 @@ import PaginationMixin from '~/components/mixins/Pagination.vue'
|
||||||
import RadioCard from '~/components/radios/Card.vue'
|
import RadioCard from '~/components/radios/Card.vue'
|
||||||
import Pagination from '~/components/Pagination.vue'
|
import Pagination from '~/components/Pagination.vue'
|
||||||
import useLogger from '~/composables/useLogger'
|
import useLogger from '~/composables/useLogger'
|
||||||
import useSharedLabels from '../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
const logger = useLogger()
|
const logger = useLogger()
|
||||||
|
|
||||||
|
|
|
@ -202,12 +202,12 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { merge } from 'lodash-es'
|
import { merge } from 'lodash-es'
|
||||||
import time from '~/utils/time'
|
import time from '~/utils/time'
|
||||||
import { normalizeQuery, parseTokens } from '~/search'
|
import { normalizeQuery, parseTokens } from '~/utils/search'
|
||||||
import Pagination from '~/components/Pagination.vue'
|
import Pagination from '~/components/Pagination.vue'
|
||||||
import ActionTable from '~/components/common/ActionTable.vue'
|
import ActionTable from '~/components/common/ActionTable.vue'
|
||||||
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
||||||
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
||||||
import useSharedLabels from '../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -187,12 +187,12 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { merge } from 'lodash-es'
|
import { merge } from 'lodash-es'
|
||||||
import time from '~/utils/time'
|
import time from '~/utils/time'
|
||||||
import { normalizeQuery, parseTokens } from '~/search'
|
import { normalizeQuery, parseTokens } from '~/utils/search'
|
||||||
import Pagination from '~/components/Pagination.vue'
|
import Pagination from '~/components/Pagination.vue'
|
||||||
import ActionTable from '~/components/common/ActionTable.vue'
|
import ActionTable from '~/components/common/ActionTable.vue'
|
||||||
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
||||||
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
||||||
import useSharedLabels from '../../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -186,12 +186,12 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { merge } from 'lodash-es'
|
import { merge } from 'lodash-es'
|
||||||
import time from '~/utils/time'
|
import time from '~/utils/time'
|
||||||
import { normalizeQuery, parseTokens } from '~/search'
|
import { normalizeQuery, parseTokens } from '~/utils/search'
|
||||||
import Pagination from '~/components/Pagination.vue'
|
import Pagination from '~/components/Pagination.vue'
|
||||||
import ActionTable from '~/components/common/ActionTable.vue'
|
import ActionTable from '~/components/common/ActionTable.vue'
|
||||||
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
||||||
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
||||||
import useSharedLabels from '../../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -136,11 +136,11 @@ import time from '~/utils/time'
|
||||||
import Pagination from '~/components/Pagination.vue'
|
import Pagination from '~/components/Pagination.vue'
|
||||||
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
||||||
import EditCard from '~/components/library/EditCard.vue'
|
import EditCard from '~/components/library/EditCard.vue'
|
||||||
import { normalizeQuery, parseTokens } from '~/search'
|
import { normalizeQuery, parseTokens } from '~/utils/search'
|
||||||
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
||||||
|
|
||||||
import edits from '~/edits'
|
import useEditConfigs from '~/composables/useEditConfigs'
|
||||||
import useSharedLabels from '../../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -153,7 +153,8 @@ export default {
|
||||||
},
|
},
|
||||||
setup () {
|
setup () {
|
||||||
const sharedLabels = useSharedLabels()
|
const sharedLabels = useSharedLabels()
|
||||||
return { sharedLabels }
|
const configs = useEditConfigs()
|
||||||
|
return { sharedLabels, configs }
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
@ -244,7 +245,10 @@ export default {
|
||||||
response.data.results.forEach((e) => {
|
response.data.results.forEach((e) => {
|
||||||
self.targets[k][e.id] = {
|
self.targets[k][e.id] = {
|
||||||
payload: e,
|
payload: e,
|
||||||
currentState: edits.getCurrentStateForObj(e, edits.getConfigs.bind(self)()[k])
|
currentState: configs[k].fields.reduce((state/*: Record<string, unknown> */, field) => {
|
||||||
|
state[field.id] = { value: field.getValue(e) }
|
||||||
|
return state
|
||||||
|
}, {})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, error => {
|
}, error => {
|
||||||
|
|
|
@ -217,12 +217,12 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { merge } from 'lodash-es'
|
import { merge } from 'lodash-es'
|
||||||
import time from '~/utils/time'
|
import time from '~/utils/time'
|
||||||
import { normalizeQuery, parseTokens } from '~/search'
|
import { normalizeQuery, parseTokens } from '~/utils/search'
|
||||||
import Pagination from '~/components/Pagination.vue'
|
import Pagination from '~/components/Pagination.vue'
|
||||||
import ActionTable from '~/components/common/ActionTable.vue'
|
import ActionTable from '~/components/common/ActionTable.vue'
|
||||||
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
||||||
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
||||||
import useSharedLabels from '../../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -148,14 +148,14 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { merge } from 'lodash-es'
|
import { merge } from 'lodash-es'
|
||||||
import time from '~/utils/time'
|
import time from '~/utils/time'
|
||||||
import { normalizeQuery, parseTokens } from '~/search'
|
import { normalizeQuery, parseTokens } from '~/utils/search'
|
||||||
import Pagination from '~/components/Pagination.vue'
|
import Pagination from '~/components/Pagination.vue'
|
||||||
import ActionTable from '~/components/common/ActionTable.vue'
|
import ActionTable from '~/components/common/ActionTable.vue'
|
||||||
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
||||||
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
||||||
import ImportStatusModal from '~/components/library/ImportStatusModal.vue'
|
import ImportStatusModal from '~/components/library/ImportStatusModal.vue'
|
||||||
import { truncate } from '~/utils/filters'
|
import { truncate } from '~/utils/filters'
|
||||||
import useSharedLabels from '../../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -200,12 +200,12 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { merge } from 'lodash-es'
|
import { merge } from 'lodash-es'
|
||||||
import time from '~/utils/time'
|
import time from '~/utils/time'
|
||||||
import { normalizeQuery, parseTokens } from '~/search'
|
import { normalizeQuery, parseTokens } from '~/utils/search'
|
||||||
import Pagination from '~/components/Pagination.vue'
|
import Pagination from '~/components/Pagination.vue'
|
||||||
import ActionTable from '~/components/common/ActionTable.vue'
|
import ActionTable from '~/components/common/ActionTable.vue'
|
||||||
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
||||||
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
||||||
import useSharedLabels from '../../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -309,14 +309,14 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { merge } from 'lodash-es'
|
import { merge } from 'lodash-es'
|
||||||
import time from '~/utils/time'
|
import time from '~/utils/time'
|
||||||
import { normalizeQuery, parseTokens } from '~/search'
|
import { normalizeQuery, parseTokens } from '~/utils/search'
|
||||||
import Pagination from '~/components/Pagination.vue'
|
import Pagination from '~/components/Pagination.vue'
|
||||||
import ActionTable from '~/components/common/ActionTable.vue'
|
import ActionTable from '~/components/common/ActionTable.vue'
|
||||||
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
||||||
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
||||||
import ImportStatusModal from '~/components/library/ImportStatusModal.vue'
|
import ImportStatusModal from '~/components/library/ImportStatusModal.vue'
|
||||||
import { humanSize, truncate } from '~/utils/filters'
|
import { humanSize, truncate } from '~/utils/filters'
|
||||||
import useSharedLabels from '../../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -173,12 +173,12 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { merge } from 'lodash-es'
|
import { merge } from 'lodash-es'
|
||||||
import time from '~/utils/time'
|
import time from '~/utils/time'
|
||||||
import { normalizeQuery, parseTokens } from '~/search'
|
import { normalizeQuery, parseTokens } from '~/utils/search'
|
||||||
import Pagination from '~/components/Pagination.vue'
|
import Pagination from '~/components/Pagination.vue'
|
||||||
import ActionTable from '~/components/common/ActionTable.vue'
|
import ActionTable from '~/components/common/ActionTable.vue'
|
||||||
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
||||||
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
||||||
import useSharedLabels from '../../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -187,7 +187,7 @@ import time from '~/utils/time'
|
||||||
import Pagination from '~/components/Pagination.vue'
|
import Pagination from '~/components/Pagination.vue'
|
||||||
import ActionTable from '~/components/common/ActionTable.vue'
|
import ActionTable from '~/components/common/ActionTable.vue'
|
||||||
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
||||||
import useSharedLabels from '../../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -396,7 +396,7 @@ import NoteForm from '~/components/manage/moderation/NoteForm.vue'
|
||||||
import NotesThread from '~/components/manage/moderation/NotesThread.vue'
|
import NotesThread from '~/components/manage/moderation/NotesThread.vue'
|
||||||
import ReportCategoryDropdown from '~/components/moderation/ReportCategoryDropdown.vue'
|
import ReportCategoryDropdown from '~/components/moderation/ReportCategoryDropdown.vue'
|
||||||
import InstancePolicyModal from '~/components/manage/moderation/InstancePolicyModal.vue'
|
import InstancePolicyModal from '~/components/manage/moderation/InstancePolicyModal.vue'
|
||||||
import entities from '~/entities'
|
import useReportConfigs from '~/composables/moderation/useReportConfigs.ts'
|
||||||
import { setUpdate } from '~/utils'
|
import { setUpdate } from '~/utils'
|
||||||
import showdown from 'showdown'
|
import showdown from 'showdown'
|
||||||
|
|
||||||
|
@ -418,6 +418,9 @@ export default {
|
||||||
initObj: { type: Object, required: true },
|
initObj: { type: Object, required: true },
|
||||||
currentState: { type: String, required: false, default: '' }
|
currentState: { type: String, required: false, default: '' }
|
||||||
},
|
},
|
||||||
|
setup () {
|
||||||
|
return { configs: useReportConfigs() }
|
||||||
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
obj: this.initObj,
|
obj: this.initObj,
|
||||||
|
@ -430,7 +433,6 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
configs: entities.getConfigs,
|
|
||||||
previousState () {
|
previousState () {
|
||||||
if (this.obj.is_applied) {
|
if (this.obj.is_applied) {
|
||||||
// mutation was applied, we use the previous state that is stored
|
// mutation was applied, we use the previous state that is stored
|
||||||
|
@ -466,15 +468,13 @@ export default {
|
||||||
const payload = this.obj.target_state
|
const payload = this.obj.target_state
|
||||||
const fields = this.configs[this.target.type].moderatedFields
|
const fields = this.configs[this.target.type].moderatedFields
|
||||||
return fields.map((fieldConfig) => {
|
return fields.map((fieldConfig) => {
|
||||||
const dummyRepr = (v) => { return v }
|
const getValueRepr = fieldConfig.getValueRepr ?? (i => i)
|
||||||
const getValueRepr = fieldConfig.getValueRepr || dummyRepr
|
return {
|
||||||
const d = {
|
|
||||||
id: fieldConfig.id,
|
id: fieldConfig.id,
|
||||||
label: fieldConfig.label,
|
label: fieldConfig.label,
|
||||||
value: payload[fieldConfig.id],
|
value: payload[fieldConfig.id],
|
||||||
repr: castValue(getValueRepr(payload[fieldConfig.id]))
|
repr: castValue(getValueRepr(payload[fieldConfig.id]))
|
||||||
}
|
}
|
||||||
return d
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
target () {
|
target () {
|
||||||
|
|
|
@ -161,7 +161,7 @@ import { merge } from 'lodash-es'
|
||||||
import Pagination from '~/components/Pagination.vue'
|
import Pagination from '~/components/Pagination.vue'
|
||||||
import ActionTable from '~/components/common/ActionTable.vue'
|
import ActionTable from '~/components/common/ActionTable.vue'
|
||||||
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
||||||
import useSharedLabels from '../../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -204,7 +204,7 @@ import time from '~/utils/time'
|
||||||
import Pagination from '~/components/Pagination.vue'
|
import Pagination from '~/components/Pagination.vue'
|
||||||
import ActionTable from '~/components/common/ActionTable.vue'
|
import ActionTable from '~/components/common/ActionTable.vue'
|
||||||
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
||||||
import useSharedLabels from '../../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import { normalizeQuery, parseTokens, compileTokens } from '~/search'
|
import { normalizeQuery, parseTokens, compileTokens } from '~/utils/search'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { useGettext } from 'vue3-gettext'
|
import { useGettext } from 'vue3-gettext'
|
||||||
import useSharedLabels from '~/composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
import { useVModel } from '@vueuse/core'
|
import { useVModel } from '@vueuse/core'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
|
@ -102,7 +102,7 @@ import $ from 'jquery'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
import useLogger from '~/composables/useLogger'
|
import useLogger from '~/composables/useLogger'
|
||||||
import useSharedLabels from '~/composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
const logger = useLogger()
|
const logger = useLogger()
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ const show = useVModel(props, 'show', emit)
|
||||||
|
|
||||||
const control = ref()
|
const control = ref()
|
||||||
const initModal = () => {
|
const initModal = () => {
|
||||||
// @ts-expect-error
|
// @ts-expect-error modal is from semantic ui
|
||||||
control.value = $(modal.value).modal({
|
control.value = $(modal.value).modal({
|
||||||
duration: 100,
|
duration: 100,
|
||||||
onApprove: () => emit('approved'),
|
onApprove: () => emit('approved'),
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
export const DYNAMIC_RANGE = 40 // dB
|
||||||
|
|
||||||
|
export default (volume: number) => {
|
||||||
|
if (volume <= 0.0) {
|
||||||
|
return 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
// (1.0; 0.0) -> (0; -DYNAMIC_RANGE) dB
|
||||||
|
const dB = (volume - 1) * DYNAMIC_RANGE
|
||||||
|
return Math.pow(10, dB / 20)
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
import { gettext } from '~/init/locale'
|
||||||
|
import { Album, Artist, Content, Track } from '~/types'
|
||||||
|
|
||||||
|
interface ConfigField {
|
||||||
|
id: string
|
||||||
|
label: string
|
||||||
|
type: 'content' | 'attachment' | 'tags' | 'text' | 'license'
|
||||||
|
inputType?: 'text' | 'number'
|
||||||
|
required: boolean
|
||||||
|
getValue: (obj: EditObject) => unknown
|
||||||
|
getValueRepr?: (obj: any) => string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EditObject = Artist | Album | Track
|
||||||
|
export type EditObjectType = 'artist' | 'album' | 'track'
|
||||||
|
type Configs = Record<EditObjectType, { fields: ConfigField[] }>
|
||||||
|
|
||||||
|
const { $pgettext } = gettext
|
||||||
|
const getContentValueRepr = (val: Content) => val.text
|
||||||
|
|
||||||
|
const description: ConfigField = {
|
||||||
|
id: 'description',
|
||||||
|
type: 'content',
|
||||||
|
required: true,
|
||||||
|
label: $pgettext('*/*/*/Noun', 'Description'),
|
||||||
|
getValue: (obj) => obj.description ?? { text: '', content_type: 'text/markdown' },
|
||||||
|
getValueRepr: getContentValueRepr
|
||||||
|
}
|
||||||
|
|
||||||
|
const cover: ConfigField = {
|
||||||
|
id: 'cover',
|
||||||
|
type: 'attachment',
|
||||||
|
required: false,
|
||||||
|
label: $pgettext('Content/*/*/Noun', 'Cover'),
|
||||||
|
getValue: (obj) => obj.cover?.uuid ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
const tags: ConfigField = {
|
||||||
|
id: 'tags',
|
||||||
|
type: 'tags',
|
||||||
|
required: true,
|
||||||
|
label: $pgettext('*/*/*/Noun', 'Tags'),
|
||||||
|
getValue: (obj) => { return obj.tags },
|
||||||
|
getValueRepr: (tags: string[]) => tags.slice().sort().join('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Get params from typescript type somehow?
|
||||||
|
export default (): Configs => ({
|
||||||
|
artist: {
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
id: 'name',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
label: $pgettext('*/*/*/Noun', 'Name'),
|
||||||
|
getValue: (artist) => (artist as Artist).name
|
||||||
|
},
|
||||||
|
description,
|
||||||
|
cover,
|
||||||
|
tags
|
||||||
|
]
|
||||||
|
},
|
||||||
|
album: {
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
id: 'title',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
label: $pgettext('*/*/*/Noun', 'Title'),
|
||||||
|
getValue: (album) => (album as Album).title
|
||||||
|
},
|
||||||
|
description,
|
||||||
|
{
|
||||||
|
id: 'release_date',
|
||||||
|
type: 'text',
|
||||||
|
required: false,
|
||||||
|
label: $pgettext('Content/*/*/Noun', 'Release date'),
|
||||||
|
getValue: (album) => (album as Album).release_date
|
||||||
|
},
|
||||||
|
cover,
|
||||||
|
tags
|
||||||
|
]
|
||||||
|
},
|
||||||
|
track: {
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
id: 'title',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
label: $pgettext('*/*/*/Noun', 'Title'),
|
||||||
|
getValue: (track) => (track as Track).title
|
||||||
|
},
|
||||||
|
description,
|
||||||
|
cover,
|
||||||
|
{
|
||||||
|
id: 'position',
|
||||||
|
type: 'text',
|
||||||
|
inputType: 'number',
|
||||||
|
required: false,
|
||||||
|
label: $pgettext('*/*/*/Short, Noun', 'Position'),
|
||||||
|
getValue: (track) => (track as Track).position
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'copyright',
|
||||||
|
type: 'text',
|
||||||
|
required: false,
|
||||||
|
label: $pgettext('Content/Track/*/Noun', 'Copyright'),
|
||||||
|
getValue: (track) => (track as Track).copyright
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'license',
|
||||||
|
type: 'license',
|
||||||
|
required: false,
|
||||||
|
label: $pgettext('Content/*/*/Noun', 'License'),
|
||||||
|
getValue: (track) => (track as Track).license
|
||||||
|
},
|
||||||
|
tags
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
|
@ -0,0 +1,183 @@
|
||||||
|
import { gettext } from '~/init/locale'
|
||||||
|
import { RouteLocationRaw } from 'vue-router'
|
||||||
|
|
||||||
|
interface ModeratedField {
|
||||||
|
id: string
|
||||||
|
label: string
|
||||||
|
getValueRepr?: (obj: any) => string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Entity {
|
||||||
|
label: string
|
||||||
|
icon: string
|
||||||
|
getDeleteUrl?: (object: any) => string
|
||||||
|
urls: {
|
||||||
|
getDetail?: (object: any) => RouteLocationRaw
|
||||||
|
getAdminDetail?: (object: any) => RouteLocationRaw
|
||||||
|
}
|
||||||
|
moderatedFields: ModeratedField[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EntityObjectType = 'artist' | 'album' | 'track' | 'library' | 'playlist' | 'account' | 'channel'
|
||||||
|
type Configs = Record<EntityObjectType, Entity>
|
||||||
|
|
||||||
|
const { $pgettext } = gettext
|
||||||
|
|
||||||
|
const tags: ModeratedField = {
|
||||||
|
id: 'tags',
|
||||||
|
label: $pgettext('*/*/*/Noun', 'Tags'),
|
||||||
|
getValueRepr: (tags: string[]) => tags.slice().sort().join('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
const name: ModeratedField = {
|
||||||
|
id: 'name',
|
||||||
|
label: $pgettext('*/*/*/Noun', 'Name')
|
||||||
|
}
|
||||||
|
|
||||||
|
const creationDate: ModeratedField = {
|
||||||
|
id: 'creation_date',
|
||||||
|
label: $pgettext('Content/*/*/Noun', 'Creation date')
|
||||||
|
}
|
||||||
|
|
||||||
|
const musicBrainzId: ModeratedField = {
|
||||||
|
id: 'mbid',
|
||||||
|
label: $pgettext('*/*/*/Noun', 'MusicBrainz ID')
|
||||||
|
}
|
||||||
|
|
||||||
|
const visibility: ModeratedField = {
|
||||||
|
id: 'privacy_level',
|
||||||
|
label: $pgettext('*/*/*', 'Visibility')
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (): Configs => ({
|
||||||
|
artist: {
|
||||||
|
label: $pgettext('*/*/*/Noun', 'Artist'),
|
||||||
|
icon: 'users',
|
||||||
|
getDeleteUrl: (obj) => {
|
||||||
|
return `manage/library/artists/${obj.id}/`
|
||||||
|
},
|
||||||
|
urls: {
|
||||||
|
getDetail: (obj) => ({ name: 'library.artists.detail', params: { id: obj.id } }),
|
||||||
|
getAdminDetail: (obj) => ({ name: 'manage.library.artists.detail', params: { id: obj.id } })
|
||||||
|
},
|
||||||
|
moderatedFields: [
|
||||||
|
name,
|
||||||
|
creationDate,
|
||||||
|
tags,
|
||||||
|
musicBrainzId
|
||||||
|
]
|
||||||
|
},
|
||||||
|
album: {
|
||||||
|
label: $pgettext('*/*/*', 'Album'),
|
||||||
|
icon: 'play',
|
||||||
|
getDeleteUrl: (obj) => {
|
||||||
|
return `manage/library/albums/${obj.id}/`
|
||||||
|
},
|
||||||
|
urls: {
|
||||||
|
getDetail: (obj) => ({ name: 'library.albums.detail', params: { id: obj.id } }),
|
||||||
|
getAdminDetail: (obj) => ({ name: 'manage.library.albums.detail', params: { id: obj.id } })
|
||||||
|
},
|
||||||
|
moderatedFields: [
|
||||||
|
{
|
||||||
|
id: 'title',
|
||||||
|
label: $pgettext('*/*/*/Noun', 'Title')
|
||||||
|
},
|
||||||
|
creationDate,
|
||||||
|
{
|
||||||
|
id: 'release_date',
|
||||||
|
label: $pgettext('Content/*/*/Noun', 'Release date')
|
||||||
|
},
|
||||||
|
tags,
|
||||||
|
musicBrainzId
|
||||||
|
]
|
||||||
|
},
|
||||||
|
track: {
|
||||||
|
label: $pgettext('*/*/*/Noun', 'Track'),
|
||||||
|
icon: 'music',
|
||||||
|
getDeleteUrl: (obj) => {
|
||||||
|
return `manage/library/tracks/${obj.id}/`
|
||||||
|
},
|
||||||
|
urls: {
|
||||||
|
getDetail: (obj) => ({ name: 'library.tracks.detail', params: { id: obj.id } }),
|
||||||
|
getAdminDetail: (obj) => ({ name: 'manage.library.tracks.detail', params: { id: obj.id } })
|
||||||
|
},
|
||||||
|
moderatedFields: [
|
||||||
|
{
|
||||||
|
id: 'title',
|
||||||
|
label: $pgettext('*/*/*/Noun', 'Title')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'position',
|
||||||
|
label: $pgettext('*/*/*/Short, Noun', 'Position')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'copyright',
|
||||||
|
label: $pgettext('Content/Track/*/Noun', 'Copyright')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'license',
|
||||||
|
label: $pgettext('Content/*/*/Noun', 'License')
|
||||||
|
},
|
||||||
|
tags,
|
||||||
|
musicBrainzId
|
||||||
|
]
|
||||||
|
},
|
||||||
|
library: {
|
||||||
|
label: $pgettext('*/*/*/Noun', 'Library'),
|
||||||
|
icon: 'book',
|
||||||
|
getDeleteUrl: (obj) => {
|
||||||
|
return `manage/library/libraries/${obj.uuid}/`
|
||||||
|
},
|
||||||
|
urls: {
|
||||||
|
getAdminDetail: (obj) => ({ name: 'manage.library.libraries.detail', params: { id: obj.uuid } })
|
||||||
|
},
|
||||||
|
moderatedFields: [
|
||||||
|
name,
|
||||||
|
{
|
||||||
|
id: 'description',
|
||||||
|
label: $pgettext('*/*/*/Noun', 'Description')
|
||||||
|
},
|
||||||
|
visibility
|
||||||
|
]
|
||||||
|
},
|
||||||
|
playlist: {
|
||||||
|
label: $pgettext('*/*/*', 'Playlist'),
|
||||||
|
icon: 'list',
|
||||||
|
urls: {
|
||||||
|
getDetail: (obj) => ({ name: 'library.playlists.detail', params: { id: obj.id } })
|
||||||
|
// getAdminDetail: (obj) => ({name: 'manage.playlists.detail', params: {id: obj.id}}}
|
||||||
|
},
|
||||||
|
moderatedFields: [
|
||||||
|
name,
|
||||||
|
visibility
|
||||||
|
]
|
||||||
|
},
|
||||||
|
account: {
|
||||||
|
label: $pgettext('*/*/*/Noun', 'Account'),
|
||||||
|
icon: 'user',
|
||||||
|
urls: {
|
||||||
|
getDetail: (obj) => ({ name: 'profile.full.overview', params: { username: obj.preferred_username, domain: obj.domain } }),
|
||||||
|
getAdminDetail: (obj) => ({ name: 'manage.moderation.accounts.detail', params: { id: `${obj.preferred_username}@${obj.domain}` } })
|
||||||
|
},
|
||||||
|
moderatedFields: [
|
||||||
|
name,
|
||||||
|
{
|
||||||
|
id: 'summary',
|
||||||
|
label: $pgettext('*/*/*/Noun', 'Bio')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
channel: {
|
||||||
|
label: $pgettext('*/*/*', 'Channel'),
|
||||||
|
icon: 'stream',
|
||||||
|
urls: {
|
||||||
|
getDetail: (obj) => ({ name: 'channels.detail', params: { id: obj.uuid } }),
|
||||||
|
getAdminDetail: (obj) => ({ name: 'manage.channels.detail', params: { id: obj.uuid } })
|
||||||
|
},
|
||||||
|
moderatedFields: [
|
||||||
|
name,
|
||||||
|
creationDate,
|
||||||
|
tags
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
|
@ -1,191 +0,0 @@
|
||||||
function getTagsValueRepr (val) {
|
|
||||||
if (!val) {
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
return val.slice().sort().join('\n')
|
|
||||||
}
|
|
||||||
|
|
||||||
function getContentValueRepr (val) {
|
|
||||||
return val.text
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
getConfigs () {
|
|
||||||
const description = {
|
|
||||||
id: 'description',
|
|
||||||
type: 'content',
|
|
||||||
required: true,
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Description'),
|
|
||||||
getValue: (obj) => { return obj.description || { text: null, content_type: 'text/markdown' } },
|
|
||||||
getValueRepr: getContentValueRepr
|
|
||||||
}
|
|
||||||
const cover = {
|
|
||||||
id: 'cover',
|
|
||||||
type: 'attachment',
|
|
||||||
required: false,
|
|
||||||
label: this.$pgettext('Content/*/*/Noun', 'Cover'),
|
|
||||||
getValue: (obj) => {
|
|
||||||
if (obj.cover) {
|
|
||||||
return obj.cover.uuid
|
|
||||||
} else {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
artist: {
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
id: 'name',
|
|
||||||
type: 'text',
|
|
||||||
required: true,
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Name'),
|
|
||||||
getValue: (obj) => { return obj.name }
|
|
||||||
},
|
|
||||||
description,
|
|
||||||
cover,
|
|
||||||
{
|
|
||||||
id: 'tags',
|
|
||||||
type: 'tags',
|
|
||||||
required: true,
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Tags'),
|
|
||||||
getValue: (obj) => { return obj.tags },
|
|
||||||
getValueRepr: getTagsValueRepr
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
album: {
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
id: 'title',
|
|
||||||
type: 'text',
|
|
||||||
required: true,
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Title'),
|
|
||||||
getValue: (obj) => { return obj.title }
|
|
||||||
},
|
|
||||||
description,
|
|
||||||
{
|
|
||||||
id: 'release_date',
|
|
||||||
type: 'text',
|
|
||||||
required: false,
|
|
||||||
label: this.$pgettext('Content/*/*/Noun', 'Release date'),
|
|
||||||
getValue: (obj) => { return obj.release_date }
|
|
||||||
},
|
|
||||||
cover,
|
|
||||||
{
|
|
||||||
id: 'tags',
|
|
||||||
type: 'tags',
|
|
||||||
required: true,
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Tags'),
|
|
||||||
getValue: (obj) => { return obj.tags },
|
|
||||||
getValueRepr: getTagsValueRepr
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
track: {
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
id: 'title',
|
|
||||||
type: 'text',
|
|
||||||
required: true,
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Title'),
|
|
||||||
getValue: (obj) => { return obj.title }
|
|
||||||
},
|
|
||||||
description,
|
|
||||||
cover,
|
|
||||||
{
|
|
||||||
id: 'position',
|
|
||||||
type: 'text',
|
|
||||||
inputType: 'number',
|
|
||||||
required: false,
|
|
||||||
label: this.$pgettext('*/*/*/Short, Noun', 'Position'),
|
|
||||||
getValue: (obj) => { return obj.position }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'copyright',
|
|
||||||
type: 'text',
|
|
||||||
required: false,
|
|
||||||
label: this.$pgettext('Content/Track/*/Noun', 'Copyright'),
|
|
||||||
getValue: (obj) => { return obj.copyright }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'license',
|
|
||||||
type: 'license',
|
|
||||||
required: false,
|
|
||||||
label: this.$pgettext('Content/*/*/Noun', 'License'),
|
|
||||||
getValue: (obj) => { return obj.license }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'tags',
|
|
||||||
type: 'tags',
|
|
||||||
required: true,
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Tags'),
|
|
||||||
getValue: (obj) => { return obj.tags },
|
|
||||||
getValueRepr: getTagsValueRepr
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
getConfig () {
|
|
||||||
return this.configs[this.objectType]
|
|
||||||
},
|
|
||||||
getFieldConfig (configs, type, fieldId) {
|
|
||||||
const c = configs[type]
|
|
||||||
return c.fields.filter((f) => {
|
|
||||||
return f.id === fieldId
|
|
||||||
})[0]
|
|
||||||
},
|
|
||||||
getCurrentState () {
|
|
||||||
const self = this
|
|
||||||
const s = {}
|
|
||||||
this.config.fields.forEach(f => {
|
|
||||||
s[f.id] = { value: f.getValue(self.object) }
|
|
||||||
})
|
|
||||||
return s
|
|
||||||
},
|
|
||||||
getCurrentStateForObj (obj, config) {
|
|
||||||
const s = {}
|
|
||||||
config.fields.forEach(f => {
|
|
||||||
s[f.id] = { value: f.getValue(obj) }
|
|
||||||
})
|
|
||||||
return s
|
|
||||||
},
|
|
||||||
|
|
||||||
getCanDelete () {
|
|
||||||
if (this.obj.is_applied || this.obj.is_approved) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (!this.$store.state.auth.authenticated) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
this.obj.created_by.full_username === this.$store.state.auth.fullUsername ||
|
|
||||||
this.$store.state.auth.availablePermissions.library
|
|
||||||
)
|
|
||||||
},
|
|
||||||
getCanApprove () {
|
|
||||||
if (this.obj.is_applied) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (!this.$store.state.auth.authenticated) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return this.$store.state.auth.availablePermissions.library
|
|
||||||
},
|
|
||||||
getCanEdit () {
|
|
||||||
if (!this.$store.state.auth.authenticated) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const libraryPermission = this.$store.state.auth.availablePermissions.library
|
|
||||||
const objData = this.object || {}
|
|
||||||
let isOwner = false
|
|
||||||
if (objData.attributed_to) {
|
|
||||||
isOwner = this.$store.state.auth.fullUsername === objData.attributed_to.full_username
|
|
||||||
}
|
|
||||||
return libraryPermission || isOwner
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
import EmbedFrame from './EmbedFrame.vue'
|
import EmbedFrame from './EmbedFrame.vue'
|
||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
|
|
||||||
// @ts-expect-error
|
// @ts-expect-error vue-plyr has no types defined
|
||||||
import VuePlyr from 'vue-plyr'
|
import VuePlyr from 'vue-plyr'
|
||||||
|
|
||||||
const app = createApp(EmbedFrame)
|
const app = createApp(EmbedFrame)
|
||||||
|
|
|
@ -1,245 +0,0 @@
|
||||||
function getTagsValueRepr (val) {
|
|
||||||
if (!val) {
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
return val.slice().sort().join('\n')
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
getConfigs () {
|
|
||||||
return {
|
|
||||||
artist: {
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Artist'),
|
|
||||||
icon: 'users',
|
|
||||||
getDeleteUrl: (obj) => {
|
|
||||||
return `manage/library/artists/${obj.id}/`
|
|
||||||
},
|
|
||||||
urls: {
|
|
||||||
getDetail: (obj) => { return { name: 'library.artists.detail', params: { id: obj.id } } },
|
|
||||||
getAdminDetail: (obj) => { return { name: 'manage.library.artists.detail', params: { id: obj.id } } }
|
|
||||||
},
|
|
||||||
moderatedFields: [
|
|
||||||
{
|
|
||||||
id: 'name',
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Name'),
|
|
||||||
getValue: (obj) => { return obj.name }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'creation_date',
|
|
||||||
label: this.$pgettext('Content/*/*/Noun', 'Creation date'),
|
|
||||||
getValue: (obj) => { return obj.creation_date }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'tags',
|
|
||||||
type: 'tags',
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Tags'),
|
|
||||||
getValue: (obj) => { return obj.tags },
|
|
||||||
getValueRepr: getTagsValueRepr
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'mbid',
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'MusicBrainz ID'),
|
|
||||||
getValue: (obj) => { return obj.mbid }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
album: {
|
|
||||||
label: this.$pgettext('*/*/*', 'Album'),
|
|
||||||
icon: 'play',
|
|
||||||
getDeleteUrl: (obj) => {
|
|
||||||
return `manage/library/albums/${obj.id}/`
|
|
||||||
},
|
|
||||||
urls: {
|
|
||||||
getDetail: (obj) => { return { name: 'library.albums.detail', params: { id: obj.id } } },
|
|
||||||
getAdminDetail: (obj) => { return { name: 'manage.library.albums.detail', params: { id: obj.id } } }
|
|
||||||
},
|
|
||||||
moderatedFields: [
|
|
||||||
{
|
|
||||||
id: 'title',
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Title'),
|
|
||||||
getValue: (obj) => { return obj.title }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'creation_date',
|
|
||||||
label: this.$pgettext('Content/*/*/Noun', 'Creation date'),
|
|
||||||
getValue: (obj) => { return obj.creation_date }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'release_date',
|
|
||||||
label: this.$pgettext('Content/*/*/Noun', 'Release date'),
|
|
||||||
getValue: (obj) => { return obj.release_date }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'tags',
|
|
||||||
type: 'tags',
|
|
||||||
required: true,
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Tags'),
|
|
||||||
getValue: (obj) => { return obj.tags },
|
|
||||||
getValueRepr: getTagsValueRepr
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'mbid',
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'MusicBrainz ID'),
|
|
||||||
getValue: (obj) => { return obj.mbid }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
track: {
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Track'),
|
|
||||||
icon: 'music',
|
|
||||||
getDeleteUrl: (obj) => {
|
|
||||||
return `manage/library/tracks/${obj.id}/`
|
|
||||||
},
|
|
||||||
urls: {
|
|
||||||
getDetail: (obj) => { return { name: 'library.tracks.detail', params: { id: obj.id } } },
|
|
||||||
getAdminDetail: (obj) => { return { name: 'manage.library.tracks.detail', params: { id: obj.id } } }
|
|
||||||
},
|
|
||||||
moderatedFields: [
|
|
||||||
{
|
|
||||||
id: 'title',
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Title'),
|
|
||||||
getValue: (obj) => { return obj.title }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'position',
|
|
||||||
label: this.$pgettext('*/*/*/Short, Noun', 'Position'),
|
|
||||||
getValue: (obj) => { return obj.position }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'copyright',
|
|
||||||
label: this.$pgettext('Content/Track/*/Noun', 'Copyright'),
|
|
||||||
getValue: (obj) => { return obj.copyright }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'license',
|
|
||||||
label: this.$pgettext('Content/*/*/Noun', 'License'),
|
|
||||||
getValue: (obj) => { return obj.license }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'tags',
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Tags'),
|
|
||||||
getValue: (obj) => { return obj.tags },
|
|
||||||
getValueRepr: getTagsValueRepr
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'mbid',
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'MusicBrainz ID'),
|
|
||||||
getValue: (obj) => { return obj.mbid }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
library: {
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Library'),
|
|
||||||
icon: 'book',
|
|
||||||
getDeleteUrl: (obj) => {
|
|
||||||
return `manage/library/libraries/${obj.uuid}/`
|
|
||||||
},
|
|
||||||
urls: {
|
|
||||||
getAdminDetail: (obj) => { return { name: 'manage.library.libraries.detail', params: { id: obj.uuid } } }
|
|
||||||
},
|
|
||||||
moderatedFields: [
|
|
||||||
{
|
|
||||||
id: 'name',
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Name'),
|
|
||||||
getValue: (obj) => { return obj.name }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'description',
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Description'),
|
|
||||||
getValue: (obj) => { return obj.position }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'privacy_level',
|
|
||||||
label: this.$pgettext('*/*/*', 'Visibility'),
|
|
||||||
getValue: (obj) => { return obj.privacy_level }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
playlist: {
|
|
||||||
label: this.$pgettext('*/*/*', 'Playlist'),
|
|
||||||
icon: 'list',
|
|
||||||
urls: {
|
|
||||||
getDetail: (obj) => { return { name: 'library.playlists.detail', params: { id: obj.id } } }
|
|
||||||
// getAdminDetail: (obj) => { return {name: 'manage.playlists.detail', params: {id: obj.id}}}
|
|
||||||
},
|
|
||||||
moderatedFields: [
|
|
||||||
{
|
|
||||||
id: 'name',
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Name'),
|
|
||||||
getValue: (obj) => { return obj.name }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'privacy_level',
|
|
||||||
label: this.$pgettext('*/*/*', 'Visibility'),
|
|
||||||
getValue: (obj) => { return obj.privacy_level }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
account: {
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Account'),
|
|
||||||
icon: 'user',
|
|
||||||
urls: {
|
|
||||||
getDetail: (obj) => { return { name: 'profile.full.overview', params: { username: obj.preferred_username, domain: obj.domain } } },
|
|
||||||
getAdminDetail: (obj) => { return { name: 'manage.moderation.accounts.detail', params: { id: `${obj.preferred_username}@${obj.domain}` } } }
|
|
||||||
},
|
|
||||||
moderatedFields: [
|
|
||||||
{
|
|
||||||
id: 'name',
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Name'),
|
|
||||||
getValue: (obj) => { return obj.name }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'summary',
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Bio'),
|
|
||||||
getValue: (obj) => { return obj.summary }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
channel: {
|
|
||||||
label: this.$pgettext('*/*/*', 'Channel'),
|
|
||||||
icon: 'stream',
|
|
||||||
urls: {
|
|
||||||
getDetail: (obj) => { return { name: 'channels.detail', params: { id: obj.uuid } } },
|
|
||||||
getAdminDetail: (obj) => { return { name: 'manage.channels.detail', params: { id: obj.uuid } } }
|
|
||||||
},
|
|
||||||
moderatedFields: [
|
|
||||||
{
|
|
||||||
id: 'name',
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Name'),
|
|
||||||
getValue: (obj) => { return obj.name }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'creation_date',
|
|
||||||
label: this.$pgettext('Content/*/*/Noun', 'Creation date'),
|
|
||||||
getValue: (obj) => { return obj.creation_date }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'tags',
|
|
||||||
type: 'tags',
|
|
||||||
label: this.$pgettext('*/*/*/Noun', 'Tags'),
|
|
||||||
getValue: (obj) => { return obj.tags },
|
|
||||||
getValueRepr: getTagsValueRepr
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
getConfig () {
|
|
||||||
return this.configs[this.objectType]
|
|
||||||
},
|
|
||||||
getFieldConfig (configs, type, fieldId) {
|
|
||||||
const c = configs[type]
|
|
||||||
return c.fields.filter((f) => {
|
|
||||||
return f.id === fieldId
|
|
||||||
})[0]
|
|
||||||
},
|
|
||||||
getCurrentStateForObj (obj, config) {
|
|
||||||
const s = {}
|
|
||||||
config.fields.forEach(f => {
|
|
||||||
s[f.id] = { value: f.getValue(obj) }
|
|
||||||
})
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -7,14 +7,14 @@ export const install: InitModule = ({ app, store }) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
app.directive('dropdown', function (el, binding) {
|
app.directive('dropdown', function (el, binding) {
|
||||||
// @ts-expect-error
|
// @ts-expect-error dropdown is from semantic ui
|
||||||
jQuery(el).dropdown({
|
jQuery(el).dropdown({
|
||||||
selectOnKeydown: false,
|
selectOnKeydown: false,
|
||||||
action (text: string, value: string, $el: JQuery<HTMLElement>) {
|
action (text: string, value: string, $el: JQuery<HTMLElement>) {
|
||||||
// used to ensure focusing the dropdown and clicking via keyboard
|
// used to ensure focusing the dropdown and clicking via keyboard
|
||||||
// works as expected
|
// works as expected
|
||||||
$el[0]?.click()
|
$el[0]?.click()
|
||||||
// @ts-expect-error
|
// @ts-expect-error dropdown is from semantic ui
|
||||||
jQuery(el).find('.ui.dropdown').dropdown('hide')
|
jQuery(el).find('.ui.dropdown').dropdown('hide')
|
||||||
},
|
},
|
||||||
...(binding.value || {})
|
...(binding.value || {})
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import router from '~/router'
|
import router from '~/router'
|
||||||
import store from '~/store'
|
import store from '~/store'
|
||||||
|
// @ts-expect-error typescript does not know about configureCompat
|
||||||
import { configureCompat, createApp, defineAsyncComponent, h } from 'vue'
|
import { configureCompat, createApp, defineAsyncComponent, h } from 'vue'
|
||||||
import useLogger from '~/composables/useLogger'
|
import useLogger from '~/composables/useLogger'
|
||||||
import useTheme from '~/composables/useTheme'
|
import useTheme from '~/composables/useTheme'
|
||||||
|
@ -49,10 +50,8 @@ Promise.all(modules).finally(() => {
|
||||||
logger.info('Everything loaded!')
|
logger.info('Everything loaded!')
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO (wvffle): Migrate to pinia
|
|
||||||
// TODO (wvffle): Check for mixin merging: https://v3-migration.vuejs.org/breaking-changes/data-option.html#mixin-merge-behavior-change=
|
// TODO (wvffle): Check for mixin merging: https://v3-migration.vuejs.org/breaking-changes/data-option.html#mixin-merge-behavior-change=
|
||||||
// TODO (wvffle): Use emits options: https://v3-migration.vuejs.org/breaking-changes/emits-option.html
|
// TODO (wvffle): Use emits options: https://v3-migration.vuejs.org/breaking-changes/emits-option.html
|
||||||
// TODO (wvffle): Find all array watchers and make them deep
|
// TODO (wvffle): Find all array watchers and make them deep
|
||||||
// TODO (wvffle): Migrate to <script setup>
|
// TODO (wvffle): Migrate to <script setup>
|
||||||
// TODO (wvffle): Replace `from '(../)+` with `from '~/`
|
// TODO (wvffle): Replace `from '(../)+` with `from '~/`
|
||||||
// TODO (wvffle): Remove `allowJs` from tsconfig.json
|
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
import sanitizeHtml from 'sanitize-html'
|
|
||||||
|
|
||||||
const allowedTags = [
|
|
||||||
'h3',
|
|
||||||
'h4',
|
|
||||||
'h5',
|
|
||||||
'h6',
|
|
||||||
'blockquote',
|
|
||||||
'p',
|
|
||||||
'a',
|
|
||||||
'ul',
|
|
||||||
'ol',
|
|
||||||
'nl',
|
|
||||||
'li',
|
|
||||||
'b',
|
|
||||||
'i',
|
|
||||||
'strong',
|
|
||||||
'em',
|
|
||||||
'strike',
|
|
||||||
'code',
|
|
||||||
'hr',
|
|
||||||
'br',
|
|
||||||
'div',
|
|
||||||
'table',
|
|
||||||
'thead',
|
|
||||||
'caption',
|
|
||||||
'tbody',
|
|
||||||
'tr',
|
|
||||||
'th',
|
|
||||||
'td',
|
|
||||||
'pre'
|
|
||||||
]
|
|
||||||
const allowedAttributes = {
|
|
||||||
a: ['href', 'name', 'target'],
|
|
||||||
// We don't currently allow img itself by default, but this
|
|
||||||
// would make sense if we did. You could add srcset here,
|
|
||||||
// and if you do the URL is checked for safety
|
|
||||||
img: ['src']
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function sanitize (input) {
|
|
||||||
return sanitizeHtml(input, { allowedAttributes, allowedTags })
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
export function normalizeQuery (query) {
|
|
||||||
// given a string such as 'this is "my query" go', returns
|
|
||||||
// an array of tokens like this: ['this', 'is', 'my query', 'go']
|
|
||||||
if (!query) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
return query.match(/\\?.|^$/g).reduce((p, c) => {
|
|
||||||
if (c === '"') {
|
|
||||||
p.quote ^= 1
|
|
||||||
} else if (!p.quote && c === ' ') {
|
|
||||||
p.a.push('')
|
|
||||||
} else {
|
|
||||||
p.a[p.a.length - 1] += c.replace(/\\(.)/, '$1')
|
|
||||||
}
|
|
||||||
return p
|
|
||||||
}, { a: [''] }).a
|
|
||||||
}
|
|
||||||
|
|
||||||
export function parseTokens (tokens) {
|
|
||||||
// given an array of tokens as returned by normalizeQuery,
|
|
||||||
// returns a list of objects such as [
|
|
||||||
// {
|
|
||||||
// field: 'status',
|
|
||||||
// value: 'pending'
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// field: null,
|
|
||||||
// value: 'hello'
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
return tokens.map(t => {
|
|
||||||
// we split the token on ":"
|
|
||||||
const parts = t.split(/:(.+)/)
|
|
||||||
if (parts.length === 1) {
|
|
||||||
// no field specified
|
|
||||||
return { field: null, value: t }
|
|
||||||
}
|
|
||||||
// first item is the field, second is the value, possibly quoted
|
|
||||||
const field = parts[0]
|
|
||||||
let rawValue = parts[1]
|
|
||||||
|
|
||||||
// we remove surrounding quotes if any
|
|
||||||
if (rawValue[0] === '"') {
|
|
||||||
rawValue = rawValue.substring(1)
|
|
||||||
}
|
|
||||||
if (rawValue.slice(-1) === '"') {
|
|
||||||
rawValue = rawValue.substring(0, rawValue.length - 1)
|
|
||||||
}
|
|
||||||
return { field, value: rawValue }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function compileTokens (tokens) {
|
|
||||||
// given a list of tokens as returned by parseTokens,
|
|
||||||
// returns a string query
|
|
||||||
const parts = tokens.map(t => {
|
|
||||||
let v = t.value
|
|
||||||
const k = t.field
|
|
||||||
if (v.indexOf(' ') > -1) {
|
|
||||||
v = `"${v}"`
|
|
||||||
}
|
|
||||||
if (k) {
|
|
||||||
return `${k}:${v}`
|
|
||||||
} else {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return parts.join(' ')
|
|
||||||
}
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { Store } from 'vuex'
|
||||||
|
|
||||||
|
declare module '@vue/runtime-core' {
|
||||||
|
interface ComponentCustomProperties {
|
||||||
|
$store: Store<any>
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import { createStore } from 'vuex'
|
import { createStore, Store } from 'vuex'
|
||||||
import createPersistedState from 'vuex-persistedstate'
|
import createPersistedState from 'vuex-persistedstate'
|
||||||
|
|
||||||
import favorites from './favorites'
|
import favorites from './favorites'
|
||||||
|
@ -12,8 +12,14 @@ import radios from './radios'
|
||||||
import player from './player'
|
import player from './player'
|
||||||
import playlists from './playlists'
|
import playlists from './playlists'
|
||||||
import ui from './ui'
|
import ui from './ui'
|
||||||
|
import { InjectionKey } from 'vue'
|
||||||
|
|
||||||
export default createStore({
|
export interface RootState {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const key: InjectionKey<Store<RootState>> = Symbol('vuex state injection key')
|
||||||
|
export default createStore<RootState>({
|
||||||
modules: {
|
modules: {
|
||||||
ui,
|
ui,
|
||||||
auth,
|
auth,
|
||||||
|
|
|
@ -33,20 +33,41 @@ export type ContentCategory = 'podcast'
|
||||||
|
|
||||||
export interface Artist {
|
export interface Artist {
|
||||||
id: string
|
id: string
|
||||||
|
|
||||||
name: string
|
name: string
|
||||||
|
description: Content
|
||||||
|
cover?: Cover
|
||||||
|
tags: string[]
|
||||||
|
|
||||||
content_category: ContentCategory
|
content_category: ContentCategory
|
||||||
|
albums: Album[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Album {
|
export interface Album {
|
||||||
id: string
|
id: string
|
||||||
|
|
||||||
|
title: string
|
||||||
|
description: Content
|
||||||
|
release_date?: string
|
||||||
|
cover?: Cover
|
||||||
|
tags: string[]
|
||||||
|
|
||||||
artist: Artist
|
artist: Artist
|
||||||
tracks_count: number
|
tracks_count: number
|
||||||
title: string
|
tracks: Track[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Track {
|
export interface Track {
|
||||||
id: string
|
id: string
|
||||||
|
|
||||||
title: string
|
title: string
|
||||||
|
description: Content
|
||||||
|
cover?: Cover
|
||||||
|
position?: number
|
||||||
|
copyright?: string
|
||||||
|
license?: License
|
||||||
|
tags: string[]
|
||||||
|
|
||||||
album?: Album
|
album?: Album
|
||||||
artist?: Artist
|
artist?: Artist
|
||||||
}
|
}
|
||||||
|
@ -56,6 +77,16 @@ export interface Channel {
|
||||||
artist?: Artist
|
artist?: Artist
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Cover {
|
||||||
|
uuid: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface License {
|
||||||
|
code: string
|
||||||
|
name: string
|
||||||
|
url: string
|
||||||
|
}
|
||||||
|
|
||||||
// API stuff
|
// API stuff
|
||||||
export interface APIErrorResponse {
|
export interface APIErrorResponse {
|
||||||
[key: string]: APIErrorResponse | string[]
|
[key: string]: APIErrorResponse | string[]
|
||||||
|
@ -111,12 +142,13 @@ export interface FileSystem {
|
||||||
content: FSEntry[]
|
content: FSEntry[]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Form stuff
|
// Content stuff
|
||||||
export interface FormHelpText {
|
export interface Content {
|
||||||
content_type: string
|
content_type: 'text/plain' | 'text/markdown'
|
||||||
text?: string
|
text: string // TODO (wvffle): Ensure it's not nullable from backend side
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Form stuff
|
||||||
export interface FormField {
|
export interface FormField {
|
||||||
label: string
|
label: string
|
||||||
input_type: 'short_text' | 'long_text'
|
input_type: 'short_text' | 'long_text'
|
||||||
|
@ -125,7 +157,7 @@ export interface FormField {
|
||||||
|
|
||||||
export interface Form {
|
export interface Form {
|
||||||
fields: FormField[]
|
fields: FormField[]
|
||||||
help_text: FormHelpText
|
help_text: Content
|
||||||
}
|
}
|
||||||
|
|
||||||
// Yet uncategorized stuff
|
// Yet uncategorized stuff
|
||||||
|
@ -135,9 +167,3 @@ export interface Actor {
|
||||||
is_local: boolean
|
is_local: boolean
|
||||||
domain: string
|
domain: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface License {
|
|
||||||
code: string
|
|
||||||
name: string
|
|
||||||
url: string
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
export function hashCode (str) { // java String#hashCode
|
// java String#hashCode
|
||||||
|
export function hashCode (str: string) {
|
||||||
let hash = 0
|
let hash = 0
|
||||||
for (let i = 0; i < str.length; i++) {
|
for (let i = 0; i < str.length; i++) {
|
||||||
hash = str.charCodeAt(i) + ((hash << 5) - hash)
|
hash = str.charCodeAt(i) + ((hash << 5) - hash)
|
||||||
|
@ -6,7 +7,7 @@ export function hashCode (str) { // java String#hashCode
|
||||||
return hash
|
return hash
|
||||||
}
|
}
|
||||||
|
|
||||||
export function intToRGB (i) {
|
export function intToRGB (i: number) {
|
||||||
const c = (i & 0x00FFFFFF).toString(16).toUpperCase()
|
const c = (i & 0x00FFFFFF).toString(16).toUpperCase()
|
||||||
return '00000'.substring(0, 6 - c.length) + c
|
return '00000'.substring(0, 6 - c.length) + c
|
||||||
}
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
interface Token {
|
||||||
|
field: string | null
|
||||||
|
value: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeQuery (query: string): string[] {
|
||||||
|
// given a string such as 'this is "my query" go', returns
|
||||||
|
// an array of tokens like this: ['this', 'is', 'my query', 'go']
|
||||||
|
if (!query) return []
|
||||||
|
|
||||||
|
const match = query.match(/\\?.|^$/g)
|
||||||
|
if (!match) return []
|
||||||
|
|
||||||
|
const { tokens } = match.reduce((state, c) => {
|
||||||
|
if (c === '"') {
|
||||||
|
state.quote ^= 1
|
||||||
|
} else if (!state.quote && c === ' ') {
|
||||||
|
state.tokens.push('')
|
||||||
|
} else {
|
||||||
|
state.tokens[state.tokens.length - 1] += c.replace(/\\(.)/, '$1')
|
||||||
|
}
|
||||||
|
|
||||||
|
return state
|
||||||
|
}, { tokens: [''], quote: 0 })
|
||||||
|
|
||||||
|
return tokens
|
||||||
|
}
|
||||||
|
|
||||||
|
const unquote = (str: string) => {
|
||||||
|
if (str[0] === '"') str = str.slice(1)
|
||||||
|
if (str[str.length - 1] === '"') str = str.slice(0, -1)
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseTokens (normalizedQuery: string[]): Token[] {
|
||||||
|
// given an array of tokens as returned by normalizeQuery,
|
||||||
|
// returns a list of objects such as [
|
||||||
|
// {
|
||||||
|
// field: 'status',
|
||||||
|
// value: 'pending'
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// field: null,
|
||||||
|
// value: 'hello'
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
return normalizedQuery.map(t => {
|
||||||
|
// we split the token on ":"
|
||||||
|
const parts = t.split(/:(.+)/)
|
||||||
|
if (parts.length === 1) {
|
||||||
|
// no field specified
|
||||||
|
return { field: null, value: t }
|
||||||
|
}
|
||||||
|
|
||||||
|
// first item is the field, second is the value, possibly quoted
|
||||||
|
const [field, value] = parts
|
||||||
|
|
||||||
|
// we remove surrounding quotes if any
|
||||||
|
return { field, value: unquote(value) }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function compileTokens (tokens: Token[]) {
|
||||||
|
// given a list of tokens as returned by parseTokens,
|
||||||
|
// returns a string query
|
||||||
|
const parts = tokens.map(token => {
|
||||||
|
const { field } = token
|
||||||
|
let { value } = token
|
||||||
|
|
||||||
|
if (value.includes(' ')) {
|
||||||
|
value = `"${value}"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field) {
|
||||||
|
return `${field}:${value}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
})
|
||||||
|
|
||||||
|
return parts.join(' ')
|
||||||
|
}
|
|
@ -366,7 +366,7 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { humanSize, truncate } from '~/utils/filters'
|
import { humanSize, truncate } from '~/utils/filters'
|
||||||
import useLogger from '~/composables/useLogger'
|
import useLogger from '~/composables/useLogger'
|
||||||
import useSharedLabels from '../../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
const logger = useLogger()
|
const logger = useLogger()
|
||||||
|
|
||||||
|
|
|
@ -386,7 +386,7 @@ import axios from 'axios'
|
||||||
import ImportStatusModal from '~/components/library/ImportStatusModal.vue'
|
import ImportStatusModal from '~/components/library/ImportStatusModal.vue'
|
||||||
import time from '~/utils/time'
|
import time from '~/utils/time'
|
||||||
import { humanSize, truncate } from '~/utils/filters'
|
import { humanSize, truncate } from '~/utils/filters'
|
||||||
import useSharedLabels from '../../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -133,9 +133,9 @@ import Pagination from '~/components/Pagination.vue'
|
||||||
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
||||||
import ReportCard from '~/components/manage/moderation/ReportCard.vue'
|
import ReportCard from '~/components/manage/moderation/ReportCard.vue'
|
||||||
import ReportCategoryDropdown from '~/components/moderation/ReportCategoryDropdown.vue'
|
import ReportCategoryDropdown from '~/components/moderation/ReportCategoryDropdown.vue'
|
||||||
import { normalizeQuery, parseTokens } from '~/search'
|
import { normalizeQuery, parseTokens } from '~/utils/search'
|
||||||
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
||||||
import useSharedLabels from '../../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -130,9 +130,9 @@ import time from '~/utils/time'
|
||||||
import Pagination from '~/components/Pagination.vue'
|
import Pagination from '~/components/Pagination.vue'
|
||||||
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
import OrderingMixin from '~/components/mixins/Ordering.vue'
|
||||||
import UserRequestCard from '~/components/manage/moderation/UserRequestCard.vue'
|
import UserRequestCard from '~/components/manage/moderation/UserRequestCard.vue'
|
||||||
import { normalizeQuery, parseTokens } from '~/search'
|
import { normalizeQuery, parseTokens } from '~/utils/search'
|
||||||
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
||||||
import useSharedLabels from '../../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -78,7 +78,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { humanSize } from '~/utils/filters'
|
import { humanSize } from '~/utils/filters'
|
||||||
import useSharedLabels from '../../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: { library: { type: Object, required: true } },
|
props: { library: { type: Object, required: true } },
|
||||||
|
|
|
@ -268,7 +268,7 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { merge } from 'lodash-es'
|
import { merge } from 'lodash-es'
|
||||||
import time from '~/utils/time'
|
import time from '~/utils/time'
|
||||||
import { normalizeQuery, parseTokens } from '~/search'
|
import { normalizeQuery, parseTokens } from '~/utils/search'
|
||||||
|
|
||||||
import Pagination from '~/components/Pagination.vue'
|
import Pagination from '~/components/Pagination.vue'
|
||||||
import ActionTable from '~/components/common/ActionTable.vue'
|
import ActionTable from '~/components/common/ActionTable.vue'
|
||||||
|
@ -276,7 +276,7 @@ import OrderingMixin from '~/components/mixins/Ordering.vue'
|
||||||
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
import SmartSearchMixin from '~/components/mixins/SmartSearch.vue'
|
||||||
import ImportStatusModal from '~/components/library/ImportStatusModal.vue'
|
import ImportStatusModal from '~/components/library/ImportStatusModal.vue'
|
||||||
import { humanSize, truncate } from '~/utils/filters'
|
import { humanSize, truncate } from '~/utils/filters'
|
||||||
import useSharedLabels from '../../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -121,7 +121,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import useSharedLabels from '../../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: { library: { type: Object, default: null } },
|
props: { library: { type: Object, default: null } },
|
||||||
|
|
|
@ -213,7 +213,7 @@
|
||||||
<script>
|
<script>
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { humanSize } from '~/utils/filters'
|
import { humanSize } from '~/utils/filters'
|
||||||
import { compileTokens } from '~/search'
|
import { compileTokens } from '~/utils/search'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data () {
|
data () {
|
||||||
|
|
|
@ -144,7 +144,7 @@ import OrderingMixin from '~/components/mixins/Ordering.vue'
|
||||||
import PaginationMixin from '~/components/mixins/Pagination.vue'
|
import PaginationMixin from '~/components/mixins/Pagination.vue'
|
||||||
import PlaylistCardList from '~/components/playlists/CardList.vue'
|
import PlaylistCardList from '~/components/playlists/CardList.vue'
|
||||||
import Pagination from '~/components/Pagination.vue'
|
import Pagination from '~/components/Pagination.vue'
|
||||||
import useSharedLabels from '../../composables/useSharedLabels'
|
import useSharedLabels from '~/composables/locale/useSharedLabels'
|
||||||
|
|
||||||
const FETCH_URL = 'playlists/'
|
const FETCH_URL = 'playlists/'
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,6 @@
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"lib": ["dom", "esnext", "webworker"],
|
"lib": ["dom", "esnext", "webworker"],
|
||||||
|
|
||||||
"allowJs": true,
|
|
||||||
|
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"strictNullChecks": true,
|
"strictNullChecks": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
@ -33,6 +31,5 @@
|
||||||
"vueCompilerOptions": {
|
"vueCompilerOptions": {
|
||||||
"experimentalCompatMode": 2
|
"experimentalCompatMode": 2
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.vue"],
|
"include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.vue", "vite.config.ts"]
|
||||||
"references": [{ "path": "./tsconfig.node.json" }]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"composite": true,
|
|
||||||
"module": "esnext",
|
|
||||||
"moduleResolution": "node"
|
|
||||||
},
|
|
||||||
"include": ["vite.config.ts"]
|
|
||||||
}
|
|
Loading…
Reference in New Issue