fine-tuning kanban
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -19,11 +19,13 @@
|
||||
let columns = $derived(states?Object.keys(states).length+1:1);
|
||||
let dragged = null;
|
||||
let users = {};
|
||||
let ready = $state(false);
|
||||
|
||||
async function load(){
|
||||
loadProject();
|
||||
loadStates();
|
||||
await loadProject();
|
||||
await loadStates();
|
||||
await loadTasks({project_id:+id,parent_task_id:0});
|
||||
ready = true;
|
||||
}
|
||||
|
||||
async function loadProject(){
|
||||
@@ -31,6 +33,11 @@
|
||||
const resp = await fetch(url,{credentials:'include'});
|
||||
if (resp.ok){
|
||||
project = await resp.json();
|
||||
for (var uid of Object.keys(project.members)){
|
||||
let member = project.members[uid];
|
||||
users[uid] = member.user.name;
|
||||
if (!tasks[uid]) tasks[uid] = {};
|
||||
}
|
||||
error = null;
|
||||
} else {
|
||||
error = await resp.text();
|
||||
@@ -68,7 +75,7 @@
|
||||
var member = task.members[user_id];
|
||||
if (member.permission.name == 'OWNER') owner = user_id;
|
||||
if (member.permission.name == 'ASSIGNEE') assignee = user_id;
|
||||
users[user_id] = member.user.name;
|
||||
|
||||
}
|
||||
if (!assignee) assignee = owner;
|
||||
task.assignee = assignee;
|
||||
@@ -116,31 +123,6 @@
|
||||
onMount(load);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.box,
|
||||
.head,
|
||||
.user{
|
||||
border-radius: 5px;
|
||||
margin: 2px;
|
||||
min-height: 50px;
|
||||
color: black;
|
||||
padding: 2px;
|
||||
}
|
||||
.box{
|
||||
background: orange;
|
||||
}
|
||||
.head,
|
||||
.user{
|
||||
background: black;
|
||||
border: 1px solid orange;
|
||||
color: orange;
|
||||
text-align: center;
|
||||
}
|
||||
.highlight{
|
||||
background: #4b3000;
|
||||
}
|
||||
</style>
|
||||
|
||||
{#if project}
|
||||
<h1 onclick={ev => router.navigate(`/project/${project.id}/view`)}>{project.name}</h1>
|
||||
{/if}
|
||||
@@ -148,6 +130,7 @@
|
||||
<span class="error">{error}</span>
|
||||
{/if}
|
||||
|
||||
{#if ready}
|
||||
<div class="kanban" style="display: grid; grid-template-columns: {`repeat(${columns}, auto)`}">
|
||||
<div class="head">{t('user')}</div>
|
||||
{#if states}
|
||||
@@ -155,10 +138,10 @@
|
||||
<div class="head">{t('state_'+state.toLowerCase())}</div>
|
||||
{/each}
|
||||
{/if}
|
||||
{#each Object.entries(tasks) as [user,stateList]}
|
||||
<div class="user">{users[user]}</div>
|
||||
{#each Object.entries(tasks) as [uid,stateList]}
|
||||
<div class="user">{users[uid]}</div>
|
||||
{#each Object.entries(states) as [state,name]}
|
||||
<div class={[state, highlight.user == user && highlight.state == state ? 'highlight':'']} ondragover={ev => hover(ev,user,state)} ondrop={ev => drop(user,state)} >
|
||||
<div class={[state, highlight.user == uid && highlight.state == state ? 'highlight':'']} ondragover={ev => hover(ev,uid,state)} ondrop={ev => drop(uid,state)} >
|
||||
{#if stateList[state]}
|
||||
{#each Object.values(stateList[state]).sort((a,b) => a.name.localeCompare(b.name)) as task}
|
||||
<Card onclick={() => router.navigate(`/task/${task.id}/view`)} ondragstart={ev => dragged=task} {task} />
|
||||
@@ -167,4 +150,5 @@
|
||||
</div>
|
||||
{/each}
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -1,7 +1,21 @@
|
||||
<script>
|
||||
let { ondragstart, task } = $props();
|
||||
let { onclick, ondragstart, task } = $props();
|
||||
</script>
|
||||
|
||||
<div draggable="true" class="box" {ondragstart} >
|
||||
{task.name}
|
||||
<div draggable="true" class="box" {onclick} {ondragstart} >
|
||||
<span class="title">{task.name}</span>
|
||||
{#if task.estimated_time}
|
||||
<span class="estimate">
|
||||
({task.estimated_time} h)
|
||||
</span>
|
||||
{/if}
|
||||
{#if task.due_date}
|
||||
<span class="due_date">
|
||||
{#if task.start_date}
|
||||
{task.start_date}
|
||||
{/if}
|
||||
→ {task.due_date}
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
@@ -146,22 +146,38 @@ textarea{
|
||||
.kanban .box,
|
||||
.kanban .head,
|
||||
.kanban .user{
|
||||
border-radius: 5px;
|
||||
margin: 2px;
|
||||
min-height: 50px;
|
||||
color: black;
|
||||
padding: 2px;
|
||||
}
|
||||
border-radius: 5px;
|
||||
margin: 2px;
|
||||
min-height: 50px;
|
||||
color: black;
|
||||
padding: 2px;
|
||||
}
|
||||
.kanban .box{
|
||||
background: orange;
|
||||
}
|
||||
background: orange;
|
||||
position: relative;
|
||||
}
|
||||
.kanban .head,
|
||||
.kanban .user{
|
||||
background: black;
|
||||
border: 1px solid orange;
|
||||
color: orange;
|
||||
text-align: center;
|
||||
}
|
||||
background: black;
|
||||
border: 1px solid orange;
|
||||
color: orange;
|
||||
text-align: center;
|
||||
}
|
||||
.kanban .highlight{
|
||||
background: #4b3000;
|
||||
}
|
||||
background: #4b3000;
|
||||
}
|
||||
.kanban .estimate{
|
||||
border: 0 none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
font-weight: bold;
|
||||
font-size: 0.6em;
|
||||
}
|
||||
.kanban .due_date{
|
||||
position: absolute;
|
||||
font-weight: bold;
|
||||
font-size: 0.6em;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user