diff --git a/prisma/migrations/20240425200550_saved_filters/migration.sql b/prisma/migrations/20240425200550_saved_filters/migration.sql deleted file mode 100644 index 621074c..0000000 --- a/prisma/migrations/20240425200550_saved_filters/migration.sql +++ /dev/null @@ -1,13 +0,0 @@ --- CreateTable -CREATE TABLE "saved_filter" ( - "id" SERIAL NOT NULL, - "user_id" INTEGER NOT NULL, - "view" TEXT NOT NULL, - "name" TEXT NOT NULL, - "query" TEXT NOT NULL, - - CONSTRAINT "saved_filter_pkey" PRIMARY KEY ("id") -); - --- AddForeignKey -ALTER TABLE "saved_filter" ADD CONSTRAINT "saved_filter_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 38f77ff..c401ae1 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -40,7 +40,6 @@ model User { accounts Account[] EntryVersion EntryVersion[] EntryExecution EntryExecution[] - SavedFilter SavedFilter[] @@map("users") } @@ -81,8 +80,8 @@ model Patient { full_name String? @default(dbgenerated("((first_name || ' '::text) || last_name)")) @ignore - @@index([full_name(ops: raw("gin_trgm_ops"))], map: "patients_full_name", type: Gin) @@map("patients") + @@index([full_name(ops: raw("gin_trgm_ops"))], map: "patients_full_name", type: Gin) } // Entry category (e.g. Blood test, Exams, ...) @@ -108,8 +107,8 @@ model Entry { tsvec Unsupported("tsvector")? - @@index([tsvec], type: Gin) @@map("entries") + @@index([tsvec], type: Gin) } model EntryVersion { @@ -129,8 +128,8 @@ model EntryVersion { created_at DateTime @default(now()) - @@index([entry_id]) @@map("entry_versions") + @@index([entry_id]) } model EntryExecution { @@ -145,19 +144,6 @@ model EntryExecution { created_at DateTime @default(now()) - @@index([entry_id]) @@map("entry_executions") -} - -model SavedFilter { - id Int @id @default(autoincrement()) - - user User @relation(fields: [user_id], references: [id]) - user_id Int - - view String - name String - query String - - @@map("saved_filter") + @@index([entry_id]) } diff --git a/src/app.d.ts b/src/app.d.ts index 0b9d41b..4e30e3c 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -20,4 +20,40 @@ declare global { } } +declare module "@gramex/url/encode" { + export default function encode(obj: unknown, settings?: { + listBracket?: boolean; + listIndex?: boolean; + objBracket?: boolean; + sortKeys?: boolean; + drop?: unknown[]; + }): string; + +} +declare module "@gramex/url/index" { + export { default as encode } from "@gramex/url/encode"; + import { default as update } from "@gramex/url/update"; + export { update }; + export const decode: (url: string, settings?: { + convert?: boolean; + forceList?: boolean; + pruneString?: boolean; + }) => unknown; + +} +declare module "@gramex/url/update" { + export default function update(obj: unknown, url: string, settings?: { + convert?: boolean; + forceList?: boolean; + pruneString?: boolean; + pruneObject?: boolean; + pruneArray?: boolean; + }): unknown; + +} +declare module "@gramex/url" { + import main = require("@gramex/url/index"); + export = main; +} + export {}; diff --git a/src/lib/components/filter/FilterBar.svelte b/src/lib/components/filter/FilterBar.svelte index daf6a16..82c0688 100644 --- a/src/lib/components/filter/FilterBar.svelte +++ b/src/lib/components/filter/FilterBar.svelte @@ -8,7 +8,6 @@ import Autocomplete from "./Autocomplete.svelte"; import EntryFilterChip from "./FilterChip.svelte"; - import SavedFilters from "./SavedFilters.svelte"; import type { FilterDef, FilterQdata, @@ -28,7 +27,6 @@ export let hiddenFilters: string[] = []; /** True if a separate search field should be displayed */ export let search = false; - export let view: string; let autocomplete: Autocomplete | undefined; let activeFilters: FilterData[] = []; @@ -248,8 +246,6 @@ - - diff --git a/src/lib/components/filter/SavedFilters.svelte b/src/lib/components/filter/SavedFilters.svelte deleted file mode 100644 index e0e17fb..0000000 --- a/src/lib/components/filter/SavedFilters.svelte +++ /dev/null @@ -1,82 +0,0 @@ - - - -
-
- Gespeicherte Filter: -
- - {#if filters} - {#each filters as filter, i (filter.id)} - remove(i)} - onSave={() => update(i)} - > - {filter.name} - - {/each} - {:else} - - {/if} - - -
diff --git a/src/lib/components/table/FilteredEntryTable.svelte b/src/lib/components/table/FilteredEntryTable.svelte index 75a11c6..bfdec34 100644 --- a/src/lib/components/table/FilteredEntryTable.svelte +++ b/src/lib/components/table/FilteredEntryTable.svelte @@ -57,13 +57,10 @@ filterData={query.filter} hiddenFilters={patientId !== null ? ["patient"] : []} onUpdate={filterUpdate} - view="plan" > - + - - diff --git a/src/lib/components/ui/LoadingIcon.svelte b/src/lib/components/ui/LoadingIcon.svelte deleted file mode 100644 index 246f41b..0000000 --- a/src/lib/components/ui/LoadingIcon.svelte +++ /dev/null @@ -1,17 +0,0 @@ - - -{#if show} - -{/if} diff --git a/src/lib/server/query/savedFilter.ts b/src/lib/server/query/savedFilter.ts deleted file mode 100644 index 761a2c7..0000000 --- a/src/lib/server/query/savedFilter.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { SavedFilter, SavedFilterNew } from "$lib/shared/model"; - -import { prisma } from "$lib/server/prisma"; - -export async function newSavedFilter(filter: SavedFilterNew, user_id: number): Promise { - const created = await prisma.savedFilter.create({ - data: { - user_id, - ...filter, - }, - }); - return created.id; -} - -export async function updateSavedFilter(id: number, query: string, user_id: number) { - await prisma.savedFilter.update({ where: { id, user_id }, data: { query } }); -} - -export async function deleteSavedFilter(id: number, user_id: number) { - await prisma.savedFilter.delete({ where: { id, user_id } }); -} - -export async function getSavedFilters(user_id: number, view: string): Promise { - return prisma.savedFilter.findMany({ - select: { id: true, name: true, query: true }, - where: { user_id, view }, - }); -} diff --git a/src/lib/server/trpc/router.ts b/src/lib/server/trpc/router.ts index 8301107..85ad3b4 100644 --- a/src/lib/server/trpc/router.ts +++ b/src/lib/server/trpc/router.ts @@ -5,7 +5,6 @@ import { categoryRouter } from "./routes/category"; import { entryRouter } from "./routes/entry"; import { patientRouter } from "./routes/patient"; import { roomRouter } from "./routes/room"; -import { savedFilterRouter } from "./routes/savedFilter"; import { stationRouter } from "./routes/station"; import { userRouter } from "./routes/user"; @@ -22,7 +21,6 @@ export const router = t.router({ room: roomRouter, patient: patientRouter, user: userRouter, - savedFilter: savedFilterRouter, }); export type Router = typeof router; diff --git a/src/lib/server/trpc/routes/category.ts b/src/lib/server/trpc/routes/category.ts index 2333808..b8f6f59 100644 --- a/src/lib/server/trpc/routes/category.ts +++ b/src/lib/server/trpc/routes/category.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -import { ZEntityId, ZCategoryNew } from "$lib/shared/model/validation"; +import { fields, ZCategoryNew } from "$lib/shared/model/validation"; import { deleteCategory, @@ -12,6 +12,8 @@ import { import { t, trpcWrap } from ".."; +const ZEntityId = fields.EntityId(); + export const categoryRouter = t.router({ list: t.procedure.query(async () => trpcWrap(getCategories)), get: t.procedure diff --git a/src/lib/server/trpc/routes/entry.ts b/src/lib/server/trpc/routes/entry.ts index 94d3ea3..9c3427e 100644 --- a/src/lib/server/trpc/routes/entry.ts +++ b/src/lib/server/trpc/routes/entry.ts @@ -1,11 +1,11 @@ import { z } from "zod"; import { + fields, ZEntriesQuery, ZEntryExecutionNew, ZEntryNew, ZEntryVersionNew, - ZEntityId, } from "$lib/shared/model/validation"; import { executionsDiff, versionsDiff } from "$lib/shared/util/diff"; @@ -23,6 +23,8 @@ import { import { t, trpcWrap } from ".."; +const ZEntityId = fields.EntityId(); + export const entryRouter = t.router({ get: t.procedure.input(ZEntityId).query(async (opts) => trpcWrap(async () => { const [entry, n_versions, n_executions] = await Promise.all([ diff --git a/src/lib/server/trpc/routes/patient.ts b/src/lib/server/trpc/routes/patient.ts index dfe77a3..16fa97f 100644 --- a/src/lib/server/trpc/routes/patient.ts +++ b/src/lib/server/trpc/routes/patient.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -import { ZEntityId, ZPatientNew, ZPatientsQuery } from "$lib/shared/model/validation"; +import { fields, ZPatientNew, ZPatientsQuery } from "$lib/shared/model/validation"; import { deletePatient, @@ -15,6 +15,8 @@ import { import { t, trpcWrap } from ".."; +const ZEntityId = fields.EntityId(); + export const patientRouter = t.router({ getNames: t.procedure.query(async () => trpcWrap(getPatientNames)), get: t.procedure.input(ZEntityId).query(async (opts) => trpcWrap(async () => { diff --git a/src/lib/server/trpc/routes/room.ts b/src/lib/server/trpc/routes/room.ts index 9872f2d..8d88e88 100644 --- a/src/lib/server/trpc/routes/room.ts +++ b/src/lib/server/trpc/routes/room.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -import { ZEntityId, ZRoomNew } from "$lib/shared/model/validation"; +import { fields, ZRoomNew } from "$lib/shared/model/validation"; import { deleteRoom, getRoom, getRooms, newRoom, updateRoom, @@ -8,6 +8,8 @@ import { import { t, trpcWrap } from ".."; +const ZEntityId = fields.EntityId(); + export const roomRouter = t.router({ list: t.procedure.query(async (opts) => trpcWrap(getRooms)), get: t.procedure diff --git a/src/lib/server/trpc/routes/savedFilter.ts b/src/lib/server/trpc/routes/savedFilter.ts deleted file mode 100644 index 78d9388..0000000 --- a/src/lib/server/trpc/routes/savedFilter.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { - ZEntityId, ZSavedFilterNew, ZSavedFilterUpdate, fields, -} from "$lib/shared/model/validation"; - -import { - deleteSavedFilter, getSavedFilters, newSavedFilter, updateSavedFilter, -} from "$lib/server/query/savedFilter"; - -import { t, trpcWrap } from ".."; - -export const savedFilterRouter = t.router({ - get: t.procedure.input(fields.NameString()).query(async (opts) => trpcWrap( - async () => getSavedFilters(opts.ctx.user.id, opts.input), - )), - create: t.procedure.input(ZSavedFilterNew).mutation(async (opts) => trpcWrap( - async () => newSavedFilter(opts.input, opts.ctx.user.id), - )), - update: t.procedure.input(ZSavedFilterUpdate).mutation(async (opts) => trpcWrap( - async () => updateSavedFilter(opts.input.id, opts.input.query, opts.ctx.user.id), - )), - delete: t.procedure.input(ZEntityId).mutation(async (opts) => trpcWrap( - async () => deleteSavedFilter(opts.input, opts.ctx.user.id), - )), -}); diff --git a/src/lib/server/trpc/routes/station.ts b/src/lib/server/trpc/routes/station.ts index d611f86..80e7944 100644 --- a/src/lib/server/trpc/routes/station.ts +++ b/src/lib/server/trpc/routes/station.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -import { ZEntityId, ZStationNew } from "$lib/shared/model/validation"; +import { fields, ZStationNew } from "$lib/shared/model/validation"; import { deleteStation, @@ -12,6 +12,8 @@ import { import { t, trpcWrap } from ".."; +const ZEntityId = fields.EntityId(); + export const stationRouter = t.router({ list: t.procedure.query(getStations), get: t.procedure diff --git a/src/lib/server/trpc/routes/user.ts b/src/lib/server/trpc/routes/user.ts index 0f25f65..9fab4cd 100644 --- a/src/lib/server/trpc/routes/user.ts +++ b/src/lib/server/trpc/routes/user.ts @@ -1,11 +1,13 @@ import { z } from "zod"; -import { ZEntityId, ZPagination } from "$lib/shared/model/validation"; +import { fields, ZPagination } from "$lib/shared/model/validation"; import { getUser, getUserNames, getUsers } from "$lib/server/query"; import { t, trpcWrap } from ".."; +const ZEntityId = fields.EntityId(); + export const userRouter = t.router({ list: t.procedure .input(z.object({ pagination: ZPagination }).partial()) diff --git a/src/lib/shared/model/model.ts b/src/lib/shared/model/model.ts index e3c75de..42239f6 100644 --- a/src/lib/shared/model/model.ts +++ b/src/lib/shared/model/model.ts @@ -127,11 +127,3 @@ export type EntryExecution = { export type EntryExecutionNew = { text: string; }; - -export type SavedFilter = { - id: number; - name: string; - query: string; -}; - -export type SavedFilterNew = Omit & { view: string }; diff --git a/src/lib/shared/model/validation.test.ts b/src/lib/shared/model/validation.test.ts index 3f76cdb..a012136 100644 --- a/src/lib/shared/model/validation.test.ts +++ b/src/lib/shared/model/validation.test.ts @@ -1,6 +1,6 @@ import { expect, test } from "vitest"; -import { ZEntriesFilter, fields } from "./validation"; +import { fields } from "./validation"; test("date string", () => { const DateString = fields.DateString(); @@ -14,17 +14,3 @@ test("date string", () => { const dsError = DateString.safeParse("2024-30-10"); expect(dsError.success).toBe(false); }); - -test("filter data", () => { - // Strings from query params should be converted and order kept - const entriesFilter = ZEntriesFilter.parse({ - done: "true", - category: [{ id: "1", name: "CA" }], - author: [{ id: "1", name: "Max Mustermann" }], - }); - expect(entriesFilter).toStrictEqual({ - done: true, - category: [{ id: 1, name: "CA" }], - author: [{ id: 1, name: "Max Mustermann" }], - }); -}); diff --git a/src/lib/shared/model/validation.ts b/src/lib/shared/model/validation.ts index 3c0cffd..9b1d0e7 100644 --- a/src/lib/shared/model/validation.ts +++ b/src/lib/shared/model/validation.ts @@ -11,7 +11,6 @@ import type { PaginationRequest, PatientNew, RoomNew, - SavedFilterNew, StationNew, User, } from "."; @@ -41,27 +40,6 @@ export const fields = { const coercedUint = z.coerce.number().int().nonnegative(); const coercedBool = z.string().toLowerCase().transform((v) => v === "true").or(z.boolean()); -function returnDataInSameOrderAsPassed>( - schema: Schema, -) { - return z.any().transform((value, ctx) => { - const parsed = schema.safeParse(value); - if (parsed.success) { - const res: z.infer = {}; - for (const key of Object.keys(value)) { - if (key in parsed.data) { - // @ts-expect-error keys are safe - res[key] = parsed.data[key]; - } - } - return res; - } else { - parsed.error.issues.forEach((iss) => ctx.addIssue(iss)); - } - }); -} - -export const ZEntityId = fields.EntityId(); export const ZUrlEntityId = coercedUint; export const ZUser = implement().with({ @@ -138,7 +116,7 @@ const paginatedQuery = (f: T) => z }) .partial(); -export const ZEntriesFilter = returnDataInSameOrderAsPassed(z +export const ZEntriesFilter = z .object({ author: ZFilterList, category: ZFilterList, @@ -150,11 +128,11 @@ export const ZEntriesFilter = returnDataInSameOrderAsPassed(z search: z.string(), station: ZFilterList, }) - .partial()); + .partial(); export const ZEntriesQuery = paginatedQuery(ZEntriesFilter); -export const ZPatientsFilter = returnDataInSameOrderAsPassed(z +export const ZPatientsFilter = z .object({ search: z.string(), room: ZFilterList, @@ -162,17 +140,6 @@ export const ZPatientsFilter = returnDataInSameOrderAsPassed(z hidden: coercedBool, includeHidden: z.coerce.boolean(), }) - .partial()); + .partial(); export const ZPatientsQuery = paginatedQuery(ZPatientsFilter); - -export const ZSavedFilterNew = implement().with({ - view: fields.NameString(), - name: fields.NameString(), - query: z.string(), -}); - -export const ZSavedFilterUpdate = z.object({ - id: ZEntityId, - query: z.string(), -}); diff --git a/src/lib/shared/util/diff.test.ts b/src/lib/shared/util/diff.test.ts index 8d018cb..52f7902 100644 --- a/src/lib/shared/util/diff.test.ts +++ b/src/lib/shared/util/diff.test.ts @@ -50,7 +50,7 @@ test("versions diff", () => { id: 1, name: "Laborabnahme", description: "Blutabnahme zur Untersuchung im Labor", - color: "#FF0000", + color: "FF0000", }, created_at: new Date("2024-02-10T11:31:00.000Z"), date: "2024-01-12", diff --git a/src/routes/(app)/plan/+page.svelte b/src/routes/(app)/plan/+page.svelte index cbd54f1..5d1d5b7 100644 --- a/src/routes/(app)/plan/+page.svelte +++ b/src/routes/(app)/plan/+page.svelte @@ -13,5 +13,5 @@ - Neuer Eintrag + Neuer Eintrag