From 34729cf1cf89cd9be33c71ed4d2acf790391ba9e Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 8 Apr 2026 10:32:51 -0400 Subject: [PATCH] feat(knowledge): add task cards with status/priority/due-date display --- frontend/src/views/KnowledgeView.vue | 122 +++++++++++++++++++++------ 1 file changed, 98 insertions(+), 24 deletions(-) diff --git a/frontend/src/views/KnowledgeView.vue b/frontend/src/views/KnowledgeView.vue index c881a7e..b28e3be 100644 --- a/frontend/src/views/KnowledgeView.vue +++ b/frontend/src/views/KnowledgeView.vue @@ -15,7 +15,7 @@ const chatStore = useChatStore(); interface KnowledgeItem { id: number; - note_type: "note" | "person" | "place" | "list"; + note_type: "note" | "person" | "place" | "list" | "task"; title: string; snippet: string; tags: string[]; @@ -33,6 +33,10 @@ interface KnowledgeItem { checked_count?: number; list_items?: { text: string; checked: boolean }[]; body?: string; + // Task-specific + status?: string; + priority?: string; + due_date?: string; } interface UpcomingEvent { @@ -44,7 +48,7 @@ interface UpcomingEvent { // ─── Filter state ───────────────────────────────────────────────────────────── -const activeType = ref<"" | "note" | "person" | "place" | "list">(""); +const activeType = ref<"" | "note" | "person" | "place" | "list" | "task">(""); const activeTag = ref(""); const sortMode = ref<"modified" | "created" | "alpha" | "type">("modified"); const searchQuery = ref(""); @@ -69,7 +73,18 @@ const newNoteMenuOpen = ref(false); function createNew(type: string) { newNoteMenuOpen.value = false; - router.push(type === "note" ? "/notes/new" : `/notes/new?type=${type}`); + if (type === "task") { + router.push("/tasks/new"); + } else { + router.push(type === "note" ? "/notes/new" : `/notes/new?type=${type}`); + } +} + +function onClickOutsideNewNote(e: MouseEvent) { + const wrap = document.querySelector('.new-note-wrap'); + if (wrap && !wrap.contains(e.target as Node)) { + newNoteMenuOpen.value = false; + } } // ─── Two-tier pagination ────────────────────────────────────────────────────── @@ -307,8 +322,17 @@ async function toggleListItem(item: KnowledgeItem, index: number) { // ─── Navigation helpers ─────────────────────────────────────────────────────── +function isOverdue(item: KnowledgeItem): boolean { + if (!item.due_date || item.status === 'done' || item.status === 'cancelled') return false; + return new Date(item.due_date) < new Date(new Date().toDateString()); +} + function openItem(item: KnowledgeItem) { - router.push(`/notes/${item.id}`); + if (item.note_type === 'task') { + router.push(`/tasks/${item.id}`); + } else { + router.push(`/notes/${item.id}`); + } } function formatDate(iso: string): string { @@ -344,6 +368,7 @@ function setupObserver() { // ─── Lifecycle ──────────────────────────────────────────────────────────────── onMounted(async () => { + document.addEventListener('click', onClickOutsideNewNote); await reset(); fetchTags(); fetchCounts(); @@ -353,6 +378,7 @@ onMounted(async () => { }); onUnmounted(() => { + document.removeEventListener('click', onClickOutsideNewNote); if (searchDebounce) clearTimeout(searchDebounce); observer?.disconnect(); }); @@ -392,10 +418,9 @@ onUnmounted(() => {