From 65df45482fc566e645d057075bc133a00863dd7b Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Mon, 28 Jul 2025 22:50:08 +0200 Subject: [PATCH] implemented adding notes to projects and tasks Signed-off-by: Stephan Richter --- .../srsoftware/umbrella/core/model/Note.java | 2 +- frontend/src/Components/MarkdownEditor.svelte | 7 +++- frontend/src/routes/notes/List.svelte | 41 ++++++++++++++----- frontend/src/routes/project/View.svelte | 5 +++ frontend/src/routes/task/View.svelte | 12 +++--- .../srsoftware/umbrella/notes/NoteModule.java | 6 ++- translations/src/main/resources/de.json | 2 + 7 files changed, 55 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Note.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Note.java index 31d68cd..ca0b1df 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Note.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Note.java @@ -34,7 +34,7 @@ public record Note(long id, String module, long entityId, long authorId, String USER_ID,authorId, TEXT,text, RENDERED,markdown(text), - TIMESTAMP,timestamp + TIMESTAMP,timestamp.withNano(0) ); } } diff --git a/frontend/src/Components/MarkdownEditor.svelte b/frontend/src/Components/MarkdownEditor.svelte index b755f03..3e52b0d 100644 --- a/frontend/src/Components/MarkdownEditor.svelte +++ b/frontend/src/Components/MarkdownEditor.svelte @@ -51,7 +51,12 @@ if (simple) { value.source = editValue.source; value.rendered = editValue.rendered; - } else if (ev.keyCode == 13 && ev.ctrlKey) applyEdit(); + } + if (ev.keyCode == 13 && ev.ctrlKey){ + if (simple){ + onSet(editValue.source); + } else applyEdit(); + } if (ev.keyCode == 27) resetEdit(); if (timer) clearTimeout(timer); diff --git a/frontend/src/routes/notes/List.svelte b/frontend/src/routes/notes/List.svelte index 6af18f0..bfcee7b 100644 --- a/frontend/src/routes/notes/List.svelte +++ b/frontend/src/routes/notes/List.svelte @@ -2,16 +2,16 @@ import { onMount } from 'svelte'; import { api } from '../../urls.svelte.js'; import { t } from '../../translations.svelte.js'; - + import { user } from '../../user.svelte.js'; import Editor from '../../Components/MarkdownEditor.svelte'; let error = $state(null); let { module = null, entity_id = null } = $props(); let note = $state({source:null,rendered:null}); let notes = $state(null); + let authors = $state(null); - async function onclick(){ - alert(note.source); + async function saveNote(){ const url = api(`notes/${module}/${entity_id}`); const resp = await fetch(url,{ credentials:'include', @@ -19,8 +19,15 @@ body:note.source }); if (resp.ok){ + let newNote = await resp.json(); + authors[user.id] = user; + notes[newNote.id] = newNote; + note = {source:'',rendered:''}; + error = null; + return true; } else { error = await resp.text(); + return false; } } @@ -28,7 +35,9 @@ const url = api(`notes/${module}/${entity_id}`); const resp = await fetch(url,{credentials:'include'}); if (resp.ok){ - notes = await resp.json(); + const data = await resp.json(); + notes = data.notes; + authors = data.authors; } else { error = await resp.text(); } @@ -37,19 +46,31 @@ onMount(load) -

{t('notes')}

+ + {#if error} {error} {/if} - {#if notes} {#each Object.entries(notes) as [a,b]}
- User {b.user_id} – {b.timestamp.replace('T',' ')} + {authors[b.user_id].name} + {b.timestamp.replace('T',' ')} {@html b.rendered}
{/each} {/if} - - - \ No newline at end of file +
+ + +
\ No newline at end of file diff --git a/frontend/src/routes/project/View.svelte b/frontend/src/routes/project/View.svelte index 5bb9f7a..4104f46 100644 --- a/frontend/src/routes/project/View.svelte +++ b/frontend/src/routes/project/View.svelte @@ -8,6 +8,7 @@ import LineEditor from '../../Components/LineEditor.svelte'; import MarkdownEditor from '../../Components/MarkdownEditor.svelte'; import MemberEditor from '../../Components/MemberEditor.svelte'; + import Notes from '../notes/List.svelte'; import StateSelector from '../../Components/StateSelector.svelte'; import Tags from '../tags/TagList.svelte'; import TaskList from '../task/TaskList.svelte'; @@ -211,3 +212,7 @@ {/if} +
+

{t('notes')}

+ +
\ No newline at end of file diff --git a/frontend/src/routes/task/View.svelte b/frontend/src/routes/task/View.svelte index 655e9a4..9379850 100644 --- a/frontend/src/routes/task/View.svelte +++ b/frontend/src/routes/task/View.svelte @@ -294,12 +294,10 @@ +id)} /> - - {t('notes')} - - - - -{/if} \ No newline at end of file +{/if} +
+

{t('notes')}

+ +
\ No newline at end of file diff --git a/notes/src/main/java/de/srsoftware/umbrella/notes/NoteModule.java b/notes/src/main/java/de/srsoftware/umbrella/notes/NoteModule.java index 0993070..b7e7157 100644 --- a/notes/src/main/java/de/srsoftware/umbrella/notes/NoteModule.java +++ b/notes/src/main/java/de/srsoftware/umbrella/notes/NoteModule.java @@ -19,12 +19,14 @@ import de.srsoftware.umbrella.core.api.UserService; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.model.Note; import de.srsoftware.umbrella.core.model.Token; +import de.srsoftware.umbrella.core.model.UmbrellaUser; import java.io.IOException; import java.time.LocalDateTime; import java.util.Collection; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; public class NoteModule extends BaseHandler implements NoteService { private final NotesDb notesDb; @@ -71,7 +73,9 @@ public class NoteModule extends BaseHandler implements NoteService { if (module == null) throw unprocessable("Module missing in path."); var head = path.pop(); long entityId = Long.parseLong(head); - return sendContent(ex, mapValues(getNotes(module,entityId))); + var notes = getNotes(module,entityId); + var authors = notes.values().stream().map(Note::authorId).distinct().map(users::loadUser).collect(Collectors.toMap(UmbrellaUser::id,UmbrellaUser::toMap)); + return sendContent(ex, Map.of("notes",mapValues(notes),"authors",authors)); } catch (NumberFormatException e){ return sendContent(ex,HTTP_UNPROCESSABLE,"Entity id missing in path."); } catch (UmbrellaException e){ diff --git a/translations/src/main/resources/de.json b/translations/src/main/resources/de.json index 620fc8e..e2a6cb7 100644 --- a/translations/src/main/resources/de.json +++ b/translations/src/main/resources/de.json @@ -46,6 +46,7 @@ "data_sent": "Daten übermittelt", "date": "Datum", "delete": "löschen", + "delete_task": "Aufgabe löschen ", "DELETE_USERS": "Nutzer löschen", "delivery_date": "Lieferdatum", "description": "Beschreibung", @@ -187,6 +188,7 @@ "show_closed": "geschlossene anzeigen", "show_kanban": "Kanban-Ansicht", "start_date": "Startdatum", + "started": "angefangen", "state": "Status", "state_cancelled": "abgebrochen", "state_complete": "abgeschlossen",