funkwhale/front/src/components/admin/SettingsGroup.vue

248 wiersze
7.2 KiB
Vue
Czysty Zwykły widok Historia

2022-07-04 22:02:39 +00:00
<script setup lang="ts">
import type { BackendError, SettingsGroup, SettingsDataEntry, FunctionRef, Form } from '~/types'
import axios from 'axios'
import SignupFormBuilder from '~/components/admin/SignupFormBuilder.vue'
import useFormData from '~/composables/useFormData'
import { ref, computed, reactive } from 'vue'
import { useStore } from '~/store'
import useLogger from '~/composables/useLogger'
interface Props {
group: SettingsGroup
settingsData: SettingsDataEntry[]
}
const props = defineProps<Props>()
const values = reactive({} as Record<string, unknown | Form | string>)
const result = ref<boolean | null>(null)
const errors = ref([] as string[])
2023-09-01 12:09:58 +00:00
const logger = useLogger()
const store = useStore()
// TODO (wvffle): Use VueUse
2022-07-04 22:02:39 +00:00
const fileRefs = reactive({} as Record<string, HTMLInputElement>)
const setFileRef = (identifier: string) => (el: FunctionRef) => {
2023-09-01 12:09:58 +00:00
logger.debug(el)
2022-07-04 22:02:39 +00:00
fileRefs[identifier] = el as HTMLInputElement
}
const settings = computed(() => {
const byIdentifier = props.settingsData.reduce((acc, entry) => {
acc[entry.identifier] = entry
return acc
}, {} as Record<string, SettingsDataEntry>)
return props.group.settings.map(entry => {
return { ...byIdentifier[entry.name], fieldType: entry.fieldType, fieldParams: entry.fieldParams || {} }
})
})
const fileSettings = computed(() => settings.value.filter(setting => setting.field.widget.class === 'ImageWidget'))
for (const setting of settings.value) {
values[setting.identifier] = setting.value
}
const isLoading = ref(false)
const save = async () => {
errors.value = []
result.value = null
let postData: unknown = values
let contentType = 'application/json'
if (fileSettings.value.length > 0) {
2022-07-21 01:21:36 +00:00
const fileSettingsIDs = fileSettings.value.map((setting) => setting.identifier)
2022-07-04 22:02:39 +00:00
const data = settings.value.reduce((data, setting) => {
if (fileSettingsIDs.includes(setting.identifier)) {
const input = fileRefs[setting.identifier]
const { files } = input
logger.debug('ref', input, files)
if (files && files.length > 0) {
data[setting.identifier] = files[0]
}
} else {
data[setting.identifier] = values[setting.identifier] as string
}
return data
2022-07-21 01:21:36 +00:00
}, {} as Record<string, string | File>)
2022-07-04 22:02:39 +00:00
contentType = 'multipart/form-data'
postData = useFormData(data)
}
try {
const response = await axios.post('instance/admin/settings/bulk/', postData, {
headers: { 'Content-Type': contentType }
})
result.value = true
for (const setting of response.data) {
values[setting.identifier] = setting.value
}
2022-07-30 18:44:49 +00:00
await store.dispatch('instance/fetchSettings')
2022-07-04 22:02:39 +00:00
} catch (error) {
errors.value = (error as BackendError).backendErrors
}
isLoading.value = false
}
</script>
<template>
2021-12-06 10:35:20 +00:00
<form
:id="group.id"
class="ui form component-settings-group"
@submit.prevent="save"
>
<div class="ui divider" />
2021-12-06 10:35:20 +00:00
<h3 class="ui header">
{{ group.label }}
</h3>
<div
v-if="errors.length > 0"
role="alert"
class="ui negative message"
>
<h4 class="header">
2022-09-18 23:12:39 +00:00
{{ $t('components.admin.SettingsGroup.header.error') }}
2021-12-06 10:35:20 +00:00
</h4>
<ul class="list">
2021-12-06 10:35:20 +00:00
<li
v-for="(error, key) in errors"
:key="key"
>
{{ error }}
</li>
</ul>
</div>
2021-12-06 10:35:20 +00:00
<div
v-if="result"
class="ui positive message"
>
2022-09-18 23:12:39 +00:00
{{ $t('components.admin.SettingsGroup.message.success') }}
</div>
2021-12-06 10:35:20 +00:00
<div
v-for="(setting, key) in settings"
:key="key"
class="ui field"
>
<template v-if="setting.field.widget.class !== 'CheckboxInput'">
<label :for="setting.identifier">{{ setting.verbose_name }}</label>
2021-12-06 10:35:20 +00:00
<p v-if="setting.help_text">
{{ setting.help_text }}
</p>
</template>
2021-12-06 10:35:20 +00:00
<content-form
v-if="setting.fieldType === 'markdown'"
v-bind="setting.fieldParams"
2022-07-19 01:29:43 +00:00
v-model="values[setting.identifier]"
2021-12-06 10:35:20 +00:00
/>
2022-09-02 20:58:06 +00:00
<!-- eslint-disable vue/valid-v-model -->
2020-03-18 10:57:33 +00:00
<signup-form-builder
v-else-if="setting.fieldType === 'formBuilder'"
2022-07-04 22:02:39 +00:00
v-model="values[setting.identifier] as Form"
:signup-approval-enabled="!!values.moderation__signup_approval_enabled"
2021-12-06 10:35:20 +00:00
/>
2022-09-02 20:58:06 +00:00
<!-- eslint-enable vue/valid-v-model -->
<input
2021-12-06 10:35:20 +00:00
v-else-if="setting.field.widget.class === 'PasswordInput'"
:id="setting.identifier"
2021-12-06 10:35:20 +00:00
v-model="values[setting.identifier]"
:name="setting.identifier"
type="password"
class="ui input"
2021-12-06 10:35:20 +00:00
>
<input
2021-12-06 10:35:20 +00:00
v-else-if="setting.field.widget.class === 'TextInput'"
:id="setting.identifier"
2021-12-06 10:35:20 +00:00
v-model="values[setting.identifier]"
:name="setting.identifier"
type="text"
class="ui input"
2021-12-06 10:35:20 +00:00
>
<input
2021-12-06 10:35:20 +00:00
v-else-if="setting.field.class === 'IntegerField'"
:id="setting.identifier"
2021-12-06 10:35:20 +00:00
v-model.number="values[setting.identifier]"
:name="setting.identifier"
type="number"
class="ui input"
2021-12-06 10:35:20 +00:00
>
2022-09-02 20:58:06 +00:00
<!-- eslint-disable vue/valid-v-model -->
<textarea
2021-12-06 10:35:20 +00:00
v-else-if="setting.field.widget.class === 'Textarea'"
:id="setting.identifier"
2022-07-04 22:02:39 +00:00
v-model="values[setting.identifier] as string"
:name="setting.identifier"
type="text"
class="ui input"
2021-12-06 10:35:20 +00:00
/>
2022-09-02 20:58:06 +00:00
<!-- eslint-enable vue/valid-v-model -->
2021-12-06 10:35:20 +00:00
<div
v-else-if="setting.field.widget.class === 'CheckboxInput'"
class="ui toggle checkbox"
>
2022-09-02 20:58:06 +00:00
<!-- eslint-disable vue/valid-v-model -->
<input
:id="setting.identifier"
2022-07-04 22:02:39 +00:00
v-model="values[setting.identifier] as boolean"
2021-12-06 10:35:20 +00:00
:name="setting.identifier"
type="checkbox"
>
2022-09-02 20:58:06 +00:00
<!-- eslint-enable vue/valid-v-model -->
<label :for="setting.identifier">{{ setting.verbose_name }}</label>
2021-12-06 10:35:20 +00:00
<p v-if="setting.help_text">
{{ setting.help_text }}
</p>
</div>
<select
v-else-if="setting.field.class === 'MultipleChoiceField'"
2021-12-06 10:35:20 +00:00
:id="setting.identifier"
v-model="values[setting.identifier]"
multiple
2021-12-06 10:35:20 +00:00
class="ui search selection dropdown"
>
<option
2022-08-31 18:43:25 +00:00
v-for="v in setting.additional_data?.choices"
2022-07-04 22:02:39 +00:00
:key="v[0]"
2021-12-06 10:35:20 +00:00
:value="v[0]"
>
{{ v[1] }}
</option>
</select>
2019-09-17 09:03:32 +00:00
<div v-else-if="setting.field.widget.class === 'ImageWidget'">
2021-12-06 10:35:20 +00:00
<input
:id="setting.identifier"
2022-07-04 22:02:39 +00:00
:ref="setFileRef(setting.identifier)"
2021-12-06 10:35:20 +00:00
type="file"
>
2019-09-17 09:03:32 +00:00
<div v-if="values[setting.identifier]">
2021-12-06 10:35:20 +00:00
<div class="ui hidden divider" />
<h3 class="ui header">
2022-09-18 23:12:39 +00:00
{{ $t('components.admin.SettingsGroup.header.image') }}
2021-12-06 10:35:20 +00:00
</h3>
<img
v-if="values[setting.identifier]"
class="ui image"
alt=""
:src="$store.getters['instance/absoluteUrl'](values[setting.identifier])"
>
2019-09-17 09:03:32 +00:00
</div>
</div>
</div>
<button
type="submit"
2021-12-06 10:35:20 +00:00
:class="['ui', {'loading': isLoading}, 'right', 'floated', 'success', 'button']"
>
2022-09-18 23:12:39 +00:00
{{ $t('components.admin.SettingsGroup.button.save') }}
</button>
</form>
</template>