Skip to content

Notetaking-1(Introduced notes-taking,highlights,comments,canvas,AI-chat,translate in saperate Notes Section)#23

Open
parthdude07 wants to merge 3 commits into
genesis-kb:mainfrom
parthdude07:notetaking
Open

Notetaking-1(Introduced notes-taking,highlights,comments,canvas,AI-chat,translate in saperate Notes Section)#23
parthdude07 wants to merge 3 commits into
genesis-kb:mainfrom
parthdude07:notetaking

Conversation

@parthdude07

@parthdude07 parthdude07 commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Summary by cubic

Adds Phase 1 note-taking and a transcript whiteboard, and migrates the backend to the new multi‑source DB schema with improved full‑text search.

  • New Features

    • Notes: create/edit/pin, colors and tags, quote selected transcript text, search/filter/sort; stored in localStorage with auto‑migration; shown in Transcript “Notes” tab and Library.
    • Whiteboard: visualize notes as concept nodes with connections; per‑transcript graphs saved locally; built with @xyflow/react.
    • Toolbar: new actions to add note, extract concept, ask question, and translate from selected text.
    • Chat: supports a pending prompt passed from other UI elements.
    • Backend: queries updated to the v2 schema (content items, speakers, summaries) and now return duration_seconds; FTS RPC updated for normalized tables.
  • Migration

    • Database: run NEW_DB_SCRIPTS
      • Dry run: python NEW_DB_SCRIPTS/migrate_schema.py --dry-run
      • Execute: python NEW_DB_SCRIPTS/migrate_schema.py
      • Indexes: python NEW_DB_SCRIPTS/add_indexes.py
      • Supabase RPC: run backend/supabase/migrations/001_full_text_search.sql
    • App: install new dependency and build
      • npm install
      • npm install @xyflow/react if not auto‑installed

Written for commit 64921f4. Summary will update on new commits.

Review in cubic

@parthdude07 parthdude07 changed the base branch from dev to main June 17, 2026 08:36

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

19 issues found across 28 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="types.ts">

<violation number="1" location="types.ts:49">
P0: `result.tags || []` breaks when tags is an object — truthy non-null object skips the `[]` fallback, then spread `...result.tags` throws `object is not iterable` at runtime.</violation>
</file>

<file name="src/components/notes/NoteEditor.tsx">

<violation number="1" location="src/components/notes/NoteEditor.tsx:87">
P2: Escape handler on parent div cancels editor when pressing Escape inside the tag input. NoteTagInput captures Enter but does not stopPropagation, so Escape bubbles up and triggers onCancel, unexpectedly closing the entire editor.</violation>

<violation number="2" location="src/components/notes/NoteEditor.tsx:206">
P3: Keyboard shortcut hint only mentions 'Ctrl+Enter' but handler also supports Cmd+Enter (e.metaKey) for Mac users. Hint should reference both modifiers.</violation>
</file>

<file name="src/components/notes/TranscriptNotes.tsx">

<violation number="1" location="src/components/notes/TranscriptNotes.tsx:64">
P1: Component performs state updates and parent callback inside render. Move this pending-text consumption logic to `useEffect` to avoid render-phase side effects and re-render loops.</violation>
</file>

<file name="src/components/HighlightToolbar.tsx">

<violation number="1" location="src/components/HighlightToolbar.tsx:232">
P2: Icon-only buttons are missing `aria-label`, reducing accessibility for assistive tech users.</violation>
</file>

<file name="src/components/notes/NoteTagInput.tsx">

<violation number="1" location="src/components/notes/NoteTagInput.tsx:44">
P2: Remove button for each tag has no `aria-label`, making it inaccessible to screen reader users.</violation>

<violation number="2" location="src/components/notes/NoteTagInput.tsx:54">
P2: The `<input>` element lacks an accessible label, which can cause issues for screen reader users navigating the form.</violation>
</file>

<file name="src/components/notes/NoteCard.tsx">

<violation number="1" location="src/components/notes/NoteCard.tsx:86">
P2: Action buttons are hidden by default on mobile, making note actions hard to discover/use on touch devices. Set default opacity visible and only hide on `sm+` until hover/focus.</violation>
</file>

<file name="NEW_DB_SCRIPTS/add_indexes.py">

<violation number="1" location="NEW_DB_SCRIPTS/add_indexes.py:4">
P3: Unused import `create_engine` adds dead code and reduces clarity.</violation>

<violation number="2" location="NEW_DB_SCRIPTS/add_indexes.py:73">
P2: Mandatory pg_trgm creation can fail and block all index creation. Make extension creation best-effort or remove it unless trigram operators are actually used.</violation>
</file>

<file name="backend/src/utils/dataProcessor.js">

<violation number="1" location="backend/src/utils/dataProcessor.js:189">
P2: Falsy check on `row.duration_seconds` treats `0` as missing. A 0-second duration should display as `0:00`, not `N/A`.</violation>
</file>

<file name="src/pages/Library.tsx">

<violation number="1" location="src/pages/Library.tsx:69">
P2: Notes tab sort ignores `pinned` state, so pinned notes are not reliably kept at the top.</violation>

<violation number="2" location="src/pages/Library.tsx:433">
P2: `onEdit` uses `window.location.href`, forcing full-page reload instead of SPA navigation.</violation>
</file>

<file name="src/hooks/useWhiteboard.ts">

<violation number="1" location="src/hooks/useWhiteboard.ts:12">
P1: State is not reset when `transcriptId` changes, so previous transcript graph can leak into a new transcript and be saved under the wrong key. Reset loading/data before reading localStorage for the new transcript.</violation>

<violation number="2" location="src/hooks/useWhiteboard.ts:17">
P2: Parsed localStorage data is not shape-validated before setting React Flow state. Non-array `nodes`/`edges` can cause runtime errors in downstream graph operations.</violation>
</file>

<file name="src/components/whiteboard/TranscriptWhiteboard.tsx">

<violation number="1" location="src/components/whiteboard/TranscriptWhiteboard.tsx:26">
P2: Notes list is recomputed every render, forcing avoidable concept-sync work. Memoize allNotes by transcript/function deps to prevent unnecessary node reconciliation.</violation>

<violation number="2" location="src/components/whiteboard/TranscriptWhiteboard.tsx:73">
P2: Delete action applies note deletion to every selected node id, including non-concept nodes. This can trigger incorrect deletions/false success toasts and leaves selected non-concept nodes undeleted.</violation>

<violation number="3" location="src/components/whiteboard/TranscriptWhiteboard.tsx:138">
P3: Timeout in FitViewOnLoad is not cleaned up. This leaves stale delayed callbacks and can run fitView after unmount/update.</violation>
</file>

<file name="backend/supabase/migrations/001_full_text_search.sql">

<violation number="1" location="backend/supabase/migrations/001_full_text_search.sql:51">
P3: `speakers` array order is nondeterministic because `array_agg` has no `ORDER BY`. This causes unstable API payloads and noisy cache diffs.</violation>
</file>

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

Comment thread types.ts
summary: string | null;
tags: string[];
categories: string[];
tags: string[] | object;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0: result.tags || [] breaks when tags is an object — truthy non-null object skips the [] fallback, then spread ...result.tags throws object is not iterable at runtime.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At types.ts, line 49:

<comment>`result.tags || []` breaks when tags is an object — truthy non-null object skips the `[]` fallback, then spread `...result.tags` throws `object is not iterable` at runtime.</comment>

<file context>
@@ -46,10 +46,10 @@ export interface RawTranscript {
   summary: string | null;
-  tags: string[];
-  categories: string[];
+  tags: string[] | object;
+  categories: string[] | object;
+  topics?: string[] | object;
</file context>


// Auto-open editor when pendingSelectedText arrives
const [consumedText, setConsumedText] = useState<string | undefined>(undefined)
if (pendingSelectedText && pendingSelectedText !== consumedText) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Component performs state updates and parent callback inside render. Move this pending-text consumption logic to useEffect to avoid render-phase side effects and re-render loops.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/components/notes/TranscriptNotes.tsx, line 64:

<comment>Component performs state updates and parent callback inside render. Move this pending-text consumption logic to `useEffect` to avoid render-phase side effects and re-render loops.</comment>

<file context>
@@ -0,0 +1,350 @@
+
+  // Auto-open editor when pendingSelectedText arrives
+  const [consumedText, setConsumedText] = useState<string | undefined>(undefined)
+  if (pendingSelectedText && pendingSelectedText !== consumedText) {
+    setConsumedText(pendingSelectedText)
+    setActiveTab('notes')
</file context>

Comment on lines +12 to +26
useEffect(() => {
try {
const stored = localStorage.getItem(`${STORAGE_KEY}-${transcriptId}`);
if (stored) {
const parsed = JSON.parse(stored);
if (parsed.nodes) setNodes(parsed.nodes);
if (parsed.edges) setEdges(parsed.edges);
}
} catch (e) {
console.error("Failed to load whiteboard state:", e);
}
setIsLoaded(true);
}, [transcriptId]);

// Save to local storage

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: State is not reset when transcriptId changes, so previous transcript graph can leak into a new transcript and be saved under the wrong key. Reset loading/data before reading localStorage for the new transcript.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/useWhiteboard.ts, line 12:

<comment>State is not reset when `transcriptId` changes, so previous transcript graph can leak into a new transcript and be saved under the wrong key. Reset loading/data before reading localStorage for the new transcript.</comment>

<file context>
@@ -0,0 +1,51 @@
+  const [isLoaded, setIsLoaded] = useState(false);
+
+  // Load from local storage
+  useEffect(() => {
+    try {
+      const stored = localStorage.getItem(`${STORAGE_KEY}-${transcriptId}`);
</file context>
Suggested change
useEffect(() => {
try {
const stored = localStorage.getItem(`${STORAGE_KEY}-${transcriptId}`);
if (stored) {
const parsed = JSON.parse(stored);
if (parsed.nodes) setNodes(parsed.nodes);
if (parsed.edges) setEdges(parsed.edges);
}
} catch (e) {
console.error("Failed to load whiteboard state:", e);
}
setIsLoaded(true);
}, [transcriptId]);
// Save to local storage
useEffect(() => {
setIsLoaded(false);
setNodes([]);
setEdges([]);
try {
const stored = localStorage.getItem(`${STORAGE_KEY}-${transcriptId}`);
if (stored) {
const parsed = JSON.parse(stored);
if (Array.isArray(parsed.nodes)) setNodes(parsed.nodes);
if (Array.isArray(parsed.edges)) setEdges(parsed.edges);
}
} catch (e) {
console.error("Failed to load whiteboard state:", e);
}
setIsLoaded(true);
}, [transcriptId]);

e.preventDefault()
handleSave()
}
if (e.key === 'Escape') {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Escape handler on parent div cancels editor when pressing Escape inside the tag input. NoteTagInput captures Enter but does not stopPropagation, so Escape bubbles up and triggers onCancel, unexpectedly closing the entire editor.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/components/notes/NoteEditor.tsx, line 87:

<comment>Escape handler on parent div cancels editor when pressing Escape inside the tag input. NoteTagInput captures Enter but does not stopPropagation, so Escape bubbles up and triggers onCancel, unexpectedly closing the entire editor.</comment>

<file context>
@@ -0,0 +1,240 @@
+        e.preventDefault()
+        handleSave()
+      }
+      if (e.key === 'Escape') {
+        e.preventDefault()
+        onCancel()
</file context>

</div>
<div className="flex items-center justify-between gap-1 px-1">
<div className="flex items-center gap-1">
<button onClick={handleCopySelectedText} className="p-1.5 rounded hover:bg-secondary text-muted-foreground hover:text-foreground transition-colors" title="Copy"><Copy className="w-4 h-4" /></button>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Icon-only buttons are missing aria-label, reducing accessibility for assistive tech users.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/components/HighlightToolbar.tsx, line 232:

<comment>Icon-only buttons are missing `aria-label`, reducing accessibility for assistive tech users.</comment>

<file context>
@@ -174,90 +188,57 @@ export function HighlightToolbar({
-        </div>
+          <div className="flex items-center justify-between gap-1 px-1">
+            <div className="flex items-center gap-1">
+              <button onClick={handleCopySelectedText} className="p-1.5 rounded hover:bg-secondary text-muted-foreground hover:text-foreground transition-colors" title="Copy"><Copy className="w-4 h-4" /></button>
+              {onAddNote && <button onClick={() => { onAddNote(selectedText); setToolbarVisible(false); }} className="p-1.5 rounded hover:bg-secondary text-muted-foreground hover:text-foreground transition-colors" title="Add Note"><StickyNote className="w-4 h-4" /></button>}
+              {onExtractConcept && <button onClick={() => { onExtractConcept(selectedText); setToolbarVisible(false); }} className="p-1.5 rounded hover:bg-secondary text-amber-500 hover:text-amber-600 transition-colors" title="Extract Concept"><Sparkles className="w-4 h-4" /></button>}
</file context>

}, [conceptNotes, setNodes, isLoaded]);

const handleDeleteSelected = () => {
selectedNodeIds.forEach(id => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Delete action applies note deletion to every selected node id, including non-concept nodes. This can trigger incorrect deletions/false success toasts and leaves selected non-concept nodes undeleted.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/components/whiteboard/TranscriptWhiteboard.tsx, line 73:

<comment>Delete action applies note deletion to every selected node id, including non-concept nodes. This can trigger incorrect deletions/false success toasts and leaves selected non-concept nodes undeleted.</comment>

<file context>
@@ -0,0 +1,145 @@
+  }, [conceptNotes, setNodes, isLoaded]);
+
+  const handleDeleteSelected = () => {
+    selectedNodeIds.forEach(id => {
+      deleteNote(id);
+    });
</file context>


<div className="flex items-center gap-3">
<span className="hidden sm:inline text-xs text-muted-foreground font-mono">
Ctrl+Enter to save

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Keyboard shortcut hint only mentions 'Ctrl+Enter' but handler also supports Cmd+Enter (e.metaKey) for Mac users. Hint should reference both modifiers.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/components/notes/NoteEditor.tsx, line 206:

<comment>Keyboard shortcut hint only mentions 'Ctrl+Enter' but handler also supports Cmd+Enter (e.metaKey) for Mac users. Hint should reference both modifiers.</comment>

<file context>
@@ -0,0 +1,240 @@
+          
+          <div className="flex items-center gap-3">
+            <span className="hidden sm:inline text-xs text-muted-foreground font-mono">
+              Ctrl+Enter to save
+            </span>
+          <div className="flex items-center gap-2">
</file context>

import os
import sys
import logging
from sqlalchemy import create_engine, text

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Unused import create_engine adds dead code and reduces clarity.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At NEW_DB_SCRIPTS/add_indexes.py, line 4:

<comment>Unused import `create_engine` adds dead code and reduces clarity.</comment>

<file context>
@@ -0,0 +1,88 @@
+import os
+import sys
+import logging
+from sqlalchemy import create_engine, text
+from dotenv import load_dotenv
+
</file context>

Comment on lines +138 to +140
setTimeout(() => {
fitView({ padding: 0.2, duration: 800 });
}, 200);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Timeout in FitViewOnLoad is not cleaned up. This leaves stale delayed callbacks and can run fitView after unmount/update.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/components/whiteboard/TranscriptWhiteboard.tsx, line 138:

<comment>Timeout in FitViewOnLoad is not cleaned up. This leaves stale delayed callbacks and can run fitView after unmount/update.</comment>

<file context>
@@ -0,0 +1,145 @@
+  
+  useEffect(() => {
+    if (nodesCount > 0) {
+      setTimeout(() => {
+        fitView({ padding: 0.2, duration: 800 });
+      }, 200);
</file context>
Suggested change
setTimeout(() => {
fitView({ padding: 0.2, duration: 800 });
}, 200);
const timer = setTimeout(() => {
fitView({ padding: 0.2, duration: 800 });
}, 200);
return () => clearTimeout(timer);

t.summary,
ts_rank(t.fts, tsquery_val) AS rank,
c.title,
COALESCE(array_agg(DISTINCT s.name) FILTER (WHERE s.name IS NOT NULL), '{}') AS speakers,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: speakers array order is nondeterministic because array_agg has no ORDER BY. This causes unstable API payloads and noisy cache diffs.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/supabase/migrations/001_full_text_search.sql, line 51:

<comment>`speakers` array order is nondeterministic because `array_agg` has no `ORDER BY`. This causes unstable API payloads and noisy cache diffs.</comment>

<file context>
@@ -41,29 +38,35 @@ AS $$
-    t.summary,
-    ts_rank(t.fts, tsquery_val) AS rank,
+    c.title,
+    COALESCE(array_agg(DISTINCT s.name) FILTER (WHERE s.name IS NOT NULL), '{}') AS speakers,
+    c.event_date,
+    tx.name AS conference,
</file context>
Suggested change
COALESCE(array_agg(DISTINCT s.name) FILTER (WHERE s.name IS NOT NULL), '{}') AS speakers,
COALESCE(array_agg(DISTINCT s.name ORDER BY s.name) FILTER (WHERE s.name IS NOT NULL), '{}') AS speakers,

@parthdude07 parthdude07 changed the title Notetaking Notetaking-1 Jun 19, 2026
@Sansh2356

Copy link
Copy Markdown

@parthdude07 change the title of PR to specifics of the changes in the PR .

@parthdude07 parthdude07 changed the title Notetaking-1 Notetaking-1(Introduced notes-taking,highlights,comments,canvas,AI-chat,translate in saperate Notes Section) Jun 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants