From 22094e7ccc4f88f6e2c22c4b83c05dfc7ee7c55b Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Tue, 17 Mar 2026 09:55:11 +0100 Subject: [PATCH] implemented autocomplete for filter in kanban Signed-off-by: Stephan Richter --- frontend/src/Components/Autocomplete.svelte | 17 ++++++----- frontend/src/routes/project/Kanban.svelte | 34 +++++++++++++++------ 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/frontend/src/Components/Autocomplete.svelte b/frontend/src/Components/Autocomplete.svelte index ad859226..35a02c88 100644 --- a/frontend/src/Components/Autocomplete.svelte +++ b/frontend/src/Components/Autocomplete.svelte @@ -4,13 +4,15 @@ let { + autofocus = false, getCandidates = dummyGetCandidates, onCommit = dummyOnCommit, onSelect = dummyOnSelect, + candidate = $bindable({ display : '' }) } = $props(); const ignore = ['ArrowLeft','ArrowRight']; - let candidate = $state({ display : '' }); + //let candidate = $state({ display : '' }); let selected = $state([]); let candidates = $derived(getCandidates(candidate.display)); @@ -36,6 +38,8 @@ // either the selected candidate or // an anonymous object with the entered text in the display field console.warn(`onCommit(${JSON.stringify(candidate)}) not overridden!`); + // if the method returns true, the field will be cleared after committing + return true; } function dummyOnSelect(candidate){ @@ -78,8 +82,7 @@ if (ev.key == 'Enter') { candidates = []; selected = []; - onCommit(candidate); - candidate = { display : '' }; + if (onCommit(candidate)) candidate = { display : '' }; } return false; } @@ -97,15 +100,15 @@ -
- + + {#if candidates && candidates.length > 0} {/if} -
\ No newline at end of file + \ No newline at end of file diff --git a/frontend/src/routes/project/Kanban.svelte b/frontend/src/routes/project/Kanban.svelte index f04f329d..07341024 100644 --- a/frontend/src/routes/project/Kanban.svelte +++ b/frontend/src/routes/project/Kanban.svelte @@ -2,11 +2,12 @@ import { onDestroy, onMount } from 'svelte'; import { useTinyRouter } from 'svelte-tiny-router'; - import { api, patch, post, eventStream, target } from '../../urls.svelte.js'; + import { api, get, patch, post, eventStream, target } from '../../urls.svelte.js'; import { error, messages, yikes } from '../../warn.svelte'; import { t } from '../../translations.svelte.js'; import { user } from '../../user.svelte.js'; + import Autocomplete from '../../Components/Autocomplete.svelte'; import Card from './KanbanCard.svelte'; import LineEditor from '../../Components/LineEditor.svelte'; import MarkdownEditor from '../../Components/MarkdownEditor.svelte'; @@ -16,12 +17,12 @@ let connectionStatus = 'disconnected'; let { id } = $props(); let descr = $state(false); - let filter_input = $state(''); + let filter_input = $state({display:''}); let router = useTinyRouter(); - if (router.hasQueryParam('filter')) filter_input = router.getQueryParam('filter'); + if (router.hasQueryParam('filter')) filter_input = {display:router.getQueryParam('filter')}; let dragged = null; let highlight = $state({}); - let filter = $derived(filter_input.toLowerCase()); + let filter = $derived(filter_input.display.toLowerCase()); let project = $state(null); let tasks = $state({}); let users = []; @@ -29,7 +30,7 @@ let info = $state(null); let task_form = $state(false); let stateList = {}; - $effect(() => updateUrl(filter_input)); + $effect(() => updateUrl(filter_input.display)); function byName(a,b) { return a.name.localeCompare(b.name); @@ -92,6 +93,17 @@ } } + async function getCandidates(input){ + if (!input || input.length <3) return []; + const url = api(`tags/search/${encodeURI(input)}`); + const res = await get(url); + if (res.ok){ + yikes(); + const list = await res.json(); + return list.map(elem => {return {display:elem}}); + } else error(res); + } + function handleCreateEvent(evt){ handleEvent(evt,'create'); } @@ -191,6 +203,10 @@ } } + function onCommit(){ + return false; + } + function openTask(task_id){ window.open(`/task/${task_id}/view`, '_blank').focus(); } @@ -219,8 +235,8 @@ const user_ids = Object.values(project.members).map(member => member.user.id); const data = { url : location.href, - tags : ['Kanban', project.name, filter_input], - comment : `${project.name}: ${filter_input}`, + tags : ['Kanban', project.name, filter_input.display], + comment : `${project.name}: ${filter_input.display}`, share : user_ids } const url = api('bookmark'); @@ -239,7 +255,7 @@ function updateUrl(){ let url = window.location.origin + window.location.pathname; - if (filter_input) url += '?filter=' + encodeURI(filter_input); + if (filter_input.display) url += '?filter=' + encodeURI(filter_input.display); window.history.replaceState(window.history.state, '', url); } @@ -272,7 +288,7 @@
- + {t('filter')}