From 1da4050813231f362012e3456ce5f200217e56c6 Mon Sep 17 00:00:00 2001 From: beo3000 Date: Sat, 21 Feb 2026 08:28:28 +0100 Subject: [PATCH] added wiedervorlage --- .../src/lib/components/JournalView.svelte | 27 +++-- .../lib/components/WiedervorlageCard.svelte | 110 ++++++++++++++++++ .../components/WiedervorlageSection.svelte | 22 ++++ ka-note/client/src/lib/db/repositories.ts | 31 ++++- ka-note/client/src/lib/db/schema.ts | 9 ++ ka-note/client/src/lib/stores/agenda.ts | 9 ++ ka-note/server/src/lib/sync-service.ts | 2 + ka-note/shared/src/types.ts | 2 + 8 files changed, 203 insertions(+), 9 deletions(-) create mode 100644 ka-note/client/src/lib/components/WiedervorlageCard.svelte create mode 100644 ka-note/client/src/lib/components/WiedervorlageSection.svelte diff --git a/ka-note/client/src/lib/components/JournalView.svelte b/ka-note/client/src/lib/components/JournalView.svelte index ffe59b2..7f856dd 100644 --- a/ka-note/client/src/lib/components/JournalView.svelte +++ b/ka-note/client/src/lib/components/JournalView.svelte @@ -8,6 +8,7 @@ import RenderedMarkdown from './RenderedMarkdown.svelte'; import DateNavigator from './DateNavigator.svelte'; import ConfirmDialog from './ConfirmDialog.svelte'; + import WiedervorlageSection from './WiedervorlageSection.svelte'; interface Props { contextId: string; @@ -22,6 +23,7 @@ let entryEditor: MarkdownEditor; let selectedDate = $state(today()); let selectedLinkedContextId = $state(''); + let wiedervorlageChecked = $state(false); // All meeting contexts for the link dropdown const meetingContexts = liveQuery(() => @@ -70,13 +72,14 @@ } else { const text = body ? `${title}\n${body}` : title; await getOrCreateJournalTopic(); - await createHistoryEntry(JOURNAL_TOPIC_ID, selectedDate, text); + await createHistoryEntry(JOURNAL_TOPIC_ID, selectedDate, text, null, wiedervorlageChecked); } entryTitle = ''; entryText = ''; entryEditor?.clear(); selectedLinkedContextId = ''; + wiedervorlageChecked = false; } function handleTitleKeypress(e: KeyboardEvent) { @@ -192,14 +195,24 @@ minHeight="60px" onchange={(md) => entryText = md} /> - +
+ + {#if !selectedLinkedContextId} + + {/if} +
+ + {#if filteredEntries.length > 0}
{selectedDate}
diff --git a/ka-note/client/src/lib/components/WiedervorlageCard.svelte b/ka-note/client/src/lib/components/WiedervorlageCard.svelte new file mode 100644 index 0000000..c2122db --- /dev/null +++ b/ka-note/client/src/lib/components/WiedervorlageCard.svelte @@ -0,0 +1,110 @@ + + +
+
+ ⏰ Wiedervorlage {entry.wiedervorlageDate} +
+
+
{title}
+ {#if body} +
{body}
+ {/if} +
+ + {#if showVerschieben} +
+ + + +
+ {:else if showConvert} +
+ + + +
+ {:else} +
+ + + +
+ {/if} +
diff --git a/ka-note/client/src/lib/components/WiedervorlageSection.svelte b/ka-note/client/src/lib/components/WiedervorlageSection.svelte new file mode 100644 index 0000000..c45a0e6 --- /dev/null +++ b/ka-note/client/src/lib/components/WiedervorlageSection.svelte @@ -0,0 +1,22 @@ + + +{#if ($pending ?? []).length > 0} +
+
+ Wiedervorlage ({($pending ?? []).length}) +
+ {#each $pending ?? [] as entry (entry.id)} + + {/each} +
+{/if} diff --git a/ka-note/client/src/lib/db/repositories.ts b/ka-note/client/src/lib/db/repositories.ts index 40953ac..194dc7d 100644 --- a/ka-note/client/src/lib/db/repositories.ts +++ b/ka-note/client/src/lib/db/repositories.ts @@ -1,5 +1,5 @@ import { db } from './schema'; -import { newId, now } from './helpers'; +import { newId, now, today } from './helpers'; import type { AgendaContext, Topic, HistoryEntry, Rating, ContextType, TopicStatus, ProjectMeta, PersonMeta, CompanyMeta } from '@ka-note/shared'; // --- Contexts --- @@ -203,8 +203,9 @@ export async function getAllHistoryByContext(contextId: string): Promise<(Histor return allHistory; } -export async function createHistoryEntry(topicId: string, date: string, text: string, linkedContextId: string | null = null): Promise { +export async function createHistoryEntry(topicId: string, date: string, text: string, linkedContextId: string | null = null, wiedervorlage = false): Promise { const existing = await getHistoryByTopic(topicId); + const autoWiedervorlage = date > today() || wiedervorlage; const entry: HistoryEntry = { id: newId(), topicId, @@ -213,6 +214,8 @@ export async function createHistoryEntry(topicId: string, date: string, text: st sortOrder: existing.length, linkedContextId, doneAt: null, + wiedervorlageDate: autoWiedervorlage ? date : null, + wiedervorlageResolvedAt: null, updatedAt: now(), deletedAt: null, version: 1 @@ -221,6 +224,30 @@ export async function createHistoryEntry(topicId: string, date: string, text: st return entry; } +export async function setWiedervorlage(id: string, date: string): Promise { + const entry = await db.historyEntries.get(id); + if (entry) { + await db.historyEntries.update(id, { wiedervorlageDate: date, wiedervorlageResolvedAt: null, updatedAt: now(), version: entry.version + 1 }); + } +} + +export async function resolveWiedervorlage(id: string): Promise { + const entry = await db.historyEntries.get(id); + if (entry) { + await db.historyEntries.update(id, { wiedervorlageResolvedAt: now(), updatedAt: now(), version: entry.version + 1 }); + } +} + +export async function convertToTopic(entryId: string, contextId: string): Promise { + const entry = await db.historyEntries.get(entryId); + if (!entry) throw new Error('Entry not found'); + const lines = entry.text.split('\n'); + const title = lines[0].trim(); + const topic = await createTopic(contextId, title); + await resolveWiedervorlage(entryId); + return topic; +} + export async function updateHistoryEntry(id: string, text: string): Promise { const entry = await db.historyEntries.get(id); if (entry) { diff --git a/ka-note/client/src/lib/db/schema.ts b/ka-note/client/src/lib/db/schema.ts index 6299e06..b9aed6c 100644 --- a/ka-note/client/src/lib/db/schema.ts +++ b/ka-note/client/src/lib/db/schema.ts @@ -68,6 +68,15 @@ export class KaNoteDB extends Dexie { if (ctx.isFavorite === undefined) ctx.isFavorite = false; }); }); + + this.version(7).stores({ + historyEntries: 'id, topicId, date, sortOrder, deletedAt, linkedContextId, doneAt, wiedervorlageDate, wiedervorlageResolvedAt' + }).upgrade(tx => { + return tx.table('historyEntries').toCollection().modify(entry => { + if (entry.wiedervorlageDate === undefined) entry.wiedervorlageDate = null; + if (entry.wiedervorlageResolvedAt === undefined) entry.wiedervorlageResolvedAt = null; + }); + }); } } diff --git a/ka-note/client/src/lib/stores/agenda.ts b/ka-note/client/src/lib/stores/agenda.ts index 9d40983..682af3d 100644 --- a/ka-note/client/src/lib/stores/agenda.ts +++ b/ka-note/client/src/lib/stores/agenda.ts @@ -118,3 +118,12 @@ export function ratingsForPerson(personName: string) { .toArray() ); } + +export function pendingWiedervorlage(date: string) { + return liveQuery(() => + db.historyEntries + .where('wiedervorlageDate').belowOrEqual(date) + .filter(e => !e.wiedervorlageResolvedAt && !e.deletedAt) + .toArray() + ); +} diff --git a/ka-note/server/src/lib/sync-service.ts b/ka-note/server/src/lib/sync-service.ts index 6b57a56..a3079d6 100644 --- a/ka-note/server/src/lib/sync-service.ts +++ b/ka-note/server/src/lib/sync-service.ts @@ -52,6 +52,8 @@ function mapHistoryEntry(row: typeof historyEntries.$inferSelect): HistoryEntry sortOrder: row.sortOrder, linkedContextId: row.linkedContextId, doneAt: row.doneAt, + wiedervorlageDate: (row as any).wiedervorlageDate ?? null, + wiedervorlageResolvedAt: (row as any).wiedervorlageResolvedAt ?? null, updatedAt: row.updatedAt, deletedAt: row.deletedAt, version: row.version, diff --git a/ka-note/shared/src/types.ts b/ka-note/shared/src/types.ts index f9b4131..1bae3ad 100644 --- a/ka-note/shared/src/types.ts +++ b/ka-note/shared/src/types.ts @@ -57,6 +57,8 @@ export interface HistoryEntry extends SyncEntity { sortOrder: number; linkedContextId: string | null; doneAt: string | null; + wiedervorlageDate: string | null; // YYYY-MM-DD + wiedervorlageResolvedAt: string | null; // ISO timestamp } export interface Rating extends SyncEntity {