Fix v-if with v-for

This commit is contained in:
Kasper Seweryn 2022-05-01 16:35:58 +02:00 committed by Georg Krause
parent 57aef1001e
commit 4865bf77be
5 changed files with 186 additions and 182 deletions

View File

@ -24,7 +24,6 @@ module.exports = {
], ],
rules: { rules: {
'vue/no-v-html': 'off', // TODO: tackle this properly 'vue/no-v-html': 'off', // TODO: tackle this properly
'vue/no-use-v-if-with-v-for': 'off',
// NOTE: Handled by typescript // NOTE: Handled by typescript
'no-undef': 'off', 'no-undef': 'off',
@ -42,6 +41,9 @@ module.exports = {
// TODO (wvffle): Migration to pinia // TODO (wvffle): Migration to pinia
// Vuex 3 store does not have types defined, hence we use `any` // 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'
} }
} }

View File

@ -72,75 +72,74 @@
</translate> </translate>
</div> </div>
</div> </div>
<template <template v-if="plugin.conf?.length > 0">
v-for="(field, key) in plugin.conf" <template v-for="(field, key) in plugin.conf">
v-if="plugin.conf && plugin.conf.length > 0" <div
> v-if="field.type === 'text'"
<div :key="key"
v-if="field.type === 'text'" class="field"
: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"
> >
<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 <div
v-if="field.help" v-if="field.type === 'long_text'"
v-html="markdown.makeHtml(field.help)" :key="key"
/> class="field"
</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"
> >
<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 <div
v-if="field.help" v-if="field.type === 'url'"
v-html="markdown.makeHtml(field.help)" :key="key"
/> class="field"
</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"
> >
<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 <div
v-if="field.help" v-if="field.type === 'password'"
v-html="markdown.makeHtml(field.help)" :key="key"
/> class="field"
</div> >
<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> </template>
<button <button
type="submit" type="submit"

View File

@ -97,8 +97,7 @@
</template> </template>
<template v-else> <template v-else>
<span <span
v-for="(part, key) in field.diff" v-for="(part, key) in field.diff.filter(p => !p.added)"
v-if="!part.added"
:key="key" :key="key"
:class="['diff', {removed: part.removed}]" :class="['diff', {removed: part.removed}]"
> >
@ -125,8 +124,7 @@
</template> </template>
<template v-else> <template v-else>
<span <span
v-for="(part, key) in field.diff" v-for="(part, key) in field.diff.filter(p => !p.removed)"
v-if="!part.removed"
:key="key" :key="key"
:class="['diff', {added: part.added}]" :class="['diff', {added: part.added}]"
> >

View File

@ -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. You don't have the permission to edit this object, but you can suggest changes. Once submitted, suggestions will be reviewed before approval.
</translate> </translate>
</div> </div>
<div <template v-if="values">
v-for="fieldConfig in config.fields" <div
v-if="values" v-for="fieldConfig in config.fields"
:key="fieldConfig.id" :key="fieldConfig.id"
class="ui field" class="ui field"
> >
<template v-if="fieldConfig.type === 'text'"> <template v-if="fieldConfig.type === 'text'">
<label :for="fieldConfig.id">{{ fieldConfig.label }}</label> <label :for="fieldConfig.id">{{ fieldConfig.label }}</label>
<input <input
:id="fieldConfig.id" :id="fieldConfig.id"
v-model="values[fieldConfig.id]" v-model="values[fieldConfig.id]"
:type="fieldConfig.inputType || 'text'" :type="fieldConfig.inputType || 'text'"
:required="fieldConfig.required" :required="fieldConfig.required"
:name="fieldConfig.id" :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"
> >
{{ license.name }} </template>
</option> <template v-else-if="fieldConfig.type === 'license'">
</select> <label :for="fieldConfig.id">{{ fieldConfig.label }}</label>
<button
class="ui tiny basic left floated button" <select
form="noop" :id="fieldConfig.id"
@click.prevent="values[fieldConfig.id] = null" ref="license"
> v-model="values[fieldConfig.id]"
<i class="x icon" /> :required="fieldConfig.required"
<translate translate-context="Content/Library/Button.Label"> class="ui fluid search dropdown"
Clear >
</translate> <option :value="null">
</button> <translate translate-context="*/*/*">
</template> N/A
<template v-else-if="fieldConfig.type === 'content'"> </translate>
<label :for="fieldConfig.id">{{ fieldConfig.label }}</label> </option>
<content-form <option
v-model="values[fieldConfig.id].text" v-for="license in licenses"
:field-id="fieldConfig.id" :key="license.code"
:rows="3" :value="license.code"
/> >
</template> {{ license.name }}
<template v-else-if="fieldConfig.type === 'attachment'"> </option>
<attachment-input </select>
:id="fieldConfig.id" <button
v-model="values[fieldConfig.id]" class="ui tiny basic left floated button"
:initial-value="initialValues[fieldConfig.id]" form="noop"
:required="fieldConfig.required" @click.prevent="values[fieldConfig.id] = null"
:name="fieldConfig.id" >
@delete="values[fieldConfig.id] = initialValues[fieldConfig.id]" <i class="x icon" />
> <translate translate-context="Content/Library/Button.Label">
<span>{{ fieldConfig.label }}</span> Clear
</attachment-input> </translate>
</template> </button>
<template v-else-if="fieldConfig.type === 'tags'"> </template>
<label :for="fieldConfig.id">{{ fieldConfig.label }}</label> <template v-else-if="fieldConfig.type === 'content'">
<tags-selector <label :for="fieldConfig.id">{{ fieldConfig.label }}</label>
:id="fieldConfig.id" <content-form
ref="tags" v-model="values[fieldConfig.id].text"
v-model="values[fieldConfig.id]" :field-id="fieldConfig.id"
required="fieldConfig.required" :rows="3"
/> />
<button </template>
class="ui tiny basic left floated button" <template v-else-if="fieldConfig.type === 'attachment'">
form="noop" <attachment-input
@click.prevent="values[fieldConfig.id] = []" :id="fieldConfig.id"
> v-model="values[fieldConfig.id]"
<i class="x icon" /> :initial-value="initialValues[fieldConfig.id]"
<translate translate-context="Content/Library/Button.Label"> :required="fieldConfig.required"
Clear :name="fieldConfig.id"
</translate> @delete="values[fieldConfig.id] = initialValues[fieldConfig.id]"
</button> >
</template> <span>{{ fieldConfig.label }}</span>
<div v-if="fieldValuesChanged(fieldConfig.id)"> </attachment-input>
<button </template>
class="ui tiny basic right floated reset button" <template v-else-if="fieldConfig.type === 'tags'">
form="noop" <label :for="fieldConfig.id">{{ fieldConfig.label }}</label>
@click.prevent="resetField(fieldConfig.id)" <tags-selector
> :id="fieldConfig.id"
<i class="undo icon" /> ref="tags"
<translate translate-context="Content/Library/Button.Label"> v-model="values[fieldConfig.id]"
Reset to initial value required="fieldConfig.required"
</translate> />
</button> <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>
</div> </template>
<div class="field"> <div class="field">
<label for="summary"><translate translate-context="*/*/*">Summary (optional)</translate></label> <label for="summary"><translate translate-context="*/*/*">Summary (optional)</translate></label>
<textarea <textarea

View File

@ -189,8 +189,7 @@
<table class="queue"> <table class="queue">
<tbody> <tbody>
<tr <tr
v-for="(track, index) in tracks" v-for="(track, index) in filteredTracks"
v-if="track.sources.length > 0"
:id="'queue-item-' + index" :id="'queue-item-' + index"
:key="index" :key="index"
role="button" role="button"
@ -249,6 +248,7 @@ import axios from 'axios'
import Logo from '~/components/Logo.vue' import Logo from '~/components/Logo.vue'
import updateQueryString from '~/composables/updateQueryString' import updateQueryString from '~/composables/updateQueryString'
import time from '~/utils/time' import time from '~/utils/time'
import { reactive, computed } from 'vue'
function getURLParams () { function getURLParams () {
let match let match
@ -265,6 +265,12 @@ function getURLParams () {
export default { export default {
name: 'App', name: 'App',
components: { Logo }, components: { Logo },
setup () {
const tracks = reactive([])
const filteredTracks = computed(() => tracks.filter(track => track.sources.length > 0))
return { tracks, filteredTracks }
},
data () { data () {
return { return {
time, time,
@ -273,7 +279,6 @@ export default {
error: null, error: null,
type: null, type: null,
id: null, id: null,
tracks: [],
autoplay: false, autoplay: false,
url: null, url: null,
isLoading: true, isLoading: true,
@ -404,26 +409,25 @@ export default {
}) })
}, },
fetchTrack (id) { fetchTrack (id) {
const self = this
const url = `${this.baseUrl}/api/v1/tracks/${id}/` const url = `${this.baseUrl}/api/v1/tracks/${id}/`
axios.get(url).then(response => { axios.get(url).then(() => {
self.tracks = self.parseTracks([response.data]) this.tracks = this.parseTracks([response.data])
self.isLoading = false this.isLoading = false
}).catch(error => { }).catch(error => {
if (error.response) { if (error.response) {
if (error.response.status === 404) { if (error.response.status === 404) {
self.error = 'server_not_found' this.error = 'server_not_found'
} else if (error.response.status === 403) { } else if (error.response.status === 403) {
self.error = 'server_requires_auth' this.error = 'server_requires_auth'
} else if (error.response.status === 500) { } else if (error.response.status === 500) {
self.error = 'server_error' this.error = 'server_error'
} else { } else {
self.error = 'server_unknown_error' this.error = 'server_unknown_error'
} }
} else { } else {
self.error = 'server_unknown_error' this.error = 'server_unknown_error'
} }
self.isLoading = false this.isLoading = false
}) })
}, },
fetchTracks (filters, path) { fetchTracks (filters, path) {