fix(form): editing form for library objects
This commit is contained in:
parent
61e6b3fa0f
commit
32093949c7
|
@ -9,21 +9,19 @@ import { useStore } from '~/store'
|
|||
|
||||
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 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 Input from '~/components/ui/Input.vue'
|
||||
import Textarea from "~/components/ui/Textarea.vue"
|
||||
import Pills from "~/components/ui/Pills.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 {
|
||||
objectType: EditObjectType
|
||||
object: EditObject
|
||||
|
@ -147,14 +145,17 @@ const resetField = (fieldId: string) => {
|
|||
:obj="submittedMutation"
|
||||
:current-state="currentState"
|
||||
/>
|
||||
<Link
|
||||
<Button
|
||||
solid primary
|
||||
@click.prevent="submittedMutation = null"
|
||||
>
|
||||
{{ t('components.library.EditForm.button.new') }}
|
||||
</Link>
|
||||
</Button>
|
||||
</Alert>
|
||||
<div v-else>
|
||||
<Layout gap-32 v-else>
|
||||
|
||||
<!-- Previous edits -->
|
||||
|
||||
<edit-list
|
||||
:filters="editListFilters"
|
||||
:url="mutationsUrl"
|
||||
|
@ -188,7 +189,10 @@ const resetField = (fieldId: string) => {
|
|||
</empty-state>
|
||||
</template>
|
||||
</edit-list>
|
||||
<Layout form
|
||||
|
||||
<!-- Add new edits -->
|
||||
|
||||
<form style="display: contents;"
|
||||
@submit.prevent="submit()"
|
||||
>
|
||||
<div class="ui hidden divider" />
|
||||
|
@ -213,86 +217,82 @@ const resetField = (fieldId: string) => {
|
|||
>
|
||||
{{ t('components.library.EditForm.message.noPermission') }}
|
||||
</Alert>
|
||||
<template v-if="values">
|
||||
<div
|
||||
v-for="fieldConfig in config.fields"
|
||||
:key="fieldConfig.id"
|
||||
class="ui field"
|
||||
>
|
||||
<template v-if="fieldConfig.type === 'text'">
|
||||
<Spacer :size="64"/>
|
||||
<Input
|
||||
:id="fieldConfig.id"
|
||||
v-model="values[fieldConfig.id]"
|
||||
:type="fieldConfig.inputType || 'text'"
|
||||
:required="fieldConfig.required"
|
||||
:name="fieldConfig.id"
|
||||
:label="fieldConfig.label"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="fieldConfig.type === 'license'">
|
||||
<label :for="fieldConfig.id">{{ fieldConfig.label }}</label>
|
||||
<Layout stack gap-8
|
||||
v-if="values"
|
||||
v-for="fieldConfig in config.fields"
|
||||
:key="fieldConfig.id"
|
||||
class="ui field"
|
||||
>
|
||||
<template v-if="fieldConfig.type === 'text'">
|
||||
<Input
|
||||
:id="fieldConfig.id"
|
||||
v-model="values[fieldConfig.id]"
|
||||
:type="fieldConfig.inputType || 'text'"
|
||||
:required="fieldConfig.required"
|
||||
:name="fieldConfig.id"
|
||||
:label="fieldConfig.label"
|
||||
/>
|
||||
</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"
|
||||
<select
|
||||
:id="fieldConfig.id"
|
||||
ref="license"
|
||||
v-model="values[fieldConfig.id]"
|
||||
:required="fieldConfig.required"
|
||||
class="ui fluid search dropdown"
|
||||
>
|
||||
<option :value="null">
|
||||
{{ t('components.library.EditForm.notApplicable') }}
|
||||
</option>
|
||||
<option
|
||||
v-for="{ code, name } in licenses"
|
||||
:key="code"
|
||||
:value="code"
|
||||
>
|
||||
<option :value="null">
|
||||
{{ t('components.library.EditForm.notApplicable') }}
|
||||
</option>
|
||||
<option
|
||||
v-for="{ code, name } in licenses"
|
||||
:key="code"
|
||||
:value="code"
|
||||
>
|
||||
{{ name }}
|
||||
</option>
|
||||
</select>
|
||||
{{ name }}
|
||||
</option>
|
||||
</select>
|
||||
<Button
|
||||
tiny
|
||||
icon="bi-x"
|
||||
form="noop"
|
||||
@click.prevent="values[fieldConfig.id] = null"
|
||||
>
|
||||
{{ t('components.library.EditForm.button.clear') }}
|
||||
</Button>
|
||||
</template>
|
||||
<template v-else-if="fieldConfig.type === 'content'">
|
||||
<Textarea
|
||||
:label="fieldConfig.label"
|
||||
v-model="values[fieldConfig.id].text"
|
||||
:field-id="fieldConfig.id"
|
||||
:rows="3"
|
||||
/>
|
||||
</template>
|
||||
<!-- TODO: Style Attachment Input -->
|
||||
<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'">
|
||||
<Pills
|
||||
:id="fieldConfig.id"
|
||||
:label="fieldConfig.label"
|
||||
ref="tags"
|
||||
v-model="values[fieldConfig.id]"
|
||||
required="fieldConfig.required"
|
||||
>
|
||||
<Button
|
||||
tiny
|
||||
icon="bi-x"
|
||||
form="noop"
|
||||
@click.prevent="values[fieldConfig.id] = null"
|
||||
>
|
||||
{{ t('components.library.EditForm.button.clear') }}
|
||||
</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>
|
||||
<!-- TODO: Style Attachment Input -->
|
||||
<template v-else-if="fieldConfig.type === 'attachment'">
|
||||
<Spacer />
|
||||
<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'">
|
||||
<Spacer/>
|
||||
<Pills
|
||||
:id="fieldConfig.id"
|
||||
:label="fieldConfig.label"
|
||||
ref="tags"
|
||||
v-model="values[fieldConfig.id]"
|
||||
required="fieldConfig.required"
|
||||
>
|
||||
<Button
|
||||
class="ui tiny basic left floated button"
|
||||
icon="bi-x"
|
||||
form="noop"
|
||||
@click.prevent="values[fieldConfig.id] = []"
|
||||
|
@ -300,40 +300,37 @@ const resetField = (fieldId: string) => {
|
|||
{{ t('components.library.EditForm.button.clear') }}
|
||||
</Button>
|
||||
</Pills>
|
||||
</template>
|
||||
<div v-if="fieldValuesChanged(fieldConfig.id)">
|
||||
<Button
|
||||
tiny
|
||||
alignSelf="end"
|
||||
icon="bi-arrow-counterclockwise"
|
||||
form="noop"
|
||||
@click.prevent="resetField(fieldConfig.id)"
|
||||
>
|
||||
{{ t('components.library.EditForm.button.reset') }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<Button low-height
|
||||
alignSelf="end"
|
||||
icon="bi-arrow-counterclockwise"
|
||||
form="noop"
|
||||
:disabled="fieldValuesChanged(fieldConfig.id) ? undefined : true"
|
||||
@click.prevent="resetField(fieldConfig.id)"
|
||||
>
|
||||
{{ t('components.library.EditForm.button.reset') }}
|
||||
</Button>
|
||||
</Layout>
|
||||
<Spacer/>
|
||||
<Textarea
|
||||
id="change-summary"
|
||||
v-model="summary"
|
||||
name="change-summary"
|
||||
rows="3"
|
||||
initialLines="3"
|
||||
:label="t('components.library.EditForm.label.summary')"
|
||||
:placeholder="labels.summaryPlaceholder"
|
||||
/>
|
||||
<Button
|
||||
v-if="objectType === 'track'"
|
||||
:to="{name: 'library.tracks.detail', params: {id: object.id }}"
|
||||
>
|
||||
{{ t('components.library.EditForm.button.cancel') }}
|
||||
</Button>
|
||||
<Button
|
||||
v-if="objectType === 'track'"
|
||||
:to="{name: 'library.tracks.detail', params: {id: object.id }}"
|
||||
>
|
||||
{{ t('components.library.EditForm.button.cancel') }}
|
||||
</Button>
|
||||
</Textarea>
|
||||
<Button
|
||||
:class="['ui', 'right', 'floated', 'success', 'button']"
|
||||
:isLoading="isLoading"
|
||||
primary
|
||||
type="submit"
|
||||
:disabled="isLoading || !mutationPayload"
|
||||
>
|
||||
<span v-if="canEdit">
|
||||
|
@ -343,6 +340,6 @@ const resetField = (fieldId: string) => {
|
|||
{{ t('components.library.EditForm.button.suggest') }}
|
||||
</span>
|
||||
</Button>
|
||||
</Layout>
|
||||
</div>
|
||||
</form>
|
||||
</Layout>
|
||||
</template>
|
||||
|
|
|
@ -20,6 +20,12 @@
|
|||
> .pill-content {
|
||||
padding: 0.45em 0.75em 0.55em 0.75em;
|
||||
white-space: nowrap;
|
||||
min-width: 28px;
|
||||
border-radius: inherit;
|
||||
&:focus-visible, &:focus {
|
||||
outline: 2px solid var(--focus-ring-color);
|
||||
outline-offset: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
> .pill-image {
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
@ -16,8 +16,8 @@ export interface EditableConfigField extends ConfigField {
|
|||
id: EditObjectType
|
||||
}
|
||||
|
||||
export type EditObject = (Partial<Artist> | Partial<Album> | Partial<Track>) & { attributed_to: Actor }
|
||||
export type EditObjectType = 'artist' | 'album' | 'track'
|
||||
export type EditObject = (Partial<Album> | Partial<Track>) & { attributed_to: Actor }
|
||||
export type EditObjectType = 'album' | 'track'
|
||||
type Configs = Record<EditObjectType, { fields: (EditableConfigField|ConfigField)[] }>
|
||||
|
||||
const getContentValueRepr = (val: Content) => val.text
|
||||
|
@ -48,25 +48,15 @@ export default (): Configs => {
|
|||
type: 'tags',
|
||||
required: true,
|
||||
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')
|
||||
}
|
||||
|
||||
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: {
|
||||
fields: [
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue