Compare commits
9 commits
Author | SHA1 | Date | |
---|---|---|---|
a69c474d1d |
|||
c6abf633f8 |
|||
88a5040f9c |
|||
cdb344609c |
|||
4a3155c33a |
|||
a4eebb944f |
|||
d5e9a9469f |
|||
f76e7fd97f |
|||
068c7961ae |
15 changed files with 87 additions and 51 deletions
|
@ -50,6 +50,7 @@ jobs:
|
|||
id: e2etest
|
||||
run: |
|
||||
pnpm run build -l silent
|
||||
npx playwright install chromium
|
||||
pnpm run test:e2e
|
||||
- name: 💢 Upload E2E report
|
||||
if: ${{ failure() && steps.e2etest.conclusion == 'failure' }}
|
||||
|
@ -67,7 +68,7 @@ jobs:
|
|||
- name: 👁️ Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-depth: 1 # important to fetch tag logs
|
||||
|
||||
- name: 📦 pnpm install
|
||||
run: pnpm install
|
||||
|
|
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -3,6 +3,22 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
|
||||
|
||||
## [v0.3.4](https://code.thetadev.de/HSA/Visitenbuch/compare/v0.3.3..v0.3.4) - 2024-05-16
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- Select table entries on doubleclick - ([c6abf63](https://code.thetadev.de/HSA/Visitenbuch/commit/c6abf633f8ae5e9b562dda36f9f7ab4d6adcb4e1))
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- Escape HTML for licenses file - ([f76e7fd](https://code.thetadev.de/HSA/Visitenbuch/commit/f76e7fd97f62d9b41ecbabc3334c2c1876be253d))
|
||||
- Use btn-id class for all tables - ([d5e9a94](https://code.thetadev.de/HSA/Visitenbuch/commit/d5e9a9469f0c57939367141985a97d8404fd6fbe))
|
||||
- Avoid global state, use context for savedFilters - ([a4eebb9](https://code.thetadev.de/HSA/Visitenbuch/commit/a4eebb944f55da8e87cc899eebada0bd3fd37aa8))
|
||||
- Close autocomplete on defocus - ([4a3155c](https://code.thetadev.de/HSA/Visitenbuch/commit/4a3155c33aa354973d4e0ca3ffeab2b7fd442040))
|
||||
- Remove process.on hooks (not necessary) - ([cdb3446](https://code.thetadev.de/HSA/Visitenbuch/commit/cdb344609cde80084876faea9f80e7b26b01d0f2))
|
||||
- Autocomplete not closing on tab - ([88a5040](https://code.thetadev.de/HSA/Visitenbuch/commit/88a5040f9c4e19ae3efb5ad0894c8dc5b905a92e))
|
||||
|
||||
|
||||
## [v0.3.3](https://code.thetadev.de/HSA/Visitenbuch/compare/v0.3.2..v0.3.3) - 2024-05-14
|
||||
|
||||
### 🚀 Features
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "visitenbuch",
|
||||
"version": "0.3.3",
|
||||
"version": "0.3.4",
|
||||
"private": true,
|
||||
"license": "AGPL-3.0",
|
||||
"scripts": {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
|
|
|
@ -31,7 +31,3 @@ export const handle = sequence(
|
|||
authorization,
|
||||
createTRPCHandle({ router, createContext }),
|
||||
);
|
||||
|
||||
// Allow server application to exit
|
||||
process.on("SIGINT", () => process.exit()); // Ctrl+C
|
||||
process.on("SIGTERM", () => process.exit()); // docker stop
|
||||
|
|
|
@ -166,6 +166,14 @@
|
|||
if (opened) {
|
||||
onClose(kb);
|
||||
}
|
||||
// select remaining item if autoselect is enabled
|
||||
if (!selection) {
|
||||
if (!noAutoselect1 && filteredItems.length === 1) {
|
||||
selectListItem(filteredItems[0], true);
|
||||
} else {
|
||||
setInputValue("");
|
||||
}
|
||||
}
|
||||
opened = false;
|
||||
}
|
||||
|
||||
|
@ -185,43 +193,38 @@
|
|||
}
|
||||
|
||||
function onKeyDown(e: KeyboardEvent): void {
|
||||
let { key } = e;
|
||||
if (key === "Tab" && e.shiftKey) key = "ShiftTab";
|
||||
const fnmap: Record<string, () => void> = {
|
||||
Tab: () => close,
|
||||
ShiftTab: () => close,
|
||||
ArrowDown: () => {
|
||||
switch (e.key) {
|
||||
case "Tab":
|
||||
close();
|
||||
break;
|
||||
case "ArrowDown":
|
||||
open();
|
||||
if (highlightIndex < filteredItems.length - 1) {
|
||||
highlightIndex++;
|
||||
highlight();
|
||||
}
|
||||
},
|
||||
ArrowUp: () => {
|
||||
break;
|
||||
case "ArrowUp":
|
||||
open();
|
||||
if (highlightIndex > 0) {
|
||||
highlightIndex--;
|
||||
highlight();
|
||||
}
|
||||
},
|
||||
Escape: () => {
|
||||
break;
|
||||
case "Escape":
|
||||
e.stopPropagation();
|
||||
if (opened) {
|
||||
if (inputElm) inputElm.focus();
|
||||
close();
|
||||
}
|
||||
},
|
||||
Backspace: () => {
|
||||
break;
|
||||
case "Backspace":
|
||||
if (inputValue().length === 0) {
|
||||
onBackspace();
|
||||
} else if (selection) {
|
||||
clearSelection();
|
||||
}
|
||||
},
|
||||
};
|
||||
const fn = fnmap[key];
|
||||
if (typeof fn === "function") {
|
||||
fn();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -234,16 +237,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
function onBlur(): void {
|
||||
if (!selection) {
|
||||
if (!noAutoselect1 && filteredItems.length === 1) {
|
||||
selectListItem(filteredItems[0], true);
|
||||
} else {
|
||||
setInputValue("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function highlight(): void {
|
||||
if (browser && opened) {
|
||||
window.setTimeout(() => {
|
||||
|
@ -303,12 +296,11 @@
|
|||
on:focus={open}
|
||||
on:keydown={onKeyDown}
|
||||
on:keypress={onKeyPress}
|
||||
on:blur={onBlur}
|
||||
use:floatingRef
|
||||
/>
|
||||
|
||||
{#if opened && filteredItems.length > 0}
|
||||
<div bind:this={listElm} class="autocomplete-list" use:floatingContent>
|
||||
<div bind:this={listElm} class="autocomplete-list" tabindex="-1" use:floatingContent>
|
||||
{#each filteredItems as item, i}
|
||||
<div
|
||||
class="autocomplete-list-item"
|
||||
|
@ -344,7 +336,12 @@
|
|||
|
||||
{#if clearBtn && selection}
|
||||
<div class="absolute bottom-0 right-0 h-full flex items-center">
|
||||
<IconButton cls="" path={mdiClose} title="Löschen" on:click={clearSelection} />
|
||||
<IconButton
|
||||
cls=""
|
||||
path={mdiClose}
|
||||
tabindex={-1}
|
||||
title="Löschen"
|
||||
on:click={clearSelection} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
@ -8,12 +8,14 @@
|
|||
import { toastError, toastInfo } from "$lib/shared/util/toast";
|
||||
|
||||
import Icon from "$lib/components/ui/Icon.svelte";
|
||||
import { savedFilters } from "$lib/stores";
|
||||
import { getSavedFilters } from "$lib/stores";
|
||||
|
||||
import Chip from "./SavedFilterChip.svelte";
|
||||
|
||||
export let view: string;
|
||||
|
||||
const savedFilters = getSavedFilters();
|
||||
|
||||
$: filters = $savedFilters[view] ?? [];
|
||||
|
||||
function getQuery(): string {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { goto } from "$app/navigation";
|
||||
|
||||
import type { RouterOutput } from "$lib/shared/trpc";
|
||||
import { formatDate } from "$lib/shared/util";
|
||||
|
||||
|
@ -39,6 +41,7 @@
|
|||
class="transition-colors hover:bg-neutral-content/10"
|
||||
class:done={entry.execution?.done}
|
||||
class:priority={entry.current_version.priority}
|
||||
on:dblclick={() => { void goto("/entry/" + entry.id); }}
|
||||
>
|
||||
<td
|
||||
><a
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { goto } from "$app/navigation";
|
||||
|
||||
import { mdiFilter } from "@mdi/js";
|
||||
|
||||
import { URL_ENTRIES } from "$lib/shared/constants";
|
||||
|
@ -34,10 +36,11 @@
|
|||
<tr
|
||||
class="transition-colors hover:bg-neutral-content/10"
|
||||
class:p-hidden={patient.hidden}
|
||||
on:dblclick={() => { void goto("/patient/" + patient.id); }}
|
||||
>
|
||||
<td
|
||||
><a
|
||||
class="btn btn-xs btn-primary"
|
||||
class="btn btn-xs btn-primary btn-id"
|
||||
aria-label="Eintrag anzeigen"
|
||||
href="/patient/{patient.id}">{patient.id}</a
|
||||
></td
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { getContext } from "svelte";
|
||||
import { derived, writable, type Writable } from "svelte/store";
|
||||
|
||||
import type { SavedFilter } from "$lib/shared/model";
|
||||
|
@ -6,4 +7,6 @@ import type { SavedFilter } from "$lib/shared/model";
|
|||
export const screenWidth = writable(0);
|
||||
export const screenWidthSmall = derived(screenWidth, ($mainWidth) => $mainWidth < 500);
|
||||
|
||||
export const savedFilters: Writable<Record<string, SavedFilter[]>> = writable({});
|
||||
// Context key: "savedFilters"
|
||||
export type SavedFilters = Writable<Record<string, SavedFilter[]>>;
|
||||
export const getSavedFilters: () => SavedFilters = () => getContext("savedFilters");
|
||||
|
|
|
@ -3,16 +3,22 @@
|
|||
import type { LayoutData } from "./$types";
|
||||
|
||||
import { mdiAccount, mdiHome } from "@mdi/js";
|
||||
import { setContext } from "svelte";
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
import { defaultFilterUrl, defaultVisitUrl } from "$lib/shared/util";
|
||||
|
||||
import Icon from "$lib/components/ui/Icon.svelte";
|
||||
import NavLink from "$lib/components/ui/NavLink.svelte";
|
||||
import { savedFilters } from "$lib/stores";
|
||||
import type { SavedFilters } from "$lib/stores";
|
||||
|
||||
export let data: LayoutData;
|
||||
|
||||
const savedFilters: SavedFilters = writable();
|
||||
|
||||
$: savedFilters.set(data.savedFilters);
|
||||
|
||||
setContext("savedFilters", savedFilters);
|
||||
</script>
|
||||
|
||||
<div class="navbar-outer">
|
||||
|
|
|
@ -4,9 +4,11 @@
|
|||
|
||||
import { defaultFilterUrl } from "$lib/shared/util";
|
||||
|
||||
import { savedFilters } from "$lib/stores";
|
||||
import { getSavedFilters } from "$lib/stores";
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
const savedFilters = getSavedFilters();
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
<tbody>
|
||||
{#each data.rooms as room (room.id)}
|
||||
<tr>
|
||||
<td><a class="btn btn-sm" href="/room/{room.id}">{room.name}</a></td>
|
||||
<td><a class="btn btn-sm btn-id" href="/room/{room.id}">{room.name}</a></td>
|
||||
<td>{room.station.name}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
{#each data.stations as station (station.id)}
|
||||
<tr>
|
||||
<td>
|
||||
<a class="btn btn-sm" href="/station/{station.id}">{station.name}</a>
|
||||
<a class="btn btn-sm btn-id" href="/station/{station.id}">{station.name}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
|
|
|
@ -23,7 +23,8 @@ export default defineConfig({
|
|||
createViteLicensePlugin({
|
||||
additionalFiles: {
|
||||
"oss-licenses.html": (packages) => {
|
||||
let res = `<html>
|
||||
let res = `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Visitenbuch - Lizenzen</title>
|
||||
</head>
|
||||
|
@ -31,6 +32,12 @@ export default defineConfig({
|
|||
<h1>Open-Source-Lizenzen</h1>
|
||||
<a href="./oss-licenses.json">JSON-formatted license list</a>
|
||||
`;
|
||||
const escapeHTML = (s: string | null) => s ? s.replaceAll("&", "&")
|
||||
.replaceAll("<", "<")
|
||||
.replaceAll(">", ">")
|
||||
.replaceAll('"', """)
|
||||
.replaceAll("'", "'") : "";
|
||||
|
||||
for (const _p of packages) {
|
||||
type LicenseMetaExt = LicenseMeta & {
|
||||
repository: string | null,
|
||||
|
@ -54,13 +61,13 @@ export default defineConfig({
|
|||
}
|
||||
|
||||
res += `<div class="package">\n`;
|
||||
res += `<h3><a href="https://www.npmjs.com/package/${p.name}" target="_blank" rel="noopener noreferrer">${p.name}</a></h3>\n`;
|
||||
res += `<h3><a href="https://www.npmjs.com/package/${escapeHTML(p.name)}" target="_blank" rel="noopener noreferrer">${escapeHTML(p.name)}</a></h3>\n`;
|
||||
res += `<table>\n`;
|
||||
res += `<tr><td>Version:</td><td>${p.version}</td></tr>\n`;
|
||||
if (aut) res += `<tr><td>Author:</td><td>${aut}</td></tr>\n`;
|
||||
res += `<tr><td>License:</td><td>${p.license}</td></tr>\n`;
|
||||
if (repoUrl) res += `<tr><td>Repository:</td><td><a href="${repoUrl}" target="_blank" rel="noopener noreferrer">${repoUrl}</a></td></tr>\n`;
|
||||
else if (rp) res += `<tr><td>Repository:</td><td>${rp}</td></tr>\n`;
|
||||
res += `<tr><td>Version:</td><td>${escapeHTML(p.version)}</td></tr>\n`;
|
||||
if (aut) res += `<tr><td>Author:</td><td>${escapeHTML(aut)}</td></tr>\n`;
|
||||
res += `<tr><td>License:</td><td>${escapeHTML(p.license)}</td></tr>\n`;
|
||||
if (repoUrl) res += `<tr><td>Repository:</td><td><a href="${escapeHTML(repoUrl)}" target="_blank" rel="noopener noreferrer">${escapeHTML(repoUrl)}</a></td></tr>\n`;
|
||||
else if (rp) res += `<tr><td>Repository:</td><td>${escapeHTML(rp)}</td></tr>\n`;
|
||||
res += `</table>\n`;
|
||||
res += "</div>";
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue