// Atlas · Enterprise Internal Repository const { useState: useStateRepo, useEffect: useEffectRepo, useRef: useRefRepo } = React; function renderSummaryMarkdown(text) { if (!text) return null; const mono = { fontFamily: "var(--mono)", fontSize: 12 }; const prose = { fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" }; const elements = []; const lines = text.split("\n"); let i = 0; const formatInline = (str) => { const parts = []; const re = /(\*\*(.+?)\*\*|`(.+?)`|\*(.+?)\*)/g; let last = 0, m; while ((m = re.exec(str)) !== null) { if (m.index > last) parts.push(str.slice(last, m.index)); if (m[2] !== undefined) parts.push(React.createElement("strong", { key: m.index }, m[2])); else if (m[3] !== undefined) parts.push(React.createElement("code", { key: m.index, style: { ...mono, background: "var(--bg-2)", padding: "1px 4px", borderRadius: 3, fontSize: 11 } }, m[3])); else if (m[4] !== undefined) parts.push(React.createElement("em", { key: m.index }, m[4])); last = m.index + m[0].length; } if (last < str.length) parts.push(str.slice(last)); return parts.length === 1 && typeof parts[0] === "string" ? parts[0] : parts; }; while (i < lines.length) { const line = lines[i]; if (!line.trim()) { i++; continue; } if (line.startsWith("## ")) { elements.push(React.createElement("div", { key: i, style: { ...prose, fontWeight: 700, fontSize: 14, color: "var(--ink)", marginTop: 4, marginBottom: 10, borderBottom: "1px solid var(--line-2)", paddingBottom: 6 } }, formatInline(line.slice(3)))); } else if (line.startsWith("### ")) { elements.push(React.createElement("div", { key: i, style: { ...prose, fontWeight: 600, fontSize: 13, color: "var(--ink)", marginTop: 16, marginBottom: 6 } }, formatInline(line.slice(4)))); } else if (line.startsWith("- ")) { elements.push(React.createElement("div", { key: i, style: { ...prose, fontSize: 13, display: "flex", gap: 6, marginBottom: 5, lineHeight: 1.6 } }, React.createElement("span", { style: { color: "var(--ink-3)", flexShrink: 0 } }, "–"), React.createElement("span", { style: { color: "var(--ink-2)" } }, formatInline(line.slice(2))) )); } else { elements.push(React.createElement("div", { key: i, style: { ...prose, fontSize: 13, color: "var(--ink-2)", marginBottom: 3, lineHeight: 1.6 } }, formatInline(line))); } i++; } return elements; } function formatActivityDate(ts) { if (!ts) return ""; const d = new Date(ts); return d.toLocaleDateString("en-US", { month: "short", day: "numeric" }); } function Repository({ user, isRepoAdmin, isOrgAdmin }) { const [tab, setTab] = useStateRepo("documents"); const [documents, setDocuments] = useStateRepo([]); const [summary, setSummary] = useStateRepo(""); const [activityLog, setActivityLog] = useStateRepo([]); const [teamData, setTeamData] = useStateRepo(null); const [loading, setLoading] = useStateRepo(false); const [error, setError] = useStateRepo(null); const [summaryOpen, setSummaryOpen] = useStateRepo(false); const [howToOpen, setHowToOpen] = useStateRepo(false); const [activityOpen, setActivityOpen] = useStateRepo(false); const [searchQ, setSearchQ] = useStateRepo(""); const [searchResults, setSearchResults] = useStateRepo([]); const [searchLoading, setSearchLoading] = useStateRepo(false); const [searchError, setSearchError] = useStateRepo(null); const [tagOverviewOpen, setTagOverviewOpen] = useStateRepo(false); const [guidelinesOpen, setGuidelinesOpen] = useStateRepo(false); const [uploadDragging, setUploadDragging] = useStateRepo(false); const [uploading, setUploading] = useStateRepo(false); const [uploadError, setUploadError] = useStateRepo(null); const [editingTitle, setEditingTitle] = useStateRepo({}); const [editingTag, setEditingTag] = useStateRepo({}); const [tagFilter, setTagFilter] = useStateRepo([]); const [summaryUpdating, setSummaryUpdating] = useStateRepo(false); const [standardTags, setStandardTags] = useStateRepo([]); const [tagGuideOpen, setTagGuideOpen] = useStateRepo(false); const [approveRoles, setApproveRoles] = useStateRepo({}); const [inviteEmail, setInviteEmail] = useStateRepo(""); const [inviteRole, setInviteRole] = useStateRepo("member"); const [inviteStatus, setInviteStatus] = useStateRepo(null); const [inviteError, setInviteError] = useStateRepo(null); const fileInputRef = useRefRepo(null); const searchTimer = useRefRepo(null); useEffectRepo(() => { loadData(); }, []); const loadData = async () => { setLoading(true); setError(null); try { const [repoData, team] = await Promise.all([ apiGet("/api/repository"), apiGet("/api/team").catch(() => null), ]); setDocuments(repoData.documents || []); setSummary(repoData.summary || ""); setSummaryUpdating(repoData.summary_updating || false); setActivityLog(repoData.activity_log || []); setStandardTags(repoData.standard_tags || []); setTeamData(team); } catch (e) { setError(e.message); } finally { setLoading(false); } }; useEffectRepo(() => { if (!summaryUpdating) return; const id = setInterval(async () => { try { const data = await apiGet("/api/repository"); setSummary(data.summary || ""); setDocuments(data.documents || []); setActivityLog(data.activity_log || []); if (!data.summary_updating) { setSummaryUpdating(false); clearInterval(id); } } catch {} }, 4000); return () => clearInterval(id); }, [summaryUpdating]); useEffectRepo(() => { if (!searchQ.trim()) { setSearchResults([]); return; } clearTimeout(searchTimer.current); searchTimer.current = setTimeout(async () => { setSearchLoading(true); setSearchError(null); try { const data = await apiGet(`/api/repository/search?q=${encodeURIComponent(searchQ.trim())}`); setSearchResults(data.results || []); } catch (e) { setSearchError("Search unavailable — " + e.message); setSearchResults([]); } finally { setSearchLoading(false); } }, 400); return () => clearTimeout(searchTimer.current); }, [searchQ]); const handleUploadFile = async (file) => { setUploadError(null); setUploading(true); try { const fd = new FormData(); fd.append("file", file); const res = await fetch("/api/repository/upload", { method: "POST", body: fd }); if (!res.ok) { const err = await res.json().catch(() => ({})); throw new Error(err.detail || "Upload failed"); } const doc = await res.json(); setDocuments(prev => [...prev, doc]); setSummaryUpdating(true); } catch (e) { setUploadError(e.message); } finally { setUploading(false); } }; const handleDrop = (e) => { e.preventDefault(); setUploadDragging(false); const file = e.dataTransfer.files[0]; if (file) handleUploadFile(file); }; const handleDelete = async (doc_id) => { if (!confirm("Delete this document? This cannot be undone.")) return; try { const res = await fetch(`/api/repository/${doc_id}`, { method: "DELETE" }); if (!res.ok) throw new Error("Delete failed"); setDocuments(prev => prev.filter(d => d.doc_id !== doc_id)); setSummaryUpdating(true); // Refresh activity log after delete const data = await apiGet("/api/repository").catch(() => null); if (data) setActivityLog(data.activity_log || []); } catch (e) { alert(e.message); } }; const handleTitleSave = async (doc_id, title) => { try { const res = await fetch(`/api/repository/${doc_id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ title }), }); if (res.ok) { const updated = await res.json(); setDocuments(prev => prev.map(d => d.doc_id === doc_id ? updated : d)); } } catch {} setEditingTitle(prev => { const n = { ...prev }; delete n[doc_id]; return n; }); }; const handleTagsSave = async (doc_id, tags) => { try { const res = await fetch(`/api/repository/${doc_id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ tags }), }); if (res.ok) { const updated = await res.json(); setDocuments(prev => prev.map(d => d.doc_id === doc_id ? updated : d)); } } catch {} }; const handleAddTag = async (doc_id, newTag, currentTags) => { const trimmed = newTag.trim().toLowerCase(); setEditingTag(prev => { const n = { ...prev }; delete n[doc_id]; return n; }); if (!trimmed || currentTags.includes(trimmed)) return; await handleTagsSave(doc_id, [...currentTags, trimmed]); }; const handleRemoveTag = async (doc_id, tag, currentTags) => { await handleTagsSave(doc_id, currentTags.filter(t => t !== tag)); }; const handleSuggestTags = async (doc_id) => { try { const res = await fetch(`/api/repository/${doc_id}/suggest-tags`, { method: "POST" }); if (!res.ok) throw new Error("Failed"); await loadData(); } catch (e) { alert("Could not auto-tag: " + e.message); } }; const handleTeamAction = async (memberEmail, action, extra = {}) => { try { const res = await fetch(`/api/team/members/${encodeURIComponent(memberEmail)}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action, ...extra }), }); if (!res.ok) { const e = await res.json().catch(() => ({})); throw new Error(e.detail || "Action failed"); } const team = await apiGet("/api/team"); setTeamData(team); } catch (e) { alert(e.message); } }; const mono = { fontFamily: "var(--mono)", fontSize: 12 }; const prose = { fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif", fontSize: 13, lineHeight: 1.5 }; const TAG_COLORS = { "competitive intelligence": { bg: "#EEF2FF", border: "#C7D2FE", text: "#4338CA" }, "clinical data": { bg: "#ECFDF5", border: "#6EE7B7", text: "#065F46" }, "market research": { bg: "#FFF7ED", border: "#FED7AA", text: "#9A3412" }, "regulatory": { bg: "#FEF2F2", border: "#FECACA", text: "#991B1B" }, "internal strategy": { bg: "#F0F9FF", border: "#BAE6FD", text: "#0C4A6E" }, "financial": { bg: "#FEFCE8", border: "#FDE68A", text: "#92400E" }, "technical": { bg: "#F0FDF4", border: "#BBF7D0", text: "#14532D" }, "published literature": { bg: "#FAF5FF", border: "#E9D5FF", text: "#6B21A8" }, "presentations": { bg: "#FFF1F2", border: "#FECDD3", text: "#9F1239" }, "contracts": { bg: "#F8FAFC", border: "#CBD5E1", text: "#334155" }, "case studies": { bg: "#FFFBEB", border: "#FCD34D", text: "#78350F" }, "protocols & SOPs": { bg: "#F0FDFA", border: "#99F6E4", text: "#134E4A" }, }; const tagStyle = (tag, active) => { const c = TAG_COLORS[tag]; if (active) return { background: c ? c.text : "var(--ink)", color: "#fff", border: `1px solid ${c ? c.text : "var(--ink)"}` }; return c ? { background: c.bg, border: `1px solid ${c.border}`, color: c.text } : { background: "var(--bg-2)", border: "1px solid var(--line-2)", color: "var(--ink-2)" }; }; const pill = (color, bg) => ({ color, background: bg, fontSize: 11, fontWeight: 600, padding: "2px 7px", borderRadius: 4, display: "inline-block", fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif", }); const statusBadge = (status) => { if (status === "indexed") return Indexed; if (status === "no_text") return No text; return Processing; }; const fmtBytes = (n) => { if (!n && n !== 0) return ""; if (n >= 1024 * 1024) return `${(n / (1024 * 1024)).toFixed(1)} MB`; if (n >= 1024) return `${Math.round(n / 1024)} KB`; return `${n} B`; }; // Self-explaining truncation pill — distinguishes the page cap from the chunk cap so a // dense doc that hit the chunk limit doesn't show a healthy page count next to a bare warning. const truncationPill = (doc) => { if (!doc.truncated) return null; const msg = doc.truncation_reason === "chunks" ? `Indexed first ${doc.chunk_count} passages (chunk limit reached) — some content not indexed` : `Indexed first ${doc.indexed_pages} of ${doc.total_pages} pages — remainder not indexed`; return Truncated; }; const embedPill = (doc) => { if (doc.embed_status === "embedded" || doc.embed_status === undefined) return null; const msg = doc.embed_status === "pending" ? "Semantic embedding pending — using keyword (TF-IDF) search for this doc until re-indexed" : "Keyword (TF-IDF) search only — not semantically indexed"; return Keyword only; }; if (loading) return (
Loading repository…
); if (error) return (
Error: {error}
); const renderActivitySidebar = () => { if (!isRepoAdmin) return null; return (
{activityOpen ? (
{isRepoAdmin && (
Tips
Works well
  • PDFs and Word docs with selectable text
  • Research reports, competitive briefs, white papers
  • Meeting notes, memos, technical SOPs
Avoid
  • Files with passwords or API keys
  • Scanned images without readable text
  • Spreadsheets, images, executables
After upload
  • Tags are applied automatically. You can refine or add more anytime.
  • Documents are available to agents immediately after processing completes
)}
) : ( )}
); }; const renderTagOverview = () => { const tagMap = {}; documents.forEach(doc => { (doc.tags || []).forEach(tag => { if (!tagMap[tag]) tagMap[tag] = []; tagMap[tag].push(doc.title || doc.filename); }); }); const tags = Object.keys(tagMap).sort(); if (!tags.length) return null; return (
{tagOverviewOpen && (
{tags.map(tag => (
{tag} {tagMap[tag].length}
{tagMap[tag].map((title, i) => ( · {title} ))}
))}
)}
); }; const renderDocuments = () => (
{/* Main column */}
{/* Repository summary */} {(summary || summaryUpdating) && (
{summaryOpen && (
{summaryUpdating && !summary && (
Generating summary…
)} {summary && renderSummaryMarkdown(summary)}
)}
)} {/* Tag Overview — live from document tags */} {renderTagOverview()} {/* Search */}
setSearchQ(e.target.value)} placeholder="Search document content…" style={{ width: "100%", padding: "10px 12px", border: "1px solid var(--line-2)", borderRadius: 6, ...prose, background: "var(--bg)", color: "var(--ink)", boxSizing: "border-box", outline: "none", }} /> {searchLoading && ( searching… )}
{!searchQ.trim() && (
Searches the text content of all indexed documents.
)} {searchError && (
{searchError}
)} {searchResults.length > 0 && (
{searchResults.map((r, i) => (
{r.doc_title} · p.{r.page}
{r.excerpt}
))}
)} {searchQ.trim() && !searchLoading && !searchError && searchResults.length === 0 && (
No results. Only documents with extractable text are searchable.
)}
{/* Tag Reference panel */} {standardTags.length > 0 && (
{tagGuideOpen && (
{standardTags.map(tag => ( {tag} ))}
These tags are suggested automatically when you upload documents. You can also add custom tags (anything outside this list).
)}
)} {/* Tag filter bar */} {(() => { const allTags = [...new Set(documents.flatMap(d => d.tags || []))].sort(); if (!allTags.length) return null; return (
Filter: {allTags.map(tag => { const active = tagFilter.includes(tag); return ( ); })} {tagFilter.length > 0 && ( )}
); })()} {/* Document table */} {documents.length === 0 ? (
{isRepoAdmin ? "Upload your first document to get started." : "No documents yet. Ask your repository admin to add files."}
) : (
{["Filename", "Title", "Tags", "Status", "Uploaded by", "Date", ""].map(h => ( ))} {documents.filter(doc => tagFilter.length === 0 || (doc.tags || []).some(t => tagFilter.includes(t))).map(doc => ( ))}
{h}
{doc.filename} {isRepoAdmin && editingTitle[doc.doc_id] !== undefined ? ( setEditingTitle(prev => ({ ...prev, [doc.doc_id]: e.target.value }))} onBlur={() => handleTitleSave(doc.doc_id, editingTitle[doc.doc_id])} onKeyDown={e => { if (e.key === "Enter") handleTitleSave(doc.doc_id, editingTitle[doc.doc_id]); if (e.key === "Escape") setEditingTitle(prev => { const n = { ...prev }; delete n[doc.doc_id]; return n; }); }} style={{ width: "100%", ...prose, padding: "2px 4px", border: "1px solid var(--ink)", borderRadius: 3, background: "var(--bg)", color: "var(--ink)", outline: "none" }} /> ) : (
{doc.title} {isRepoAdmin && ( )}
)}
{(doc.tags || []).map(tag => ( {tag} {isRepoAdmin && ( )} ))} {isRepoAdmin && (doc.tags || []).length === 0 && editingTag[doc.doc_id] === undefined && ( )} {isRepoAdmin && ( editingTag[doc.doc_id] !== undefined ? (
setEditingTag(prev => ({ ...prev, [doc.doc_id]: e.target.value }))} onBlur={() => handleAddTag(doc.doc_id, editingTag[doc.doc_id] || "", doc.tags || [])} onKeyDown={e => { if (e.key === "Enter") handleAddTag(doc.doc_id, editingTag[doc.doc_id], doc.tags || []); if (e.key === "Escape") setEditingTag(prev => { const n = { ...prev }; delete n[doc.doc_id]; return n; }); }} style={{ width: "100%", ...mono, fontSize: 11, padding: "3px 8px", border: "1px solid var(--ink)", borderRadius: 6, background: "var(--bg)", color: "var(--ink)", outline: "none", boxSizing: "border-box" }} /> {(() => { const existing = doc.tags || []; const q = (editingTag[doc.doc_id] || "").toLowerCase(); const suggestions = standardTags.filter(t => !existing.includes(t) && (!q || t.includes(q))); if (!suggestions.length) return null; return (
{suggestions.slice(0, 8).map(s => ( ))}
); })()}
) : ( ) )}
{statusBadge(doc.status)} {truncationPill(doc)} {embedPill(doc)}
{doc.status === "indexed" && ( {doc.total_pages ? `${doc.indexed_pages} of ${doc.total_pages} pages · ` : ""} {doc.chunk_count != null ? `${doc.chunk_count} passages` : ""} {doc.size_bytes ? ` · ${fmtBytes(doc.size_bytes)}` : ""} )}
{doc.uploaded_by.split("@")[0]} {(doc.uploaded_at || "").slice(0, 10)} {isRepoAdmin && ( )}
)} {/* Upload zone — repo admin only, at the bottom */} {isRepoAdmin && (
{ e.preventDefault(); setUploadDragging(true); }} onDragLeave={() => setUploadDragging(false)} onDrop={handleDrop} onClick={() => fileInputRef.current?.click()} style={{ border: `2px dashed ${uploadDragging ? "var(--ink)" : "var(--line-2)"}`, borderRadius: 8, padding: 24, textAlign: "center", cursor: "pointer", background: uploadDragging ? "var(--bg-2)" : "transparent", transition: "border-color 0.15s, background 0.15s", }} > { const f = e.target.files[0]; if (f) handleUploadFile(f); e.target.value = ""; }} /> {uploading ? ( Uploading… ) : (
Drop a file or click to upload
PDF, Word, TXT, Markdown · PDF/Word up to 25 MB · Text up to 5 MB
)}
{uploadError && (
{uploadError}
)}
)}
{/* Activity sidebar */} {tab === "documents" && renderActivitySidebar()}
); const renderTeam = () => { if (!teamData) return
Loading team…
; const ROLE_LABELS = { member: "Member", repo_admin: "Repo Admin", org_admin: "Org Admin" }; return (
{isOrgAdmin && (
Pending Requests
{(!teamData.pending_requests || teamData.pending_requests.length === 0) ? (
No pending join requests.
) : ( teamData.pending_requests.map(r => (
{r.name ? `${r.name} (${r.email})` : r.email} {(r.requested_at || "").slice(0, 10)}
)) )}
)} {isOrgAdmin && teamData.denied_requests?.length > 0 && (
Denied Requests
{teamData.denied_requests.map(r => (
{r.name ? `${r.name} (${r.email})` : r.email} denied {(r.denied_at || "").slice(0, 10)}
))}
)}
Members
{(teamData.members || []).map(m => (
{m.name ? `${m.name} (${m.email})` : m.email} {(m.joined_at || "").slice(0, 10)} {isOrgAdmin && m.email !== user?.email ? ( <> ) : ( {ROLE_LABELS[m.role] || m.role} )}
))}
{isOrgAdmin && (
Invite Member
{ setInviteEmail(e.target.value); setInviteStatus(null); setInviteError(null); }} style={{ ...prose, flex: 1, padding: "6px 10px", border: "1px solid var(--line-2)", borderRadius: 4, background: "var(--bg)", color: "var(--ink)", outline: "none" }} />
{inviteStatus === "sent" &&
Invited successfully — they'll have access on next login.
} {inviteStatus === "error" &&
{inviteError}
}
)}
{(() => { const isOnlyOrgAdmin = isOrgAdmin && (teamData?.members || []).filter(m => m.role === "org_admin").length === 1; return ( <> {isOnlyOrgAdmin && (
You are the only org admin. Assign another org admin before leaving.
)} ); })()}
); }; return (
{/* Tabs */}
{(user?.solo_repo ? ["documents"] : ["documents", "team"]).map(t => ( ))}
{tab === "documents" ? renderDocuments() : renderTeam()}
); }