diff options
Diffstat (limited to 'packages/frontend/src/components/MkFormDialog.vue')
| -rw-r--r-- | packages/frontend/src/components/MkFormDialog.vue | 99 |
1 files changed, 23 insertions, 76 deletions
diff --git a/packages/frontend/src/components/MkFormDialog.vue b/packages/frontend/src/components/MkFormDialog.vue index 142ccb12a3..091721b40b 100644 --- a/packages/frontend/src/components/MkFormDialog.vue +++ b/packages/frontend/src/components/MkFormDialog.vue @@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only :width="450" :canClose="false" :withOkButton="true" - :okButtonDisabled="false" + :okButtonDisabled="!canSave" @click="cancel()" @ok="ok()" @close="cancel()" @@ -20,66 +20,16 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 32px;"> - <div v-if="Object.keys(form).filter(item => !form[item].hidden).length > 0" class="_gaps_m"> - <template v-for="(v, k) in Object.fromEntries(Object.entries(form))"> - <template v-if="typeof v.hidden == 'function' ? v.hidden(values) : v.hidden"></template> - <MkInput v-else-if="v.type === 'number'" v-model="values[k]" type="number" :step="v.step || 1"> - <template #label><span v-text="v.label || k"></span><span v-if="v.required === false"> ({{ i18n.ts.optional }})</span></template> - <template v-if="v.description" #caption>{{ v.description }}</template> - </MkInput> - <MkInput v-else-if="v.type === 'string' && !v.multiline" v-model="values[k]" type="text" :mfmAutocomplete="v.treatAsMfm"> - <template #label><span v-text="v.label || k"></span><span v-if="v.required === false"> ({{ i18n.ts.optional }})</span></template> - <template v-if="v.description" #caption>{{ v.description }}</template> - </MkInput> - <MkTextarea v-else-if="v.type === 'string' && v.multiline" v-model="values[k]" :mfmAutocomplete="v.treatAsMfm" :mfmPreview="v.treatAsMfm"> - <template #label><span v-text="v.label || k"></span><span v-if="v.required === false"> ({{ i18n.ts.optional }})</span></template> - <template v-if="v.description" #caption>{{ v.description }}</template> - </MkTextarea> - <MkSwitch v-else-if="v.type === 'boolean'" v-model="values[k]"> - <span v-text="v.label || k"></span> - <template v-if="v.description" #caption>{{ v.description }}</template> - </MkSwitch> - <MkSelect v-else-if="v.type === 'enum'" v-model="values[k]" :items="getMkSelectDef(v)"> - <template #label><span v-text="v.label || k"></span><span v-if="v.required === false"> ({{ i18n.ts.optional }})</span></template> - </MkSelect> - <MkRadios v-else-if="v.type === 'radio'" v-model="values[k]"> - <template #label><span v-text="v.label || k"></span><span v-if="v.required === false"> ({{ i18n.ts.optional }})</span></template> - <option v-for="option in v.options" :key="getRadioKey(option)" :value="option.value">{{ option.label }}</option> - </MkRadios> - <MkRange v-else-if="v.type === 'range'" v-model="values[k]" :min="v.min" :max="v.max" :step="v.step" :textConverter="v.textConverter"> - <template #label><span v-text="v.label || k"></span><span v-if="v.required === false"> ({{ i18n.ts.optional }})</span></template> - <template v-if="v.description" #caption>{{ v.description }}</template> - </MkRange> - <MkButton v-else-if="v.type === 'button'" @click="v.action($event, values)"> - <span v-text="v.content || k"></span> - </MkButton> - <XFile - v-else-if="v.type === 'drive-file'" - :fileId="v.defaultFileId" - :validate="async f => !v.validate || await v.validate(f)" - @update="f => values[k] = f" - /> - </template> - </div> - <MkResult v-else type="empty"/> + <MkForm v-model="values" :form="form" @canSaveStateChange="onCanSaveStateChanged"/> </div> </MkModalWindow> </template> <script lang="ts" setup> -import { reactive, useTemplateRef } from 'vue'; -import MkInput from './MkInput.vue'; -import MkTextarea from './MkTextarea.vue'; -import MkSwitch from './MkSwitch.vue'; -import MkSelect from './MkSelect.vue'; -import MkRange from './MkRange.vue'; -import MkButton from './MkButton.vue'; -import MkRadios from './MkRadios.vue'; -import XFile from './MkFormDialog.file.vue'; -import type { MkSelectItem } from '@/components/MkSelect.vue'; -import type { Form, EnumFormItem, RadioFormItem } from '@/utility/form.js'; +import { ref, useTemplateRef } from 'vue'; +import type { Form } from '@/utility/form.js'; import MkModalWindow from '@/components/MkModalWindow.vue'; -import { i18n } from '@/i18n.js'; +import MkForm from '@/components/MkForm.vue'; const props = defineProps<{ title: string; @@ -96,19 +46,30 @@ const emit = defineEmits<{ }>(); const dialog = useTemplateRef('dialog'); -const values = reactive({}); -for (const item in props.form) { - if ('default' in props.form[item]) { - values[item] = props.form[item].default ?? null; - } else { - values[item] = null; +const values = ref((() => { + const obj: Record<string, any> = {}; + for (const item in props.form) { + if ('default' in props.form[item]) { + obj[item] = props.form[item].default ?? null; + } else { + obj[item] = null; + } } + return obj; +})()); + +const canSave = ref(true); + +function onCanSaveStateChanged(newCanSave: boolean) { + canSave.value = newCanSave; } function ok() { + if (!canSave.value) return; + emit('done', { - result: values, + result: values.value, }); dialog.value?.close(); } @@ -119,18 +80,4 @@ function cancel() { }); dialog.value?.close(); } - -function getMkSelectDef(def: EnumFormItem): MkSelectItem[] { - return def.enum.map((v) => { - if (typeof v === 'string') { - return { value: v, label: v }; - } else { - return { value: v.value, label: v.label }; - } - }); -} - -function getRadioKey(e: RadioFormItem['options'][number]) { - return typeof e.value === 'string' ? e.value : JSON.stringify(e.value); -} </script> |