Browse Source

kanban bugfixes & improvements

kanban
Stephan Richter 3 months ago
parent
commit
2ce9ebbc6d
  1. 69
      frontend/src/routes/project/Kanban.svelte
  2. 3
      frontend/src/routes/task/Add.svelte
  3. 23
      task/src/main/java/de/srsoftware/umbrella/task/TaskModule.java

69
frontend/src/routes/project/Kanban.svelte

@ -11,14 +11,16 @@ @@ -11,14 +11,16 @@
let router = useTinyRouter();
let states = $state(null);
let tasks = $state({});
let highlight = $state({});
let columns = $derived(states?Object.keys(states).length+1:1);
let dragged = null;
let users = {};
async function load(){
loadProject();
loadStates();
await loadTasks({project_id:+id,parent_task_id:0});
console.log(tasks);
}
async function loadProject(){
@ -53,28 +55,56 @@ @@ -53,28 +55,56 @@
});
if (resp.ok){
var json = await resp.json();
console.clear();
for (var task_id of Object.keys(json)) {
let task = json[task_id];
let state = task.status.name;
let state = task.status.code;
let owner = null;
let assignee = null;
for (var uid of Object.keys(task.members)){
var member = task.members[uid];
if (member.permission.name == 'OWNER') owner = member.user.name;
if (member.permission.name == 'ASSIGNEE') assignee = member.user.name;
for (var user_id of Object.keys(task.members)){
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;
if (!tasks[assignee]) tasks[assignee] = {};
if (!tasks[assignee][state]) tasks[assignee][state] = {};
tasks[assignee][state][task_id] = task;
}
console.log(tasks);
} else {
error = await resp.text();
}
}
async function drop(user,state){
let task = dragged;
dragged = null;
highlight = {};
if (task.assignee == user && task.status.code == state) return; // no change
let patch = {members:{},status:+state}
patch.members[user] = 'ASSIGNEE';
const url = api(`task/${task.id}`);
const resp = await fetch(url,{
credentials: 'include',
method: 'PATCH',
body: JSON.stringify(patch)
});
if (resp.ok){
delete tasks[task.assignee][task.status.code][task.id]
tasks[user][state][task.id] = task;
error = null;
} else {
error = await resp.text();
}
}
function hover(ev,user,state){
ev.preventDefault();
highlight = {user:user,state:state};
}
onMount(load);
</script>
@ -95,13 +125,13 @@ @@ -95,13 +125,13 @@
.user{
background: lime;
}
.empty{
background: repeating-linear-gradient(45deg,transparent,transparent 10px,#ccc 10px,#ccc 20px),linear-gradient(to bottom,#eee,#999);
.highlight{
background: red;
}
</style>
{#if project}
<h1>{project.name} : {t('kanban_view')}</h1>
<h1 onclick={ev => router.navigate(`/project/${project.id}/view`)}>{project.name}</h1>
{/if}
{#if error}
<span class="error">{error}</span>
@ -111,17 +141,18 @@ @@ -111,17 +141,18 @@
<div class="head">{t('user')}</div>
{#if states}
{#each Object.entries(states) as [sid,state]}
<div class="head">{t(state)}</div>
<div class="head">{t('state_'+state.toLowerCase())}</div>
{/each}
{/if}
{#each Object.entries(tasks) as [user,states]}
<div class="user">{user}</div>
{#each Object.entries(states) as [state,list]}
<div>
{#each Object.entries(list) as [tid,task]}
<div class="box" onclick={() => router.navigate(`/task/${task.id}/view`)}>{task.name}</div>
{#each Object.entries(tasks) as [user,stateList]}
<div class="user">{users[user]}</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)} >
{#if stateList[state]}
{#each Object.entries(stateList[state]) as [tid,task]}
<div draggable="true" class="box" onclick={() => router.navigate(`/task/${task.id}/view`)} ondragstart={ev => dragged=task} >{task.name}</div>
{/each}
<div class="empty box"></div>
{/if}
</div>
{/each}
{/each}

3
frontend/src/routes/task/Add.svelte

@ -111,6 +111,9 @@ @@ -111,6 +111,9 @@
<fieldset>
<legend>{t('add_task')}</legend>
{#if error}
<span class="error">{error}</span>
{/if}
<table {onkeydown}>
<tbody>
<tr>

23
task/src/main/java/de/srsoftware/umbrella/task/TaskModule.java

@ -218,13 +218,21 @@ public class TaskModule extends BaseHandler implements TaskService { @@ -218,13 +218,21 @@ public class TaskModule extends BaseHandler implements TaskService {
} catch (NumberFormatException e) {
throw invalidFieldException(USER_ID,"long");
}
if (!(json.get(key) instanceof Number number)) throw invalidFieldException(PERMISSION,"int");
var permission = Permission.of(number.intValue());
var permission = switch (json.get(key)){
case Number code -> Permission.of(code.intValue());
case String name -> Permission.valueOf(name);
default -> throw invalidFieldException(PERMISSION,"int / String");
};
if (permission == OWNER) { // if a new person is about to become the task owner
for (var member : members.values()){ // alter the previous owners to editors
if (member.permission() == OWNER) members.put(member.user().id(),new Member(member.user(),EDIT));
}
}
if (permission == ASSIGNEE) { // if a new person is about to become the task owner
for (var member : members.values()){ // alter the previous owners to editors
if (member.permission() == ASSIGNEE) members.put(member.user().id(),new Member(member.user(),EDIT));
}
}
members.put(userId,new Member(users.loadUser(userId),permission));
task.dirty(MEMBERS);
}
@ -253,8 +261,6 @@ public class TaskModule extends BaseHandler implements TaskService { @@ -253,8 +261,6 @@ public class TaskModule extends BaseHandler implements TaskService {
projects.loadMembers(List.of(project));
var member = project.members().get(user.id());
if (member == null || member.permission() == READ_ONLY) throw forbidden("You are not allowed to create new tasks in this project");
Task task = Task.of(json);
task = taskDb.save(task);
for (var key : memberData.keySet()){
long userId = Long.parseLong(key);
if (!(memberData.get(key) instanceof JSONObject nested)) throw invalidFieldException("members."+userId,"JSON");
@ -264,7 +270,14 @@ public class TaskModule extends BaseHandler implements TaskService { @@ -264,7 +270,14 @@ public class TaskModule extends BaseHandler implements TaskService {
String username = nested.has(USER) && nested.get(USER) instanceof JSONObject userData && userData.get(NAME) instanceof String n ? n : key;
throw new UmbrellaException(HTTP_BAD_REQUEST,"User {0} is no member of the leading project and cannot be assigned to this task",username);
}
taskDb.setMember(task.id(),userId,Permission.of(code.intValue()));
}
Task task = Task.of(json);
task = taskDb.save(task);
for (var key : memberData.keySet()){
long userId = Long.parseLong(key);
var code = memberData.getJSONObject(key).getJSONObject(PERMISSION).getInt(CODE);
taskDb.setMember(task.id(),userId,Permission.of(code));
}
return sendContent(ex,task);
}

Loading…
Cancel
Save