[WIP] refactor(front): radio pages

This commit is contained in:
ArneBo 2025-01-23 22:59:10 +01:00
parent dc3c141225
commit a87305be1c
6 changed files with 201 additions and 201 deletions

View File

@ -249,7 +249,7 @@ const updatePage = (page: number) => {
<Pagination <Pagination
v-if="paginateResults" v-if="paginateResults"
:pages="paginateBy" :pages="paginateBy"
v-model:page="page" :page="page"
@update:current="updatePage" @update:current="updatePage"
/> />
</div> </div>
@ -277,7 +277,7 @@ const updatePage = (page: number) => {
<Pagination <Pagination
v-if="paginateResults" v-if="paginateResults"
:pages="paginateBy" :pages="paginateBy"
v-model:page="page" :page="page"
@update:current="updatePage" @update:current="updatePage"
/> />
</div> </div>

View File

@ -12,16 +12,15 @@ import { sortedUniq } from 'lodash-es'
import { useStore } from '~/store' import { useStore } from '~/store'
import axios from 'axios' import axios from 'axios'
import $ from 'jquery'
import Layout from '~/components/ui/Layout.vue' import Layout from '~/components/ui/Layout.vue'
import Section from '~/components/ui/Section.vue' import Section from '~/components/ui/Section.vue'
import Pagination from '~/components/ui/Pagination.vue' import Pagination from '~/components/ui/Pagination.vue'
import RadioCard from '~/components/radios/Card.vue' import RadioCard from '~/components/radios/Card.vue'
import Button from '~/components/ui/Button.vue' import Button from '~/components/ui/Button.vue'
import Link from '~/components/ui/Link.vue' import Alert from '~/components/ui/Alert.vue'
import Card from '~/components/ui/Card.vue'
import Input from '~/components/ui/Input.vue' import Input from '~/components/ui/Input.vue'
import Spacer from '~/components/ui/Spacer.vue'
import useSharedLabels from '~/composables/locale/useSharedLabels' import useSharedLabels from '~/composables/locale/useSharedLabels'
import useOrdering from '~/composables/navigation/useOrdering' import useOrdering from '~/composables/navigation/useOrdering'
@ -103,8 +102,6 @@ onOrderingUpdate(() => {
fetchData() fetchData()
}) })
onMounted(() => $('.ui.dropdown').dropdown())
const { t } = useI18n() const { t } = useI18n()
const labels = computed(() => ({ const labels = computed(() => ({
searchPlaceholder: t('components.library.Radios.placeholder.search'), searchPlaceholder: t('components.library.Radios.placeholder.search'),
@ -165,7 +162,7 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
id="radios-ordering" id="radios-ordering"
:label="t('components.library.Radios.ordering.label')" :label="t('components.library.Radios.ordering.label')"
v-model="ordering" v-model="ordering"
class="ui dropdown" class="dropdown"
> >
<option <option
v-for="(option, key) in orderingOptions" v-for="(option, key) in orderingOptions"
@ -179,7 +176,7 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
id="radios-ordering-direction" id="radios-ordering-direction"
:label="t('components.library.Radios.ordering.direction.label')" :label="t('components.library.Radios.ordering.direction.label')"
v-model="orderingDirection" v-model="orderingDirection"
class="ui dropdown" class="dropdown"
> >
<option value="+"> <option value="+">
{{ t('components.library.Radios.ordering.direction.ascending') }} {{ t('components.library.Radios.ordering.direction.ascending') }}
@ -192,7 +189,7 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
id="radios-results" id="radios-results"
:label="t('components.library.Radios.pagination.results')" :label="t('components.library.Radios.pagination.results')"
v-model="paginateBy" v-model="paginateBy"
class="ui dropdown" class="dropdown"
> >
<option <option
v-for="opt in paginateOptions" v-for="opt in paginateOptions"
@ -204,23 +201,25 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
</select> </select>
</Layout> </Layout>
<div class="ui hidden divider" /> <div class="ui hidden divider" />
<div <Alert
blue
style="align-items: center;"
v-if="result && result.results.length === 0" v-if="result && result.results.length === 0"
class="ui placeholder segment"
> >
<div class="ui icon header"> <i class="bi bi-broadcast-pin" style="font-size: 80px" />
<i class="feed icon" /> <Spacer />
{{ t('components.library.Radios.empty.noResults') }} {{ t('components.library.Radios.empty.noResults') }}
</div> <Spacer />
<router-link <Button
v-if="store.state.auth.authenticated" v-if="store.state.auth.authenticated"
primary
style="align-self:center;"
:to="{name: 'library.radios.build'}" :to="{name: 'library.radios.build'}"
class="ui success button labeled icon" icon="bi-boombox-fill"
> >
<i class="rss icon" />
{{ t('components.library.Radios.button.add') }} {{ t('components.library.Radios.button.add') }}
</router-link> </Button>
</div> </Alert>
<div <div
v-if="result && result.results.length > 0" v-if="result && result.results.length > 0"
class="ui cards" class="ui cards"
@ -234,8 +233,8 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
</div> </div>
<Pagination <Pagination
v-if="result && result.count > paginateBy" v-if="result && result.count > paginateBy"
:page="page" v-model:page="page"
:pages="Math.ceil((result?.results.length || 0)/paginateBy)" :pages="Math.ceil(result.count / paginateBy)"
/> />
</Layout> </Layout>
</template> </template>

View File

@ -4,13 +4,19 @@ import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import axios from 'axios' import axios from 'axios'
import $ from 'jquery'
import useErrorHandler from '~/composables/useErrorHandler' import useErrorHandler from '~/composables/useErrorHandler'
import TrackTable from '~/components/audio/track/Table.vue' import TrackTable from '~/components/audio/track/Table.vue'
import RadioButton from '~/components/radios/Button.vue' import RadioButton from '~/components/radios/Button.vue'
import BuilderFilter from './Filter.vue' import BuilderFilter from './Filter.vue'
import Button from '~/components/ui/Button.vue'
import Layout from '~/components/ui/Layout.vue'
import Input from '~/components/ui/Input.vue'
import Toggle from '~/components/ui/Toggle.vue'
import Textarea from '~/components/ui/Textarea.vue'
import Alert from '~/components/ui/Alert.vue'
import Spacer from '~/components/ui/Spacer.vue'
export interface BuilderFilter { export interface BuilderFilter {
type: string type: string
@ -185,161 +191,149 @@ const save = async () => {
isLoading.value = false isLoading.value = false
} }
onMounted(() => {
$('.ui.dropdown').dropdown()
})
</script> </script>
<template> <template>
<div <Layout
stack
main
v-title="labels.title" v-title="labels.title"
class="ui vertical stripe segment"
> >
<div> <section>
<section> <h1>
<h2 class="ui header"> {{ t('components.library.radios.Builder.header.builder') }}
{{ t('components.library.radios.Builder.header.builder') }} </h1>
</h2> <p>
<p> {{ t('components.library.radios.Builder.description.builder') }}
{{ t('components.library.radios.Builder.description.builder') }} </p>
</p> <Spacer />
<div class="ui form"> <Layout form>
<div <Alert
v-if="success" v-if="success"
class="ui positive message" green
>
<h4 class="header">
<template v-if="radioName">
{{ t('components.library.radios.Builder.header.updated') }}
</template>
<template v-else>
{{ t('components.library.radios.Builder.header.created') }}
</template>
</h4>
</Alert>
<Input
id="name"
v-model="radioName"
:label="t('components.library.radios.Builder.label.name')"
name="name"
type="text"
:placeholder="labels.placeholder.name"
/>
<Textarea
id="description"
v-model="radioDesc"
:label="t('components.library.radios.Builder.label.description')"
rows="2"
type="text"
:placeholder="labels.placeholder.description"
/>
<Toggle
id="public"
v-model="isPublic"
type="checkbox"
:label="t('components.library.radios.Builder.label.public')"
/>
<Button
:disabled="!canSave"
:class="['ui', 'success', {loading: isLoading}, 'button']"
primary
@click="save"
>
{{ t('components.library.radios.Builder.button.save') }}
</Button>
<radio-button
v-if="id"
type="custom"
:custom-radio-id="id"
/>
</Layout>
<div class="ui form">
<div class="inline field">
<label
id="radioFilterLabel"
for="radio-filters"
>{{ t('components.library.radios.Builder.label.filter') }}</label>
<select
id="radio-filters"
v-model="currentFilterType"
class="ui dropdown"
> >
<h4 class="header"> <option value="">
<template v-if="radioName"> {{ t('components.library.radios.Builder.option.filter') }}
{{ t('components.library.radios.Builder.header.updated') }} </option>
</template> <option
<template v-else> v-for="f in availableFilters"
{{ t('components.library.radios.Builder.header.created') }} :key="f.label"
</template> :value="f.type"
</h4>
</div>
<div class="">
<div class="field">
<label for="name">{{ t('components.library.radios.Builder.label.name') }}</label>
<input
id="name"
v-model="radioName"
name="name"
type="text"
:placeholder="labels.placeholder.name"
>
</div>
<div class="field">
<label for="description">{{ t('components.library.radios.Builder.label.description') }}</label>
<textarea
id="description"
v-model="radioDesc"
rows="2"
type="text"
:placeholder="labels.placeholder.description"
/>
</div>
<div class="ui toggle checkbox">
<input
id="public"
v-model="isPublic"
type="checkbox"
>
<label for="public">{{ t('components.library.radios.Builder.label.public') }}</label>
</div>
<div class="ui hidden divider" />
<button
:disabled="!canSave"
:class="['ui', 'success', {loading: isLoading}, 'button']"
@click="save"
> >
{{ t('components.library.radios.Builder.button.save') }} {{ f.label }}
</button> </option>
<radio-button </select>
v-if="id" <Button
type="custom" id="addFilter"
:custom-radio-id="id" primary
/> :disabled="!currentFilterType"
</div> @click="add"
>
{{ t('components.library.radios.Builder.button.filter') }}
</Button>
</div> </div>
<div class="ui form"> <p v-if="currentFilter">
<div class="inline field"> {{ currentFilter.help_text }}
<label </p>
id="radioFilterLabel" </div>
for="radio-filters" <table class="ui table">
>{{ t('components.library.radios.Builder.label.filter') }}</label> <thead>
<select <tr>
id="radio-filters" <th class="two wide">
v-model="currentFilterType" {{ t('components.library.radios.Builder.table.filter.header.name') }}
class="ui dropdown" </th>
> <th class="one wide">
<option value=""> {{ t('components.library.radios.Builder.table.filter.header.exclude') }}
{{ t('components.library.radios.Builder.option.filter') }} </th>
</option> <th class="six wide">
<option {{ t('components.library.radios.Builder.table.filter.header.config') }}
v-for="f in availableFilters" </th>
:key="f.label" <th class="five wide">
:value="f.type" {{ t('components.library.radios.Builder.table.filter.header.candidates') }}
> </th>
{{ f.label }} <th class="two wide">
</option> {{ t('components.library.radios.Builder.table.filter.header.actions') }}
</select> </th>
<button </tr>
id="addFilter" </thead>
:disabled="!currentFilterType" <tbody>
class="ui button" <builder-filter
@click="add" v-for="(f, index) in filters"
> :key="f.hash"
{{ t('components.library.radios.Builder.button.filter') }} v-model:data="filters[index]"
</button> @delete="deleteFilter(index)"
</div>
<p v-if="currentFilter">
{{ currentFilter.help_text }}
</p>
</div>
<table class="ui table">
<thead>
<tr>
<th class="two wide">
{{ t('components.library.radios.Builder.table.filter.header.name') }}
</th>
<th class="one wide">
{{ t('components.library.radios.Builder.table.filter.header.exclude') }}
</th>
<th class="six wide">
{{ t('components.library.radios.Builder.table.filter.header.config') }}
</th>
<th class="five wide">
{{ t('components.library.radios.Builder.table.filter.header.candidates') }}
</th>
<th class="two wide">
{{ t('components.library.radios.Builder.table.filter.header.actions') }}
</th>
</tr>
</thead>
<tbody>
<builder-filter
v-for="(f, index) in filters"
:key="f.hash"
v-model:data="filters[index]"
@delete="deleteFilter(index)"
/>
</tbody>
</table>
<template v-if="checkResult && checkResult.candidates && checkResult.candidates.count">
<h3 class="ui header">
{{ t('components.library.radios.Builder.header.matches', checkResult.candidates.count) }}
</h3>
<track-table
v-if="checkResult.candidates.sample"
:tracks="checkResult.candidates.sample"
:playable="true"
:show-position="false"
:show-duration="false"
:display-actions="false"
/> />
</template> </tbody>
</section> </table>
</div> <template v-if="checkResult && checkResult.candidates && checkResult.candidates.count">
</div> <h3 class="ui header">
{{ t('components.library.radios.Builder.header.matches', checkResult.candidates.count) }}
</h3>
<track-table
v-if="checkResult.candidates.sample"
:tracks="checkResult.candidates.sample"
:playable="true"
:show-position="false"
:show-duration="false"
:display-actions="false"
/>
</template>
</section>
</Layout>
</template> </template>

View File

@ -205,12 +205,12 @@ fetchCandidates()
</semantic-modal> </semantic-modal>
</td> </td>
<td> <td>
<button <Button
class="ui danger button" destructive
@click="emit('delete')" @click="emit('delete')"
> >
{{ t('components.library.radios.Filter.removeButton') }} {{ t('components.library.radios.Filter.removeButton') }}
</button> </Button>
</td> </td>
</tr> </tr>
</template> </template>

View File

@ -79,7 +79,7 @@ const toggleRadio = () => {
<Button <Button
:is-active="running" :is-active="running"
solid primary solid primary
icon="bi-broadcast" icon="bi-boombox-fill"
@click="toggleRadio" @click="toggleRadio"
> >
{{ buttonLabel }} {{ buttonLabel }}

View File

@ -7,6 +7,7 @@ import { useI18n } from 'vue-i18n'
import RadioButton from './Button.vue' import RadioButton from './Button.vue'
import Card from '~/components/ui/Card.vue' import Card from '~/components/ui/Card.vue'
import Spacer from '~/components/ui/Spacer.vue'
interface Props { interface Props {
type: string type: string
@ -47,26 +48,29 @@ const customRadioId = computed(() => props.customRadio?.id ?? null)
> >
{{ radio.description }} {{ radio.description }}
</div> </div>
<Spacer />
<div class="extra content"> <div class="extra content">
<user-link <user-link
v-if="radio.user" v-if="radio.user"
:user="radio.user" :user="radio.user"
class="left floated" class="left floated"
/> />
<radio-button <radio-button
class="right floated button" class="right floated button"
:type="type" :type="type"
:custom-radio-id="customRadioId" :custom-radio-id="customRadioId"
:object-id="objectId" :object-id="objectId"
/> />
<Link
v-if="store.state.auth.authenticated && type === 'custom' && radio.user.id === store.state.auth.profile?.id"
class="ui success button right floated"
:to="{name: 'library.radios.edit', params: {id: customRadioId }}"
>
{{ t('components.radios.Card.button.edit') }}
</Link>
</div> </div>
<template #action>
<Button
v-if="store.state.auth.authenticated && type === 'custom' && radio.user.id === store.state.auth.profile?.id"
class="ui success button right floated"
:to="{name: 'library.radios.edit', params: {id: customRadioId }}"
>
{{ t('components.radios.Card.button.edit') }}
</Button>
</template>
</Card> </Card>
<Card <Card
v-else v-else
@ -80,23 +84,26 @@ const customRadioId = computed(() => props.customRadio?.id ?? null)
> >
{{ radio.description }} {{ radio.description }}
</div> </div>
<Spacer />
<div class="extra content"> <div class="extra content">
<user-link <user-link
v-if="radio.user" v-if="radio.user"
:user="radio.user" :user="radio.user"
/> />
<radio-button <radio-button
:type="type" :type="type"
:custom-radio-id="customRadioId" :custom-radio-id="customRadioId"
:object-id="objectId" :object-id="objectId"
/> />
<Link
v-if="store.state.auth.authenticated && type === 'custom' && radio.user.id === store.state.auth.profile?.id"
class="ui success button right floated"
:to="{name: 'library.radios.edit', params: {id: customRadioId }}"
>
{{ t('components.radios.Card.button.edit') }}
</Link>
</div> </div>
<template #action>
<Button
v-if="store.state.auth.authenticated && type === 'custom' && radio.user.id === store.state.auth.profile?.id"
class="ui success button right floated"
:to="{name: 'library.radios.edit', params: {id: customRadioId }}"
>
{{ t('components.radios.Card.button.edit') }}
</Button>
</template>
</Card> </Card>
</template> </template>