feat(frontend): move KB section to URL-driven /kb/[id]/... routes#77
Conversation
Implements the Conversations section PR from the frontend re-haul (spec: docs/superpowers/specs/2026-05-21-frontend-rehaul-conversations-design.md). Builds on the umbrella shell PR. Routing - /conversations with query-driven tabs (?tab=real|transcripts). - ?id=<rowId> selects the right-pane detail; refresh / back / forward preserve both tab and selection. - /conversations/real/<id> and /conversations/transcripts/<id> kept as permalink-style routes that redirect into the split-view URL. UI - Master-detail split inside both tabs: sidebar list on the left, detail content on the right. - Auto-selects the first row when no ?id= is present. - Real conversations list backed by the new org-scoped Convex query; detail view reuses groupMessagesWithToolCalls + ToolCallGroup from the agent playground for consistent rendering (read-only). - Transcripts tab embeds the existing livechat upload + stats + per- conversation analysis flow; LivechatView is replaced by the new TranscriptsPane / TranscriptDetail pair. Backend - crud/conversations.listForOrg: org-scoped list with agent name and last-message preview hydration. Shell tweaks (used only by /conversations today) - TabsLayout switched from path-based to ?tab= query-driven tabs; removes the duplicate breadcrumb + title above the tab strip. - TabsLayout now strictly viewport-bounded so the detail pane scrolls internally instead of growing the page. - sidebars.ts: drop the match: predicate functions that cannot be serialised across the RSC boundary into EntityDetailLayout; default prefix-match already covers the highlighting behaviour. Cleanup - /kb page no longer mounts LivechatView (icon-rail removed, KB page is documents-only). Livechat is now reachable only via /conversations. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Moves legacy /kb, /dataset, /retrievers, /retrievers/results pages under
the new /kb/<id>/configure and /kb/<id>/evaluate/{datasets,retrievers,
experiments} structure per the umbrella re-haul. KB id is now URL-driven;
the legacy global KB dropdown and ?kb= search-param hook are no longer
used by these pages.
Shell:
- Add Spinner and ErrorToast shared components.
- Add useKbBreadcrumb hook to dedupe per-page KB lookups used for breadcrumbs.
- EntityDetailLayout: collapsible sidebar with icons in collapsed mode,
fullWidth prop for content that should bust max-w-7xl, and h-screen
flex shell so detail boxes fill the viewport.
- sidebars: add icons for Configure/Datasets/Retrievers/Experiments (and
agent equivalents).
New routes:
- /kb - landing grid of KBs.
- /kb/[id]/configure - documents master/detail.
- /kb/[id]/evaluate/datasets - question datasets list.
- /kb/[id]/evaluate/datasets/[datasetId] - question+ground-truth viewer.
- /kb/[id]/evaluate/retrievers - retrievers list.
- /kb/[id]/evaluate/retrievers/[rid] - retriever tabs.
- /kb/[id]/evaluate/experiments - experiment runs.
- /kb/[id]/evaluate/experiments/[expId] - experiment run detail.
- /kb/[id]/evaluate - redirect to /datasets.
Removed:
- app/kb/page.tsx (legacy single-KB page; replaced by landing+configure).
- app/dataset/ (whole tree).
- app/retrievers/ (whole tree incl. results/[experimentId]).
Not touched (handled by sibling PRs):
- app/experiments/ and app/experiments/[id]/ - Agents PR will delete.
- app/evaluators/ - Agents PR scope.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…ation' into worktree-frontend-rehaul-kb-branch # Conflicts: # packages/frontend/src/app/kb/page.tsx # packages/frontend/src/components/shell/sidebars.ts
Retrievers are production-inference primitives (used by experiments but not eval-only), so they no longer belong inside the Evaluate group. Sidebar now reads: Configure → Retrievers → Evaluate (Datasets, Experiments). Route moved from /kb/[id]/evaluate/retrievers/... to /kb/[id]/retrievers/... Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
WalkthroughThis PR restructures the conversations and knowledge base interfaces. It adds a backend Convex query for organization conversations with enriched metadata, replaces conversations stub pages with pane-based components supporting two-way tabbed navigation, redesigns the KB section from a master-detail page to a landing page with organized sub-routes, enhances shell layout components with collapsible sidebars and query-based tab switching, and consolidates retriever management from scattered routes into a kb-scoped hierarchy. ChangesConversations Backend Query and Pane Components
Shell Components and KB Sidebar Configuration
Knowledge Base Page Hierarchy and Routing
🎯 4 (Complex) | ⏱️ ~60 minutes 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Actionable comments posted: 18
🧹 Nitpick comments (1)
packages/frontend/src/app/kb/[id]/configure/page.tsx (1)
81-88: ⚡ Quick winAdd user feedback when document deletion fails.
The catch block only logs to console. Users won't know the deletion failed. Consider using the
ErrorToastcomponent (already used elsewhere in this PR) or adding state to display the error.Proposed approach
+ const [deleteError, setDeleteError] = useState<string | null>(null); + async function handleDeleteDoc(docId: Id<"documents">) { try { + setDeleteError(null); await removeDoc({ id: docId }); if (selectedDocId === docId) setSelectedDocId(null); } catch (err) { console.error("Failed to delete document:", err); + setDeleteError("Failed to delete document. Please try again."); } }Then render:
{deleteError && <ErrorToast message={deleteError} onDismiss={() => setDeleteError(null)} />}
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: af3eaf65-2e23-410c-9a51-96112004f74d
📒 Files selected for processing (29)
packages/backend/convex/crud/conversations.tspackages/frontend/src/app/conversations/page.tsxpackages/frontend/src/app/conversations/real/[conversationId]/page.tsxpackages/frontend/src/app/conversations/transcripts/[id]/page.tsxpackages/frontend/src/app/conversations/transcripts/page.tsxpackages/frontend/src/app/dataset/page.tsxpackages/frontend/src/app/kb/[id]/configure/page.tsxpackages/frontend/src/app/kb/[id]/evaluate/datasets/[datasetId]/page.tsxpackages/frontend/src/app/kb/[id]/evaluate/datasets/page.tsxpackages/frontend/src/app/kb/[id]/evaluate/experiments/[expId]/page.tsxpackages/frontend/src/app/kb/[id]/evaluate/experiments/page.tsxpackages/frontend/src/app/kb/[id]/evaluate/page.tsxpackages/frontend/src/app/kb/[id]/evaluate/retrievers/[rid]/page.tsxpackages/frontend/src/app/kb/[id]/evaluate/retrievers/page.tsxpackages/frontend/src/app/kb/[id]/retrievers/[rid]/page.tsxpackages/frontend/src/app/kb/[id]/retrievers/page.tsxpackages/frontend/src/app/kb/page.tsxpackages/frontend/src/app/retrievers/page.tsxpackages/frontend/src/components/conversations/RealConversationDetail.tsxpackages/frontend/src/components/conversations/RealConversationsPane.tsxpackages/frontend/src/components/conversations/TranscriptDetail.tsxpackages/frontend/src/components/conversations/TranscriptsPane.tsxpackages/frontend/src/components/shell/EntityDetailLayout.tsxpackages/frontend/src/components/shell/ErrorToast.tsxpackages/frontend/src/components/shell/Spinner.tsxpackages/frontend/src/components/shell/TabsLayout.tsxpackages/frontend/src/components/shell/sidebars.tspackages/frontend/src/components/shell/sidebars.tsxpackages/frontend/src/lib/useKbBreadcrumb.ts
💤 Files with no reviewable changes (6)
- packages/frontend/src/components/shell/sidebars.ts
- packages/frontend/src/app/conversations/transcripts/page.tsx
- packages/frontend/src/app/dataset/page.tsx
- packages/frontend/src/app/retrievers/page.tsx
- packages/frontend/src/app/kb/[id]/evaluate/retrievers/[rid]/page.tsx
- packages/frontend/src/app/kb/[id]/evaluate/retrievers/page.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use TypeScript strict mode and ESM ("type": "module") throughout the project
Files:
packages/frontend/src/app/conversations/real/[conversationId]/page.tsxpackages/frontend/src/app/conversations/transcripts/[id]/page.tsxpackages/frontend/src/lib/useKbBreadcrumb.tspackages/frontend/src/app/kb/[id]/evaluate/page.tsxpackages/frontend/src/components/shell/ErrorToast.tsxpackages/frontend/src/components/conversations/TranscriptDetail.tsxpackages/frontend/src/components/conversations/RealConversationDetail.tsxpackages/frontend/src/components/shell/Spinner.tsxpackages/backend/convex/crud/conversations.tspackages/frontend/src/app/conversations/page.tsxpackages/frontend/src/app/kb/[id]/retrievers/page.tsxpackages/frontend/src/app/kb/page.tsxpackages/frontend/src/app/kb/[id]/retrievers/[rid]/page.tsxpackages/frontend/src/components/shell/sidebars.tsxpackages/frontend/src/components/conversations/RealConversationsPane.tsxpackages/frontend/src/components/shell/EntityDetailLayout.tsxpackages/frontend/src/app/kb/[id]/evaluate/datasets/[datasetId]/page.tsxpackages/frontend/src/app/kb/[id]/configure/page.tsxpackages/frontend/src/components/shell/TabsLayout.tsxpackages/frontend/src/app/kb/[id]/evaluate/experiments/page.tsxpackages/frontend/src/app/kb/[id]/evaluate/datasets/page.tsxpackages/frontend/src/app/kb/[id]/evaluate/experiments/[expId]/page.tsxpackages/frontend/src/components/conversations/TranscriptsPane.tsx
packages/frontend/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Frontend must use Convex reactive queries (useQuery/useMutation) for real-time UI updates
Files:
packages/frontend/src/app/conversations/real/[conversationId]/page.tsxpackages/frontend/src/app/conversations/transcripts/[id]/page.tsxpackages/frontend/src/lib/useKbBreadcrumb.tspackages/frontend/src/app/kb/[id]/evaluate/page.tsxpackages/frontend/src/components/shell/ErrorToast.tsxpackages/frontend/src/components/conversations/TranscriptDetail.tsxpackages/frontend/src/components/conversations/RealConversationDetail.tsxpackages/frontend/src/components/shell/Spinner.tsxpackages/frontend/src/app/conversations/page.tsxpackages/frontend/src/app/kb/[id]/retrievers/page.tsxpackages/frontend/src/app/kb/page.tsxpackages/frontend/src/app/kb/[id]/retrievers/[rid]/page.tsxpackages/frontend/src/components/shell/sidebars.tsxpackages/frontend/src/components/conversations/RealConversationsPane.tsxpackages/frontend/src/components/shell/EntityDetailLayout.tsxpackages/frontend/src/app/kb/[id]/evaluate/datasets/[datasetId]/page.tsxpackages/frontend/src/app/kb/[id]/configure/page.tsxpackages/frontend/src/components/shell/TabsLayout.tsxpackages/frontend/src/app/kb/[id]/evaluate/experiments/page.tsxpackages/frontend/src/app/kb/[id]/evaluate/datasets/page.tsxpackages/frontend/src/app/kb/[id]/evaluate/experiments/[expId]/page.tsxpackages/frontend/src/components/conversations/TranscriptsPane.tsx
packages/frontend/**/*.{tsx,css,json}
📄 CodeRabbit inference engine (CLAUDE.md)
Frontend design system uses dark theme, JetBrains Mono font, and custom color token accent (
#6ee7b7)
Files:
packages/frontend/src/app/conversations/real/[conversationId]/page.tsxpackages/frontend/src/app/conversations/transcripts/[id]/page.tsxpackages/frontend/src/app/kb/[id]/evaluate/page.tsxpackages/frontend/src/components/shell/ErrorToast.tsxpackages/frontend/src/components/conversations/TranscriptDetail.tsxpackages/frontend/src/components/conversations/RealConversationDetail.tsxpackages/frontend/src/components/shell/Spinner.tsxpackages/frontend/src/app/conversations/page.tsxpackages/frontend/src/app/kb/[id]/retrievers/page.tsxpackages/frontend/src/app/kb/page.tsxpackages/frontend/src/app/kb/[id]/retrievers/[rid]/page.tsxpackages/frontend/src/components/shell/sidebars.tsxpackages/frontend/src/components/conversations/RealConversationsPane.tsxpackages/frontend/src/components/shell/EntityDetailLayout.tsxpackages/frontend/src/app/kb/[id]/evaluate/datasets/[datasetId]/page.tsxpackages/frontend/src/app/kb/[id]/configure/page.tsxpackages/frontend/src/components/shell/TabsLayout.tsxpackages/frontend/src/app/kb/[id]/evaluate/experiments/page.tsxpackages/frontend/src/app/kb/[id]/evaluate/datasets/page.tsxpackages/frontend/src/app/kb/[id]/evaluate/experiments/[expId]/page.tsxpackages/frontend/src/components/conversations/TranscriptsPane.tsx
packages/frontend/src/{app,components}/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Use Convex reactive queries (useQuery/useMutation) hooks for real-time UI updates in frontend
Files:
packages/frontend/src/app/conversations/real/[conversationId]/page.tsxpackages/frontend/src/app/conversations/transcripts/[id]/page.tsxpackages/frontend/src/app/kb/[id]/evaluate/page.tsxpackages/frontend/src/components/shell/ErrorToast.tsxpackages/frontend/src/components/conversations/TranscriptDetail.tsxpackages/frontend/src/components/conversations/RealConversationDetail.tsxpackages/frontend/src/components/shell/Spinner.tsxpackages/frontend/src/app/conversations/page.tsxpackages/frontend/src/app/kb/[id]/retrievers/page.tsxpackages/frontend/src/app/kb/page.tsxpackages/frontend/src/app/kb/[id]/retrievers/[rid]/page.tsxpackages/frontend/src/components/shell/sidebars.tsxpackages/frontend/src/components/conversations/RealConversationsPane.tsxpackages/frontend/src/components/shell/EntityDetailLayout.tsxpackages/frontend/src/app/kb/[id]/evaluate/datasets/[datasetId]/page.tsxpackages/frontend/src/app/kb/[id]/configure/page.tsxpackages/frontend/src/components/shell/TabsLayout.tsxpackages/frontend/src/app/kb/[id]/evaluate/experiments/page.tsxpackages/frontend/src/app/kb/[id]/evaluate/datasets/page.tsxpackages/frontend/src/app/kb/[id]/evaluate/experiments/[expId]/page.tsxpackages/frontend/src/components/conversations/TranscriptsPane.tsx
packages/frontend/**/*.{tsx,ts,css}
📄 CodeRabbit inference engine (AGENTS.md)
Apply dark theme with JetBrains Mono font and accent color
#6ee7b7in frontend design system using Tailwind CSS v4
Files:
packages/frontend/src/app/conversations/real/[conversationId]/page.tsxpackages/frontend/src/app/conversations/transcripts/[id]/page.tsxpackages/frontend/src/lib/useKbBreadcrumb.tspackages/frontend/src/app/kb/[id]/evaluate/page.tsxpackages/frontend/src/components/shell/ErrorToast.tsxpackages/frontend/src/components/conversations/TranscriptDetail.tsxpackages/frontend/src/components/conversations/RealConversationDetail.tsxpackages/frontend/src/components/shell/Spinner.tsxpackages/frontend/src/app/conversations/page.tsxpackages/frontend/src/app/kb/[id]/retrievers/page.tsxpackages/frontend/src/app/kb/page.tsxpackages/frontend/src/app/kb/[id]/retrievers/[rid]/page.tsxpackages/frontend/src/components/shell/sidebars.tsxpackages/frontend/src/components/conversations/RealConversationsPane.tsxpackages/frontend/src/components/shell/EntityDetailLayout.tsxpackages/frontend/src/app/kb/[id]/evaluate/datasets/[datasetId]/page.tsxpackages/frontend/src/app/kb/[id]/configure/page.tsxpackages/frontend/src/components/shell/TabsLayout.tsxpackages/frontend/src/app/kb/[id]/evaluate/experiments/page.tsxpackages/frontend/src/app/kb/[id]/evaluate/datasets/page.tsxpackages/frontend/src/app/kb/[id]/evaluate/experiments/[expId]/page.tsxpackages/frontend/src/components/conversations/TranscriptsPane.tsx
packages/frontend/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use Clerk AuthGate component for centralized authentication and organization gating in the frontend
Files:
packages/frontend/src/components/shell/ErrorToast.tsxpackages/frontend/src/components/conversations/TranscriptDetail.tsxpackages/frontend/src/components/conversations/RealConversationDetail.tsxpackages/frontend/src/components/shell/Spinner.tsxpackages/frontend/src/components/shell/sidebars.tsxpackages/frontend/src/components/conversations/RealConversationsPane.tsxpackages/frontend/src/components/shell/EntityDetailLayout.tsxpackages/frontend/src/components/shell/TabsLayout.tsxpackages/frontend/src/components/conversations/TranscriptsPane.tsx
packages/backend/convex/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
packages/backend/convex/**/*.ts: Every public Convex function must call getAuthContext(ctx) to extract userId/orgId for org-scoped access control
Files with "use node" directive can ONLY contain actions; mutations/queries must be in separate files
ctx.vectorSearch() is only available in actions, not queries. Use pattern: vectorSearch in action → hydrate via internalQuery
Sub-path imports from eval-lib's /langsmith and /llm can ONLY be used in "use node" action files; use /shared sub-path for shared utilities
packages/backend/convex/**/*.ts: Organize backend (Convex) into domain directories (crud/, generation/, retrieval/, experiments/, langsmith/) with file-based routing mapping files to API functions
Files with 'use node' directive can ONLY contain actions — mutations and queries must be in separate files
Every public Convex function must call getAuthContext(ctx) to extract userId/orgId for org-scoped access control
Files:
packages/backend/convex/crud/conversations.ts
packages/backend/convex/crud/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Use Clerk JWT authentication for org-scoped access control with user record sync via users.getOrCreate helper
Files:
packages/backend/convex/crud/conversations.ts
packages/backend/convex/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (packages/backend/CLAUDE.md)
packages/backend/convex/**/*.{ts,tsx,js,jsx}: Always readconvex/_generated/ai/guidelines.mdfirst for important guidelines on how to correctly use Convex APIs and patterns
Follow rules inconvex/_generated/ai/guidelines.mdwhich override Convex knowledge from training data
Files:
packages/backend/convex/crud/conversations.ts
packages/backend/convex/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (packages/backend/AGENTS.md)
Always read
convex/_generated/ai/guidelines.mdfirst for important guidelines on how to correctly use Convex APIs and patterns
Files:
packages/backend/convex/crud/conversations.ts
🔇 Additional comments (13)
packages/frontend/src/app/kb/page.tsx (1)
3-11: LGTM!Also applies to: 13-21, 23-54, 59-71
packages/frontend/src/app/kb/[id]/configure/page.tsx (1)
1-79: LGTM!Also applies to: 90-287
packages/frontend/src/components/conversations/RealConversationDetail.tsx (1)
16-17: LGTM!Also applies to: 19-97
packages/frontend/src/components/conversations/TranscriptDetail.tsx (1)
12-36: LGTM!packages/frontend/src/app/conversations/page.tsx (1)
5-25: LGTM!packages/frontend/src/app/conversations/real/[conversationId]/page.tsx (1)
3-10: LGTM!packages/frontend/src/app/conversations/transcripts/[id]/page.tsx (1)
3-10: LGTM!packages/frontend/src/app/kb/[id]/evaluate/page.tsx (1)
1-10: LGTM!packages/frontend/src/app/kb/[id]/evaluate/datasets/page.tsx (1)
1-166: LGTM!packages/frontend/src/components/shell/sidebars.tsx (1)
29-43: LGTM!Also applies to: 45-61
packages/frontend/src/lib/useKbBreadcrumb.ts (1)
11-20: LGTM!packages/frontend/src/app/kb/[id]/retrievers/page.tsx (1)
16-95: LGTM!Also applies to: 120-127
packages/frontend/src/app/kb/[id]/retrievers/[rid]/page.tsx (1)
17-46: LGTM!Also applies to: 52-98, 122-126
| const agents = await Promise.all( | ||
| conv.agentIds.map(async (id) => { | ||
| const a = await ctx.db.get(id); | ||
| return a ? { _id: a._id, name: a.name } : null; | ||
| }), |
There was a problem hiding this comment.
Enforce org scoping on joined agent records
Line 46-Line 50 fetch and return agent metadata by ID without verifying org ownership. This can leak cross-org agent names if a conversation contains foreign agentIds.
Suggested fix
const agents = await Promise.all(
conv.agentIds.map(async (id) => {
const a = await ctx.db.get(id);
- return a ? { _id: a._id, name: a.name } : null;
+ return a && a.orgId === orgId ? { _id: a._id, name: a.name } : null;
}),
);As per coding guidelines, "Every public Convex function must call getAuthContext(ctx) to extract userId/orgId for org-scoped access control."
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const agents = await Promise.all( | |
| conv.agentIds.map(async (id) => { | |
| const a = await ctx.db.get(id); | |
| return a ? { _id: a._id, name: a.name } : null; | |
| }), | |
| const agents = await Promise.all( | |
| conv.agentIds.map(async (id) => { | |
| const a = await ctx.db.get(id); | |
| return a && a.orgId === orgId ? { _id: a._id, name: a.name } : null; | |
| }), |
| const dataset = useQuery(api.crud.datasets.get, { id: datasetId }); | ||
| const { labelOverrides: kbLabelOverrides } = useKbBreadcrumb(kbId); | ||
|
|
||
| const browseQuestions = useQuery(api.crud.questions.byDataset, { datasetId }); |
There was a problem hiding this comment.
Enforce KB/dataset route consistency before rendering and delete actions.
Line 30 and Line 33 scope data by datasetId only, while navigation/context is derived from kbId. A mismatched /kb/[id]/.../[datasetId] URL can load (and then delete) a dataset outside the URL KB context.
Use a KB-scoped fetch/delete path (or explicitly guard that the fetched dataset belongs to kbId and redirect/not-found on mismatch).
Also applies to: 113-119
| const data = useQuery(api.experiments.results.getDetailForExperiment, { | ||
| experimentId: expId, | ||
| experimentId, | ||
| }); |
There was a problem hiding this comment.
Scope experiment detail to the URL KB context.
The detail query uses only experimentId, but the page shell/back routes are built from kbId. A mismatched /kb/[id]/evaluate/experiments/[expId] URL can render under the wrong KB context.
Use a KB-scoped detail endpoint (or verify experiment ownership against kbId and redirect/not-found on mismatch).
Also applies to: 82-85
| const [showCreateModal, setShowCreateModal] = useState(false); | ||
| const [selectedRunId, setSelectedRunId] = useState<Id<"experimentRuns"> | null>(null); | ||
|
|
There was a problem hiding this comment.
Preserve selected run from the runId URL param.
This page never initializes selectedRunId from ?runId=..., so returning from detail routes loses the prior run context and resets selection.
Initialize selectedRunId from URL query on first render so deep links/back links remain stable.
Also applies to: 25-54
| } catch (err) { | ||
| console.error("Failed to start indexing:", err); | ||
| } |
There was a problem hiding this comment.
Show indexing start failures to users instead of console-only logging.
If indexing fails to start, there’s no visible feedback in the page. Add an inline error or toast so retry behavior is clear.
| <Link | ||
| href={item.href} | ||
| title={item.label} | ||
| className={`w-8 h-8 flex items-center justify-center rounded transition-colors ${ | ||
| active | ||
| ? "bg-bg-surface text-accent" | ||
| : "text-text-muted hover:text-text hover:bg-bg-elevated" | ||
| }`} | ||
| > | ||
| {item.icon ?? <span className="text-[10px]">{item.label.charAt(0)}</span>} | ||
| </Link> |
There was a problem hiding this comment.
Add explicit accessible names for icon-only controls.
title is not a reliable accessible name. Add aria-label on collapsed icon links and the sidebar toggle button.
Suggested fix
- <Link
+ <Link
href={item.href}
title={item.label}
+ aria-label={item.label}
className={`w-8 h-8 flex items-center justify-center rounded transition-colors ${
active
? "bg-bg-surface text-accent"
: "text-text-muted hover:text-text hover:bg-bg-elevated"
}`}
>
@@
- <button
+ <button
onClick={toggle}
+ aria-label={collapsed ? "Expand sidebar" : "Collapse sidebar"}
className="ml-auto w-6 h-6 flex items-center justify-center rounded text-text-dim hover:text-text hover:bg-bg-elevated transition-colors shrink-0"
title={collapsed ? "Expand sidebar" : "Collapse sidebar"}
>Also applies to: 158-162
| <div className="fixed bottom-4 right-4 z-[70] max-w-md bg-bg-elevated border border-red-500/30 rounded-lg p-3 shadow-2xl animate-fade-in"> | ||
| <p className="text-xs text-red-400">{message}</p> | ||
| <button |
There was a problem hiding this comment.
Expose toast as an ARIA alert.
Error toasts should announce automatically to screen readers.
Suggested fix
- <div className="fixed bottom-4 right-4 z-[70] max-w-md bg-bg-elevated border border-red-500/30 rounded-lg p-3 shadow-2xl animate-fade-in">
+ <div
+ role="alert"
+ aria-live="assertive"
+ className="fixed bottom-4 right-4 z-[70] max-w-md bg-bg-elevated border border-red-500/30 rounded-lg p-3 shadow-2xl animate-fade-in"
+ >| <span className="inline-flex items-center gap-2 text-text-dim text-xs"> | ||
| <span | ||
| className={`${dim} border-2 border-accent/30 border-t-accent rounded-full animate-spin`} | ||
| /> | ||
| {label && <span>{label}</span>} | ||
| </span> |
There was a problem hiding this comment.
Provide screen-reader status semantics for loading.
When label is absent, assistive tech gets no loading cue.
Suggested fix
- <span className="inline-flex items-center gap-2 text-text-dim text-xs">
+ <span
+ role="status"
+ aria-live="polite"
+ className="inline-flex items-center gap-2 text-text-dim text-xs"
+ >
<span
className={`${dim} border-2 border-accent/30 border-t-accent rounded-full animate-spin`}
/>
{label && <span>{label}</span>}
+ {!label && <span className="sr-only">Loading</span>}
</span>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <span className="inline-flex items-center gap-2 text-text-dim text-xs"> | |
| <span | |
| className={`${dim} border-2 border-accent/30 border-t-accent rounded-full animate-spin`} | |
| /> | |
| {label && <span>{label}</span>} | |
| </span> | |
| <span | |
| role="status" | |
| aria-live="polite" | |
| className="inline-flex items-center gap-2 text-text-dim text-xs" | |
| > | |
| <span | |
| className={`${dim} border-2 border-accent/30 border-t-accent rounded-full animate-spin`} | |
| /> | |
| {label && <span>{label}</span>} | |
| {!label && <span className="sr-only">Loading</span>} | |
| </span> |
| <h2 className="text-lg font-semibold text-text mb-4">{title}</h2> | ||
| <div className="border-b border-border flex gap-1 mb-6"> | ||
| <main className="flex-1 min-h-0 max-w-7xl w-full mx-auto px-6 py-4 flex flex-col"> | ||
| <div className="border-b border-border flex gap-1 mb-4 flex-shrink-0"> |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In Tailwind CSS v4, is flex-shrink-0deprecated/removed in favor ofshrink-0?
💡 Result:
In Tailwind CSS v4, the class flex-shrink-0 has been superseded by shrink-0, and flex-shrink has been superseded by shrink [1]. While flex-shrink-0 is considered a legacy class and was marked as deprecated during the transition to v4 [1], Tailwind Labs added support back into the framework to ensure compatibility for existing projects [2]. However, the current official documentation for Tailwind CSS v4 now emphasizes the use of the shrink and shrink-0 utilities [3]. It is recommended to use the npx @tailwindcss/upgrade`` tool when migrating projects [4][5]. This official upgrade utility is designed to automatically identify and replace deprecated classes, such as flex-shrink-0, with their canonical equivalents (`shrink-0`) in your codebase [1][5].
Citations:
- 1: Migrate legacy classes to the v4 alternative tailwindlabs/tailwindcss#14643
- 2: https://github.com/tailwindlabs/tailwindcss/blob/f369e22172dcda93ee526696aacc3e974918db47/CHANGELOG.md
- 3: https://tailwindcss.com/docs/flex-shrink
- 4: https://tailwindcss.com/docs/upgrade-guide
- 5: https://www.digitalapplied.com/blog/tailwind-css-v4-2026-migration-best-practices
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="packages/frontend/src/components/shell/TabsLayout.tsx"
sed -n '30,50p' "$FILE"Repository: Tars-Technologies/cx-agent-evals
Length of output: 913
Update Tailwind v4 shrink utility class
In packages/frontend/src/components/shell/TabsLayout.tsx the flex-shrink-0 utility is the legacy name; Tailwind v4’s preferred equivalent is shrink-0. Change:
<div className="border-b border-border flex gap-1 mb-4 flex-shrink-0">to use shrink-0 instead.
| const href = | ||
| t.value === defaultValue | ||
| ? pathname | ||
| : `${pathname}?${paramName}=${t.value}`; |
There was a problem hiding this comment.
Preserve existing query params when building tab links.
Current tab links overwrite the full query string, so switching tabs can drop other URL state.
Suggested fix
{tabs.map((t) => {
const active = current === t.value;
- const href =
- t.value === defaultValue
- ? pathname
- : `${pathname}?${paramName}=${t.value}`;
+ const nextParams = new URLSearchParams(searchParams?.toString());
+ if (t.value === defaultValue) {
+ nextParams.delete(paramName);
+ } else {
+ nextParams.set(paramName, t.value);
+ }
+ const qs = nextParams.toString();
+ const href = qs ? `${pathname}?${qs}` : pathname;
return (3315de4
into
worktree-frontend-rehaul-umbrella-branch
Resolves shell/route conflicts from integrating the conversation and KB sections alongside the agent-eval work: - shell/sidebars.tsx: keep KB's top-level Retrievers route + drop the old evaluate/retrievers child (KB restructure); keep the agent sidebar's "Error analysis" entry + match() (replaces open/axial coding); drop the now-unused axial-coding icon. - shell/EntityDetailLayout.tsx: keep the agent branch's `embedded` prop + `inner` render pattern (superset; the file tail already depends on it). - conversations/transcripts/[id]/page.tsx: keep umbrella's redirect to the new /conversations?tab=transcripts view (the prior stub is obsolete). Also fixes a pre-existing type error carried in from the KB branch (kb/[id]/retrievers/page.tsx): retriever status is ready|indexing|error|configuring (no "pending"); compare against "configuring" so in-progress shows yellow and only error shows red. This was the real cause of #77's failing Vercel build. Frontend + backend typecheck clean; backend suite 304 pass (1 pre-existing unrelated knowledgeBases flake). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Section PR #2 of the frontend re-haul. Moves the legacy
/kb,/dataset,/retrievers,/retrievers/resultspages under the new/kb/<id>/configure,/kb/<id>/retrievers, and/kb/<id>/evaluate/{datasets,experiments}structure per the KB spec.Base:
worktree-frontend-rehaul-umbrella-branch— this PR depends on the umbrella shell (TopBar, EntityDetailLayout, Breadcrumbs, sidebars) merging first.Sidebar IA
Retrievers sit at the top level (peer to Evaluate), not inside it — they are production-inference primitives that experiments consume, not eval-only artifacts.
New routes
/kb(rewrite)/kblist portion/kb/[id]/configure/kbdocument master-detail/kb/[id]/retrievers/retrievers(create mode)/kb/[id]/retrievers/[rid]/retrieverstabs (Index/Query+Search/Refine/Playground)/kb/[id]/evaluate/datasets/kb/[id]/evaluate/datasets/dataset(questions only — conv-sim moves to Agents)/kb/[id]/evaluate/datasets/[datasetId]/kb/[id]/evaluate/experiments/retrievers(experiment mode)/kb/[id]/evaluate/experiments/[expId]/retrievers/results/[experimentId]KB id is now URL-driven.
KBDropdownanduseKbFromUrlare no longer used by these pages (they remain in the codebase for the still-untouched/experimentsand/evaluatorspages, which the Agents PR will remove).Shell additions
Lightweight helpers added under
components/shell/andlib/:Spinner— replaces ~10 inline copies of the dot-spinner JSX.ErrorToast— replaces the bottom-right red toast block.useKbBreadcrumb— single subscription + breadcrumb override map; replaces a duplicateduseQuery(api.crud.knowledgeBases.get, ...)in every KB sub-page.EntityDetailLayoutupgrades:fullWidthprop to bustmax-w-7xlfor content-heavy pages.h-screenflex shell so detail boxes fill the viewport instead of using brittlecalc(100vh - Xrem)heights.sidebars.tsx— adds icons for Configure/Retrievers/Datasets/Experiments (and Agent equivalents).Deleted
packages/frontend/src/app/dataset/(whole tree).packages/frontend/src/app/retrievers/(whole tree incl.results/[experimentId]).Intentionally not touched
app/experiments/andapp/experiments/[id]/— contain mixed agent+retriever experiment code; the Agents PR will delete them.app/evaluators/— Agents PR scope.Header.tsx/ModeSelector.tsx/KBDropdown.tsx/useKbFromUrl.ts— still imported by the untouched pages.Test plan
/kblanding shows all KBs for the current org; + New KB modal works./kb/<id>/configurewith breadcrumbKnowledge Base / <name> / Configure./kb/<id>/retrievers/<rid>works on fresh load./kb/<id>/evaluate→ redirects to/datasets.🤖 Generated with Claude Code