From 992dd9cb10a0bcddc59db399daf5e1f57d6a2dd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksa=20Siri=C5=A1ki?= <31509435+aleksasiriski@users.noreply.github.com> Date: Wed, 25 Dec 2024 16:19:04 +0100 Subject: [PATCH 1/5] fix(docker-compose): add folder as volume for dev db --- docker-compose.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index d79b2b7..86d9a16 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,3 +9,6 @@ services: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB} + volumes: + - './database:/var/lib/postgresql/data:z' + restart: never From 8ab3f23f309052a4620639d20f284e4096de5c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksa=20Siri=C5=A1ki?= <31509435+aleksasiriski@users.noreply.github.com> Date: Wed, 25 Dec 2024 16:19:18 +0100 Subject: [PATCH 2/5] fix(docker-compose): add exposed ports for ssh tunnel --- docker-compose.prod.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index b828ec8..9a468a0 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -73,6 +73,8 @@ services: build: context: . dockerfile: docker/postgres.Dockerfile + ports: + - 5432:5432 environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} From 6a9d20925d4ea524f0dd2c2a17bfd0616540e7bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksa=20Siri=C5=A1ki?= <31509435+aleksasiriski@users.noreply.github.com> Date: Wed, 25 Dec 2024 16:19:47 +0100 Subject: [PATCH 3/5] fix(search): switch to POST for search and show toast on toggle state --- src/routes/(dashboard)/+page.server.ts | 59 +++++++++++++++++++++++--- src/routes/(dashboard)/+page.svelte | 55 ++++++++++++++++-------- 2 files changed, 91 insertions(+), 23 deletions(-) diff --git a/src/routes/(dashboard)/+page.server.ts b/src/routes/(dashboard)/+page.server.ts index 331bd75..4b06bdd 100644 --- a/src/routes/(dashboard)/+page.server.ts +++ b/src/routes/(dashboard)/+page.server.ts @@ -6,11 +6,10 @@ import { Employee, Student, type Person } from '$lib/types/person'; import { invalidateSession } from '$lib/server/db/session'; import { deleteSessionTokenCookie } from '$lib/server/session'; -export const load: PageServerLoad = async ({ url }) => { +export const load: PageServerLoad = async () => { try { - const searchQuery = url.searchParams.get('q') ?? undefined; - const studentsP = getStudents(1000, 0, searchQuery); - const employeesP = getEmployees(1000, 0, searchQuery); + const studentsP = getStudents(1000, 0, undefined); + const employeesP = getEmployees(1000, 0, undefined); const students = await studentsP; const employees = await employeesP; @@ -38,18 +37,62 @@ export const load: PageServerLoad = async ({ url }) => { ]; return { - searchQuery, persons }; } catch (err: unknown) { console.debug(`Failed to get students and employees: ${(err as Error).message}`); return fail(500, { + persons: [] as Person[], message: 'Failed to get students and employees' }); } }; export const actions: Actions = { + search: async ({ request }) => { + try { + const formData = await request.formData(); + const searchQuery = formData.get('q')?.toString() ?? undefined; + + const studentsP = getStudents(1000, 0, searchQuery); + const employeesP = getEmployees(1000, 0, searchQuery); + const students = await studentsP; + const employees = await employeesP; + + const persons: Person[] = [ + ...students.map((s) => ({ + id: s.id, + type: Student, + identifier: s.index, + fname: s.fname, + lname: s.lname, + department: s.department, + building: s.building, + state: s.state + })), + ...employees.map((e) => ({ + id: e.id, + type: Employee, + identifier: e.email, + fname: e.fname, + lname: e.lname, + department: e.department, + building: e.building, + state: e.state + })) + ]; + + return { + searchQuery, + persons + }; + } catch (err: unknown) { + console.debug(`Failed to search: ${(err as Error).message}`); + return fail(500, { + message: 'Failed to search' + }); + } + }, togglestate: async ({ request, locals }) => { try { const formData = await request.formData(); @@ -86,10 +129,14 @@ export const actions: Actions = { } else if (type === Employee) { await toggleEmployeeState(id, building, creator); } else { - return fail(400, { + return fail(500, { message: 'Invalid type (neither student nor employee)' }); } + + return { + message: 'Successfully toggled state' + }; } catch (err: unknown) { console.debug(`Failed to toggle state: ${(err as Error).message}`); return fail(400, { diff --git a/src/routes/(dashboard)/+page.svelte b/src/routes/(dashboard)/+page.svelte index 729056c..9bc35d6 100644 --- a/src/routes/(dashboard)/+page.svelte +++ b/src/routes/(dashboard)/+page.svelte @@ -5,33 +5,54 @@ import Search from 'lucide-svelte/icons/search'; import Reset from 'lucide-svelte/icons/list-restart'; import DataTable from './data-table.svelte'; + import { toast } from 'svelte-sonner'; + import { page } from '$app/stores'; import { columns } from './columns'; + import { enhance } from '$app/forms'; + import { goto } from '$app/navigation'; let { data, form: actionData } = $props(); - const searchQuery = data.searchQuery; - let searchBox: HTMLFormElement | null; + $effect(() => { + const msg = actionData?.message; + if (msg !== undefined) { + if ($page.status === 200) { + toast.success(msg); + } else { + toast.error(msg); + } + } + }); + + let searchQuery = $state(''); + const persons = $derived(actionData?.persons ?? data.persons ?? []);