working on journal

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
2026-07-28 08:46:31 +02:00
parent e614880d71
commit 722a6ae97e
7 changed files with 120 additions and 40 deletions
@@ -5,7 +5,6 @@ import static de.srsoftware.umbrella.core.constants.Field.*;
import static java.util.Optional.*; import static java.util.Optional.*;
import de.srsoftware.tools.Diff; import de.srsoftware.tools.Diff;
import de.srsoftware.tools.Mappable;
import de.srsoftware.umbrella.core.model.ObjectWithId; import de.srsoftware.umbrella.core.model.ObjectWithId;
import de.srsoftware.umbrella.core.model.Translatable; import de.srsoftware.umbrella.core.model.Translatable;
import de.srsoftware.umbrella.core.model.UmbrellaUser; import de.srsoftware.umbrella.core.model.UmbrellaUser;
@@ -5,32 +5,91 @@ import static de.srsoftware.umbrella.core.Util.mapMarkdown;
import static de.srsoftware.umbrella.core.constants.Field.*; import static de.srsoftware.umbrella.core.constants.Field.*;
import static java.time.ZoneOffset.UTC; import static java.time.ZoneOffset.UTC;
import de.srsoftware.tools.Mappable;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Objects;
public record Bookmark(long urlId, String url, String comment, LocalDateTime timestamp, Collection<String> tags) implements Mappable { public final class Bookmark extends ObjectWithId {
private final String url;
private final String comment;
private final LocalDateTime timestamp;
private final Collection<String> tags;
public static Bookmark of(ResultSet rs) throws SQLException { public Bookmark(long urlId, String url, String comment, LocalDateTime timestamp, Collection<String> tags) {
return new Bookmark(rs.getLong(ID),rs.getString(URL),rs.getString(COMMENT),LocalDateTime.ofEpochSecond(rs.getLong(TIMESTAMP),0, UTC),new ArrayList<>()); super(urlId);
this.url = url;
this.comment = comment;
this.timestamp = timestamp;
this.tags = tags;
} }
public static Bookmark of(long urlId, String url, String comment, LocalDateTime timestamp){ public static Bookmark of(ResultSet rs) throws SQLException {
return new Bookmark(urlId,url,comment,timestamp,new ArrayList<>()); return new Bookmark(rs.getLong(ID), rs.getString(URL), rs.getString(COMMENT), LocalDateTime.ofEpochSecond(rs.getLong(TIMESTAMP), 0, UTC), new ArrayList<>());
}
public static Bookmark of(long urlId, String url, String comment, LocalDateTime timestamp) {
return new Bookmark(urlId, url, comment, timestamp, new ArrayList<>());
} }
@Override @Override
public Map<String, Object> toMap() { public Map<String, Object> toMap() {
return Map.of( return map(
ID, urlId,
URL, url, URL, url,
COMMENT, mapMarkdown(comment), COMMENT, mapMarkdown(comment),
TAGS, tags, TAGS, tags,
TIMESTAMP, timestamp.withNano(0) TIMESTAMP, timestamp.withNano(0)
); );
} }
public long urlId() {
return id();
}
public String url() {
return url;
}
public String comment() {
return comment;
}
public LocalDateTime timestamp() {
return timestamp;
}
public Collection<String> tags() {
return tags;
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null || obj.getClass() != this.getClass()) return false;
var that = (Bookmark) obj;
return this.urlId() == that.urlId() &&
Objects.equals(this.url, that.url) &&
Objects.equals(this.comment, that.comment) &&
Objects.equals(this.timestamp, that.timestamp) &&
Objects.equals(this.tags, that.tags);
}
@Override
public int hashCode() {
return Objects.hash(urlId(), url, comment, timestamp, tags);
}
@Override
public String toString() {
return "Bookmark[" +
"urlId=" + urlId() + ", " +
"url=" + url + ", " +
"comment=" + comment + ", " +
"timestamp=" + timestamp + ", " +
"tags=" + tags + ']';
}
} }
@@ -4,13 +4,11 @@ import de.srsoftware.tools.Mappable;
import de.srsoftware.umbrella.core.constants.Field; import de.srsoftware.umbrella.core.constants.Field;
import java.security.InvalidParameterException; import java.security.InvalidParameterException;
import java.time.LocalDate;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
public abstract class ObjectWithId implements Mappable { public abstract class ObjectWithId implements Mappable {
private final long id; private long id;
public ObjectWithId(long id){ public ObjectWithId(long id){
this.id = id; this.id = id;
@@ -20,6 +18,11 @@ public abstract class ObjectWithId implements Mappable {
return id; return id;
} }
public ObjectWithId setId(long newValue){
id = newValue;
return this;
}
protected Map<String, Object> map(Object ... keysAndValues) { protected Map<String, Object> map(Object ... keysAndValues) {
if (keysAndValues.length % 2 != 0) throw new InvalidParameterException("Expected even number of keys and parameters!"); if (keysAndValues.length % 2 != 0) throw new InvalidParameterException("Expected even number of keys and parameters!");
var map = new HashMap<String, Object>(); var map = new HashMap<String, Object>();
@@ -7,7 +7,6 @@ import static de.srsoftware.umbrella.core.constants.Field.*;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*;
import static java.lang.System.Logger.Level.WARNING; import static java.lang.System.Logger.Level.WARNING;
import de.srsoftware.tools.Mappable;
import de.srsoftware.umbrella.core.constants.Field; import de.srsoftware.umbrella.core.constants.Field;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
@@ -15,9 +14,9 @@ import java.time.LocalDate;
import java.util.*; import java.util.*;
import org.json.JSONObject; import org.json.JSONObject;
public class Task implements Mappable { public class Task extends ObjectWithId {
public static final System.Logger LOG = System.getLogger(Task.class.getSimpleName()); public static final System.Logger LOG = System.getLogger(Task.class.getSimpleName());
private final long id, projectId; private final long projectId;
private Long parentTaskId; private Long parentTaskId;
private String description, name; private String description, name;
private final Set<Long> requiredTasksIds; private final Set<Long> requiredTasksIds;
@@ -30,7 +29,7 @@ public class Task implements Mappable {
private final Set<String> tags = new HashSet<>(); private final Set<String> tags = new HashSet<>();
public Task (long id, long projectId, Long parentTaskId, String name, String description, int status, Double estimatedTime, LocalDate start, LocalDate dueDate, boolean showClosed, boolean noIndex, Map<Long,Member> members, int priority){ public Task (long id, long projectId, Long parentTaskId, String name, String description, int status, Double estimatedTime, LocalDate start, LocalDate dueDate, boolean showClosed, boolean noIndex, Map<Long,Member> members, int priority){
this.id = id; super(id);
this.projectId = projectId; this.projectId = projectId;
this.parentTaskId = parentTaskId; this.parentTaskId = parentTaskId;
this.name = name; this.name = name;
@@ -82,10 +81,6 @@ public class Task implements Mappable {
return members.containsKey(user.id()); return members.containsKey(user.id());
} }
public long id(){
return id;
}
public boolean isDirty() { public boolean isDirty() {
return !dirtyFields.isEmpty(); return !dirtyFields.isEmpty();
} }
@@ -229,28 +224,27 @@ public class Task implements Mappable {
} }
public Map<String,Object> toMap(boolean renderMarkdown){ public Map<String,Object> toMap(boolean renderMarkdown){
var map = new HashMap<String,Object>();
var memberMap = new HashMap<Long,Map<String,Object>>(); var memberMap = new HashMap<Long,Map<String,Object>>();
if (members != null) for (var entry : members.entrySet()){ if (members != null) for (var entry : members.entrySet()){
memberMap.put(entry.getKey(),entry.getValue().toMap()); memberMap.put(entry.getKey(),entry.getValue().toMap());
} }
map.put(ID, id); return map(
map.put(PROJECT_ID, projectId); PROJECT_ID, projectId,
map.put(PARENT_TASK_ID, parentTaskId); PARENT_TASK_ID, parentTaskId,
map.put(PRIORITY,priority); PRIORITY,priority,
map.put(NAME, name); NAME, name,
map.put(DESCRIPTION, renderMarkdown ? mapMarkdown(description) : Map.of(SOURCE,description)); DESCRIPTION, renderMarkdown ? mapMarkdown(description) : Map.of(SOURCE,description),
map.put(STATUS, status); STATUS, status,
map.put(EST_TIME, estimatedTime); EST_TIME, estimatedTime,
map.put(START_DATE,start); START_DATE,start,
map.put(DUE_DATE,dueDate); DUE_DATE,dueDate,
map.put(NO_INDEX,noIndex); NO_INDEX,noIndex,
map.put(MEMBERS,memberMap); MEMBERS,memberMap,
map.put(REQUIRED_TASKS_IDS,requiredTasksIds); REQUIRED_TASKS_IDS,requiredTasksIds,
map.put(SHOW_CLOSED,showClosed); SHOW_CLOSED,showClosed,
map.put(TOTAL_PRIO,totalPrio()); TOTAL_PRIO,totalPrio(),
map.put(TAGS,tags); TAGS,tags
return map; );
} }
@Override @Override
@@ -0,0 +1,17 @@
<script>
import { api, get } from '../../urls.svelte';
import { error, yikes } from '../../warn.svelte';
import { t } from '../../translations.svelte';
let { module, entityId } = $props();
async function loadJournal(){
const url = api(`journal/${module}/${entityId}`);
const res = await get(url);
if (res.ok) {
} else error(res);
}
$effect(loadJournal);
</script>
...
+6 -1
View File
@@ -8,6 +8,7 @@
import { timetrack } from '../../user.svelte.js'; import { timetrack } from '../../user.svelte.js';
import { now } from '../../time.svelte'; import { now } from '../../time.svelte';
import Journal from '../journal/related.svelte';
import LineEditor from '../../Components/LineEditor.svelte'; import LineEditor from '../../Components/LineEditor.svelte';
import MarkdownEditor from '../../Components/MarkdownEditor.svelte'; import MarkdownEditor from '../../Components/MarkdownEditor.svelte';
import ParentSelector from './ParentSelector.svelte'; import ParentSelector from './ParentSelector.svelte';
@@ -363,9 +364,13 @@
{/if} {/if}
</div> </div>
<h3>{t('Journal')}</h3>
<div>
<Journal module="task" entityId={id} />
</div>
<h3>{t('notes')}</h3> <h3>{t('notes')}</h3>
<div> <div>
<Notes module="task" entity_id={id} /> <Notes module="task" entity_id={id} />
</div> </div>
</div> </div>
{/if} {/if}
@@ -476,7 +476,10 @@ public class SqliteDb extends BaseDb implements StockDb {
var rs = insertInto(TABLE_ITEMS, OWNER, OWNER_NUMBER, Field.CODE, NAME, DESCRIPTION, LOCATION_ID) var rs = insertInto(TABLE_ITEMS, OWNER, OWNER_NUMBER, Field.CODE, NAME, DESCRIPTION, LOCATION_ID)
.values(item.owner().dbCode(), number, item.code(), item.name(), item.description(), item.location().id()) .values(item.owner().dbCode(), number, item.code(), item.name(), item.description(), item.location().id())
.execute(db).getGeneratedKeys(); .execute(db).getGeneratedKeys();
if (rs.next()) item.id(rs.getLong(1)).ownerNumber(number); if (rs.next()) {
item.setId(rs.getLong(1));
item.ownerNumber(number);
}
rs.close(); rs.close();
} catch (SQLException e) { } catch (SQLException e) {
throw failedToStoreObject(item.name()).causedBy(e); throw failedToStoreObject(item.name()).causedBy(e);