working on time list

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
2025-08-18 01:23:29 +02:00
parent cedb798af8
commit 8bb44d0d7f
9 changed files with 52 additions and 15 deletions

View File

@@ -27,7 +27,7 @@
} }
if (company_id) { if (company_id) {
for (let comp of companies){ for (let comp of Object.keys(companies)){
if (comp.id == company_id){ if (comp.id == company_id){
load(comp); load(comp);
break; break;
@@ -80,7 +80,7 @@
</script> </script>
<fieldset> <fieldset>
<legend>{selected_company ? t( 'list_of',selected_company.name) : t('document_list')}</legend> <legend>{selected_company ? t( 'docs_of_company',{company:selected_company.name}) : t('document_list')}</legend>
{#if error} {#if error}
<div class="error">{error}</div> <div class="error">{error}</div>
{/if} {/if}

View File

@@ -49,8 +49,8 @@
<div> <div>
<h1>Times</h1> <h1>Times</h1>
{#if projects} {#if projects}
{#each projects as project,idx1} {#each Object.entries(projects) as [pid,project]}
<button onclick={() => loadTimes(project.id)}>{project.name}</button> <button onclick={() => loadTimes(+pid)}>{project.name}</button>
{/each} {/each}
{/if} {/if}
{#if times} {#if times}

View File

@@ -1,10 +1,12 @@
/* © SRSoftware 2025 */ /* © SRSoftware 2025 */
package de.srsoftware.umbrella.time; package de.srsoftware.umbrella.time;
import static de.srsoftware.tools.jdbc.Condition.equal;
import static de.srsoftware.tools.jdbc.Condition.in; import static de.srsoftware.tools.jdbc.Condition.in;
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL; import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
import static de.srsoftware.tools.jdbc.Query.select; import static de.srsoftware.tools.jdbc.Query.select;
import static de.srsoftware.umbrella.core.Constants.ID; import static de.srsoftware.umbrella.core.Constants.ID;
import static de.srsoftware.umbrella.core.Constants.USER_ID;
import static de.srsoftware.umbrella.time.Constants.*; import static de.srsoftware.umbrella.time.Constants.*;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
@@ -24,7 +26,7 @@ public class SqliteDb implements TimeDb {
} }
@Override @Override
public Collection<Time> listTimes(Collection<Long> taskIds) throws UmbrellaException { public HashMap<Long,Time> listTimes(Collection<Long> taskIds) throws UmbrellaException {
try { try {
var rs = select(ALL).from(TABLE_TASK_TIMES).where(TASK_ID,in(taskIds.toArray())).exec(db); var rs = select(ALL).from(TABLE_TASK_TIMES).where(TASK_ID,in(taskIds.toArray())).exec(db);
var mapFromTimesToTasks = new HashMap<Long,HashSet<Long>>(); var mapFromTimesToTasks = new HashMap<Long,HashSet<Long>>();
@@ -35,11 +37,34 @@ public class SqliteDb implements TimeDb {
} }
rs.close(); rs.close();
rs = select(ALL).from(TABLE_TIMES).where(ID,in(mapFromTimesToTasks.keySet().toArray())).exec(db); rs = select(ALL).from(TABLE_TIMES).where(ID,in(mapFromTimesToTasks.keySet().toArray())).exec(db);
var times = new HashSet<Time>(); var times = new HashMap<Long,Time>();
while (rs.next()) { while (rs.next()) {
var time = Time.of(rs); var time = Time.of(rs);
time.taskIds().addAll(mapFromTimesToTasks.get(time.id())); time.taskIds().addAll(mapFromTimesToTasks.get(time.id()));
times.add(time); times.put(time.id(),time);
}
rs.close();
return times;
} catch (SQLException e) {
throw new UmbrellaException("Failed to load times for task list");
}
}
@Override
public HashMap<Long, Time> listUserTimes(long userId) {
try {
var rs = select(ALL).from(TABLE_TIMES).where(USER_ID,equal(userId)).exec(db);
var times = new HashMap<Long,Time>();
while (rs.next()) {
var time = Time.of(rs);
times.put(time.id(),time);
}
rs.close();
rs = select(ALL).from(TABLE_TASK_TIMES).where(TIME_ID,in(times.keySet().toArray())).exec(db);
while (rs.next()){
var time = times.get(rs.getLong(TIME_ID));
time.taskIds().add(rs.getLong(TASK_ID));
System.out.println(time);
} }
rs.close(); rs.close();
return times; return times;

View File

@@ -4,7 +4,10 @@ package de.srsoftware.umbrella.time;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import de.srsoftware.umbrella.core.model.Time; import de.srsoftware.umbrella.core.model.Time;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
public interface TimeDb { public interface TimeDb {
Collection<Time> listTimes(Collection<Long> taskIds) throws UmbrellaException; HashMap<Long,Time> listTimes(Collection<Long> taskIds) throws UmbrellaException;
HashMap<Long,Time> listUserTimes(long userId);
} }

View File

@@ -5,6 +5,7 @@ import static de.srsoftware.umbrella.core.ConnectionProvider.connect;
import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.Paths.LIST; import static de.srsoftware.umbrella.core.Paths.LIST;
import static de.srsoftware.umbrella.core.ResponseCode.HTTP_NOT_IMPLEMENTED; import static de.srsoftware.umbrella.core.ResponseCode.HTTP_NOT_IMPLEMENTED;
import static de.srsoftware.umbrella.core.Util.mapValues;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.forbidden; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.forbidden;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException;
import static de.srsoftware.umbrella.time.Constants.*; import static de.srsoftware.umbrella.time.Constants.*;
@@ -82,9 +83,12 @@ public class TimeModule extends BaseHandler implements TimeService {
private boolean getUserTimes(UmbrellaUser user, HttpExchange ex) throws IOException { private boolean getUserTimes(UmbrellaUser user, HttpExchange ex) throws IOException {
// TODO // TODO
var taskIds = new HashSet<Long>();
Map<Long, Project> projects = projectService().listUserProjects(user.id(), true); Map<Long, Project> projects = projectService().listUserProjects(user.id(), true);
//timeDb. for (var pid : projects.keySet()) taskIds.addAll(taskService().listProjectTasks(pid).keySet());
return sendEmptyResponse(HTTP_NOT_IMPLEMENTED,ex); var times = timeDb.listTimes(taskIds);
times.putAll(timeDb.listUserTimes(user.id()));
return sendContent(ex,mapValues(times));
} }
/* /*
@@ -138,9 +142,11 @@ public class TimeModule extends BaseHandler implements TimeService {
Map<Long,Task> tasksOfProject = taskService().listProjectTasks(projectId); Map<Long,Task> tasksOfProject = taskService().listProjectTasks(projectId);
List<Map<String, Object>> times = timeDb.listTimes(tasksOfProject.keySet()) List<Map<String, Object>> times = timeDb.listTimes(tasksOfProject.keySet())
.stream().filter(not(Time::isClosed)) .entrySet().stream()
.sorted(Comparator.comparing(Time::start)) .filter(entry -> !entry.getValue().isClosed())
.map(time -> { .sorted(Comparator.comparing(entry ->entry.getValue().start()))
.map(entry -> {
var time = entry.getValue();
var map = time.toMap(); var map = time.toMap();
var timeTasks = time.taskIds().stream().map(tasksOfProject::get).map(Task::toMap).toList(); var timeTasks = time.taskIds().stream().map(tasksOfProject::get).map(Task::toMap).toList();
map.put(TASKS,timeTasks); map.put(TASKS,timeTasks);

View File

@@ -51,6 +51,7 @@
"description": "Beschreibung", "description": "Beschreibung",
"detail": "Details", "detail": "Details",
"display_closed_tasks": "abgeschlossene Aufgaben anzeigen", "display_closed_tasks": "abgeschlossene Aufgaben anzeigen",
"docs_of_company": "Dokumente von {company}",
"document": "Dokument", "document": "Dokument",
"document_list": "Dokumente", "document_list": "Dokumente",
"documents": "Dokumente", "documents": "Dokumente",
@@ -99,7 +100,6 @@
"language": "Sprache", "language": "Sprache",
"last_customer_number": "zuletzt vergebene Kundennummer", "last_customer_number": "zuletzt vergebene Kundennummer",
"list": "Dokumente", "list": "Dokumente",
"list_of": "Dokumente von {0}",
"LIST_USERS": "Nutzer auflisten", "LIST_USERS": "Nutzer auflisten",
"loading": "lade…", "loading": "lade…",
"loading_data": "Daten werden geladen…", "loading_data": "Daten werden geladen…",

View File

@@ -91,6 +91,7 @@ td, tr{
.position_selector{ .position_selector{
background: rgba(0,0,0,0.7); background: rgba(0,0,0,0.7);
backdrop-filter: blur(3px); backdrop-filter: blur(3px);
z-index: 120;
} }
.task.cancelled > a { .task.cancelled > a {
text-decoration: line-through; text-decoration: line-through;

View File

@@ -88,6 +88,7 @@ td, tr{
.position_selector{ .position_selector{
background: rgba(0,0,0,0.7); background: rgba(0,0,0,0.7);
backdrop-filter: blur(3px); backdrop-filter: blur(3px);
z-index: 120;
} }
.task.cancelled > a { .task.cancelled > a {
text-decoration: line-through; text-decoration: line-through;

View File

@@ -88,6 +88,7 @@ td, tr{
.position_selector{ .position_selector{
background: rgba(0,0,0,0.7); background: rgba(0,0,0,0.7);
backdrop-filter: blur(3px); backdrop-filter: blur(3px);
z-index: 120;
} }
.task.cancelled > a { .task.cancelled > a {
text-decoration: line-through; text-decoration: line-through;