From 9fe94da5a6bbe8c2fe81159bbdb434c02771efeb Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Thu, 28 Aug 2025 11:45:01 +0200 Subject: [PATCH] implemented selection functions Signed-off-by: Stephan Richter --- frontend/src/routes/time/Index.svelte | 105 +++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 12 deletions(-) diff --git a/frontend/src/routes/time/Index.svelte b/frontend/src/routes/time/Index.svelte index a350633..e267ec7 100644 --- a/frontend/src/routes/time/Index.svelte +++ b/frontend/src/routes/time/Index.svelte @@ -11,6 +11,50 @@ let times = $state(null); let detail = $state(null); let sortedTimes = $derived.by(() => Object.values(times).sort((b, a) => a.start_time.localeCompare(b.start_time))); + let selected = $state({}); + let ranges = {}; + let timeMap = $derived.by(() => { + let result = { + months : {}, + years : {} + } + let lastYear = null; + let lastMonth = null; + let yearCount = 0; + let monthCount = 0; + let yearIndex = 0; + let monthIndex = 0; + for (let idx in sortedTimes){ + const time = sortedTimes[idx]; + const start = time.start_time; + const year = start.substring(0,4); + const month = start.substring(5,7); + if (year != lastYear){ + lastYear = year; + if (yearCount) result.years[yearIndex] = yearCount; + yearCount = 0; + yearIndex = idx; + } + yearCount +=1; + if (month != lastMonth){ + lastMonth = month; + if (monthCount) result.months[monthIndex] = monthCount; + monthCount = 0; + monthIndex = idx; + } + monthCount +=1; + } + if (yearCount) result.years[yearIndex] = yearCount; + if (monthCount) result.months[monthIndex] = monthCount; + console.log(result); + return result; + }); + + function calcYearMap(){ + let result = Object.values(times).length; + console.log({result:result}); + return result; + } async function loadTimes(){ const url = api('time'); @@ -26,6 +70,26 @@ router.navigate(`task/${tid}/view`); } + function toggleRange(range){ + let affected = sortedTimes.filter(time => time.start_time.startsWith(range)); + if (ranges[range]){ + delete ranges[range]; + for (let time of affected){ + if (selected[time.id]) delete selected[time.id] + } + } else { + for (let time of affected) selected[time.id] = true; + ranges[range] = true; + } + } + + function toggleSelect(time_id){ + detail = null; + if (selected[time_id]) { + delete selected[time_id] + } else selected[time_id] = true; + } + async function update(time){ const url = api(`time/${time.id}`); time.start_time = time.start_time.split(':').slice(0,2).join(':'); @@ -53,6 +117,12 @@

{t('timetracking')}

@@ -63,6 +133,8 @@ + + @@ -71,35 +143,44 @@ - {#each sortedTimes as time} - {#if detail == time.id} - + {#each sortedTimes as time,line} + + {#if timeMap.years[line]} + + {/if} + {#if timeMap.months[line]} + + {/if} + {#if detail == time.id} - - {:else} - {detail = time.id}}> - - - - - + {/if} - {/if} {/each}
{t('year')}{t('month')} {t('start_end')} {t('duration')} {t('subject')}
toggleRange(time.start_time.substring(0,4))}> + {time.start_time.substring(0,4)} + toggleRange(time.start_time.substring(0,7))}> + {time.start_time.substring(5,7)} +
+ {:else} + toggleSelect(time.id)}> {time.start_time}{#if time.end_time}…{time.end_time}{/if} {#if time.duration} + {detail = time.id}}> + {#if time.duration} {time.duration.toFixed(3)} h {/if} + {detail = time.id}}> {time.subject} + {detail = time.id}}> {#each Object.entries(time.tasks) as [tid,task]} openTask(tid)}>{task} {/each} + {detail = time.id}}> {t("state_"+time.state.name.toLowerCase())}