"use client"; import { useEffect, useState } from "react"; import { Check, FileText, Layers } from "lucide-react"; import { corpusDocuments, type CorpusDocument } from "@/lib/api"; import { displaySource } from "@/lib/format"; /** * NotebookLM-style source scoping: check/uncheck indexed documents to restrict * the next query's retrieval set. Reports the selected doc_ids to the parent * (null when everything is selected → search the whole corpus). */ export function SourceScope({ refreshKey, onChange, }: { refreshKey?: number; onChange: (docIds: string[] | null) => void; }) { const [docs, setDocs] = useState([]); const [included, setIncluded] = useState>(new Set()); useEffect(() => { let alive = true; corpusDocuments() .then((d) => { if (!alive) return; setDocs(d); setIncluded(new Set(d.map((x) => x.doc_id))); // default: all in scope }) .catch(() => {}); return () => { alive = false; }; }, [refreshKey]); // Report scope up: all-selected → null (whole corpus), else the id list. const emit = (next: Set) => { onChange(next.size === docs.length ? null : Array.from(next)); }; const toggle = (id: string) => { setIncluded((prev) => { const next = new Set(prev); next.has(id) ? next.delete(id) : next.add(id); emit(next); return next; }); }; const setAll = (all: boolean) => { const next = all ? new Set(docs.map((d) => d.doc_id)) : new Set(); setIncluded(next); emit(next); }; if (docs.length === 0) return null; const n = included.size; const scoped = n !== docs.length; return (
Scope retrieval {n}/{docs.length} ·
    {docs.map((d) => { const on = included.has(d.doc_id); return (
  • ); })}
{scoped && (

Next queries search {n} of {docs.length} documents.

)}
); }