diff --git a/.forgejo/workflows/ci.yaml b/.forgejo/workflows/ci.yaml
index e6dfd6e..d2ea852 100644
--- a/.forgejo/workflows/ci.yaml
+++ b/.forgejo/workflows/ci.yaml
@@ -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
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bda8d0a..e50f81d 100644
--- a/CHANGELOG.md
+++ b/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
diff --git a/package.json b/package.json
index bc6e46c..722de0f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "visitenbuch",
- "version": "0.3.3",
+ "version": "0.3.4",
"private": true,
"license": "AGPL-3.0",
"scripts": {
diff --git a/src/app.html b/src/app.html
index 5f0dd88..50038b5 100644
--- a/src/app.html
+++ b/src/app.html
@@ -1,5 +1,5 @@
-
+
diff --git a/src/hooks.server.ts b/src/hooks.server.ts
index a7fddf5..87c81a0 100644
--- a/src/hooks.server.ts
+++ b/src/hooks.server.ts
@@ -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
diff --git a/src/lib/components/filter/Autocomplete.svelte b/src/lib/components/filter/Autocomplete.svelte
index f1a7885..7a20f6d 100644
--- a/src/lib/components/filter/Autocomplete.svelte
+++ b/src/lib/components/filter/Autocomplete.svelte
@@ -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 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}
-
+
{#each filteredItems as item, i}
-
+
{/if}
diff --git a/src/lib/components/filter/SavedFilters.svelte b/src/lib/components/filter/SavedFilters.svelte
index 5854b2b..20baa2c 100644
--- a/src/lib/components/filter/SavedFilters.svelte
+++ b/src/lib/components/filter/SavedFilters.svelte
@@ -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 {
diff --git a/src/lib/components/table/EntryTable.svelte b/src/lib/components/table/EntryTable.svelte
index 42c2990..4af0262 100644
--- a/src/lib/components/table/EntryTable.svelte
+++ b/src/lib/components/table/EntryTable.svelte
@@ -1,4 +1,6 @@
diff --git a/src/routes/(app)/+page.svelte b/src/routes/(app)/+page.svelte
index e840d93..1c155e1 100644
--- a/src/routes/(app)/+page.svelte
+++ b/src/routes/(app)/+page.svelte
@@ -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();
diff --git a/src/routes/(app)/rooms/+page.svelte b/src/routes/(app)/rooms/+page.svelte
index 513a06f..5f7d2a6 100644
--- a/src/routes/(app)/rooms/+page.svelte
+++ b/src/routes/(app)/rooms/+page.svelte
@@ -27,7 +27,7 @@
{#each data.rooms as room (room.id)}
- {room.name} |
+ {room.name} |
{room.station.name} |
{/each}
diff --git a/src/routes/(app)/stations/+page.svelte b/src/routes/(app)/stations/+page.svelte
index 010080e..e94e7bf 100644
--- a/src/routes/(app)/stations/+page.svelte
+++ b/src/routes/(app)/stations/+page.svelte
@@ -27,7 +27,7 @@
{#each data.stations as station (station.id)}
- {station.name}
+ {station.name}
|
{/each}
diff --git a/vite.config.ts b/vite.config.ts
index 9d34322..195765a 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -23,7 +23,8 @@ export default defineConfig({
createViteLicensePlugin({
additionalFiles: {
"oss-licenses.html": (packages) => {
- let res = `
+ let res = `
+
Visitenbuch - Lizenzen
@@ -31,6 +32,12 @@ export default defineConfig({
Open-Source-Lizenzen
JSON-formatted license list
`;
+ 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 += `\n`;
- res += `
\n`;
+ res += `
\n`;
res += `
\n`;
- res += `Version: | ${p.version} |
\n`;
- if (aut) res += `Author: | ${aut} |
\n`;
- res += `License: | ${p.license} |
\n`;
- if (repoUrl) res += `Repository: | ${repoUrl} |
\n`;
- else if (rp) res += `Repository: | ${rp} |
\n`;
+ res += `Version: | ${escapeHTML(p.version)} |
\n`;
+ if (aut) res += `Author: | ${escapeHTML(aut)} |
\n`;
+ res += `License: | ${escapeHTML(p.license)} |
\n`;
+ if (repoUrl) res += `Repository: | ${escapeHTML(repoUrl)} |
\n`;
+ else if (rp) res += `Repository: | ${escapeHTML(rp)} |
\n`;
res += `
\n`;
res += "
";
}