kopia lustrzana https://dev.funkwhale.audio/funkwhale/funkwhale
Fix v-if with v-for
rodzic
57aef1001e
commit
4865bf77be
|
@ -24,7 +24,6 @@ module.exports = {
|
|||
],
|
||||
rules: {
|
||||
'vue/no-v-html': 'off', // TODO: tackle this properly
|
||||
'vue/no-use-v-if-with-v-for': 'off',
|
||||
|
||||
// NOTE: Handled by typescript
|
||||
'no-undef': 'off',
|
||||
|
@ -42,6 +41,9 @@ module.exports = {
|
|||
|
||||
// TODO (wvffle): Migration to pinia
|
||||
// Vuex 3 store does not have types defined, hence we use `any`
|
||||
'@typescript-eslint/no-explicit-any': 'off'
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
|
||||
// TODO (wvffle): Migrate to <script setup>
|
||||
'vue/require-explicit-emits': 'off'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,75 +72,74 @@
|
|||
</translate>
|
||||
</div>
|
||||
</div>
|
||||
<template
|
||||
v-for="(field, key) in plugin.conf"
|
||||
v-if="plugin.conf && plugin.conf.length > 0"
|
||||
>
|
||||
<div
|
||||
v-if="field.type === 'text'"
|
||||
:key="key"
|
||||
class="field"
|
||||
>
|
||||
<label :for="`plugin-${field.name}`">{{ field.label || field.name }}</label>
|
||||
<input
|
||||
:id="`plugin-${field.name}`"
|
||||
v-model="values[field.name]"
|
||||
type="text"
|
||||
<template v-if="plugin.conf?.length > 0">
|
||||
<template v-for="(field, key) in plugin.conf">
|
||||
<div
|
||||
v-if="field.type === 'text'"
|
||||
:key="key"
|
||||
class="field"
|
||||
>
|
||||
<label :for="`plugin-${field.name}`">{{ field.label || field.name }}</label>
|
||||
<input
|
||||
:id="`plugin-${field.name}`"
|
||||
v-model="values[field.name]"
|
||||
type="text"
|
||||
>
|
||||
<div
|
||||
v-if="field.help"
|
||||
v-html="markdown.makeHtml(field.help)"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="field.help"
|
||||
v-html="markdown.makeHtml(field.help)"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="field.type === 'long_text'"
|
||||
:key="key"
|
||||
class="field"
|
||||
>
|
||||
<label :for="`plugin-${field.name}`">{{ field.label || field.name }}</label>
|
||||
<textarea
|
||||
:id="`plugin-${field.name}`"
|
||||
v-model="values[field.name]"
|
||||
type="text"
|
||||
rows="5"
|
||||
/>
|
||||
<div
|
||||
v-if="field.help"
|
||||
v-html="markdown.makeHtml(field.help)"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="field.type === 'url'"
|
||||
:key="key"
|
||||
class="field"
|
||||
>
|
||||
<label :for="`plugin-${field.name}`">{{ field.label || field.name }}</label>
|
||||
<input
|
||||
:id="`plugin-${field.name}`"
|
||||
v-model="values[field.name]"
|
||||
type="url"
|
||||
v-if="field.type === 'long_text'"
|
||||
:key="key"
|
||||
class="field"
|
||||
>
|
||||
<label :for="`plugin-${field.name}`">{{ field.label || field.name }}</label>
|
||||
<textarea
|
||||
:id="`plugin-${field.name}`"
|
||||
v-model="values[field.name]"
|
||||
type="text"
|
||||
rows="5"
|
||||
/>
|
||||
<div
|
||||
v-if="field.help"
|
||||
v-html="markdown.makeHtml(field.help)"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="field.help"
|
||||
v-html="markdown.makeHtml(field.help)"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="field.type === 'password'"
|
||||
:key="key"
|
||||
class="field"
|
||||
>
|
||||
<label :for="`plugin-${field.name}`">{{ field.label || field.name }}</label>
|
||||
<input
|
||||
:id="`plugin-${field.name}`"
|
||||
v-model="values[field.name]"
|
||||
type="password"
|
||||
v-if="field.type === 'url'"
|
||||
:key="key"
|
||||
class="field"
|
||||
>
|
||||
<label :for="`plugin-${field.name}`">{{ field.label || field.name }}</label>
|
||||
<input
|
||||
:id="`plugin-${field.name}`"
|
||||
v-model="values[field.name]"
|
||||
type="url"
|
||||
>
|
||||
<div
|
||||
v-if="field.help"
|
||||
v-html="markdown.makeHtml(field.help)"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="field.help"
|
||||
v-html="markdown.makeHtml(field.help)"
|
||||
/>
|
||||
</div>
|
||||
v-if="field.type === 'password'"
|
||||
:key="key"
|
||||
class="field"
|
||||
>
|
||||
<label :for="`plugin-${field.name}`">{{ field.label || field.name }}</label>
|
||||
<input
|
||||
:id="`plugin-${field.name}`"
|
||||
v-model="values[field.name]"
|
||||
type="password"
|
||||
>
|
||||
<div
|
||||
v-if="field.help"
|
||||
v-html="markdown.makeHtml(field.help)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<button
|
||||
type="submit"
|
||||
|
|
|
@ -97,8 +97,7 @@
|
|||
</template>
|
||||
<template v-else>
|
||||
<span
|
||||
v-for="(part, key) in field.diff"
|
||||
v-if="!part.added"
|
||||
v-for="(part, key) in field.diff.filter(p => !p.added)"
|
||||
:key="key"
|
||||
:class="['diff', {removed: part.removed}]"
|
||||
>
|
||||
|
@ -125,8 +124,7 @@
|
|||
</template>
|
||||
<template v-else>
|
||||
<span
|
||||
v-for="(part, key) in field.diff"
|
||||
v-if="!part.removed"
|
||||
v-for="(part, key) in field.diff.filter(p => !p.removed)"
|
||||
:key="key"
|
||||
:class="['diff', {added: part.added}]"
|
||||
>
|
||||
|
|
|
@ -95,108 +95,109 @@
|
|||
You don't have the permission to edit this object, but you can suggest changes. Once submitted, suggestions will be reviewed before approval.
|
||||
</translate>
|
||||
</div>
|
||||
<div
|
||||
v-for="fieldConfig in config.fields"
|
||||
v-if="values"
|
||||
:key="fieldConfig.id"
|
||||
class="ui field"
|
||||
>
|
||||
<template v-if="fieldConfig.type === 'text'">
|
||||
<label :for="fieldConfig.id">{{ fieldConfig.label }}</label>
|
||||
<input
|
||||
:id="fieldConfig.id"
|
||||
v-model="values[fieldConfig.id]"
|
||||
:type="fieldConfig.inputType || 'text'"
|
||||
:required="fieldConfig.required"
|
||||
:name="fieldConfig.id"
|
||||
>
|
||||
</template>
|
||||
<template v-else-if="fieldConfig.type === 'license'">
|
||||
<label :for="fieldConfig.id">{{ fieldConfig.label }}</label>
|
||||
|
||||
<select
|
||||
:id="fieldConfig.id"
|
||||
ref="license"
|
||||
v-model="values[fieldConfig.id]"
|
||||
:required="fieldConfig.required"
|
||||
class="ui fluid search dropdown"
|
||||
>
|
||||
<option :value="null">
|
||||
<translate translate-context="*/*/*">
|
||||
N/A
|
||||
</translate>
|
||||
</option>
|
||||
<option
|
||||
v-for="license in licenses"
|
||||
:key="license.code"
|
||||
:value="license.code"
|
||||
<template v-if="values">
|
||||
<div
|
||||
v-for="fieldConfig in config.fields"
|
||||
:key="fieldConfig.id"
|
||||
class="ui field"
|
||||
>
|
||||
<template v-if="fieldConfig.type === 'text'">
|
||||
<label :for="fieldConfig.id">{{ fieldConfig.label }}</label>
|
||||
<input
|
||||
:id="fieldConfig.id"
|
||||
v-model="values[fieldConfig.id]"
|
||||
:type="fieldConfig.inputType || 'text'"
|
||||
:required="fieldConfig.required"
|
||||
:name="fieldConfig.id"
|
||||
>
|
||||
{{ license.name }}
|
||||
</option>
|
||||
</select>
|
||||
<button
|
||||
class="ui tiny basic left floated button"
|
||||
form="noop"
|
||||
@click.prevent="values[fieldConfig.id] = null"
|
||||
>
|
||||
<i class="x icon" />
|
||||
<translate translate-context="Content/Library/Button.Label">
|
||||
Clear
|
||||
</translate>
|
||||
</button>
|
||||
</template>
|
||||
<template v-else-if="fieldConfig.type === 'content'">
|
||||
<label :for="fieldConfig.id">{{ fieldConfig.label }}</label>
|
||||
<content-form
|
||||
v-model="values[fieldConfig.id].text"
|
||||
:field-id="fieldConfig.id"
|
||||
:rows="3"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="fieldConfig.type === 'attachment'">
|
||||
<attachment-input
|
||||
:id="fieldConfig.id"
|
||||
v-model="values[fieldConfig.id]"
|
||||
:initial-value="initialValues[fieldConfig.id]"
|
||||
:required="fieldConfig.required"
|
||||
:name="fieldConfig.id"
|
||||
@delete="values[fieldConfig.id] = initialValues[fieldConfig.id]"
|
||||
>
|
||||
<span>{{ fieldConfig.label }}</span>
|
||||
</attachment-input>
|
||||
</template>
|
||||
<template v-else-if="fieldConfig.type === 'tags'">
|
||||
<label :for="fieldConfig.id">{{ fieldConfig.label }}</label>
|
||||
<tags-selector
|
||||
:id="fieldConfig.id"
|
||||
ref="tags"
|
||||
v-model="values[fieldConfig.id]"
|
||||
required="fieldConfig.required"
|
||||
/>
|
||||
<button
|
||||
class="ui tiny basic left floated button"
|
||||
form="noop"
|
||||
@click.prevent="values[fieldConfig.id] = []"
|
||||
>
|
||||
<i class="x icon" />
|
||||
<translate translate-context="Content/Library/Button.Label">
|
||||
Clear
|
||||
</translate>
|
||||
</button>
|
||||
</template>
|
||||
<div v-if="fieldValuesChanged(fieldConfig.id)">
|
||||
<button
|
||||
class="ui tiny basic right floated reset button"
|
||||
form="noop"
|
||||
@click.prevent="resetField(fieldConfig.id)"
|
||||
>
|
||||
<i class="undo icon" />
|
||||
<translate translate-context="Content/Library/Button.Label">
|
||||
Reset to initial value
|
||||
</translate>
|
||||
</button>
|
||||
</template>
|
||||
<template v-else-if="fieldConfig.type === 'license'">
|
||||
<label :for="fieldConfig.id">{{ fieldConfig.label }}</label>
|
||||
|
||||
<select
|
||||
:id="fieldConfig.id"
|
||||
ref="license"
|
||||
v-model="values[fieldConfig.id]"
|
||||
:required="fieldConfig.required"
|
||||
class="ui fluid search dropdown"
|
||||
>
|
||||
<option :value="null">
|
||||
<translate translate-context="*/*/*">
|
||||
N/A
|
||||
</translate>
|
||||
</option>
|
||||
<option
|
||||
v-for="license in licenses"
|
||||
:key="license.code"
|
||||
:value="license.code"
|
||||
>
|
||||
{{ license.name }}
|
||||
</option>
|
||||
</select>
|
||||
<button
|
||||
class="ui tiny basic left floated button"
|
||||
form="noop"
|
||||
@click.prevent="values[fieldConfig.id] = null"
|
||||
>
|
||||
<i class="x icon" />
|
||||
<translate translate-context="Content/Library/Button.Label">
|
||||
Clear
|
||||
</translate>
|
||||
</button>
|
||||
</template>
|
||||
<template v-else-if="fieldConfig.type === 'content'">
|
||||
<label :for="fieldConfig.id">{{ fieldConfig.label }}</label>
|
||||
<content-form
|
||||
v-model="values[fieldConfig.id].text"
|
||||
:field-id="fieldConfig.id"
|
||||
:rows="3"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="fieldConfig.type === 'attachment'">
|
||||
<attachment-input
|
||||
:id="fieldConfig.id"
|
||||
v-model="values[fieldConfig.id]"
|
||||
:initial-value="initialValues[fieldConfig.id]"
|
||||
:required="fieldConfig.required"
|
||||
:name="fieldConfig.id"
|
||||
@delete="values[fieldConfig.id] = initialValues[fieldConfig.id]"
|
||||
>
|
||||
<span>{{ fieldConfig.label }}</span>
|
||||
</attachment-input>
|
||||
</template>
|
||||
<template v-else-if="fieldConfig.type === 'tags'">
|
||||
<label :for="fieldConfig.id">{{ fieldConfig.label }}</label>
|
||||
<tags-selector
|
||||
:id="fieldConfig.id"
|
||||
ref="tags"
|
||||
v-model="values[fieldConfig.id]"
|
||||
required="fieldConfig.required"
|
||||
/>
|
||||
<button
|
||||
class="ui tiny basic left floated button"
|
||||
form="noop"
|
||||
@click.prevent="values[fieldConfig.id] = []"
|
||||
>
|
||||
<i class="x icon" />
|
||||
<translate translate-context="Content/Library/Button.Label">
|
||||
Clear
|
||||
</translate>
|
||||
</button>
|
||||
</template>
|
||||
<div v-if="fieldValuesChanged(fieldConfig.id)">
|
||||
<button
|
||||
class="ui tiny basic right floated reset button"
|
||||
form="noop"
|
||||
@click.prevent="resetField(fieldConfig.id)"
|
||||
>
|
||||
<i class="undo icon" />
|
||||
<translate translate-context="Content/Library/Button.Label">
|
||||
Reset to initial value
|
||||
</translate>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="field">
|
||||
<label for="summary"><translate translate-context="*/*/*">Summary (optional)</translate></label>
|
||||
<textarea
|
||||
|
|
|
@ -189,8 +189,7 @@
|
|||
<table class="queue">
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="(track, index) in tracks"
|
||||
v-if="track.sources.length > 0"
|
||||
v-for="(track, index) in filteredTracks"
|
||||
:id="'queue-item-' + index"
|
||||
:key="index"
|
||||
role="button"
|
||||
|
@ -249,6 +248,7 @@ import axios from 'axios'
|
|||
import Logo from '~/components/Logo.vue'
|
||||
import updateQueryString from '~/composables/updateQueryString'
|
||||
import time from '~/utils/time'
|
||||
import { reactive, computed } from 'vue'
|
||||
|
||||
function getURLParams () {
|
||||
let match
|
||||
|
@ -265,6 +265,12 @@ function getURLParams () {
|
|||
export default {
|
||||
name: 'App',
|
||||
components: { Logo },
|
||||
setup () {
|
||||
const tracks = reactive([])
|
||||
const filteredTracks = computed(() => tracks.filter(track => track.sources.length > 0))
|
||||
|
||||
return { tracks, filteredTracks }
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
time,
|
||||
|
@ -273,7 +279,6 @@ export default {
|
|||
error: null,
|
||||
type: null,
|
||||
id: null,
|
||||
tracks: [],
|
||||
autoplay: false,
|
||||
url: null,
|
||||
isLoading: true,
|
||||
|
@ -404,26 +409,25 @@ export default {
|
|||
})
|
||||
},
|
||||
fetchTrack (id) {
|
||||
const self = this
|
||||
const url = `${this.baseUrl}/api/v1/tracks/${id}/`
|
||||
axios.get(url).then(response => {
|
||||
self.tracks = self.parseTracks([response.data])
|
||||
self.isLoading = false
|
||||
axios.get(url).then(() => {
|
||||
this.tracks = this.parseTracks([response.data])
|
||||
this.isLoading = false
|
||||
}).catch(error => {
|
||||
if (error.response) {
|
||||
if (error.response.status === 404) {
|
||||
self.error = 'server_not_found'
|
||||
this.error = 'server_not_found'
|
||||
} else if (error.response.status === 403) {
|
||||
self.error = 'server_requires_auth'
|
||||
this.error = 'server_requires_auth'
|
||||
} else if (error.response.status === 500) {
|
||||
self.error = 'server_error'
|
||||
this.error = 'server_error'
|
||||
} else {
|
||||
self.error = 'server_unknown_error'
|
||||
this.error = 'server_unknown_error'
|
||||
}
|
||||
} else {
|
||||
self.error = 'server_unknown_error'
|
||||
this.error = 'server_unknown_error'
|
||||
}
|
||||
self.isLoading = false
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
fetchTracks (filters, path) {
|
||||
|
|
Ładowanie…
Reference in New Issue