diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Task.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Task.java
index 4503c1c..f5a00ca 100644
--- a/core/src/main/java/de/srsoftware/umbrella/core/model/Task.java
+++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Task.java
@@ -171,7 +171,7 @@ public class Task implements Mappable {
case MEMBERS: continue;
case NAME: name = json.getString(key); break;
case NO_INDEX: noIndex = json.getBoolean(NO_INDEX); break;
- case PARENT_TASK_ID: parentTaskId = json.getLong(PARENT_TASK_ID); break;
+ case PARENT_TASK_ID: parentTaskId = json.isNull(PARENT_TASK_ID) ? null : json.getLong(PARENT_TASK_ID); break;
case PRIORITY: priority = json.getInt(PRIORITY); break;
case REQUIRED_TASKS_IDS:
requiredTasksIds.clear();
diff --git a/frontend/src/routes/task/Index.svelte b/frontend/src/routes/task/Index.svelte
index c536f0f..0cb7461 100644
--- a/frontend/src/routes/task/Index.svelte
+++ b/frontend/src/routes/task/Index.svelte
@@ -14,8 +14,9 @@
let map = $state({});
let hidden = $state({});
- async function changeState(tid,state){
- const task = tasks[tid];
+ 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}`);
@@ -25,18 +26,18 @@
body : JSON.stringify({status:stat})
});
if (resp.ok){
- tasks[tid] = await resp.json();
+ tasks[idx] = await resp.json();
} else {
error(resp);
}
}
- function abort(tid){
- changeState(tid,'CANCELLED');
+ function abort(idx){
+ changeState(idx,'CANCELLED');
}
- function complete(tid){
- changeState(tid,'COMPLETE');
+ function complete(idx){
+ changeState(idx,'COMPLETE');
}
function edit(tid){
@@ -81,16 +82,16 @@
}
}
- function open(tid){
- changeState(tid,'OPEN');
+ function open(idx){
+ changeState(idx,'OPEN');
}
- function postpone(tid){
- changeState(tid,'PENDING');
+ function postpone(idx){
+ changeState(idx,'PENDING');
}
- function start(tid){
- changeState(tid,'STARTED');
+ function start(idx){
+ changeState(idx,'STARTED');
}
onMount(load);
@@ -115,7 +116,7 @@
- {#each tasks as task (task.id)}
+ {#each tasks as task,idx}
{#if task.status > 10 && task.status < 60 && !task.no_index && projects[task.project_id]?.status < 60 && !hidden[task.id]}
| go('task',task.id)}>{task.name} |
@@ -136,11 +137,11 @@
-
-
-
-
-
+
+
+
+
+
|
{/if}
diff --git a/frontend/src/routes/task/View.svelte b/frontend/src/routes/task/View.svelte
index 9434461..193eeb9 100644
--- a/frontend/src/routes/task/View.svelte
+++ b/frontend/src/routes/task/View.svelte
@@ -140,6 +140,10 @@
showSettings = !showSettings;
}
+ function unlink_parent(){
+ update({parent_task_id:null});
+ }
+
async function update(data){
const url = api(`task/${id}`);
const resp = await fetch(url,{
@@ -151,7 +155,11 @@
yikes();
let old_task = task;
task = await resp.json();
- if (task.parent_id == old_task.parent_id) task.parent = old_task.parent;
+ if (!task.parent_id){
+ task.parent = null;
+ } else {
+ if (task.parent_id == old_task.parent_id) task.parent = old_task.parent;
+ }
return true;
} else {
error(resp);
@@ -196,6 +204,7 @@
{t('parent_task')}
{/if}
{t('task')}
diff --git a/frontend/src/routes/time/Index.svelte b/frontend/src/routes/time/Index.svelte
index 33653f1..20c845c 100644
--- a/frontend/src/routes/time/Index.svelte
+++ b/frontend/src/routes/time/Index.svelte
@@ -10,12 +10,15 @@
import TimeEditor from '../../Components/TimeRecordEditor.svelte';
+ let detail = $state(null);
let docLinks = $state(null);
let router = useTinyRouter();
+
let times = $state(null);
let tasks = {};
let projects = {};
- let detail = $state(null);
+ let project_filter = $state(null);
+ if (router.hasQueryParam('project')) project_filter = router.getQueryParam('project');
let sortedTimes = $derived.by(() => Object.values(times).map(time => ({
...time,
start: display(time.start_time),
@@ -114,6 +117,14 @@
}
}
+ function match_prj_filter(time){
+ if (!project_filter) return true;
+ for (var tid of time.task_ids){
+ if (project_filter == tasks[tid].project_id) return true;
+ }
+ return false;
+ }
+
function onAbort(){
detail = null;
}
@@ -217,6 +228,7 @@
{#each sortedTimes as time,line}
+ {#if match_prj_filter(time)}
{#if timeMap.years[line]}
| toggleRange(time.start.substring(0,4))}>
@@ -279,6 +291,7 @@
|
{/if}
+ {/if}
{/each}
diff --git a/web/src/main/resources/web/css/bloodshed-color.css b/web/src/main/resources/web/css/bloodshed-color.css
index 78bcbd4..d6f08d0 100644
--- a/web/src/main/resources/web/css/bloodshed-color.css
+++ b/web/src/main/resources/web/css/bloodshed-color.css
@@ -46,6 +46,11 @@ textarea{
background-color: black;
}
+tr:hover{
+ background: darkred;
+ color: black;
+}
+
.archive{
background: red;
color: black;
@@ -155,15 +160,21 @@ textarea{
color: yellow;
}
-.timetracks .year, .month{
- border-color: 1px solid;
-}
-
.timetracks .selected td:not(.year):not(.month){
background-color: darkred;
color: orange;
}
+.timetracks.sum {
+ background: black;
+}
+
+.timetracks .year, .month{
+ border-color: 1px solid;
+}
+
+
+
.warn {
background-color: yellow;
color: black;
diff --git a/web/src/main/resources/web/css/bloodshed.css b/web/src/main/resources/web/css/bloodshed.css
index 0585de2..31ad291 100644
--- a/web/src/main/resources/web/css/bloodshed.css
+++ b/web/src/main/resources/web/css/bloodshed.css
@@ -290,11 +290,31 @@ span.timetracking {
display: inline-block;
}
+.markdown.editing{
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ column-gap: 10px;
+}
+.markdown .buttons,
+.markdown .hint{
+ grid-column-end: span 2;
+}
+
+.editable:hover{
+ border: 1px dotted;
+}
.timetracks .year, .timetracks .month{
border: 1px solid;
}
+.timetracks.sum {
+ position: sticky;
+ top: 60px;
+ z-index: 20;
+ padding: 5px;
+}
+
.timetracks.sum span{
font-weight: bold;
}
@@ -307,23 +327,6 @@ span.timetracking {
float: right;
}
-.markdown.editing{
- position: relative;
-}
-
-.markdown.editing > *{
- width: 49%;
-}
-
-.markdown.editing > *:nth-child(2){
- position: absolute;
- right: 0;
- top: 0;
-}
-
-.markdown img{
- max-width: 75%;
-}
table{
min-width: 30vw;
@@ -370,6 +373,7 @@ a.wikilink{
.grid2{
display: grid;
grid-template-columns: 230px auto;
+ margin: 0 5px;
}
.grid2 > :nth-child(2n-1){
@@ -399,6 +403,17 @@ a.wikilink{
text-align: initial;
padding-top: 8px;
}
+
+ .markdown.editing{
+ display: block;
+ grid-template-columns: 1fr 1fr;
+ column-gap: 10px;
+ }
+
+ .markdown textarea{
+ width: calc(100% - 10px);
+ min-height: 50px;
+ }
}
fieldset.vcard{
diff --git a/web/src/main/resources/web/css/default-color.css b/web/src/main/resources/web/css/default-color.css
index 1360748..9b42b96 100644
--- a/web/src/main/resources/web/css/default-color.css
+++ b/web/src/main/resources/web/css/default-color.css
@@ -45,6 +45,15 @@ textarea{
background-color: #333;
}
+tr:hover{
+ background: orange;
+ color: black;
+}
+
+tr:hover a{
+ background: black;
+}
+
.archive{
background: black;
}
@@ -150,6 +159,11 @@ textarea{
background-color: navy;
}
+.timetracks.sum {
+ background: black;
+}
+
+
.version a.selected{
border-color: orange;
}
diff --git a/web/src/main/resources/web/css/default.css b/web/src/main/resources/web/css/default.css
index 24d7053..31ad291 100644
--- a/web/src/main/resources/web/css/default.css
+++ b/web/src/main/resources/web/css/default.css
@@ -308,6 +308,13 @@ span.timetracking {
border: 1px solid;
}
+.timetracks.sum {
+ position: sticky;
+ top: 60px;
+ z-index: 20;
+ padding: 5px;
+}
+
.timetracks.sum span{
font-weight: bold;
}
diff --git a/web/src/main/resources/web/css/winter-color.css b/web/src/main/resources/web/css/winter-color.css
index 49f2730..31996d8 100644
--- a/web/src/main/resources/web/css/winter-color.css
+++ b/web/src/main/resources/web/css/winter-color.css
@@ -41,6 +41,10 @@ textarea{
background-color: lightcyan;;
}
+tr:hover{
+ background: #afffff;
+}
+
.archive{
background: white;
}
@@ -140,6 +144,11 @@ textarea{
background-color: aquamarine;
}
+.timetracks.sum {
+ background: white;
+}
+
+
.version a.selected{
border-color: orange;
}
diff --git a/web/src/main/resources/web/css/winter.css b/web/src/main/resources/web/css/winter.css
index 0585de2..31ad291 100644
--- a/web/src/main/resources/web/css/winter.css
+++ b/web/src/main/resources/web/css/winter.css
@@ -290,11 +290,31 @@ span.timetracking {
display: inline-block;
}
+.markdown.editing{
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ column-gap: 10px;
+}
+.markdown .buttons,
+.markdown .hint{
+ grid-column-end: span 2;
+}
+
+.editable:hover{
+ border: 1px dotted;
+}
.timetracks .year, .timetracks .month{
border: 1px solid;
}
+.timetracks.sum {
+ position: sticky;
+ top: 60px;
+ z-index: 20;
+ padding: 5px;
+}
+
.timetracks.sum span{
font-weight: bold;
}
@@ -307,23 +327,6 @@ span.timetracking {
float: right;
}
-.markdown.editing{
- position: relative;
-}
-
-.markdown.editing > *{
- width: 49%;
-}
-
-.markdown.editing > *:nth-child(2){
- position: absolute;
- right: 0;
- top: 0;
-}
-
-.markdown img{
- max-width: 75%;
-}
table{
min-width: 30vw;
@@ -370,6 +373,7 @@ a.wikilink{
.grid2{
display: grid;
grid-template-columns: 230px auto;
+ margin: 0 5px;
}
.grid2 > :nth-child(2n-1){
@@ -399,6 +403,17 @@ a.wikilink{
text-align: initial;
padding-top: 8px;
}
+
+ .markdown.editing{
+ display: block;
+ grid-template-columns: 1fr 1fr;
+ column-gap: 10px;
+ }
+
+ .markdown textarea{
+ width: calc(100% - 10px);
+ min-height: 50px;
+ }
}
fieldset.vcard{