feat: add app edit page with pre-populated form
CI / lint-and-check (push) Failing after 5m3s
CI / test (push) Has been skipped
CI / docker-build (push) Has been skipped

Add /apps/[id]/edit route that loads existing app data into the form,
allowing users to update app properties. Adds edit pencil button to
AppCard (visible on hover) and i18n keys for both EN and RU.
This commit is contained in:
2026-03-25 22:42:20 +03:00
parent 44bbf7b410
commit d479726fe3
6 changed files with 134 additions and 10 deletions
+60
View File
@@ -0,0 +1,60 @@
import type { Actions, PageServerLoad } from './$types.js';
import { superValidate, setError } from 'sveltekit-superforms';
import { zod } from '$lib/utils/zod-adapter.js';
import { error, fail, redirect } from '@sveltejs/kit';
import { requireAuth } from '$lib/server/middleware/authenticate.js';
import * as appService from '$lib/server/services/appService.js';
import { createAppSchema } from '$lib/utils/validators.js';
export const load: PageServerLoad = async (event) => {
requireAuth(event);
let app;
try {
app = await appService.findById(event.params.id);
} catch {
throw error(404, 'App not found');
}
const form = await superValidate(zod(createAppSchema));
// Pre-fill form with existing app data
form.data.name = app.name;
form.data.url = app.url;
form.data.icon = app.icon ?? undefined;
form.data.iconType = app.iconType as typeof form.data.iconType;
form.data.description = app.description ?? undefined;
form.data.category = app.category ?? undefined;
form.data.tags = app.tags ?? undefined;
form.data.healthcheckEnabled = app.healthcheckEnabled;
form.data.healthcheckInterval = app.healthcheckInterval;
form.data.healthcheckMethod = app.healthcheckMethod as typeof form.data.healthcheckMethod;
form.data.healthcheckExpectedStatus = app.healthcheckExpectedStatus;
form.data.healthcheckTimeout = app.healthcheckTimeout;
form.data.integrationType = app.integrationType ?? undefined;
form.data.integrationConfig = (app.integrationConfig as string) ?? undefined;
form.data.integrationEnabled = app.integrationEnabled;
return { form, app: { id: app.id, name: app.name } };
};
export const actions: Actions = {
update: async (event) => {
requireAuth(event);
const form = await superValidate(event.request, zod(createAppSchema));
if (!form.valid) {
return fail(400, { form });
}
try {
await appService.update(event.params.id, form.data);
} catch (err) {
const message = err instanceof Error ? err.message : 'Failed to update app';
return setError(form, '', message);
}
throw redirect(303, '/apps');
}
};
+32
View File
@@ -0,0 +1,32 @@
<script lang="ts">
import { t } from 'svelte-i18n';
import type { PageData } from './$types.js';
import AppForm from '$lib/components/app/AppForm.svelte';
let { data }: { data: PageData } = $props();
</script>
<svelte:head>
<title>{$t('app.edit_title')}{data.app.name}</title>
</svelte:head>
<div class="p-6">
<div class="mx-auto max-w-3xl">
<div class="mb-6 flex items-center justify-between">
<div>
<h1 class="text-2xl font-bold text-foreground">{$t('app.edit_title')}</h1>
<p class="mt-1 text-sm text-muted-foreground">{data.app.name}</p>
</div>
<a
href="/apps"
class="rounded-lg border border-border px-4 py-2 text-sm font-medium text-foreground transition-colors hover:bg-accent focus:outline-none focus:ring-2 focus:ring-ring"
>
{$t('common.cancel')}
</a>
</div>
<div class="rounded-xl border border-border bg-card p-6 shadow-sm">
<AppForm form={data.form} action="?/update" mode="edit" />
</div>
</div>
</div>