| 
							
								 | 
							
							<script> | 
						
						
						
						
							 | 
							
								 | 
							
							    import { onMount }       from 'svelte'; | 
						
						
						
						
							 | 
							
								 | 
							
							    import { useTinyRouter } from 'svelte-tiny-router'; | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    import { api }           from '../../urls.svelte.js'; | 
						
						
						
						
							 | 
							
								 | 
							
							    import { error, yikes }  from '../../warn.svelte'; | 
						
						
						
						
							 | 
							
								 | 
							
							    import { t }             from '../../translations.svelte.js'; | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    let filter = $state(null); | 
						
						
						
						
							 | 
							
								 | 
							
							    let lower_filter = $derived(filter.toLowerCase()); | 
						
						
						
						
							 | 
							
								 | 
							
							    let inverted_filter = $state(false); | 
						
						
						
						
							 | 
							
								 | 
							
							    let projects = $state({}); | 
						
						
						
						
							 | 
							
								 | 
							
							    let router = useTinyRouter(); | 
						
						
						
						
							 | 
							
								 | 
							
							    let tasks = $state(null); | 
						
						
						
						
							 | 
							
								 | 
							
							    let bounds = $state({offset:0,limit:256}); | 
						
						
						
						
							 | 
							
								 | 
							
							    let loading = $state(true); | 
						
						
						
						
							 | 
							
								 | 
							
							    let map = $state({}); | 
						
						
						
						
							 | 
							
								 | 
							
							    let hidden = $state({}); | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    async function changeState(idx,state){ | 
						
						
						
						
							 | 
							
								 | 
							
							        const task = tasks[idx]; | 
						
						
						
						
							 | 
							
								 | 
							
							        const tid = task.id; | 
						
						
						
						
							 | 
							
								 | 
							
							        const prj  = projects[task.project_id]; | 
						
						
						
						
							 | 
							
								 | 
							
							        const stat = Object.keys(prj.allowed_states).find(k => prj.allowed_states[k] === state); | 
						
						
						
						
							 | 
							
								 | 
							
							        const url  = api(`task/${tid}`); | 
						
						
						
						
							 | 
							
								 | 
							
							        const resp = await fetch(url,{ | 
						
						
						
						
							 | 
							
								 | 
							
							            credentials : 'include', | 
						
						
						
						
							 | 
							
								 | 
							
							            method      : 'PATCH', | 
						
						
						
						
							 | 
							
								 | 
							
							            body        : JSON.stringify({status:stat}) | 
						
						
						
						
							 | 
							
								 | 
							
							        }); | 
						
						
						
						
							 | 
							
								 | 
							
							        if (resp.ok){ | 
						
						
						
						
							 | 
							
								 | 
							
							            tasks[idx] = await resp.json(); | 
						
						
						
						
							 | 
							
								 | 
							
							        } else { | 
						
						
						
						
							 | 
							
								 | 
							
							            error(resp); | 
						
						
						
						
							 | 
							
								 | 
							
							        } | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    function abort(idx){ | 
						
						
						
						
							 | 
							
								 | 
							
							        changeState(idx,'CANCELLED'); | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    function complete(idx){ | 
						
						
						
						
							 | 
							
								 | 
							
							        changeState(idx,'COMPLETE'); | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    function edit(tid){ | 
						
						
						
						
							 | 
							
								 | 
							
							        router.navigate(`/task/${tid}/edit`); | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    function filterApplies(task){ | 
						
						
						
						
							 | 
							
								 | 
							
							        if (!filter) return !inverted_filter; | 
						
						
						
						
							 | 
							
								 | 
							
							        if (task.name.toLowerCase().includes(lower_filter)) return !inverted_filter; | 
						
						
						
						
							 | 
							
								 | 
							
							        if (task.description.source.toLowerCase().includes(lower_filter)) return !inverted_filter; | 
						
						
						
						
							 | 
							
								 | 
							
							        if (projects[task.project_id].name.toLowerCase().includes(lower_filter)) return !inverted_filter; | 
						
						
						
						
							 | 
							
								 | 
							
							        if (task.parent_task_id){ | 
						
						
						
						
							 | 
							
								 | 
							
							            const parent = map[task.parent_task_id]; | 
						
						
						
						
							 | 
							
								 | 
							
							            if (parent && parent.name.toLowerCase().includes(lower_filter)) return !inverted_filter; | 
						
						
						
						
							 | 
							
								 | 
							
							        } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							        return inverted_filter; | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    function go(module, id){ | 
						
						
						
						
							 | 
							
								 | 
							
							        router.navigate(`/${module}/${id}/view`); | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    async function loadProject(pid){ | 
						
						
						
						
							 | 
							
								 | 
							
							        const url  = api(`project/${pid}`); | 
						
						
						
						
							 | 
							
								 | 
							
							        const resp = await fetch(url,{credentials:'include'}); | 
						
						
						
						
							 | 
							
								 | 
							
							        if (resp.ok){ | 
						
						
						
						
							 | 
							
								 | 
							
							            projects[pid] = await resp.json(); | 
						
						
						
						
							 | 
							
								 | 
							
							        } else { | 
						
						
						
						
							 | 
							
								 | 
							
							            error(resp); | 
						
						
						
						
							 | 
							
								 | 
							
							        } | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    async function load(){ | 
						
						
						
						
							 | 
							
								 | 
							
							        const url  = api(`task?offset=${bounds.offset}&limit=${bounds.limit}`); | 
						
						
						
						
							 | 
							
								 | 
							
							        const resp = await fetch(url,{credentials:'include'}); | 
						
						
						
						
							 | 
							
								 | 
							
							        if (resp.ok){ | 
						
						
						
						
							 | 
							
								 | 
							
							            let newTasks = await resp.json(); | 
						
						
						
						
							 | 
							
								 | 
							
							            if (bounds.offset == 0) { | 
						
						
						
						
							 | 
							
								 | 
							
							                tasks = newTasks; | 
						
						
						
						
							 | 
							
								 | 
							
							            } else tasks = tasks.concat(newTasks); | 
						
						
						
						
							 | 
							
								 | 
							
							            loading = newTasks.length; | 
						
						
						
						
							 | 
							
								 | 
							
							            if (loading){ | 
						
						
						
						
							 | 
							
								 | 
							
							                for (let task of newTasks) { | 
						
						
						
						
							 | 
							
								 | 
							
							                    map[task.id] = task; | 
						
						
						
						
							 | 
							
								 | 
							
							                    if (task.parent_task_id) hidden[task.parent_task_id] = true; | 
						
						
						
						
							 | 
							
								 | 
							
							                    let pid = task.project_id; | 
						
						
						
						
							 | 
							
								 | 
							
							                    if (pid && !projects[pid]) await loadProject(pid); | 
						
						
						
						
							 | 
							
								 | 
							
							                } | 
						
						
						
						
							 | 
							
								 | 
							
							                bounds.offset += bounds.limit; | 
						
						
						
						
							 | 
							
								 | 
							
							                load(); | 
						
						
						
						
							 | 
							
								 | 
							
							            } | 
						
						
						
						
							 | 
							
								 | 
							
							        } else { | 
						
						
						
						
							 | 
							
								 | 
							
							            error(resp); | 
						
						
						
						
							 | 
							
								 | 
							
							        } | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    function open(idx){ | 
						
						
						
						
							 | 
							
								 | 
							
							        changeState(idx,'OPEN'); | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    function postpone(idx){ | 
						
						
						
						
							 | 
							
								 | 
							
							        changeState(idx,'PENDING'); | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    function start(idx){ | 
						
						
						
						
							 | 
							
								 | 
							
							        changeState(idx,'STARTED'); | 
						
						
						
						
							 | 
							
								 | 
							
							    } | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							    onMount(load); | 
						
						
						
						
							 | 
							
								 | 
							
							</script> | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							<svelte:head> | 
						
						
						
						
							 | 
							
								 | 
							
							    <title>Umbrella – {t('tasks')}</title> | 
						
						
						
						
							 | 
							
								 | 
							
							</svelte:head> | 
						
						
						
						
							 | 
							
								 | 
							
							 | 
						
						
						
						
							 | 
							
								 | 
							
							<fieldset> | 
						
						
						
						
							 | 
							
								 | 
							
							    <legend>{loading ? t('loading_object',{object:t('task_list')}) : t('task_list')}</legend> | 
						
						
						
						
							 | 
							
								 | 
							
							    <div class="filter"> | 
						
						
						
						
							 | 
							
								 | 
							
							        <label> | 
						
						
						
						
							 | 
							
								 | 
							
							            {t('filter')}: <input type="text" bind:value={filter} > | 
						
						
						
						
							 | 
							
								 | 
							
							        </label> | 
						
						
						
						
							 | 
							
								 | 
							
							        {#if filter} | 
						
						
						
						
							 | 
							
								 | 
							
							        <label> | 
						
						
						
						
							 | 
							
								 | 
							
							            <input type="checkbox" bind:checked={inverted_filter} /> | 
						
						
						
						
							 | 
							
								 | 
							
							            {t('invert_filter')} | 
						
						
						
						
							 | 
							
								 | 
							
							        </label> | 
						
						
						
						
							 | 
							
								 | 
							
							        {/if} | 
						
						
						
						
							 | 
							
								 | 
							
							    </div> | 
						
						
						
						
							 | 
							
								 | 
							
							    {#if tasks} | 
						
						
						
						
							 | 
							
								 | 
							
							    <table> | 
						
						
						
						
							 | 
							
								 | 
							
							        <thead> | 
						
						
						
						
							 | 
							
								 | 
							
							            <tr> | 
						
						
						
						
							 | 
							
								 | 
							
							                <th>{t('name')}</th> | 
						
						
						
						
							 | 
							
								 | 
							
							                <th>{t('project')} ({t('parent_task')})</th> | 
						
						
						
						
							 | 
							
								 | 
							
							                <th>{t('state')}</th> | 
						
						
						
						
							 | 
							
								 | 
							
							                <th>{t('start_date')}</th> | 
						
						
						
						
							 | 
							
								 | 
							
							                <th>{t('due_date')}</th> | 
						
						
						
						
							 | 
							
								 | 
							
							                <th>{t('actions')}</th> | 
						
						
						
						
							 | 
							
								 | 
							
							            </tr> | 
						
						
						
						
							 | 
							
								 | 
							
							        </thead> | 
						
						
						
						
							 | 
							
								 | 
							
							        <tbody> | 
						
						
						
						
							 | 
							
								 | 
							
							            {#each tasks as task,idx} | 
						
						
						
						
							 | 
							
								 | 
							
							            {#if task.status > 10 && task.status < 60 && !task.no_index && projects[task.project_id]?.status < 60 && !hidden[task.id] && filterApplies(task)} | 
						
						
						
						
							 | 
							
								 | 
							
							            <tr> | 
						
						
						
						
							 | 
							
								 | 
							
							                <td onclick={() => go('task',task.id)}>{task.name}</td> | 
						
						
						
						
							 | 
							
								 | 
							
							                <td> | 
						
						
						
						
							 | 
							
								 | 
							
							                    <a href="#" onclick={() => go('project',task.project_id)}> {projects[task.project_id]?.name}</a> | 
						
						
						
						
							 | 
							
								 | 
							
							                    {#if task.parent_task_id} | 
						
						
						
						
							 | 
							
								 | 
							
							                    : <a href="#" onclick={() => go('task',task.parent_task_id)}>{map[task.parent_task_id]?.name}</a> | 
						
						
						
						
							 | 
							
								 | 
							
							                    {/if} | 
						
						
						
						
							 | 
							
								 | 
							
							                </td> | 
						
						
						
						
							 | 
							
								 | 
							
							                <td> | 
						
						
						
						
							 | 
							
								 | 
							
							                    {task.status % 10 ? projects[task.project_id]?.allowed_states[task.status] : t('state_'+projects[task.project_id]?.allowed_states[task.status]?.toLowerCase())} | 
						
						
						
						
							 | 
							
								 | 
							
							                </td> | 
						
						
						
						
							 | 
							
								 | 
							
							                <td> | 
						
						
						
						
							 | 
							
								 | 
							
							                    {task.start_date} | 
						
						
						
						
							 | 
							
								 | 
							
							                </td> | 
						
						
						
						
							 | 
							
								 | 
							
							                <td> | 
						
						
						
						
							 | 
							
								 | 
							
							                    {task.due_date} | 
						
						
						
						
							 | 
							
								 | 
							
							                </td> | 
						
						
						
						
							 | 
							
								 | 
							
							                <td> | 
						
						
						
						
							 | 
							
								 | 
							
							                    <button class="symbol" onclick={() => edit(task.id)} title={t('edit')} ></button> | 
						
						
						
						
							 | 
							
								 | 
							
							                    <button class="symbol" onclick={() => postpone(idx)} title={t('postpone')} ></button> | 
						
						
						
						
							 | 
							
								 | 
							
							                    <button class="symbol" onclick={() => open(idx)} title={t('state_open')}></button> | 
						
						
						
						
							 | 
							
								 | 
							
							                    <button class="symbol" onclick={() => start(idx)} title={t('start')} ></button> | 
						
						
						
						
							 | 
							
								 | 
							
							                    <button class="symbol" onclick={() => complete(idx)} title={t('complete')} ></button> | 
						
						
						
						
							 | 
							
								 | 
							
							                    <button class="symbol" onclick={() => abort(idx)} title={t('abort')} ></button> | 
						
						
						
						
							 | 
							
								 | 
							
							                </td> | 
						
						
						
						
							 | 
							
								 | 
							
							            </tr> | 
						
						
						
						
							 | 
							
								 | 
							
							            {/if} | 
						
						
						
						
							 | 
							
								 | 
							
							            {/each} | 
						
						
						
						
							 | 
							
								 | 
							
							        </tbody> | 
						
						
						
						
							 | 
							
								 | 
							
							    </table> | 
						
						
						
						
							 | 
							
								 | 
							
							    {/if} | 
						
						
						
						
							 | 
							
								 | 
							
							</fieldset> |