OpenSource Projekt-Management-Software
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

119 lines
4.2 KiB

<script>
import { onMount } from 'svelte';
import { useTinyRouter } from 'svelte-tiny-router';
import { api } from '../../urls.svelte.js';
import { t } from '../../translations.svelte.js';
const router = useTinyRouter();
let error = $state(null);
let projects = $state(null);
let companies = $state(null);
let showClosed = $state(router.query.closed == "show");
let sortedProjects = $derived.by(() => Object.values(projects).sort((a, b) => a.name.localeCompare(b.name)));
async function loadProjects(){
let url = api('company/list');
let resp = await fetch(url,{credentials:'include'});
if (resp.ok){
companies = await resp.json();
url = `${location.protocol}//${location.host.replace('5173','8080')}/api/project/list`;
resp = await fetch(url,{
credentials : 'include',
method : 'POST',
body : JSON.stringify({show_closed:showClosed})
});
if (resp.ok){
projects = await resp.json();
} else {
error = await resp.text();
}
} else {
error = await resp.text();
}
}
async function setState(pid,state_name){
const url = api(`project/${pid}`);
const resp = await fetch(url,{
credentials : 'include',
method : 'PATCH',
body : JSON.stringify({status:state_name})
});
if (resp.ok){
var prj = await resp.json();
projects[prj.id].status = prj.status;
} else {
error = await resp.text();
}
}
function show(pid){
router.navigate(`/project/${pid}/view`)
}
function toggleClosed(){
router.navigate(showClosed?'/project':'/project?closed=show');
showClosed = !showClosed;
loadProjects();
}
onMount(loadProjects);
</script>
{#if error}
<span class="error">{error}</span>
{/if}
<fieldset>
<legend>
{t('projects')}
<button onclick={() => router.navigate('/project/add')}><span class="symbol"></span> {t('create_new_project')}</button>
<button onclick={toggleClosed}><span class="symbol"></span> {t(showClosed?'hide_closed':'show_closed')}</button>
</legend>
{#if projects}
<table class="project list">
<thead>
<tr>
<th>{t('name')}</th>
<th>{t('company')}</th>
<th>{t('state')}</th>
<th>{t('members')}</th>
<th>{t('actions')}</th>
</tr>
</thead>
<tbody>
{#each sortedProjects as project}
<tr>
<td class="name">
<a href="" onclick={() => show(project.id)}>{project.name}</a>
</td>
<td class="company" onclick={() => show(project.id)} >
{#if project.company_id && companies[project.company_id]}
{companies[project.company_id].name}
{/if}
</td>
<td class="state" onclick={() => show(project.id)} >
{t("state_"+project.status.name.toLowerCase())}
</td>
<td class="members" onclick={() => show(project.id)} >
{#each Object.entries(project.members) as [uid,member]}
<div>{member.user.name}</div>
{/each}
</td>
<td class="actions">
<button class="edit symbol" title={t('edit')}></button>
{#if project.status.code < 60}
<button class="complete symbol" title={t('complete')} onclick={() => setState(project.id,'COMPLETE')} ></button>
<button class="abort symbol" title={t('abort')} onclick={() => setState(project.id,'CANCELLED')} ></button>
{:else}
<button class="open symbol" title={t('open')} onclick={() => setState(project.id,'OPEN')} ></button>
{/if}
</td>
</tr>
{/each}
</tbody>
</table>
{/if}
</fieldset>