Skip to content

Commit

Permalink
feat: #145 rework 1-click template forms logic
Browse files Browse the repository at this point in the history
  • Loading branch information
bohdan-shulha committed Aug 27, 2024
1 parent 508b935 commit b2819e5
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 29 deletions.
2 changes: 1 addition & 1 deletion resources/js/Pages/Services/Partials/DeploymentData.vue
Original file line number Diff line number Diff line change
Expand Up @@ -1570,7 +1570,7 @@ const extractFieldErrors = (basePath) => {

<div class="pt-2 select-none">
<FwbToggle
:model-value="item.backupSchedule !== null"
:model-value="item.backupSchedule != null"
:disabled="props.s3Storages.length === 0"
:class="
props.s3Storages.length === 0
Expand Down
56 changes: 56 additions & 0 deletions resources/js/Pages/Services/Partials/DynamicForm.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<script setup>
import { computed } from "vue";
import TextInput from "@/Components/TextInput.vue";
import FormField from "@/Components/FormField.vue";
const props = defineProps({
scope: String,
item: Object,
form: Object,
errors: Object,
});
const itemName = computed(() => {
if (props.scope) {
return `${props.scope}/${props.item.name}`;
}
return props.item.name;
});
</script>

<template>
<div v-if="item.type === 'v-stack'" class="flex flex-col gap-4">
<template v-for="item in item.items" :key="'v-' + item.id">
<DynamicForm
:item="item"
:form="form"
:errors="errors"
:scope="scope"
/>
</template>
</div>

<div v-else-if="item.type === 'h-stack'" class="flex flex-row gap-4">
<template v-for="item in item.items" :key="'h-' + item.id">
<DynamicForm
:item="item"
:form="form"
:errors="errors"
:scope="scope"
/>
</template>
</div>

<template v-else>
<FormField class="w-full" :error="errors[itemName]">
<template #label>{{ item.label }}</template>

<TextInput
v-if="item.type === 'text-field'"
v-model="form[itemName]"
class="w-full"
/>
</FormField>
</template>
</template>
90 changes: 62 additions & 28 deletions resources/js/Pages/Services/Partials/TemplatePicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import TextInput from "@/Components/TextInput.vue";
import FormField from "@/Components/FormField.vue";
import { makeId } from "@/id.js";
import useSWRV, { mutate } from "swrv";
import DynamicForm from "./DynamicForm.vue";
const props = defineProps({
marketplaceUrl: String,
Expand Down Expand Up @@ -45,6 +46,9 @@ const form = reactive({
});
const selectTemplate = async (template) => {
form.errors = {};
form.data = {};
state.template = await (
await fetch(props.marketplaceUrl + "/" + template.slug + ".json")
).json();
Expand Down Expand Up @@ -136,6 +140,25 @@ const mapProcessTemplate = (templateSlug, process, newIndex) => {
};
const applyTemplate = () => {
form.errors = {};
validateForm(form.data, state.template.form, form.errors);
state.extends.forEach((template) => {
console.log(
JSON.stringify({
data: form.data,
form: template.form,
errors: form.errors,
slug: template.slug,
}),
);
validateForm(form.data, template.form, form.errors, template.slug);
});
if (Object.keys(form.errors).length > 0) {
return;
}
const extendedTemplates = state.extends.reduce((acc, template) => {
return [
...acc,
Expand All @@ -159,6 +182,34 @@ const applyTemplate = () => {
},
});
};
const validateForm = (formData, schema, errors, scope) => {
switch (schema.type) {
case "v-stack":
case "h-stack":
for (const item of schema.items) {
validateForm(formData, item, errors, scope);
}
break;
case "text-field":
console.log(JSON.stringify({ formData, schema, errors, scope }));
const itemName = scope ? `${scope}/${schema.name}` : schema.name;
if (
schema.required &&
schema.format === "string" &&
(formData[itemName] == null || formData[itemName].trim() === "")
) {
errors[itemName] =
`The ${schema.label.toLowerCase()} field is required`;
}
break;
}
return Object.keys(errors).length === 0;
};
</script>
<template>
Expand Down Expand Up @@ -290,21 +341,11 @@ const applyTemplate = () => {
{{ state.template.description }}
</p>
<template
v-for="(_descriptor, prop) in state.template.form.schema
.properties"
>
<FormField class="my-2" :error="form.errors[prop]">
<template #label>{{ prop }}</template>
<TextInput
v-model="
form.data[`${state.template.slug}/${prop}`]
"
class="w-full"
/>
</FormField>
</template>
<DynamicForm
:item="state.template.form"
:form="form.data"
:errors="form.errors"
/>
<div v-for="template in state.extends">
<p
Expand All @@ -318,19 +359,12 @@ const applyTemplate = () => {
{{ template.description }}
</p>
<template
v-for="(_descriptor, prop) in template.form.schema
.properties"
>
<FormField class="my-2" :error="form.errors[prop]">
<template #label>{{ prop }}</template>
<TextInput
v-model="form.data[`${template.slug}/${prop}`]"
class="w-full"
/>
</FormField>
</template>
<DynamicForm
:item="template.form"
:scope="template.slug"
:form="form.data"
:errors="form.errors"
/>
</div>
</div>
</template>
Expand Down

0 comments on commit b2819e5

Please sign in to comment.