Compare commits
No commits in common. "9a6b8094dae44b3c1b861d671d54fb6495e85c9f" and "02ffd4a0138030c5f2b8548fbd4dc2875adea87c" have entirely different histories.
9a6b8094da
...
02ffd4a013
21 changed files with 649 additions and 690 deletions
|
@ -14,16 +14,10 @@ module.exports = {
|
||||||
parser: "svelte-eslint-parser",
|
parser: "svelte-eslint-parser",
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
parser: "@typescript-eslint/parser",
|
parser: "@typescript-eslint/parser",
|
||||||
svelteFeatures: {
|
|
||||||
experimentalGenerics: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
settings: {},
|
settings: {},
|
||||||
globals: {
|
|
||||||
$$Generic: "readonly",
|
|
||||||
},
|
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
sourceType: "module",
|
sourceType: "module",
|
||||||
ecmaVersion: 2020,
|
ecmaVersion: 2020,
|
||||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -8,3 +8,5 @@ node_modules
|
||||||
!.env.example
|
!.env.example
|
||||||
vite.config.js.timestamp-*
|
vite.config.js.timestamp-*
|
||||||
vite.config.ts.timestamp-*
|
vite.config.ts.timestamp-*
|
||||||
|
sveltekit-zero-api.d.ts
|
||||||
|
/.vscode
|
||||||
|
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"eslint.validate": ["javascript", "typescript", "svelte"]
|
|
||||||
}
|
|
52
package.json
52
package.json
|
@ -17,13 +17,13 @@
|
||||||
"test:e2e": "playwright test"
|
"test:e2e": "playwright test"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@auth/core": "^0.28.2",
|
"@auth/core": "^0.27.0",
|
||||||
"@floating-ui/core": "^1.6.0",
|
"@floating-ui/core": "^1.6.0",
|
||||||
"@mdi/js": "^7.4.47",
|
"@mdi/js": "^7.4.47",
|
||||||
"@prisma/client": "^5.12.1",
|
"@prisma/client": "^5.10.2",
|
||||||
"diff": "^5.2.0",
|
"diff": "^5.2.0",
|
||||||
"isomorphic-dompurify": "^2.6.0",
|
"isomorphic-dompurify": "^2.4.0",
|
||||||
"marked": "^12.0.1",
|
"marked": "^12.0.0",
|
||||||
"set-cookie-parser": "^2.6.0",
|
"set-cookie-parser": "^2.6.0",
|
||||||
"svelte-floating-ui": "^1.5.8",
|
"svelte-floating-ui": "^1.5.8",
|
||||||
"zod": "^3.22.4",
|
"zod": "^3.22.4",
|
||||||
|
@ -31,40 +31,40 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@faker-js/faker": "^8.4.1",
|
"@faker-js/faker": "^8.4.1",
|
||||||
"@playwright/test": "^1.42.1",
|
"@playwright/test": "^1.42.0",
|
||||||
"@sveltejs/adapter-node": "^5.0.1",
|
"@sveltejs/adapter-node": "^4.0.1",
|
||||||
"@sveltejs/kit": "^2.5.5",
|
"@sveltejs/kit": "^2.5.2",
|
||||||
"@sveltejs/vite-plugin-svelte": "^3.0.2",
|
"@sveltejs/vite-plugin-svelte": "^3.0.2",
|
||||||
"@tailwindcss/typography": "^0.5.12",
|
"@tailwindcss/typography": "^0.5.10",
|
||||||
"@trpc/client": "^10.45.2",
|
"@trpc/client": "^10.45.1",
|
||||||
"@trpc/server": "^10.45.2",
|
"@trpc/server": "^10.45.1",
|
||||||
"@types/diff": "^5.0.9",
|
"@types/diff": "^5.0.9",
|
||||||
"@types/node": "^20.12.4",
|
"@types/node": "^20.11.21",
|
||||||
"@types/set-cookie-parser": "^2.4.7",
|
"@types/set-cookie-parser": "^2.4.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.5.0",
|
"@typescript-eslint/eslint-plugin": "^7.1.0",
|
||||||
"@typescript-eslint/parser": "^7.5.0",
|
"@typescript-eslint/parser": "^7.1.0",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.17",
|
||||||
"daisyui": "^4.9.0",
|
"daisyui": "^4.7.2",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-no-relative-import-paths": "^1.5.3",
|
"eslint-plugin-no-relative-import-paths": "^1.5.3",
|
||||||
"eslint-plugin-svelte": "^2.35.1",
|
"eslint-plugin-svelte": "^2.35.1",
|
||||||
"postcss-import": "^16.1.0",
|
"postcss-import": "^16.0.1",
|
||||||
"postcss-nesting": "^12.1.1",
|
"postcss-nesting": "^12.0.4",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"prettier-plugin-svelte": "^3.2.2",
|
"prettier-plugin-svelte": "^3.2.2",
|
||||||
"prisma": "^5.12.1",
|
"prisma": "^5.10.2",
|
||||||
"svelte": "^4.2.12",
|
"svelte": "^4.2.12",
|
||||||
"svelte-check": "^3.6.9",
|
"svelte-check": "^3.6.5",
|
||||||
"sveltekit-superforms": "^2.12.2",
|
"sveltekit-superforms": "^2.6.2",
|
||||||
"tailwindcss": "^3.4.3",
|
"tailwindcss": "^3.4.1",
|
||||||
"trpc-sveltekit": "^3.6.1",
|
"trpc-sveltekit": "^3.5.27",
|
||||||
"tslib": "^2.6.2",
|
"tslib": "^2.6.2",
|
||||||
"tsx": "^4.7.2",
|
"tsx": "^4.7.1",
|
||||||
"typescript": "^5.4.3",
|
"typescript": "^5.3.3",
|
||||||
"vite": "^5.2.8",
|
"vite": "^5.1.4",
|
||||||
"vitest": "^1.4.0"
|
"vitest": "^1.3.1"
|
||||||
},
|
},
|
||||||
"type": "module"
|
"type": "module"
|
||||||
}
|
}
|
||||||
|
|
1109
pnpm-lock.yaml
1109
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -10,46 +10,33 @@
|
||||||
import { createFloatingActions } from "svelte-floating-ui";
|
import { createFloatingActions } from "svelte-floating-ui";
|
||||||
import { shift } from "svelte-floating-ui/dom";
|
import { shift } from "svelte-floating-ui/dom";
|
||||||
import outclick from "$lib/actions/outclick";
|
import outclick from "$lib/actions/outclick";
|
||||||
import type { BaseItem } from "./types";
|
import type { BaseItem, SelectionOrText } from "./types";
|
||||||
import Icon from "$lib/components/ui/Icon.svelte";
|
import Icon from "$lib/components/ui/Icon.svelte";
|
||||||
import { onMount } from "svelte";
|
|
||||||
|
|
||||||
type T = $$Generic<BaseItem>;
|
|
||||||
type OnSelectResult = { newValue: string; close: boolean };
|
type OnSelectResult = { newValue: string; close: boolean };
|
||||||
|
|
||||||
/** List of items to choose from (or an async function fetching them) */
|
export let items: BaseItem[] | (() => Promise<BaseItem[]>);
|
||||||
export let items: T[] | (() => Promise<T[]>);
|
export let selection: SelectionOrText | null = null;
|
||||||
/** Current selection of the autocomplete field */
|
|
||||||
export let selection: T | null = null;
|
|
||||||
/** Set of item IDs that should be hidden from the list */
|
|
||||||
export let hiddenIds: Set<string | number> = new Set();
|
export let hiddenIds: Set<string | number> = new Set();
|
||||||
/** Object to cache fetched items in */
|
export let cache: { [key: string]: BaseItem[] } = {};
|
||||||
export let cache: { [key: string]: T[] } = {};
|
|
||||||
/** Key in cache object under which fetched items are stored */
|
|
||||||
export let cacheKey: string | undefined = undefined;
|
export let cacheKey: string | undefined = undefined;
|
||||||
/** Input field placeholder */
|
|
||||||
export let placeholder: string | undefined = undefined;
|
export let placeholder: string | undefined = undefined;
|
||||||
/** Add horizontal padding to the input element */
|
|
||||||
export let padding = true;
|
export let padding = true;
|
||||||
/** CSS classes of the container */
|
|
||||||
export let cls = "";
|
export let cls = "";
|
||||||
/** CSS classes of the input element */
|
|
||||||
export let inputCls = "w-full bg-transparent outline-none";
|
export let inputCls = "w-full bg-transparent outline-none";
|
||||||
/**
|
export let asTextInput = false;
|
||||||
* Enable filter bar optimizations:
|
|
||||||
* - Clear input on mount
|
|
||||||
*/
|
|
||||||
export let partOfFilterbar = false;
|
|
||||||
/** Dont select item automatically on close if only 1 item is shown */
|
/** Dont select item automatically on close if only 1 item is shown */
|
||||||
export let noAutoselect1 = false;
|
export let noAutoselect1 = false;
|
||||||
/** Name of the form input. This sets a hidden field to the ID of the selected element
|
|
||||||
* (to allow Svelte Superforms to work) */
|
|
||||||
export let idInputName: string | undefined = undefined;
|
export let idInputName: string | undefined = undefined;
|
||||||
/** Function to filter shown items */
|
export let filterFn: (item: BaseItem) => boolean = () => true;
|
||||||
export let filterFn: (item: T) => boolean = () => true;
|
|
||||||
|
|
||||||
/** Selection callback. Returns the new input value after selection */
|
/** Selection callback. Returns the new input value after selection */
|
||||||
export let onSelect: (item: T, kb: boolean) => OnSelectResult | void = () => {};
|
export let onSelect: (item: SelectionOrText, kb: boolean) => OnSelectResult = (
|
||||||
|
item,
|
||||||
|
kb
|
||||||
|
) => {
|
||||||
|
return { newValue: item.name ?? "", close: true };
|
||||||
|
};
|
||||||
export let onUnselect = () => {};
|
export let onUnselect = () => {};
|
||||||
export let onClose = (kb: boolean) => {};
|
export let onClose = (kb: boolean) => {};
|
||||||
export let onBackspace = () => {};
|
export let onBackspace = () => {};
|
||||||
|
@ -57,11 +44,10 @@
|
||||||
let opened = false;
|
let opened = false;
|
||||||
let highlightIndex = 0;
|
let highlightIndex = 0;
|
||||||
let isLoading = false;
|
let isLoading = false;
|
||||||
let srcItems: T[];
|
let srcItems: BaseItem[];
|
||||||
let filteredItems: T[] = [];
|
let filteredItems: BaseItem[] = [];
|
||||||
|
|
||||||
// Reload search items if hidden ids are changed
|
$: if (hiddenIds || selection) updateSearch();
|
||||||
$: if (srcItems && hiddenIds) updateSearch();
|
|
||||||
|
|
||||||
// HTML elements
|
// HTML elements
|
||||||
let inputElm: HTMLInputElement | undefined;
|
let inputElm: HTMLInputElement | undefined;
|
||||||
|
@ -106,7 +92,7 @@
|
||||||
if (i !== -1) {
|
if (i !== -1) {
|
||||||
highlightIndex = i;
|
highlightIndex = i;
|
||||||
}
|
}
|
||||||
if (!partOfFilterbar) setInputValue(selection.name ?? "");
|
if (asTextInput) setInputValue(selection.name ?? "");
|
||||||
} else {
|
} else {
|
||||||
highlightIndex = 0;
|
highlightIndex = 0;
|
||||||
setInputValue(selection.name ?? "");
|
setInputValue(selection.name ?? "");
|
||||||
|
@ -156,34 +142,30 @@
|
||||||
if (inputElm) inputElm.focus();
|
if (inputElm) inputElm.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function close(kb = true) {
|
export function close(kb: boolean) {
|
||||||
if (opened) {
|
if (opened) {
|
||||||
onClose(kb);
|
onClose(kb);
|
||||||
}
|
}
|
||||||
opened = false;
|
opened = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectListItem(item: T | undefined, kb: boolean) {
|
function selectListItem(item: BaseItem | undefined, kb: boolean) {
|
||||||
if (item) {
|
selection = { id: item?.id, name: item?.name };
|
||||||
selection = item;
|
const selRes = onSelect(item ?? { name: inputValue() }, kb);
|
||||||
const selRes = onSelect(item, kb);
|
setInputValue(selRes.newValue);
|
||||||
setInputValue(selRes ? selRes.newValue : item.name);
|
if (selRes.close) {
|
||||||
if (!selRes || selRes.close) {
|
close(kb);
|
||||||
close(kb);
|
|
||||||
} else {
|
|
||||||
updateSearch();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
selection = null;
|
updateSearch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onKeyDown(e: KeyboardEvent) {
|
function onKeyDown(e: KeyboardEvent) {
|
||||||
let key = e.key;
|
let key = e.key;
|
||||||
if (key === "Tab" && e.shiftKey) key = "ShiftTab";
|
if (key === "Tab" && e.shiftKey) key = "ShiftTab";
|
||||||
const fnmap: { [key: string]: () => void } = {
|
const fnmap = {
|
||||||
Tab: () => close,
|
Tab: close,
|
||||||
ShiftTab: () => close,
|
ShiftTab: close,
|
||||||
ArrowDown: () => {
|
ArrowDown: () => {
|
||||||
open();
|
open();
|
||||||
if (highlightIndex < filteredItems.length - 1) {
|
if (highlightIndex < filteredItems.length - 1) {
|
||||||
|
@ -202,7 +184,7 @@
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (opened) {
|
if (opened) {
|
||||||
if (inputElm) inputElm.focus();
|
if (inputElm) inputElm.focus();
|
||||||
close();
|
close(true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Backspace: () => {
|
Backspace: () => {
|
||||||
|
@ -213,9 +195,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
// @ts-expect-error unknown map type
|
||||||
const fn = fnmap[key];
|
const fn = fnmap[key];
|
||||||
if (typeof fn === "function") {
|
if (typeof fn === "function") {
|
||||||
fn();
|
fn(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,14 +250,6 @@
|
||||||
placement: "bottom-start",
|
placement: "bottom-start",
|
||||||
middleware: [shift()],
|
middleware: [shift()],
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!partOfFilterbar) {
|
|
||||||
onMount(() => {
|
|
||||||
if (selection?.name) {
|
|
||||||
setInputValue(selection.name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex-grow {cls}" use:outclick on:outclick={close}>
|
<div class="flex-grow {cls}" use:outclick on:outclick={close}>
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
/** True if a separate search field should be displayed */
|
/** True if a separate search field should be displayed */
|
||||||
export let search = false;
|
export let search = false;
|
||||||
|
|
||||||
let autocomplete: Autocomplete<BaseItem> | undefined;
|
let autocomplete: Autocomplete | undefined;
|
||||||
let activeFilters: FilterData[] = [];
|
let activeFilters: FilterData[] = [];
|
||||||
let cache: { [key: string]: BaseItem[] } = {};
|
let cache: { [key: string]: BaseItem[] } = {};
|
||||||
let searchVal = "";
|
let searchVal = "";
|
||||||
|
@ -216,7 +216,6 @@
|
||||||
activeFilters = activeFilters;
|
activeFilters = activeFilters;
|
||||||
updateFilter();
|
updateFilter();
|
||||||
}}
|
}}
|
||||||
partOfFilterbar
|
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
class="btn btn-sm btn-circle btn-ghost absolute bottom-0 right-0"
|
class="btn btn-sm btn-circle btn-ghost absolute bottom-0 right-0"
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
export let onRemove = () => {};
|
export let onRemove = () => {};
|
||||||
export let onSelection = (selection: SelectionOrText, kb: boolean) => {};
|
export let onSelection = (selection: SelectionOrText, kb: boolean) => {};
|
||||||
|
|
||||||
let autocomplete: Autocomplete<BaseItem> | undefined;
|
let autocomplete: Autocomplete | undefined;
|
||||||
|
|
||||||
function startEditing() {
|
function startEditing() {
|
||||||
fdata.editing = true;
|
fdata.editing = true;
|
||||||
|
@ -76,9 +76,7 @@ gap-1 pl-1"
|
||||||
hiddenIds={hids}
|
hiddenIds={hids}
|
||||||
{cache}
|
{cache}
|
||||||
cacheKey={filter.id}
|
cacheKey={filter.id}
|
||||||
selection={fdata.selection?.id
|
selection={fdata.selection}
|
||||||
? { id: fdata.selection?.id, name: fdata.selection?.name ?? "" }
|
|
||||||
: null}
|
|
||||||
padding={false}
|
padding={false}
|
||||||
onSelect={(item) => {
|
onSelect={(item) => {
|
||||||
// Accept the selection if this is a free text field or the user selected a variant
|
// Accept the selection if this is a free text field or the user selected a variant
|
||||||
|
@ -91,7 +89,6 @@ gap-1 pl-1"
|
||||||
}}
|
}}
|
||||||
{onClose}
|
{onClose}
|
||||||
onBackspace={onRemove}
|
onBackspace={onRemove}
|
||||||
partOfFilterbar
|
|
||||||
/>
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<!-- svelte-ignore a11y-autofocus -->
|
<!-- svelte-ignore a11y-autofocus -->
|
||||||
|
|
|
@ -68,12 +68,16 @@
|
||||||
}}
|
}}
|
||||||
selection={patient?.room}
|
selection={patient?.room}
|
||||||
onSelect={(item) => {
|
onSelect={(item) => {
|
||||||
|
// @ts-expect-error room items have station attr
|
||||||
station = item.station;
|
station = item.station;
|
||||||
|
// @ts-expect-error ids are always numeric
|
||||||
$form.room_id = item.id;
|
$form.room_id = item.id;
|
||||||
|
return { newValue: item.name ?? "", close: true };
|
||||||
}}
|
}}
|
||||||
onUnselect={() => {
|
onUnselect={() => {
|
||||||
$form.room_id = null;
|
$form.room_id = null;
|
||||||
}}
|
}}
|
||||||
|
asTextInput
|
||||||
idInputName="room_id"
|
idInputName="room_id"
|
||||||
/>
|
/>
|
||||||
</FormField>
|
</FormField>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import FormField from "./FormField.svelte";
|
||||||
import Markdown from "./Markdown.svelte";
|
import Markdown from "./Markdown.svelte";
|
||||||
import type { InputConstraint } from "sveltekit-superforms";
|
import type { InputConstraint } from "sveltekit-superforms";
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { goto } from "$app/navigation";
|
||||||
import { mdiChevronLeft, mdiChevronRight, mdiPageFirst, mdiPageLast } from "@mdi/js";
|
import { mdiChevronLeft, mdiChevronRight, mdiPageFirst, mdiPageLast } from "@mdi/js";
|
||||||
|
|
||||||
import type { Pagination, PaginationRequest } from "$lib/shared/model";
|
import type { Pagination, PaginationRequest } from "$lib/shared/model";
|
||||||
|
|
|
@ -117,10 +117,10 @@ export async function newEntryVersion(
|
||||||
|
|
||||||
// Check if there are any updates
|
// Check if there are any updates
|
||||||
if (
|
if (
|
||||||
cver?.text === updatedVersion.text &&
|
cver.text === updatedVersion.text &&
|
||||||
cver?.date.getTime() === updatedVersion.date.getTime() &&
|
cver.date.getTime() === updatedVersion.date.getTime() &&
|
||||||
cver?.category_id === updatedVersion.category_id &&
|
cver.category_id === updatedVersion.category_id &&
|
||||||
cver?.priority === updatedVersion.priority
|
cver.priority === updatedVersion.priority
|
||||||
) {
|
) {
|
||||||
return cver.id;
|
return cver.id;
|
||||||
}
|
}
|
||||||
|
@ -160,7 +160,7 @@ export async function newEntryExecution(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there are any updates
|
// Check if there are any updates
|
||||||
if (execution.text === cex?.text) {
|
if (execution.text === cex.text) {
|
||||||
return cex.id;
|
return cex.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,18 +87,15 @@ class SearchQueryComponents {
|
||||||
*/
|
*/
|
||||||
export function parseSearchQuery(q: string): SearchQueryComponents {
|
export function parseSearchQuery(q: string): SearchQueryComponents {
|
||||||
const regexpParts = /(-)?(?:"([^"]*)"|([^"\s]+))(?:\s|$)/g;
|
const regexpParts = /(-)?(?:"([^"]*)"|([^"\s]+))(?:\s|$)/g;
|
||||||
const components = Array.from(
|
const components = Array.from(q.replaceAll("'", '"').matchAll(regexpParts), (m) => {
|
||||||
q.replaceAll("'", '"').replaceAll("\\", "\\\\").matchAll(regexpParts),
|
const negative = m[1] === "-";
|
||||||
(m) => {
|
// Exact
|
||||||
const negative = m[1] === "-";
|
if (m[2]) {
|
||||||
// Exact
|
return new SearchQueryComponent(m[2], QueryComponentType.Exact, negative);
|
||||||
if (m[2]) {
|
} else {
|
||||||
return new SearchQueryComponent(m[2], QueryComponentType.Exact, negative);
|
return new SearchQueryComponent(m[3], QueryComponentType.Normal, negative);
|
||||||
} else {
|
|
||||||
return new SearchQueryComponent(m[3], QueryComponentType.Normal, negative);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
|
|
||||||
if (
|
if (
|
||||||
components.length > 0 &&
|
components.length > 0 &&
|
||||||
|
|
|
@ -74,7 +74,7 @@ export function formatBool(val: boolean): string {
|
||||||
|
|
||||||
export function getQueryUrl(q: EntityQuery, basePath: string): string {
|
export function getQueryUrl(q: EntityQuery, basePath: string): string {
|
||||||
if (Object.values(q).filter((q) => q !== undefined).length === 0) return basePath;
|
if (Object.values(q).filter((q) => q !== undefined).length === 0) return basePath;
|
||||||
return encodeURI(basePath + "/" + encodeURIComponent(JSON.stringify(q)));
|
return basePath + "/" + JSON.stringify(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gotoEntityQuery(q: EntityQuery, basePath: string) {
|
export function gotoEntityQuery(q: EntityQuery, basePath: string) {
|
||||||
|
|
|
@ -51,12 +51,14 @@
|
||||||
}}
|
}}
|
||||||
selection={data.entry.current_version.category}
|
selection={data.entry.current_version.category}
|
||||||
onSelect={(item) => {
|
onSelect={(item) => {
|
||||||
|
// @ts-expect-error ids are always numeric
|
||||||
$form.category_id = item.id;
|
$form.category_id = item.id;
|
||||||
return { newValue: item.name ?? "", close: true };
|
return { newValue: item.name ?? "", close: true };
|
||||||
}}
|
}}
|
||||||
onUnselect={() => {
|
onUnselect={() => {
|
||||||
$form.category_id = null;
|
$form.category_id = null;
|
||||||
}}
|
}}
|
||||||
|
asTextInput
|
||||||
idInputName="category_id"
|
idInputName="category_id"
|
||||||
/>
|
/>
|
||||||
</FormField>
|
</FormField>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import CategoryField from "$lib/components/table/CategoryField.svelte";
|
||||||
import UserField from "$lib/components/table/UserField.svelte";
|
import UserField from "$lib/components/table/UserField.svelte";
|
||||||
import { formatDate } from "$lib/shared/util";
|
import { formatBool, formatDate } from "$lib/shared/util";
|
||||||
import type { PageData } from "./$types";
|
import type { PageData } from "./$types";
|
||||||
import Header from "$lib/components/ui/Header.svelte";
|
import Header from "$lib/components/ui/Header.svelte";
|
||||||
import { page } from "$app/stores";
|
import { page } from "$app/stores";
|
||||||
|
|
|
@ -27,12 +27,14 @@
|
||||||
return await trpc().room.list.query();
|
return await trpc().room.list.query();
|
||||||
}}
|
}}
|
||||||
onSelect={(item) => {
|
onSelect={(item) => {
|
||||||
|
// @ts-expect-error ids are always numeric
|
||||||
$form.room_id = item.id;
|
$form.room_id = item.id;
|
||||||
return { newValue: item.name ?? "", close: true };
|
return { newValue: item.name ?? "", close: true };
|
||||||
}}
|
}}
|
||||||
onUnselect={() => {
|
onUnselect={() => {
|
||||||
$form.room_id = null;
|
$form.room_id = null;
|
||||||
}}
|
}}
|
||||||
|
asTextInput
|
||||||
idInputName="room_id"
|
idInputName="room_id"
|
||||||
/>
|
/>
|
||||||
</FormField>
|
</FormField>
|
||||||
|
@ -44,8 +46,10 @@
|
||||||
return await trpc().patient.getNames.query();
|
return await trpc().patient.getNames.query();
|
||||||
}}
|
}}
|
||||||
onSelect={(item) => {
|
onSelect={(item) => {
|
||||||
|
// @ts-expect-error patient id
|
||||||
$form.patient_id = item.id;
|
$form.patient_id = item.id;
|
||||||
trpc()
|
trpc()
|
||||||
|
// @ts-expect-error patient id
|
||||||
.patient.get.query(item.id)
|
.patient.get.query(item.id)
|
||||||
.then((p) => {
|
.then((p) => {
|
||||||
$form.patient_first_name = p.first_name;
|
$form.patient_first_name = p.first_name;
|
||||||
|
@ -60,9 +64,11 @@
|
||||||
$form.patient_last_name = null;
|
$form.patient_last_name = null;
|
||||||
$form.patient_age = null;
|
$form.patient_age = null;
|
||||||
}}
|
}}
|
||||||
|
asTextInput
|
||||||
noAutoselect1
|
noAutoselect1
|
||||||
idInputName="patient_id"
|
idInputName="patient_id"
|
||||||
filterFn={(itm) => {
|
filterFn={(itm) => {
|
||||||
|
// @ts-expect-error patient items have room attr
|
||||||
return $form.room_id === null || itm.room_id === $form.room_id;
|
return $form.room_id === null || itm.room_id === $form.room_id;
|
||||||
}}
|
}}
|
||||||
placeholder="Neuer Patient"
|
placeholder="Neuer Patient"
|
||||||
|
@ -113,12 +119,14 @@
|
||||||
return await trpc().category.list.query();
|
return await trpc().category.list.query();
|
||||||
}}
|
}}
|
||||||
onSelect={(item) => {
|
onSelect={(item) => {
|
||||||
|
// @ts-expect-error ids are always numeric
|
||||||
$form.category_id = item.id;
|
$form.category_id = item.id;
|
||||||
return { newValue: item.name ?? "", close: true };
|
return { newValue: item.name ?? "", close: true };
|
||||||
}}
|
}}
|
||||||
onUnselect={() => {
|
onUnselect={() => {
|
||||||
$form.category_id = null;
|
$form.category_id = null;
|
||||||
}}
|
}}
|
||||||
|
asTextInput
|
||||||
idInputName="category_id"
|
idInputName="category_id"
|
||||||
/>
|
/>
|
||||||
</FormField>
|
</FormField>
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
import { z } from "zod";
|
import { ZPatientNew, ZUrlEntityId } from "$lib/shared/model/validation";
|
||||||
|
|
||||||
import { ZEntriesQuery, ZPatientNew, ZUrlEntityId } from "$lib/shared/model/validation";
|
|
||||||
import { trpc } from "$lib/shared/trpc";
|
import { trpc } from "$lib/shared/trpc";
|
||||||
import { loadWrap } from "$lib/shared/util";
|
import { loadWrap } from "$lib/shared/util";
|
||||||
import { superValidate } from "sveltekit-superforms";
|
import { superValidate } from "sveltekit-superforms";
|
||||||
|
@ -10,9 +8,10 @@ import type { PageLoad } from "./$types";
|
||||||
export const load: PageLoad = async (event) => {
|
export const load: PageLoad = async (event) => {
|
||||||
const id = ZUrlEntityId.parse(event.params.id);
|
const id = ZUrlEntityId.parse(event.params.id);
|
||||||
|
|
||||||
let query: z.infer<typeof ZEntriesQuery> = {};
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
let query: any = {};
|
||||||
if (event.params.query) {
|
if (event.params.query) {
|
||||||
query = ZEntriesQuery.parse(JSON.parse(decodeURIComponent(event.params.query)));
|
query = JSON.parse(event.params.query);
|
||||||
}
|
}
|
||||||
if (!query.filter) query.filter = {};
|
if (!query.filter) query.filter = {};
|
||||||
query.filter.patient = [{ id }];
|
query.filter.patient = [{ id }];
|
||||||
|
|
|
@ -9,7 +9,7 @@ export const load: PageLoad = async (event) => {
|
||||||
let query: z.infer<typeof ZPatientsQuery> = {};
|
let query: z.infer<typeof ZPatientsQuery> = {};
|
||||||
|
|
||||||
if (event.params.query) {
|
if (event.params.query) {
|
||||||
query = ZPatientsQuery.parse(JSON.parse(decodeURIComponent(event.params.query)));
|
query = ZPatientsQuery.parse(JSON.parse(event.params.query));
|
||||||
}
|
}
|
||||||
|
|
||||||
const patients = await loadWrap(async () => trpc(event).patient.list.query(query));
|
const patients = await loadWrap(async () => trpc(event).patient.list.query(query));
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
import { ZEntriesQuery } from "$lib/shared/model/validation";
|
|
||||||
import { trpc } from "$lib/shared/trpc";
|
import { trpc } from "$lib/shared/trpc";
|
||||||
import { loadWrap } from "$lib/shared/util";
|
import { loadWrap } from "$lib/shared/util";
|
||||||
import type { PageLoad } from "./$types";
|
import type { PageLoad } from "./$types";
|
||||||
|
|
||||||
export const load: PageLoad = async (event) => {
|
export const load: PageLoad = async (event) => {
|
||||||
let query: z.infer<typeof ZEntriesQuery> = {};
|
let query = {};
|
||||||
|
|
||||||
if (event.params.query) {
|
if (event.params.query) {
|
||||||
query = ZEntriesQuery.parse(JSON.parse(decodeURIComponent(event.params.query)));
|
query = JSON.parse(event.params.query);
|
||||||
}
|
}
|
||||||
|
|
||||||
const entries = await loadWrap(() => trpc(event).entry.list.query(query));
|
const entries = await loadWrap(() => trpc(event).entry.list.query(query));
|
||||||
|
|
|
@ -9,7 +9,9 @@ const config = {
|
||||||
|
|
||||||
kit: {
|
kit: {
|
||||||
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
||||||
adapter: adapter(),
|
adapter: adapter({
|
||||||
|
precompress: true,
|
||||||
|
}),
|
||||||
|
|
||||||
alias: {
|
alias: {
|
||||||
$api: "./src/api",
|
$api: "./src/api",
|
||||||
|
|
Loading…
Reference in a new issue