Skip to content

Commit 6be3651

Browse files
committed
Aligned timelog workitem search
1 parent 70008f8 commit 6be3651

1 file changed

Lines changed: 49 additions & 3 deletions

File tree

frontend/src/lib/dialogs/TimeLogModal.svelte

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
<script>
2+
import { onDestroy } from 'svelte';
3+
import { api } from '../api.js';
24
import { BasePicker } from '../pickers';
35
import Input from '../components/Input.svelte';
46
import Label from '../components/Label.svelte';
@@ -97,8 +99,46 @@
9799
};
98100
}));
99101
100-
// Prepare work items for combobox with workspace info
101-
const workItemOptions = $derived(workItems.map(item => ({
102+
let workItemResults = $state(null);
103+
let searchingWorkItems = $state(false);
104+
let selectedWorkItem = $state(null);
105+
let workItemSearchVersion = 0;
106+
107+
function resetWorkItemSearch() {
108+
workItemSearchVersion += 1;
109+
workItemResults = null;
110+
searchingWorkItems = false;
111+
}
112+
113+
onDestroy(() => { workItemSearchVersion += 1; });
114+
115+
async function searchWorkItems(query) {
116+
const trimmedQuery = query.trim();
117+
if (!trimmedQuery) {
118+
resetWorkItemSearch();
119+
return;
120+
}
121+
const version = ++workItemSearchVersion;
122+
searchingWorkItems = true;
123+
workItemResults = [];
124+
try {
125+
const results = await api.links.search(trimmedQuery, 'item', 20);
126+
if (version !== workItemSearchVersion) return;
127+
workItemResults = Array.isArray(results) ? results : [];
128+
} catch (error) {
129+
if (version !== workItemSearchVersion) return;
130+
console.error('Work item search failed:', error);
131+
workItemResults = [];
132+
} finally {
133+
if (version === workItemSearchVersion) searchingWorkItems = false;
134+
}
135+
}
136+
137+
// Keep a remotely selected item available after the search closes.
138+
const initialWorkItems = $derived(selectedWorkItem && !workItems.some(item => item.id === selectedWorkItem.id)
139+
? [selectedWorkItem, ...workItems]
140+
: workItems);
141+
const workItemOptions = $derived((workItemResults ?? initialWorkItems).map(item => ({
102142
id: item.id,
103143
title: item.title,
104144
subtitle: item.workspace_name || 'Unknown Workspace',
@@ -232,14 +272,20 @@
232272
<div>
233273
<Label color="default" class="mb-2">{t('time.workItemOptional')}</Label>
234274
<BasePicker
275+
id="time-log-work-item"
235276
bind:value={formData.item_id}
236277
items={workItemOptions}
237278
placeholder={t('placeholders.searchWorkItems')}
238279
allowClear={true}
239-
searchFields={['title', 'subtitle']}
280+
serverSearch={true}
281+
loading={searchingWorkItems}
282+
onSearchChange={searchWorkItems}
283+
onClose={resetWorkItemSearch}
284+
optionTestid={(option) => `time-log-work-item-option-${option.value}`}
240285
getValue={(item) => item?.id}
241286
getLabel={(item) => item?.title ?? ''}
242287
onSelect={(item) => {
288+
selectedWorkItem = item?.item ?? null;
243289
if (item && !formData.description.trim()) {
244290
formData.description = item.title;
245291
}

0 commit comments

Comments
 (0)