implemented task creation right from the canban
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -129,6 +129,10 @@ public class Task implements Mappable {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var status = Status.OPEN;
|
var status = Status.OPEN;
|
||||||
|
if (json.has(STATUS) && json.get(STATUS) instanceof JSONObject state){
|
||||||
|
if (state.get(CODE) instanceof Number code) status = Status.of(code.intValue());
|
||||||
|
if (state.get(CODE) instanceof String code) status = Status.valueOf(code);
|
||||||
|
}
|
||||||
Double estimatedTime = null;
|
Double estimatedTime = null;
|
||||||
if (json.has(ESTIMATED_TIME)) {
|
if (json.has(ESTIMATED_TIME)) {
|
||||||
if (json.get(ESTIMATED_TIME) instanceof Number est) estimatedTime = est.doubleValue();
|
if (json.get(ESTIMATED_TIME) instanceof Number est) estimatedTime = est.doubleValue();
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
import ViewTask from "./routes/task/View.svelte";
|
import ViewTask from "./routes/task/View.svelte";
|
||||||
|
|
||||||
let translations_ready = $state(false);
|
let translations_ready = $state(false);
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await loadTranslation('de','Login');
|
await loadTranslation('de','Login');
|
||||||
translations_ready = true;
|
translations_ready = true;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
let {
|
let {
|
||||||
editable = false,
|
editable = false,
|
||||||
onclick = evt => {},
|
onclick = evt => { startEdit() },
|
||||||
onSet = newVal => {return true;},
|
onSet = newVal => {return true;},
|
||||||
type = 'div',
|
type = 'div',
|
||||||
value = $bindable(null)
|
value = $bindable(null)
|
||||||
@@ -84,5 +84,5 @@
|
|||||||
{#if editable && editing}
|
{#if editable && editing}
|
||||||
<input bind:value={editValue} onkeyup={typed} autofocus />
|
<input bind:value={editValue} onkeyup={typed} autofocus />
|
||||||
{:else}
|
{:else}
|
||||||
<svelte:element this={type} {onmousedown} {onmouseup} {ontouchstart} {ontouchend} class={{editable}} title={t('double_click_to_edit')} >{value}</svelte:element>
|
<svelte:element this={type} {onclick} {onmousedown} {onmouseup} {ontouchstart} {ontouchend} class={{editable}} title={t('double_click_to_edit')} >{value}</svelte:element>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
|
|
||||||
import { api } from '../../urls.svelte.js';
|
import { api } from '../../urls.svelte.js';
|
||||||
import { t } from '../../translations.svelte.js';
|
import { t } from '../../translations.svelte.js';
|
||||||
|
import { user } from '../../user.svelte.js';
|
||||||
|
|
||||||
import Card from './KanbanCard.svelte';
|
import Card from './KanbanCard.svelte';
|
||||||
|
import LineEditor from '../../Components/LineEditor.svelte';
|
||||||
|
|
||||||
let { id } = $props();
|
let { id } = $props();
|
||||||
|
|
||||||
@@ -21,6 +23,34 @@
|
|||||||
let users = {};
|
let users = {};
|
||||||
let ready = $state(false);
|
let ready = $state(false);
|
||||||
|
|
||||||
|
async function create(name,user_id,state){
|
||||||
|
var url = api('task/add');
|
||||||
|
let task = {
|
||||||
|
description: '',
|
||||||
|
members : {},
|
||||||
|
name: name,
|
||||||
|
project_id: +id,
|
||||||
|
status : { code : +state}
|
||||||
|
}
|
||||||
|
task.members[user_id] = { permission: { name : 'ASSIGNEE' }};
|
||||||
|
task.members[user.id] = { permission: { name : 'OWNER' }};
|
||||||
|
const resp = await fetch(url,{
|
||||||
|
credentials:'include',
|
||||||
|
method:'POST',
|
||||||
|
body: JSON.stringify(task)
|
||||||
|
});
|
||||||
|
if (resp.ok) {
|
||||||
|
task = await resp.json();
|
||||||
|
task.assignee = user_id;
|
||||||
|
if (!tasks[user_id]) tasks[user_id] = {};
|
||||||
|
if (!tasks[user_id][state]) tasks[user_id][state] = {};
|
||||||
|
tasks[user_id][state][task.id] = task;
|
||||||
|
error = null;
|
||||||
|
} else {
|
||||||
|
error = await resp.text();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function load(){
|
async function load(){
|
||||||
await loadProject();
|
await loadProject();
|
||||||
await loadStates();
|
await loadStates();
|
||||||
@@ -88,13 +118,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function drop(user,state){
|
async function drop(user_id,state){
|
||||||
let task = dragged;
|
let task = dragged;
|
||||||
dragged = null;
|
dragged = null;
|
||||||
highlight = {};
|
highlight = {};
|
||||||
if (task.assignee == user && task.status.code == state) return; // no change
|
if (task.assignee == user_id && task.status.code == state) return; // no change
|
||||||
let patch = {members:{},status:+state}
|
let patch = {members:{},status:+state}
|
||||||
patch.members[user] = 'ASSIGNEE';
|
patch.members[user_id] = 'ASSIGNEE';
|
||||||
|
|
||||||
const url = api(`task/${task.id}`);
|
const url = api(`task/${task.id}`);
|
||||||
const resp = await fetch(url,{
|
const resp = await fetch(url,{
|
||||||
@@ -104,10 +134,10 @@
|
|||||||
});
|
});
|
||||||
if (resp.ok){
|
if (resp.ok){
|
||||||
delete tasks[task.assignee][task.status.code][task.id]
|
delete tasks[task.assignee][task.status.code][task.id]
|
||||||
if (!tasks[user]) tasks[user] = {}
|
if (!tasks[user_id]) tasks[user_id] = {}
|
||||||
if (!tasks[user][state]) tasks[user][state] = {}
|
if (!tasks[user_id][state]) tasks[user_id][state] = {}
|
||||||
tasks[user][state][task.id] = task;
|
tasks[user_id][state][task.id] = task;
|
||||||
task.assignee = user;
|
task.assignee = user_id;
|
||||||
task.status = {code:state,name:states[state]};
|
task.status = {code:state,name:states[state]};
|
||||||
error = null;
|
error = null;
|
||||||
} else {
|
} else {
|
||||||
@@ -115,9 +145,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function hover(ev,user,state){
|
function hover(ev,user_id,state){
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
highlight = {user:user,state:state};
|
highlight = {user:user_id,state:state};
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(load);
|
onMount(load);
|
||||||
@@ -147,6 +177,9 @@
|
|||||||
<Card onclick={() => router.navigate(`/task/${task.id}/view`)} ondragstart={ev => dragged=task} {task} />
|
<Card onclick={() => router.navigate(`/task/${task.id}/view`)} ondragstart={ev => dragged=task} {task} />
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
|
<div class="add_task">
|
||||||
|
<LineEditor value={t('add_task')} editable={true} onSet={(name) => create(name,uid,state)}/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
{/each}
|
{/each}
|
||||||
|
|||||||
@@ -293,7 +293,10 @@ public class TaskModule extends BaseHandler implements TaskService {
|
|||||||
long userId = Long.parseLong(key);
|
long userId = Long.parseLong(key);
|
||||||
if (!(memberData.get(key) instanceof JSONObject nested)) throw invalidFieldException("members."+userId,"JSON");
|
if (!(memberData.get(key) instanceof JSONObject nested)) throw invalidFieldException("members."+userId,"JSON");
|
||||||
if (!(nested.has(PERMISSION) && nested.get(PERMISSION) instanceof JSONObject permission)) throw invalidFieldException("members."+userId+".permission","JSON");
|
if (!(nested.has(PERMISSION) && nested.get(PERMISSION) instanceof JSONObject permission)) throw invalidFieldException("members."+userId+".permission","JSON");
|
||||||
if (!(permission.has(CODE) && permission.get(CODE) instanceof Number code)) throw invalidFieldException("members."+userId+".permission.code","int");
|
Permission perm = null;
|
||||||
|
if (permission.has(CODE) && permission.get(CODE) instanceof Number code) perm = Permission.of(code.intValue());
|
||||||
|
if (permission.has(NAME) && permission.get(NAME) instanceof String name) perm = Permission.valueOf(name);
|
||||||
|
if (perm == null) throw invalidFieldException("members."+userId+".permission.code","int");
|
||||||
if (!project.members().containsKey(userId)) {
|
if (!project.members().containsKey(userId)) {
|
||||||
String username = nested.has(USER) && nested.get(USER) instanceof JSONObject userData && userData.get(NAME) instanceof String n ? n : key;
|
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);
|
throw new UmbrellaException(HTTP_BAD_REQUEST,"User {0} is no member of the leading project and cannot be assigned to this task",username);
|
||||||
@@ -304,10 +307,11 @@ public class TaskModule extends BaseHandler implements TaskService {
|
|||||||
task = taskDb.save(task);
|
task = taskDb.save(task);
|
||||||
for (var key : memberData.keySet()){
|
for (var key : memberData.keySet()){
|
||||||
long userId = Long.parseLong(key);
|
long userId = Long.parseLong(key);
|
||||||
var code = memberData.getJSONObject(key).getJSONObject(PERMISSION).getInt(CODE);
|
var nested = memberData.getJSONObject(key).getJSONObject(PERMISSION);
|
||||||
taskDb.setMember(task.id(),userId,Permission.of(code));
|
var permission = nested.has(CODE) ? Permission.of(nested.getInt(CODE)) : Permission.valueOf(nested.getString(NAME));
|
||||||
|
taskDb.setMember(task.id(),userId,permission);
|
||||||
}
|
}
|
||||||
return sendContent(ex,task);
|
return sendContent(ex,loadMembers(task));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean postTaskList(UmbrellaUser user, HttpExchange ex) throws IOException {
|
private boolean postTaskList(UmbrellaUser user, HttpExchange ex) throws IOException {
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ textarea{
|
|||||||
font-weight: black;
|
font-weight: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.kanban .add_task,
|
||||||
.kanban .box,
|
.kanban .box,
|
||||||
.kanban .head,
|
.kanban .head,
|
||||||
.kanban .user{
|
.kanban .user{
|
||||||
@@ -156,6 +157,7 @@ textarea{
|
|||||||
background: orange;
|
background: orange;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
.kanban .add_task,
|
||||||
.kanban .head,
|
.kanban .head,
|
||||||
.kanban .user{
|
.kanban .user{
|
||||||
background: black;
|
background: black;
|
||||||
|
|||||||
Reference in New Issue
Block a user