implemented selection functions
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -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 @@
|
||||
|
||||
<style>
|
||||
td { vertical-align: top; }
|
||||
.year, .month{
|
||||
border: 1px solid;
|
||||
}
|
||||
.selected td:not(.year):not(.month){
|
||||
background: navy;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>{t('timetracking')}</h1>
|
||||
@@ -63,6 +133,8 @@
|
||||
<table class="timetracks">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{t('year')}</th>
|
||||
<th>{t('month')}</th>
|
||||
<th>{t('start_end')}</th>
|
||||
<th>{t('duration')}</th>
|
||||
<th>{t('subject')}</th>
|
||||
@@ -71,35 +143,44 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each sortedTimes as time}
|
||||
{#if detail == time.id}
|
||||
<tr>
|
||||
{#each sortedTimes as time,line}
|
||||
<tr class={selected[time.id]?'selected':''}>
|
||||
{#if timeMap.years[line]}
|
||||
<td class="year" rowspan={timeMap.years[line]} onclick={e => toggleRange(time.start_time.substring(0,4))}>
|
||||
{time.start_time.substring(0,4)}
|
||||
</td>
|
||||
{/if}
|
||||
{#if timeMap.months[line]}
|
||||
<td class="month" rowspan={timeMap.months[line]} onclick={e => toggleRange(time.start_time.substring(0,7))}>
|
||||
{time.start_time.substring(5,7)}
|
||||
</td>
|
||||
{/if}
|
||||
{#if detail == time.id}
|
||||
<td colspan="5">
|
||||
<TimeEditor record={time} onSet={update} />
|
||||
</td>
|
||||
</tr>
|
||||
{:else}
|
||||
<tr onclick={e => {detail = time.id}}>
|
||||
<td class="start_end">
|
||||
{:else}
|
||||
<td class="start_end" onclick={e => toggleSelect(time.id)}>
|
||||
{time.start_time}{#if time.end_time}…{time.end_time}{/if}
|
||||
</td>
|
||||
<td class="duration">{#if time.duration}
|
||||
<td class="duration" onclick={e => {detail = time.id}}>
|
||||
{#if time.duration}
|
||||
{time.duration.toFixed(3)} h
|
||||
{/if}
|
||||
</td>
|
||||
<td class="subject">
|
||||
<td class="subject" onclick={e => {detail = time.id}}>
|
||||
{time.subject}
|
||||
</td>
|
||||
<td class="tasks">
|
||||
<td class="tasks" onclick={e => {detail = time.id}}>
|
||||
{#each Object.entries(time.tasks) as [tid,task]}
|
||||
<a href="#" onclick={e => openTask(tid)}>{task}</a>
|
||||
{/each}
|
||||
</td>
|
||||
<td class="state">
|
||||
<td class="state" onclick={e => {detail = time.id}}>
|
||||
{t("state_"+time.state.name.toLowerCase())}
|
||||
</td>
|
||||
{/if}
|
||||
</tr>
|
||||
{/if}
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Reference in New Issue
Block a user