From 05c30c70a92cf76a5c10156dbdacf7529c19f5b4 Mon Sep 17 00:00:00 2001 From: Kaiohz Date: Sat, 11 Jul 2026 07:21:30 +0200 Subject: [PATCH 1/3] Improve accessibility, style, and code-splitting - Add skip link, ARIA roles/labels, and keyboard navigation - Lazy-load secondary routes with Suspense fallback - Extract shared SegmentedToggle component - Enhance focus rings, status badges, and breadcrumb semantics - Use proper ellipsis character and hide decorative icons --- src/application/App.tsx | 27 +- .../components/agent/AgentConfigForm.tsx | 580 +++++++++--------- .../components/agent/AgentConfigViewer.tsx | 417 +++++++------ .../components/agent/CreateAgentDialog.tsx | 153 +++-- .../components/agent/HITLEditor.tsx | 9 +- .../components/agent/KeyValueEditor.tsx | 9 +- .../components/agent/McpServerEditor.tsx | 9 +- .../components/agent/StringListEditor.tsx | 11 +- .../components/agent/SubAgentEditor.tsx | 11 +- .../components/chat/ChatMessage.tsx | 44 +- .../components/chat/MessageList.tsx | 41 +- .../components/layout/MainLayout.tsx | 24 +- .../components/layout/ThreadSidebar.tsx | 201 +++--- src/application/components/layout/TopNav.tsx | 90 ++- .../components/rag/BreadcrumbBar.tsx | 67 +- .../components/rag/FileContentPanel.tsx | 164 ++--- .../components/rag/IndexActionMenu.tsx | 151 ++++- .../components/rag/PipelineToggle.tsx | 52 +- src/application/components/rag/RagTabBar.tsx | 38 +- .../components/rag/WorkspaceSelector.tsx | 110 +++- .../components/shared/SegmentedToggle.tsx | 83 +++ .../components/shared/StatusBadge.tsx | 65 +- src/application/components/ui/accordion.tsx | 8 +- src/application/components/ui/button.tsx | 24 +- src/application/components/ui/dialog.tsx | 12 +- src/application/components/ui/input.tsx | 2 +- src/application/components/ui/select.tsx | 43 +- src/application/components/ui/textarea.tsx | 2 +- .../agent/AgentConfigViewer.test.tsx | 8 +- .../agent/CreateAgentDialog.test.tsx | 5 +- .../unit/components/chat/ChatMessage.test.tsx | 2 +- .../components/layout/ThreadSidebar.test.tsx | 4 +- .../components/rag/IndexActionMenu.test.tsx | 12 +- .../components/shared/StatusBadge.test.tsx | 10 +- 34 files changed, 1561 insertions(+), 927 deletions(-) create mode 100644 src/application/components/shared/SegmentedToggle.tsx diff --git a/src/application/App.tsx b/src/application/App.tsx index 12671ae..4801afa 100644 --- a/src/application/App.tsx +++ b/src/application/App.tsx @@ -1,7 +1,22 @@ +import { Suspense, lazy } from "react"; import { Routes, Route, Navigate } from "react-router-dom"; -import AgentsPage from "@/application/pages/AgentsPage"; import ChatPage from "@/application/pages/ChatPage"; -import RagPage from "@/application/pages/RagPage"; + +// Lazy-load secondary routes for code-splitting / smaller initial bundle. +const AgentsPage = lazy(() => import("@/application/pages/AgentsPage")); +const RagPage = lazy(() => import("@/application/pages/RagPage")); + +function PageFallback() { + return ( +
+

Loading…

+
+ ); +} function App() { return ( @@ -14,4 +29,10 @@ function App() { ); } -export default App; +export default function AppRoot() { + return ( + }> + + + ); +} \ No newline at end of file diff --git a/src/application/components/agent/AgentConfigForm.tsx b/src/application/components/agent/AgentConfigForm.tsx index bb24f65..8d77203 100644 --- a/src/application/components/agent/AgentConfigForm.tsx +++ b/src/application/components/agent/AgentConfigForm.tsx @@ -26,7 +26,6 @@ import { SelectTrigger, SelectValue, } from "@/application/components/ui/select"; -import { Separator } from "@/application/components/ui/separator"; import StringListEditor from "./StringListEditor"; import McpServerEditor from "./McpServerEditor"; import SubAgentEditor from "./SubAgentEditor"; @@ -35,17 +34,34 @@ import ResponseFormatEditor from "./ResponseFormatEditor"; // ─── Constants ────────────────────────────────────────────────────────────── -const ACCORDION_SECTIONS = [ - "general", - "system-prompt", - "tools-middleware", - "backend", - "hitl", - "memory-skills", - "mcp-servers", - "subagents", - "response-format", -] as const; +type SectionValue = + | "general" + | "system-prompt" + | "tools-middleware" + | "backend" + | "hitl" + | "memory-skills" + | "mcp-servers" + | "subagents" + | "response-format"; + +// Only essential sections are open by default, others can be revealed on demand. +const DEFAULT_OPEN_SECTIONS: SectionValue[] = ["general", "system-prompt"]; + +const SECTION_META: Record< + SectionValue, + { label: string; icon: string } +> = { + general: { label: "General", icon: "tune" }, + "system-prompt": { label: "System Prompt", icon: "description" }, + "tools-middleware": { label: "Tools & Middleware", icon: "build" }, + backend: { label: "Backend", icon: "storage" }, + hitl: { label: "HITL", icon: "verified_user" }, + "memory-skills": { label: "Memory & Skills", icon: "psychology" }, + "mcp-servers": { label: "MCP Servers", icon: "hub" }, + subagents: { label: "Subagents", icon: "group" }, + "response-format": { label: "Response Format", icon: "data_object" }, +}; const MIDDLEWARE_OPTIONS: { label: string; value: MiddlewareType }[] = [ { value: MiddlewareType.TODO_LIST, label: "todo_list" }, @@ -121,15 +137,18 @@ function cn(...classes: (string | false | undefined)[]): string { return classes.filter(Boolean).join(" "); } -function buildAccordionTriggerClass(active?: boolean): string { +function buildAccordionTriggerClass(): string { return cn( - "text-xs font-bold font-headline uppercase tracking-widest hover:no-underline", - active - ? "text-secondary-brand" - : "text-on-surface-variant", + "text-xs font-bold font-headline uppercase tracking-widest", + "text-on-surface hover:text-secondary-brand", + "data-[state=open]:text-secondary-brand", ); } +function showRootDir(type: BackendType): boolean { + return type === BackendType.FILESYSTEM || type === BackendType.COMPOSITE; +} + // ─── Props ────────────────────────────────────────────────────────────────── interface AgentConfigFormProps { @@ -142,6 +161,8 @@ interface AgentConfigFormProps { // ─── Component ──────────────────────────────────────────────────────────── +const FORM_ID = "agent-config-form"; + export default function AgentConfigForm({ mode, initialData, @@ -199,267 +220,251 @@ export default function AgentConfigForm({ } } - function renderSubmitLabel(): string { - if (isPending) return "Saving..."; - return mode === "create" ? "Create" : "Update"; - } - return (
-
-
- - {/* General */} - - - General - - - - - - - - -
- - setValue("debug", v)} - /> -
-
-
- - {/* System Prompt */} - - - System Prompt - - - -