summaryrefslogtreecommitdiff
path: root/packages/frontend/src/components/MkFormDialog.vue
diff options
context:
space:
mode:
Diffstat (limited to 'packages/frontend/src/components/MkFormDialog.vue')
-rw-r--r--packages/frontend/src/components/MkFormDialog.vue99
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>