fix(form): editing form for library objects

This commit is contained in:
upsiflu 2025-02-02 20:48:10 +01:00
parent 61e6b3fa0f
commit 32093949c7
3 changed files with 123 additions and 130 deletions

View File

@ -9,21 +9,19 @@ import { useStore } from '~/store'
import axios from 'axios' import axios from 'axios'
import AttachmentInput from '~/components/common/AttachmentInput.vue'
import useEditConfigs from '~/composables/moderation/useEditConfigs'
import TagsSelector from '~/components/library/TagsSelector.vue'
import EditList from '~/components/library/EditList.vue'
import EditCard from '~/components/library/EditCard.vue'
import Layout from '~/components/ui/Layout.vue' import Layout from '~/components/ui/Layout.vue'
import Button from '~/components/ui/Button.vue' import Button from '~/components/ui/Button.vue'
import Link from '~/components/ui/Link.vue'
import Section from '~/components/ui/Section.vue'
import Spacer from '~/components/ui/Spacer.vue' import Spacer from '~/components/ui/Spacer.vue'
import Input from '~/components/ui/Input.vue' import Input from '~/components/ui/Input.vue'
import Textarea from "~/components/ui/Textarea.vue" import Textarea from "~/components/ui/Textarea.vue"
import Pills from "~/components/ui/Pills.vue" import Pills from "~/components/ui/Pills.vue"
import Alert from "~/components/ui/Alert.vue" import Alert from "~/components/ui/Alert.vue"
import AttachmentInput from '~/components/common/AttachmentInput.vue'
import useEditConfigs from '~/composables/moderation/useEditConfigs'
import EditList from '~/components/library/EditList.vue'
import EditCard from '~/components/library/EditCard.vue'
interface Props { interface Props {
objectType: EditObjectType objectType: EditObjectType
object: EditObject object: EditObject
@ -147,14 +145,17 @@ const resetField = (fieldId: string) => {
:obj="submittedMutation" :obj="submittedMutation"
:current-state="currentState" :current-state="currentState"
/> />
<Link <Button
solid primary solid primary
@click.prevent="submittedMutation = null" @click.prevent="submittedMutation = null"
> >
{{ t('components.library.EditForm.button.new') }} {{ t('components.library.EditForm.button.new') }}
</Link> </Button>
</Alert> </Alert>
<div v-else> <Layout gap-32 v-else>
<!-- Previous edits -->
<edit-list <edit-list
:filters="editListFilters" :filters="editListFilters"
:url="mutationsUrl" :url="mutationsUrl"
@ -188,7 +189,10 @@ const resetField = (fieldId: string) => {
</empty-state> </empty-state>
</template> </template>
</edit-list> </edit-list>
<Layout form
<!-- Add new edits -->
<form style="display: contents;"
@submit.prevent="submit()" @submit.prevent="submit()"
> >
<div class="ui hidden divider" /> <div class="ui hidden divider" />
@ -213,14 +217,13 @@ const resetField = (fieldId: string) => {
> >
{{ t('components.library.EditForm.message.noPermission') }} {{ t('components.library.EditForm.message.noPermission') }}
</Alert> </Alert>
<template v-if="values"> <Layout stack gap-8
<div v-if="values"
v-for="fieldConfig in config.fields" 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'">
<Spacer :size="64"/>
<Input <Input
:id="fieldConfig.id" :id="fieldConfig.id"
v-model="values[fieldConfig.id]" v-model="values[fieldConfig.id]"
@ -261,8 +264,8 @@ const resetField = (fieldId: string) => {
</Button> </Button>
</template> </template>
<template v-else-if="fieldConfig.type === 'content'"> <template v-else-if="fieldConfig.type === 'content'">
<label :for="fieldConfig.id">{{ fieldConfig.label }}</label> <Textarea
<content-form :label="fieldConfig.label"
v-model="values[fieldConfig.id].text" v-model="values[fieldConfig.id].text"
:field-id="fieldConfig.id" :field-id="fieldConfig.id"
:rows="3" :rows="3"
@ -270,7 +273,6 @@ const resetField = (fieldId: string) => {
</template> </template>
<!-- TODO: Style Attachment Input --> <!-- TODO: Style Attachment Input -->
<template v-else-if="fieldConfig.type === 'attachment'"> <template v-else-if="fieldConfig.type === 'attachment'">
<Spacer />
<attachment-input <attachment-input
:id="fieldConfig.id" :id="fieldConfig.id"
v-model="values[fieldConfig.id]" v-model="values[fieldConfig.id]"
@ -283,7 +285,6 @@ const resetField = (fieldId: string) => {
</attachment-input> </attachment-input>
</template> </template>
<template v-else-if="fieldConfig.type === 'tags'"> <template v-else-if="fieldConfig.type === 'tags'">
<Spacer/>
<Pills <Pills
:id="fieldConfig.id" :id="fieldConfig.id"
:label="fieldConfig.label" :label="fieldConfig.label"
@ -292,7 +293,6 @@ const resetField = (fieldId: string) => {
required="fieldConfig.required" required="fieldConfig.required"
> >
<Button <Button
class="ui tiny basic left floated button"
icon="bi-x" icon="bi-x"
form="noop" form="noop"
@click.prevent="values[fieldConfig.id] = []" @click.prevent="values[fieldConfig.id] = []"
@ -301,39 +301,36 @@ const resetField = (fieldId: string) => {
</Button> </Button>
</Pills> </Pills>
</template> </template>
<div v-if="fieldValuesChanged(fieldConfig.id)"> <Button low-height
<Button
tiny
alignSelf="end" alignSelf="end"
icon="bi-arrow-counterclockwise" icon="bi-arrow-counterclockwise"
form="noop" form="noop"
:disabled="fieldValuesChanged(fieldConfig.id) ? undefined : true"
@click.prevent="resetField(fieldConfig.id)" @click.prevent="resetField(fieldConfig.id)"
> >
{{ t('components.library.EditForm.button.reset') }} {{ t('components.library.EditForm.button.reset') }}
</Button> </Button>
</div> </Layout>
</div>
</template>
<Spacer/> <Spacer/>
<Textarea <Textarea
id="change-summary" id="change-summary"
v-model="summary" v-model="summary"
name="change-summary" name="change-summary"
rows="3" initialLines="3"
:label="t('components.library.EditForm.label.summary')" :label="t('components.library.EditForm.label.summary')"
:placeholder="labels.summaryPlaceholder" :placeholder="labels.summaryPlaceholder"
/> >
<Button <Button
v-if="objectType === 'track'" v-if="objectType === 'track'"
:to="{name: 'library.tracks.detail', params: {id: object.id }}" :to="{name: 'library.tracks.detail', params: {id: object.id }}"
> >
{{ t('components.library.EditForm.button.cancel') }} {{ t('components.library.EditForm.button.cancel') }}
</Button> </Button>
</Textarea>
<Button <Button
:class="['ui', 'right', 'floated', 'success', 'button']" :class="['ui', 'right', 'floated', 'success', 'button']"
:isLoading="isLoading" :isLoading="isLoading"
primary primary
type="submit"
:disabled="isLoading || !mutationPayload" :disabled="isLoading || !mutationPayload"
> >
<span v-if="canEdit"> <span v-if="canEdit">
@ -343,6 +340,6 @@ const resetField = (fieldId: string) => {
{{ t('components.library.EditForm.button.suggest') }} {{ t('components.library.EditForm.button.suggest') }}
</span> </span>
</Button> </Button>
</form>
</Layout> </Layout>
</div>
</template> </template>

View File

@ -20,6 +20,12 @@
> .pill-content { > .pill-content {
padding: 0.45em 0.75em 0.55em 0.75em; padding: 0.45em 0.75em 0.55em 0.75em;
white-space: nowrap; white-space: nowrap;
min-width: 28px;
border-radius: inherit;
&:focus-visible, &:focus {
outline: 2px solid var(--focus-ring-color);
outline-offset: 5px;
}
} }
> .pill-image { > .pill-image {

View File

@ -1,4 +1,4 @@
import type { Album, Artist, Content, Track, Actor } from '~/types' import type { Album, Content, Track, Actor } from '~/types'
import { i18n } from '~/init/locale' import { i18n } from '~/init/locale'
@ -16,8 +16,8 @@ export interface EditableConfigField extends ConfigField {
id: EditObjectType id: EditObjectType
} }
export type EditObject = (Partial<Artist> | Partial<Album> | Partial<Track>) & { attributed_to: Actor } export type EditObject = (Partial<Album> | Partial<Track>) & { attributed_to: Actor }
export type EditObjectType = 'artist' | 'album' | 'track' export type EditObjectType = 'album' | 'track'
type Configs = Record<EditObjectType, { fields: (EditableConfigField|ConfigField)[] }> type Configs = Record<EditObjectType, { fields: (EditableConfigField|ConfigField)[] }>
const getContentValueRepr = (val: Content) => val.text const getContentValueRepr = (val: Content) => val.text
@ -48,25 +48,15 @@ export default (): Configs => {
type: 'tags', type: 'tags',
required: true, required: true,
label: t('composables.moderation.useEditConfigs.tags.label'), label: t('composables.moderation.useEditConfigs.tags.label'),
getValue: (obj) => { return obj.tags }, getValue: (obj) => ({
current: obj.tags || [],
others: [],
custom: [],
}),
getValueRepr: (tags: string[]) => tags.slice().sort().join('\n') getValueRepr: (tags: string[]) => tags.slice().sort().join('\n')
} }
return { return {
artist: {
fields: [
{
id: 'name',
type: 'text',
required: true,
label: t('composables.moderation.useEditConfigs.artist.name'),
getValue: (artist) => (artist as Artist).name
},
description,
cover,
tags
]
},
album: { album: {
fields: [ fields: [
{ {