Merge branch 'main' into module/stock
This commit is contained in:
@@ -171,7 +171,7 @@ public class Task implements Mappable {
|
|||||||
case MEMBERS: continue;
|
case MEMBERS: continue;
|
||||||
case NAME: name = json.getString(key); break;
|
case NAME: name = json.getString(key); break;
|
||||||
case NO_INDEX: noIndex = json.getBoolean(NO_INDEX); 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 PRIORITY: priority = json.getInt(PRIORITY); break;
|
||||||
case REQUIRED_TASKS_IDS:
|
case REQUIRED_TASKS_IDS:
|
||||||
requiredTasksIds.clear();
|
requiredTasksIds.clear();
|
||||||
|
|||||||
@@ -14,8 +14,9 @@
|
|||||||
let map = $state({});
|
let map = $state({});
|
||||||
let hidden = $state({});
|
let hidden = $state({});
|
||||||
|
|
||||||
async function changeState(tid,state){
|
async function changeState(idx,state){
|
||||||
const task = tasks[tid];
|
const task = tasks[idx];
|
||||||
|
const tid = task.id;
|
||||||
const prj = projects[task.project_id];
|
const prj = projects[task.project_id];
|
||||||
const stat = Object.keys(prj.allowed_states).find(k => prj.allowed_states[k] === state);
|
const stat = Object.keys(prj.allowed_states).find(k => prj.allowed_states[k] === state);
|
||||||
const url = api(`task/${tid}`);
|
const url = api(`task/${tid}`);
|
||||||
@@ -25,18 +26,18 @@
|
|||||||
body : JSON.stringify({status:stat})
|
body : JSON.stringify({status:stat})
|
||||||
});
|
});
|
||||||
if (resp.ok){
|
if (resp.ok){
|
||||||
tasks[tid] = await resp.json();
|
tasks[idx] = await resp.json();
|
||||||
} else {
|
} else {
|
||||||
error(resp);
|
error(resp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function abort(tid){
|
function abort(idx){
|
||||||
changeState(tid,'CANCELLED');
|
changeState(idx,'CANCELLED');
|
||||||
}
|
}
|
||||||
|
|
||||||
function complete(tid){
|
function complete(idx){
|
||||||
changeState(tid,'COMPLETE');
|
changeState(idx,'COMPLETE');
|
||||||
}
|
}
|
||||||
|
|
||||||
function edit(tid){
|
function edit(tid){
|
||||||
@@ -81,16 +82,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function open(tid){
|
function open(idx){
|
||||||
changeState(tid,'OPEN');
|
changeState(idx,'OPEN');
|
||||||
}
|
}
|
||||||
|
|
||||||
function postpone(tid){
|
function postpone(idx){
|
||||||
changeState(tid,'PENDING');
|
changeState(idx,'PENDING');
|
||||||
}
|
}
|
||||||
|
|
||||||
function start(tid){
|
function start(idx){
|
||||||
changeState(tid,'STARTED');
|
changeState(idx,'STARTED');
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(load);
|
onMount(load);
|
||||||
@@ -115,7 +116,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{#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]}
|
{#if task.status > 10 && task.status < 60 && !task.no_index && projects[task.project_id]?.status < 60 && !hidden[task.id]}
|
||||||
<tr>
|
<tr>
|
||||||
<td onclick={() => go('task',task.id)}>{task.name}</td>
|
<td onclick={() => go('task',task.id)}>{task.name}</td>
|
||||||
@@ -136,11 +137,11 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="symbol" onclick={() => edit(task.id)} title={t('edit')} ></button>
|
<button class="symbol" onclick={() => edit(task.id)} title={t('edit')} ></button>
|
||||||
<button class="symbol" onclick={() => postpone(task.id)} title={t('postpone')} ></button>
|
<button class="symbol" onclick={() => postpone(idx)} title={t('postpone')} ></button>
|
||||||
<button class="symbol" onclick={() => open(task.id)} title={t('open')}></button>
|
<button class="symbol" onclick={() => open(idx)} title={t('open')}></button>
|
||||||
<button class="symbol" onclick={() => start(task.id)} title={t('start')} ></button>
|
<button class="symbol" onclick={() => start(idx)} title={t('start')} ></button>
|
||||||
<button class="symbol" onclick={() => complete(task.id)} title={t('complete')} ></button>
|
<button class="symbol" onclick={() => complete(idx)} title={t('complete')} ></button>
|
||||||
<button class="symbol" onclick={() => abort(task.id)} title={t('abort')} ></button>
|
<button class="symbol" onclick={() => abort(idx)} title={t('abort')} ></button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -140,6 +140,10 @@
|
|||||||
showSettings = !showSettings;
|
showSettings = !showSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function unlink_parent(){
|
||||||
|
update({parent_task_id:null});
|
||||||
|
}
|
||||||
|
|
||||||
async function update(data){
|
async function update(data){
|
||||||
const url = api(`task/${id}`);
|
const url = api(`task/${id}`);
|
||||||
const resp = await fetch(url,{
|
const resp = await fetch(url,{
|
||||||
@@ -151,7 +155,11 @@
|
|||||||
yikes();
|
yikes();
|
||||||
let old_task = task;
|
let old_task = task;
|
||||||
task = await resp.json();
|
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;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
error(resp);
|
error(resp);
|
||||||
@@ -196,6 +204,7 @@
|
|||||||
<div>{t('parent_task')}</div>
|
<div>{t('parent_task')}</div>
|
||||||
<div class="parent">
|
<div class="parent">
|
||||||
<a href="#" onclick={gotoParent}>{task.parent.name}</a>
|
<a href="#" onclick={gotoParent}>{task.parent.name}</a>
|
||||||
|
<button class="symbol" title={t('unlink')} onclick={unlink_parent}></button>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div>{t('task')}</div>
|
<div>{t('task')}</div>
|
||||||
|
|||||||
@@ -10,12 +10,15 @@
|
|||||||
|
|
||||||
import TimeEditor from '../../Components/TimeRecordEditor.svelte';
|
import TimeEditor from '../../Components/TimeRecordEditor.svelte';
|
||||||
|
|
||||||
|
let detail = $state(null);
|
||||||
let docLinks = $state(null);
|
let docLinks = $state(null);
|
||||||
let router = useTinyRouter();
|
let router = useTinyRouter();
|
||||||
|
|
||||||
let times = $state(null);
|
let times = $state(null);
|
||||||
let tasks = {};
|
let tasks = {};
|
||||||
let projects = {};
|
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 => ({
|
let sortedTimes = $derived.by(() => Object.values(times).map(time => ({
|
||||||
...time,
|
...time,
|
||||||
start: display(time.start_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(){
|
function onAbort(){
|
||||||
detail = null;
|
detail = null;
|
||||||
}
|
}
|
||||||
@@ -217,6 +228,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{#each sortedTimes as time,line}
|
{#each sortedTimes as time,line}
|
||||||
|
{#if match_prj_filter(time)}
|
||||||
<tr class={selected[time.id]?'selected':''}>
|
<tr class={selected[time.id]?'selected':''}>
|
||||||
{#if timeMap.years[line]}
|
{#if timeMap.years[line]}
|
||||||
<td class="year" rowspan={timeMap.years[line]} onclick={e => toggleRange(time.start.substring(0,4))}>
|
<td class="year" rowspan={timeMap.years[line]} onclick={e => toggleRange(time.start.substring(0,4))}>
|
||||||
@@ -279,6 +291,7 @@
|
|||||||
</td>
|
</td>
|
||||||
{/if}
|
{/if}
|
||||||
</tr>
|
</tr>
|
||||||
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -46,6 +46,11 @@ textarea{
|
|||||||
background-color: black;
|
background-color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr:hover{
|
||||||
|
background: darkred;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
.archive{
|
.archive{
|
||||||
background: red;
|
background: red;
|
||||||
color: black;
|
color: black;
|
||||||
@@ -155,15 +160,21 @@ textarea{
|
|||||||
color: yellow;
|
color: yellow;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timetracks .year, .month{
|
|
||||||
border-color: 1px solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.timetracks .selected td:not(.year):not(.month){
|
.timetracks .selected td:not(.year):not(.month){
|
||||||
background-color: darkred;
|
background-color: darkred;
|
||||||
color: orange;
|
color: orange;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.timetracks.sum {
|
||||||
|
background: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timetracks .year, .month{
|
||||||
|
border-color: 1px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.warn {
|
.warn {
|
||||||
background-color: yellow;
|
background-color: yellow;
|
||||||
color: black;
|
color: black;
|
||||||
|
|||||||
@@ -290,11 +290,31 @@ span.timetracking {
|
|||||||
display: inline-block;
|
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{
|
.timetracks .year, .timetracks .month{
|
||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.timetracks.sum {
|
||||||
|
position: sticky;
|
||||||
|
top: 60px;
|
||||||
|
z-index: 20;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.timetracks.sum span{
|
.timetracks.sum span{
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
@@ -307,23 +327,6 @@ span.timetracking {
|
|||||||
float: right;
|
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{
|
table{
|
||||||
min-width: 30vw;
|
min-width: 30vw;
|
||||||
@@ -370,6 +373,7 @@ a.wikilink{
|
|||||||
.grid2{
|
.grid2{
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 230px auto;
|
grid-template-columns: 230px auto;
|
||||||
|
margin: 0 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid2 > :nth-child(2n-1){
|
.grid2 > :nth-child(2n-1){
|
||||||
@@ -399,6 +403,17 @@ a.wikilink{
|
|||||||
text-align: initial;
|
text-align: initial;
|
||||||
padding-top: 8px;
|
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{
|
fieldset.vcard{
|
||||||
|
|||||||
@@ -45,6 +45,15 @@ textarea{
|
|||||||
background-color: #333;
|
background-color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr:hover{
|
||||||
|
background: orange;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:hover a{
|
||||||
|
background: black;
|
||||||
|
}
|
||||||
|
|
||||||
.archive{
|
.archive{
|
||||||
background: black;
|
background: black;
|
||||||
}
|
}
|
||||||
@@ -150,6 +159,11 @@ textarea{
|
|||||||
background-color: navy;
|
background-color: navy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.timetracks.sum {
|
||||||
|
background: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.version a.selected{
|
.version a.selected{
|
||||||
border-color: orange;
|
border-color: orange;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -308,6 +308,13 @@ span.timetracking {
|
|||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.timetracks.sum {
|
||||||
|
position: sticky;
|
||||||
|
top: 60px;
|
||||||
|
z-index: 20;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.timetracks.sum span{
|
.timetracks.sum span{
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ textarea{
|
|||||||
background-color: lightcyan;;
|
background-color: lightcyan;;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr:hover{
|
||||||
|
background: #afffff;
|
||||||
|
}
|
||||||
|
|
||||||
.archive{
|
.archive{
|
||||||
background: white;
|
background: white;
|
||||||
}
|
}
|
||||||
@@ -140,6 +144,11 @@ textarea{
|
|||||||
background-color: aquamarine;
|
background-color: aquamarine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.timetracks.sum {
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.version a.selected{
|
.version a.selected{
|
||||||
border-color: orange;
|
border-color: orange;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -290,11 +290,31 @@ span.timetracking {
|
|||||||
display: inline-block;
|
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{
|
.timetracks .year, .timetracks .month{
|
||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.timetracks.sum {
|
||||||
|
position: sticky;
|
||||||
|
top: 60px;
|
||||||
|
z-index: 20;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.timetracks.sum span{
|
.timetracks.sum span{
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
@@ -307,23 +327,6 @@ span.timetracking {
|
|||||||
float: right;
|
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{
|
table{
|
||||||
min-width: 30vw;
|
min-width: 30vw;
|
||||||
@@ -370,6 +373,7 @@ a.wikilink{
|
|||||||
.grid2{
|
.grid2{
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 230px auto;
|
grid-template-columns: 230px auto;
|
||||||
|
margin: 0 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid2 > :nth-child(2n-1){
|
.grid2 > :nth-child(2n-1){
|
||||||
@@ -399,6 +403,17 @@ a.wikilink{
|
|||||||
text-align: initial;
|
text-align: initial;
|
||||||
padding-top: 8px;
|
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{
|
fieldset.vcard{
|
||||||
|
|||||||
Reference in New Issue
Block a user