| 
							
								 | 
							
							<script> | 
						
						
						
						
							 | 
							
								 | 
							
							    import { onMount }                from 'svelte'; | 
						
						
						
						
							 | 
							
								 | 
							
							    import { useTinyRouter }          from 'svelte-tiny-router'; | 
						
						
						
						
							 | 
							
								 | 
							
							    import { api, drop, patch, post } from '../../urls.svelte.js'; | 
						
						
						
						
							 | 
							
								 | 
							
							    import { error, yikes }           from '../../warn.svelte'; | 
						
						
						
						
							 | 
							
								 | 
							
							    import { t }         from '../../translations.svelte.js'; | 
						
						
						
						
							 | 
							
								 | 
							
							    import { timetrack } from '../../user.svelte.js'; | 
						
						
						
						
							 | 
							
								 | 
							
							    import { display }   from '../../time.svelte.js'; | 
						
						
						
						
							 | 
							
								 | 
							
							    import { now }       from '../../time.svelte'; | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    import TimeEditor from '../../Components/TimeRecordEditor.svelte'; | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    let detail = $state(null); | 
						
						
						
						
							 | 
							
								 | 
							
							    let docLinks = $state(null); | 
						
						
						
						
							 | 
							
								 | 
							
							    let router = useTinyRouter(); | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    let times = $state(null); | 
						
						
						
						
							 | 
							
								 | 
							
							    let tasks = {}; | 
						
						
						
						
							 | 
							
								 | 
							
							    let projects = {}; | 
						
						
						
						
							 | 
							
								 | 
							
							    let project_filter = $state(null); | 
						
						
						
						
							 | 
							
								 | 
							
							    if (router.hasQueryParam('project')) project_filter = router.getQueryParam('project'); | 
						
						
						
						
							 | 
							
								 | 
							
							    let sortedTimes = $derived.by(() => Object.values(times).map(time => ({ | 
						
						
						
						
							 | 
							
								 | 
							
							      ...time, | 
						
						
						
						
							 | 
							
								 | 
							
							      start: display(time.start_time), | 
						
						
						
						
							 | 
							
								 | 
							
							      end: display(time.end_time), | 
						
						
						
						
							 | 
							
								 | 
							
							      end_date: display(time.end_time)?.substring(0,10) | 
						
						
						
						
							 | 
							
								 | 
							
							    })).sort((b, a) => a.start_time - b.start_time)); | 
						
						
						
						
							 | 
							
								 | 
							
							    let selected = $state({}); | 
						
						
						
						
							 | 
							
								 | 
							
							    let ranges = {}; | 
						
						
						
						
							 | 
							
								 | 
							
							    let timeMap = $derived.by(calcYearMap); | 
						
						
						
						
							 | 
							
								 | 
							
							    let selectionSum = $derived(sortedTimes.filter(time => selected[time.id]).map(time => time.duration).reduce((acc, a) => acc + a, 0)); | 
						
						
						
						
							 | 
							
								 | 
							
							    let users = null; | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    async function addTime(task_id){ | 
						
						
						
						
							 | 
							
								 | 
							
							        const url  = api(`time/track_task/${task_id}`); | 
						
						
						
						
							 | 
							
								 | 
							
							        const resp = await post(url,now()); // create new time or return time with assigned tasks | 
						
						
						
						
							 | 
							
								 | 
							
							        if (resp.ok) { | 
						
						
						
						
							 | 
							
								 | 
							
							            const track = await resp.json(); | 
						
						
						
						
							 | 
							
								 | 
							
							            timetrack.running = track; | 
						
						
						
						
							 | 
							
								 | 
							
							        } else { | 
						
						
						
						
							 | 
							
								 | 
							
							            error(resp); | 
						
						
						
						
							 | 
							
								 | 
							
							        } | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    function calcYearMap(){ | 
						
						
						
						
							 | 
							
								 | 
							
							        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 year  = time.start.substring(0,4); | 
						
						
						
						
							 | 
							
								 | 
							
							            const month = time.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; | 
						
						
						
						
							 | 
							
								 | 
							
							        return result; | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    async function joinTimes(evt, id1, id2){ | 
						
						
						
						
							 | 
							
								 | 
							
							        evt.preventDefault(); | 
						
						
						
						
							 | 
							
								 | 
							
							        evt.stopPropagation(); | 
						
						
						
						
							 | 
							
								 | 
							
							        const url = api('time/join'); | 
						
						
						
						
							 | 
							
								 | 
							
							        const res = await post(url,`${id1}+${id2}`); | 
						
						
						
						
							 | 
							
								 | 
							
							        if (res.ok){ | 
						
						
						
						
							 | 
							
								 | 
							
							            yikes(); | 
						
						
						
						
							 | 
							
								 | 
							
							            let json = await res.json(); | 
						
						
						
						
							 | 
							
								 | 
							
							            delete times[id1]; | 
						
						
						
						
							 | 
							
								 | 
							
							            delete times[id2]; | 
						
						
						
						
							 | 
							
								 | 
							
							            times[json.id] = json; | 
						
						
						
						
							 | 
							
								 | 
							
							        } else { | 
						
						
						
						
							 | 
							
								 | 
							
							            error(res); | 
						
						
						
						
							 | 
							
								 | 
							
							        } | 
						
						
						
						
							 | 
							
								 | 
							
							        return false; | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    async function loadTimes(){ | 
						
						
						
						
							 | 
							
								 | 
							
							        const url  = api('time'); | 
						
						
						
						
							 | 
							
								 | 
							
							        const resp = await fetch(url,{credentials:'include'}); | 
						
						
						
						
							 | 
							
								 | 
							
							        if (resp.ok){ | 
						
						
						
						
							 | 
							
								 | 
							
							            var json = await resp.json(); | 
						
						
						
						
							 | 
							
								 | 
							
							            times    = json.times; | 
						
						
						
						
							 | 
							
								 | 
							
							            tasks    = json.tasks; | 
						
						
						
						
							 | 
							
								 | 
							
							            projects = json.projects; | 
						
						
						
						
							 | 
							
								 | 
							
							            docLinks = json.documents; | 
						
						
						
						
							 | 
							
								 | 
							
							            users    = json.users; | 
						
						
						
						
							 | 
							
								 | 
							
							        } else { | 
						
						
						
						
							 | 
							
								 | 
							
							            error(resp); | 
						
						
						
						
							 | 
							
								 | 
							
							        } | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    function match_prj_filter(time){ | 
						
						
						
						
							 | 
							
								 | 
							
							        if (!project_filter) return true; | 
						
						
						
						
							 | 
							
								 | 
							
							        for (var tid of time.task_ids){ | 
						
						
						
						
							 | 
							
								 | 
							
							            if (project_filter == tasks[tid].project_id) return true; | 
						
						
						
						
							 | 
							
								 | 
							
							        } | 
						
						
						
						
							 | 
							
								 | 
							
							        return false; | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    function onAbort(){ | 
						
						
						
						
							 | 
							
								 | 
							
							        detail = null; | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    function onclick(e){ | 
						
						
						
						
							 | 
							
								 | 
							
							        e.preventDefault(); | 
						
						
						
						
							 | 
							
								 | 
							
							        let href = e.target.getAttribute('href'); | 
						
						
						
						
							 | 
							
								 | 
							
							        if (href) router.navigate(href); | 
						
						
						
						
							 | 
							
								 | 
							
							        return false; | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    async function onDrop(time_id){ | 
						
						
						
						
							 | 
							
								 | 
							
							        const url = api(`time/${time_id}`); | 
						
						
						
						
							 | 
							
								 | 
							
							        const res = await drop(url); | 
						
						
						
						
							 | 
							
								 | 
							
							        if (res.ok){ | 
						
						
						
						
							 | 
							
								 | 
							
							            delete times[time_id]; | 
						
						
						
						
							 | 
							
								 | 
							
							            yikes(); | 
						
						
						
						
							 | 
							
								 | 
							
							        } else { | 
						
						
						
						
							 | 
							
								 | 
							
							            error(res); | 
						
						
						
						
							 | 
							
								 | 
							
							        } | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    async function multi_update(changeSet){ | 
						
						
						
						
							 | 
							
								 | 
							
							        console.log({ids:Object.keys(selected),patch:patch}); | 
						
						
						
						
							 | 
							
								 | 
							
							        changeSet.ids = Object.keys(selected).map(id => +id); | 
						
						
						
						
							 | 
							
								 | 
							
							        const url = api('time'); | 
						
						
						
						
							 | 
							
								 | 
							
							        const res = await patch(url,changeSet); | 
						
						
						
						
							 | 
							
								 | 
							
							        if (res.ok){ | 
						
						
						
						
							 | 
							
								 | 
							
							            yikes(); | 
						
						
						
						
							 | 
							
								 | 
							
							            var updated = await res.json(); | 
						
						
						
						
							 | 
							
								 | 
							
							            times = {...times, ...updated}; | 
						
						
						
						
							 | 
							
								 | 
							
							        } else error(res); | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    function openProject(pid){ | 
						
						
						
						
							 | 
							
								 | 
							
							        router.navigate(`/project/${pid}/view`); | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    function openTask(tid){ | 
						
						
						
						
							 | 
							
								 | 
							
							        router.navigate(`/task/${tid}/view`); | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    function toggleRange(range){ | 
						
						
						
						
							 | 
							
								 | 
							
							        let affected = sortedTimes.filter(time => time.start.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}`); | 
						
						
						
						
							 | 
							
								 | 
							
							        const res = await fetch(url,{ | 
						
						
						
						
							 | 
							
								 | 
							
							            credentials:'include', | 
						
						
						
						
							 | 
							
								 | 
							
							            method:'PATCH', | 
						
						
						
						
							 | 
							
								 | 
							
							            body:JSON.stringify(time) | 
						
						
						
						
							 | 
							
								 | 
							
							        }); | 
						
						
						
						
							 | 
							
								 | 
							
							        if (res.ok){ | 
						
						
						
						
							 | 
							
								 | 
							
							            let json = await res.json(); | 
						
						
						
						
							 | 
							
								 | 
							
							            let id = json.id; | 
						
						
						
						
							 | 
							
								 | 
							
							            for (let key of Object.keys(json)) times[id][key] = json[key]; | 
						
						
						
						
							 | 
							
								 | 
							
							            detail = null; | 
						
						
						
						
							 | 
							
								 | 
							
							            yikes(); | 
						
						
						
						
							 | 
							
								 | 
							
							            return true; | 
						
						
						
						
							 | 
							
								 | 
							
							        } else { | 
						
						
						
						
							 | 
							
								 | 
							
							            error(res); | 
						
						
						
						
							 | 
							
								 | 
							
							            return false; | 
						
						
						
						
							 | 
							
								 | 
							
							        } | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    onMount(loadTimes); | 
						
						
						
						
							 | 
							
								 | 
							
							</script> | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							<svelte:head> | 
						
						
						
						
							 | 
							
								 | 
							
							    <title>Umbrella – {t('timetracking')}</title> | 
						
						
						
						
							 | 
							
								 | 
							
							</svelte:head> | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							<h1>{t('timetracking')}</h1> | 
						
						
						
						
							 | 
							
								 | 
							
							{#if times} | 
						
						
						
						
							 | 
							
								 | 
							
							{#if selectionSum} | 
						
						
						
						
							 | 
							
								 | 
							
							<div class="timetracks sum"> | 
						
						
						
						
							 | 
							
								 | 
							
							    {t('sum_of_records')}: <span>{selectionSum.toFixed(3)} {t('hours')}</span> | 
						
						
						
						
							 | 
							
								 | 
							
							    <button class="symbol" title={t('open')} onclick={e => multi_update({state:'Open'})} ></button> | 
						
						
						
						
							 | 
							
								 | 
							
							    <button class="symbol" title={t('pending')} onclick={e => multi_update({state:'Pending'})} ></button> | 
						
						
						
						
							 | 
							
								 | 
							
							    <button class="symbol" title={t('complete')} onclick={e => multi_update({state:'Complete'})} ></button> | 
						
						
						
						
							 | 
							
								 | 
							
							</div> | 
						
						
						
						
							 | 
							
								 | 
							
							{/if} | 
						
						
						
						
							 | 
							
								 | 
							
							<table class="timetracks"> | 
						
						
						
						
							 | 
							
								 | 
							
							    <thead> | 
						
						
						
						
							 | 
							
								 | 
							
							        <tr> | 
						
						
						
						
							 | 
							
								 | 
							
							            <th>{t('year')}</th> | 
						
						
						
						
							 | 
							
								 | 
							
							            <th>{t('month')}</th> | 
						
						
						
						
							 | 
							
								 | 
							
							            <th>{t('start')}<wbr>…<wbr>{t('end')}</th> | 
						
						
						
						
							 | 
							
								 | 
							
							            <th>{t('duration')}</th> | 
						
						
						
						
							 | 
							
								 | 
							
							            <th>{t('user')}</th> | 
						
						
						
						
							 | 
							
								 | 
							
							            <th>{t('subject')}</th> | 
						
						
						
						
							 | 
							
								 | 
							
							            <th>{t('projects')} / {t('tasks')}</th> | 
						
						
						
						
							 | 
							
								 | 
							
							            <th>{t('state')}</th> | 
						
						
						
						
							 | 
							
								 | 
							
							        </tr> | 
						
						
						
						
							 | 
							
								 | 
							
							    </thead> | 
						
						
						
						
							 | 
							
								 | 
							
							    <tbody> | 
						
						
						
						
							 | 
							
								 | 
							
							        {#each sortedTimes as time,line} | 
						
						
						
						
							 | 
							
								 | 
							
							        {#if match_prj_filter(time)} | 
						
						
						
						
							 | 
							
								 | 
							
							        <tr class={selected[time.id]?'selected':''}> | 
						
						
						
						
							 | 
							
								 | 
							
							            {#if timeMap.years[line]} | 
						
						
						
						
							 | 
							
								 | 
							
							            <td class="year" rowspan={timeMap.years[line]} onclick={e => toggleRange(time.start.substring(0,4))}> | 
						
						
						
						
							 | 
							
								 | 
							
							                {time.start.substring(0,4)} | 
						
						
						
						
							 | 
							
								 | 
							
							            </td> | 
						
						
						
						
							 | 
							
								 | 
							
							            {/if} | 
						
						
						
						
							 | 
							
								 | 
							
							            {#if timeMap.months[line]} | 
						
						
						
						
							 | 
							
								 | 
							
							            <td class="month" rowspan={timeMap.months[line]} onclick={e => toggleRange(time.start.substring(0,7))}> | 
						
						
						
						
							 | 
							
								 | 
							
							                {time.start.substring(5,7)} | 
						
						
						
						
							 | 
							
								 | 
							
							            </td> | 
						
						
						
						
							 | 
							
								 | 
							
							            {/if} | 
						
						
						
						
							 | 
							
								 | 
							
							            {#if detail == time.id} | 
						
						
						
						
							 | 
							
								 | 
							
							            <td colspan="5"> | 
						
						
						
						
							 | 
							
								 | 
							
							                <TimeEditor record={time} {onAbort} {onDrop} onSet={update} /> | 
						
						
						
						
							 | 
							
								 | 
							
							            </td> | 
						
						
						
						
							 | 
							
								 | 
							
							            {:else} | 
						
						
						
						
							 | 
							
								 | 
							
							            <td class="start_end" onclick={e => toggleSelect(time.id)}> | 
						
						
						
						
							 | 
							
								 | 
							
							                {time.start}{#if time.end_time}<wbr>…<wbr>{time.start.startsWith(time.end_date)?time.end.substring(11):time.end}{/if} | 
						
						
						
						
							 | 
							
								 | 
							
							                {#if line>0 && (sortedTimes[line-1].user_id == time.user_id) && (Math.abs(sortedTimes[line-1].start_time - time.end_time)<100)} | 
						
						
						
						
							 | 
							
								 | 
							
							                <button class="symbol join" title={t('join_objects',{objects:t('times')})} onclick={e => joinTimes(e, time.id, sortedTimes[line-1].id)} ></button> | 
						
						
						
						
							 | 
							
								 | 
							
							                {/if} | 
						
						
						
						
							 | 
							
								 | 
							
							            </td> | 
						
						
						
						
							 | 
							
								 | 
							
							            <td class="duration" onclick={e => {detail = time.id}}> | 
						
						
						
						
							 | 
							
								 | 
							
							                {#if time.duration} | 
						
						
						
						
							 | 
							
								 | 
							
							                {time.duration.toFixed(3)} h | 
						
						
						
						
							 | 
							
								 | 
							
							                {/if} | 
						
						
						
						
							 | 
							
								 | 
							
							            </td> | 
						
						
						
						
							 | 
							
								 | 
							
							            <td class="user" onclick={e => {detail = time.id}}> | 
						
						
						
						
							 | 
							
								 | 
							
							                {users[time.user_id].name} | 
						
						
						
						
							 | 
							
								 | 
							
							            </td> | 
						
						
						
						
							 | 
							
								 | 
							
							            <td class="subject" onclick={e => {detail = time.id}}> | 
						
						
						
						
							 | 
							
								 | 
							
							                {time.subject} | 
						
						
						
						
							 | 
							
								 | 
							
							            </td> | 
						
						
						
						
							 | 
							
								 | 
							
							            <td class="tasks"> | 
						
						
						
						
							 | 
							
								 | 
							
							            <ul> | 
						
						
						
						
							 | 
							
								 | 
							
							                {#each time.task_ids as tid} | 
						
						
						
						
							 | 
							
								 | 
							
							                {#if tasks[tid]} | 
						
						
						
						
							 | 
							
								 | 
							
							                <li> | 
						
						
						
						
							 | 
							
								 | 
							
							                    {#if tasks[tid] && projects[tasks[tid].project_id]} | 
						
						
						
						
							 | 
							
								 | 
							
							                    <a href="/project/{tasks[tid].project_id}/view" {onclick}>{projects[tasks[tid].project_id].name}</a> / | 
						
						
						
						
							 | 
							
								 | 
							
							                    {/if} | 
						
						
						
						
							 | 
							
								 | 
							
							                    <a href="/task/{tid}/view" {onclick}>{tasks[tid].name}</a> | 
						
						
						
						
							 | 
							
								 | 
							
							                    <button class="symbol" title={t('timetracking')} onclick={e => addTime(tid)}></button> | 
						
						
						
						
							 | 
							
								 | 
							
							                </li> | 
						
						
						
						
							 | 
							
								 | 
							
							                {/if} | 
						
						
						
						
							 | 
							
								 | 
							
							                {/each} | 
						
						
						
						
							 | 
							
								 | 
							
							            </ul> | 
						
						
						
						
							 | 
							
								 | 
							
							            </td> | 
						
						
						
						
							 | 
							
								 | 
							
							            <td class="state" onclick={e => {detail = time.id}}> | 
						
						
						
						
							 | 
							
								 | 
							
							                {t("state_"+time.state.name.toLowerCase())} | 
						
						
						
						
							 | 
							
								 | 
							
							                {#if time.state.name.toLowerCase() == 'pending' && docLinks[time.id]} | 
						
						
						
						
							 | 
							
								 | 
							
							                <ul> | 
						
						
						
						
							 | 
							
								 | 
							
							                    {#each Object.entries(docLinks[time.id]) as [a,b]} | 
						
						
						
						
							 | 
							
								 | 
							
							                    <li> | 
						
						
						
						
							 | 
							
								 | 
							
							                        <a href="/document/{a}/view" {onclick}>{b}</a> | 
						
						
						
						
							 | 
							
								 | 
							
							                    </li> | 
						
						
						
						
							 | 
							
								 | 
							
							                    {/each} | 
						
						
						
						
							 | 
							
								 | 
							
							                </ul> | 
						
						
						
						
							 | 
							
								 | 
							
							                {/if} | 
						
						
						
						
							 | 
							
								 | 
							
							            </td> | 
						
						
						
						
							 | 
							
								 | 
							
							            {/if} | 
						
						
						
						
							 | 
							
								 | 
							
							        </tr> | 
						
						
						
						
							 | 
							
								 | 
							
							        {/if} | 
						
						
						
						
							 | 
							
								 | 
							
							        {/each} | 
						
						
						
						
							 | 
							
								 | 
							
							    </tbody> | 
						
						
						
						
							 | 
							
								 | 
							
							</table> | 
						
						
						
						
							 | 
							
								 | 
							
							{/if}
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 |