dynamic form updater

This commit is contained in:
Fran Jurmanović
2025-02-13 21:15:28 +01:00
parent 6bb1625f3e
commit 576d04c52a
12 changed files with 115 additions and 53 deletions

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { enhance } from '$app/forms';
import type { AssistRules } from '$models/config';
import { configFile, type AssistRules } from '$models/config';
const { config, id }: { config: AssistRules; id: string } = $props();
const editedConfig = $state({ ...config });
@@ -9,12 +9,17 @@
<form
method="POST"
action="?/assistRules"
action="?/update"
use:enhance={() => {
formLoading = true;
return async ({ update }) => {
await update({ invalidateAll: true, reset: false });
formLoading = false;
};
}}
>
<input type="hidden" name="id" value={id} />
<input type="hidden" name="file" value={configFile.assistRules} />
<div class="sm:mx-auto sm:w-full sm:max-w-7xl">
<div class="border-b border-gray-900/10 pb-12">
<h2 class="text-base/7 font-semibold text-gray-900">Assist Rules</h2>

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { enhance } from '$app/forms';
import type { Configuration } from '$models/config';
import { configFile, type Configuration } from '$models/config';
const { config, id }: { config: Configuration; id: string } = $props();
const editedConfig = $state({ ...config });
@@ -9,12 +9,17 @@
<form
method="POST"
action="?/configuration"
action="?/update"
use:enhance={() => {
formLoading = true;
return async ({ update }) => {
await update({ invalidateAll: true, reset: false });
formLoading = false;
};
}}
>
<input type="hidden" name="id" value={id} />
<input type="hidden" name="file" value={configFile.configuration} />
<div class="sm:mx-auto sm:w-full sm:max-w-7xl">
<div class="border-b border-gray-900/10 pb-12">
<h2 class="text-base/7 font-semibold text-gray-900">Configuration</h2>

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { enhance } from '$app/forms';
import type { EventConfig } from '$models/config';
import { configFile, type EventConfig } from '$models/config';
import type { Track } from '$models/lookups';
const { config, tracks, id }: { config: EventConfig; tracks: Track[]; id: string } = $props();
@@ -11,12 +11,17 @@
<form
method="POST"
action="?/event"
action="?/update"
use:enhance={() => {
formLoading = true;
return async ({ update }) => {
await update({ invalidateAll: true, reset: false });
formLoading = false;
};
}}
>
<input type="hidden" name="id" value={id} />
<input type="hidden" name="file" value={configFile.event} />
<div class="sm:mx-auto sm:w-full sm:max-w-7xl">
<div class="border-b border-gray-900/10 pb-12">
<h2 class="text-base/7 font-semibold text-gray-900">Event</h2>
@@ -215,7 +220,7 @@
<div class="input-block">
<input
bind:value={session.hourOfDay}
name={`sessions[${index}][hourOfDay]`}
name={`sessions[${index}].hourOfDay`}
disabled={formLoading}
type="number"
class="form form-input"
@@ -232,7 +237,7 @@
<div class="input-block">
<input
bind:value={session.dayOfWeekend}
name={`sessions[${index}][dayOfWeekend]`}
name={`sessions[${index}].dayOfWeekend`}
disabled={formLoading}
type="number"
class="form form-input"
@@ -249,7 +254,7 @@
<div class="input-block">
<input
bind:value={session.timeMultiplier}
name={`sessions[${index}][timeMultiplier]`}
name={`sessions[${index}].timeMultiplier`}
disabled={formLoading}
type="number"
class="form form-input"
@@ -265,7 +270,7 @@
<div class="mt-2 grid grid-cols-1">
<select
bind:value={session.sessionType}
name={`sessions[${index}][sessionType]`}
name={`sessions[${index}].sessionType`}
disabled={formLoading}
class="form form-select"
>
@@ -284,7 +289,7 @@
<div class="input-block">
<input
bind:value={session.sessionDurationMinutes}
name={`sessions[${index}][sessionDurationMinutes]`}
name={`sessions[${index}].sessionDurationMinutes`}
disabled={formLoading}
type="number"
class="form form-input"

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { enhance } from '$app/forms';
import type { EventRules } from '$models/config';
import { configFile, type EventRules } from '$models/config';
const { config, id }: { config: EventRules; id: string } = $props();
const editedConfig = $state({ ...config });
@@ -9,12 +9,17 @@
<form
method="POST"
action="?/eventRules"
action="?/update"
use:enhance={() => {
formLoading = true;
return async ({ update }) => {
await update({ invalidateAll: true, reset: false });
formLoading = false;
};
}}
>
<input type="hidden" name="id" value={id} />
<input type="hidden" name="file" value={configFile.eventRules} />
<div class="sm:mx-auto sm:w-full sm:max-w-7xl">
<div class="border-b border-gray-900/10 pb-12">
<h2 class="text-base/7 font-semibold text-gray-900">Event Rules</h2>

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { enhance } from '$app/forms';
import type { ServerSettings } from '$models/config';
import { configFile, type ServerSettings } from '$models/config';
const { config, id }: { config: ServerSettings; id: string } = $props();
const editedConfig = $state({ ...config });
@@ -10,12 +10,17 @@
<form
method="POST"
action="?/settings"
action="?/update"
use:enhance={() => {
formLoading = true;
return async ({ update }) => {
await update({ invalidateAll: true, reset: false });
formLoading = false;
};
}}
>
<input type="hidden" name="id" value={id} />
<input type="hidden" name="file" value={configFile.settings} />
<div class="sm:mx-auto sm:w-full sm:max-w-7xl">
<div class="border-b border-gray-900/10 pb-12">
<h2 class="text-base/7 font-semibold text-gray-900">Settings</h2>

View File

@@ -7,4 +7,8 @@
{@render children()}
</div>
<svelte:head>
<title>ACC Server Manager</title>
</svelte:head>
<style></style>

View File

@@ -12,6 +12,10 @@
{/each}
</div>
<svelte:head>
<title>ACC Server Manager - Dashboard</title>
</svelte:head>
<style>
.server-grid {
display: grid;

View File

@@ -4,7 +4,8 @@ import { checkAuth } from '$api/authService';
import { getTracks } from '$api/lookupService';
import { redirect } from '@sveltejs/kit';
import type { RequestEvent } from '@sveltejs/kit';
import { configFile, type Session } from '$models/config';
import { configFile, type Config, type Session } from '$models/config';
import { set } from 'lodash-es';
export const load = async (event: RequestEvent) => {
const isAuth = await checkAuth(event);
@@ -31,48 +32,40 @@ type SessionField =
| 'hourOfDay';
export const actions = {
event: async (event: RequestEvent) => {
const formData = await event.request.formData();
const id = formData.get('id') as string;
const restart = formData.get('restart') === 'true';
const object: any = {};
update: async (event: RequestEvent) => {
const { id, restart, file, data } = await destructureFormData(event);
const sessions: Array<Record<SessionField, string | number>> = [];
formData.forEach((value, key) => {
const sessionMatch = key.match(/sessions\[(\d+)\]\[(\w+)\]/);
if (sessionMatch) {
const index = parseInt(sessionMatch[1]);
const field = sessionMatch[2] as SessionField;
if (!sessions[index]) {
sessions[index] = {
hourOfDay: 0,
dayOfWeekend: 0,
timeMultiplier: 0,
sessionType: '',
sessionDurationMinutes: 0
};
}
// Assign the value to the corresponding session field
sessions[index][field] = value !== '' && !Number.isNaN(+value) ? +value : (value as string);
}
});
object.sessions = sessions;
formData.forEach((value, key) => {
switch (key) {
case 'id':
case 'restart':
case 'sessions':
return;
default:
object[key] = value != '' && !Number.isNaN(+value) ? +value : value;
}
});
await updateConfig(event, id, configFile.event, object, true, restart);
redirect(303, '/dashboard');
await updateConfig(event, id, file, data, true, restart);
}
} satisfies Actions;
async function destructureFormData(
event: RequestEvent
): Promise<{ id: string; restart: boolean; data: Config; file: configFile }> {
const formData = await event.request.formData();
const id = formData.get('id') as string;
const restart = formData.get('restart') === 'true';
const file = formData.get('file') as configFile;
const object: any = {};
formData.forEach((value, key) => {
switch (key) {
case 'id':
case 'restart':
case 'file':
return;
default:
set(object, key, parseFormField(value));
}
});
return { id, restart, data: object, file };
}
function parseFormField(value: FormDataEntryValue): string | number {
return value !== '' && !Number.isNaN(+value) ? +value : (value as string);
}
function tryParse(str: string) {
try {
return JSON.parse(str);

View File

@@ -14,6 +14,10 @@
let tab = $state(configFile.event);
</script>
<svelte:head>
<title>{server.name}</title>
</svelte:head>
<aside class="fixed top-0 left-64 z-40 h-screen w-48">
<div class="h-full overflow-y-auto bg-gray-50 px-1 py-4 dark:bg-gray-700">
<div class="flex items-center justify-center">

View File

@@ -9,6 +9,10 @@
let { error } = get(authStore);
</script>
<svelte:head>
<title>ACC Server Manager - Login</title>
</svelte:head>
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
<div class="sm:mx-auto sm:w-full sm:max-w-sm">
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">